/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.image.io; import java.net.URLDecoder; import java.net.URL; import java.net.URI; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.FileOutputStream; import java.io.FileNotFoundException; import javax.imageio.spi.ImageReaderSpi; import org.geotools.resources.i18n.ErrorKeys; /** * Base class for image readers that require {@link File} input source. If the input source * is of other kind, then the content will be copied to a temporary file. This class is used * for image formats backed by some external API (typically C/C++ libraries) working only with * files. * * @since 2.4 * * @source $URL$ * @version $Id$ * @author Antoine Hnawia * @author Martin Desruisseaux (IRD) */ public abstract class FileImageReader extends StreamImageReader { /** * The file to read. This is the same reference than {@link #input} if the later was * already a {@link File} object, or a temporary file otherwise. */ private File inputFile; /** * {@code true} if {@link #inputFile} is a temporary file. */ private boolean isTemporary; /** * Constructs a new image reader. * * @param provider The {@link ImageReaderSpi} that is invoking this constructor, * or {@code null} if none. */ public FileImageReader(final ImageReaderSpi spi) { super(spi); } /** * Returns the encoding used for {@linkplain URL} {@linkplain #input input}. * The default implementation returns {@code "UTF-8"} in all cases. Subclasses * should override this method if {@link #getInputFile} should converts {@link URL} * to {@link File} objects using a different encoding. */ public String getURLEncoding() { return "UTF-8"; } /** * Ensures that the specified file can be read. * * @throws FileNotFoundException if the file is not found or can not be read. */ private void ensureFileExists(final File file) throws FileNotFoundException { if (!file.isFile() || !file.canRead()) { throw new FileNotFoundException(getErrorResources().getString( ErrorKeys.FILE_DOES_NOT_EXIST_$1, file)); } } /** * Returns the {@linkplain #input input} as a file. If the input is not a file, * then its content is copied to a temporary file and the temporary file is returned. * * @return The {@linkplain #input input} as a file. * @throws FileNotFoundException if the file is not found or can not be read. * @throws IOException if a copy was necessary but failed. */ protected File getInputFile() throws IOException { if (inputFile != null) { ensureFileExists(inputFile); return inputFile; } if (input instanceof String) { inputFile = new File((String) input); ensureFileExists(inputFile); return inputFile; } if (input instanceof File) { inputFile = (File) input; ensureFileExists(inputFile); return inputFile; } if (input instanceof URI) { final URI sourceURI = (URI) input; if (sourceURI.getScheme().equalsIgnoreCase("file")) { inputFile = new File(sourceURI.getPath()); ensureFileExists(inputFile); return inputFile; } } if (input instanceof URL) { final URL sourceURL = (URL) input; if (sourceURL.getProtocol().equalsIgnoreCase("file")) { inputFile = new File(URLDecoder.decode(sourceURL.getPath(), getURLEncoding())); ensureFileExists(inputFile); return inputFile; } } /* * Can not convert the input directly to a file. Asks the input stream * before to create the temporary file in case an exception is thrown. */ final InputStream in = getInputStream(); /* * Creates a temporary file using the first declared image suffix * (e.g. "png"), or "tmp" if there is no suffix declared. */ String suffix = "tmp"; if (originatingProvider != null) { final String[] suffixes = originatingProvider.getFileSuffixes(); if (suffixes != null && suffixes.length != 0) { // We assume that the first file suffix is the // most representative of this file format. suffix = suffixes[0]; } } inputFile = File.createTempFile("Image", suffix); inputFile.deleteOnExit(); isTemporary = true; /* * Copy the content of the specified input stream to the temporary file. * Note that there is no need to use instance of BufferedInputStream or * BufferedOutputStream since we already use a 8 kb buffer. */ final OutputStream out = new FileOutputStream(inputFile); final byte[] buffer = new byte[8192]; int length; while ((length=in.read(buffer)) >= 0) { out.write(buffer, 0, length); } in.close(); out.close(); return inputFile; } /** * Returns {@code true} if the file given by {@link #getInputFile} is a temporary file. */ protected boolean isTemporaryFile() { return isTemporary; } /** * Returns {@code true} since image readers backed by {@link File} * object usually supports random access efficiently. */ @Override public boolean isRandomAccessEasy(final int imageIndex) throws IOException { return true; } /** * Deletes the temporary file, if any. */ @Override protected void close() throws IOException { if (inputFile != null) { if (isTemporary) { inputFile.delete(); } inputFile = null; } isTemporary = false; super.close(); } }