001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2006, Institut de Recherche pour le D�veloppement
006: * (C) 2006, Geomatys
007: *
008: * This library is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Lesser General Public
010: * License as published by the Free Software Foundation;
011: * version 2.1 of the License.
012: *
013: * This library is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * Lesser General Public License for more details.
017: */
018: package org.geotools.image.io;
019:
020: import java.net.URLDecoder;
021: import java.net.URL;
022: import java.net.URI;
023: import java.io.File;
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.io.OutputStream;
027: import java.io.FileOutputStream;
028: import java.io.FileNotFoundException;
029: import javax.imageio.spi.ImageReaderSpi;
030: import org.geotools.resources.i18n.ErrorKeys;
031:
032: /**
033: * Base class for image readers that require {@link File} input source. If the input source
034: * is of other kind, then the content will be copied to a temporary file. This class is used
035: * for image formats backed by some external API (typically C/C++ libraries) working only with
036: * files.
037: *
038: * @since 2.4
039: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/coverageio/src/main/java/org/geotools/image/io/FileImageReader.java $
040: * @version $Id: FileImageReader.java 27908 2007-11-15 16:29:28Z desruisseaux $
041: * @author Antoine Hnawia
042: * @author Martin Desruisseaux
043: */
044: public abstract class FileImageReader extends StreamImageReader {
045: /**
046: * The file to read. This is the same reference than {@link #input} if the later was
047: * already a {@link File} object, or a temporary file otherwise.
048: */
049: private File inputFile;
050:
051: /**
052: * {@code true} if {@link #inputFile} is a temporary file.
053: */
054: private boolean isTemporary;
055:
056: /**
057: * Constructs a new image reader.
058: *
059: * @param provider The {@link ImageReaderSpi} that is invoking this constructor,
060: * or {@code null} if none.
061: */
062: public FileImageReader(final ImageReaderSpi spi) {
063: super (spi);
064: }
065:
066: /**
067: * Returns the encoding used for {@linkplain URL} {@linkplain #input input}.
068: * The default implementation returns {@code "UTF-8"} in all cases. Subclasses
069: * should override this method if {@link #getInputFile} should converts {@link URL}
070: * to {@link File} objects using a different encoding.
071: */
072: public String getURLEncoding() {
073: return "UTF-8";
074: }
075:
076: /**
077: * Ensures that the specified file can be read.
078: *
079: * @throws FileNotFoundException if the file is not found or can not be read.
080: */
081: private void ensureFileExists(final File file)
082: throws FileNotFoundException {
083: if (!file.isFile() || !file.canRead()) {
084: throw new FileNotFoundException(getErrorResources()
085: .getString(ErrorKeys.FILE_DOES_NOT_EXIST_$1, file));
086: }
087: }
088:
089: /**
090: * Returns the {@linkplain #input input} as a file. If the input is not a file,
091: * then its content is copied to a temporary file and the temporary file is returned.
092: *
093: * @return The {@linkplain #input input} as a file.
094: * @throws FileNotFoundException if the file is not found or can not be read.
095: * @throws IOException if a copy was necessary but failed.
096: */
097: protected File getInputFile() throws IOException {
098: if (inputFile != null) {
099: ensureFileExists(inputFile);
100: return inputFile;
101: }
102: if (input instanceof String) {
103: inputFile = new File((String) input);
104: ensureFileExists(inputFile);
105: return inputFile;
106: }
107: if (input instanceof File) {
108: inputFile = (File) input;
109: ensureFileExists(inputFile);
110: return inputFile;
111: }
112: if (input instanceof URI) {
113: final URI sourceURI = (URI) input;
114: if (sourceURI.getScheme().equalsIgnoreCase("file")) {
115: inputFile = new File(sourceURI.getPath());
116: ensureFileExists(inputFile);
117: return inputFile;
118: }
119: }
120: if (input instanceof URL) {
121: final URL sourceURL = (URL) input;
122: if (sourceURL.getProtocol().equalsIgnoreCase("file")) {
123: inputFile = new File(URLDecoder.decode(sourceURL
124: .getPath(), getURLEncoding()));
125: ensureFileExists(inputFile);
126: return inputFile;
127: }
128: }
129: /*
130: * Can not convert the input directly to a file. Asks the input stream
131: * before to create the temporary file in case an exception is thrown.
132: */
133: final InputStream in = getInputStream();
134: /*
135: * Creates a temporary file using the first declared image suffix
136: * (e.g. "png"), or "tmp" if there is no suffix declared.
137: */
138: String suffix = "tmp";
139: if (originatingProvider != null) {
140: final String[] suffixes = originatingProvider
141: .getFileSuffixes();
142: if (suffixes != null && suffixes.length != 0) {
143: // We assume that the first file suffix is the
144: // most representative of this file format.
145: suffix = suffixes[0];
146: }
147: }
148: inputFile = File.createTempFile("Image", suffix);
149: inputFile.deleteOnExit();
150: isTemporary = true;
151: /*
152: * Copy the content of the specified input stream to the temporary file.
153: * Note that there is no need to use instance of BufferedInputStream or
154: * BufferedOutputStream since we already use a 8 kb buffer.
155: */
156: final OutputStream out = new FileOutputStream(inputFile);
157: final byte[] buffer = new byte[8192];
158: int length;
159: while ((length = in.read(buffer)) >= 0) {
160: out.write(buffer, 0, length);
161: }
162: in.close();
163: out.close();
164: return inputFile;
165: }
166:
167: /**
168: * Returns {@code true} if the file given by {@link #getInputFile} is a temporary file.
169: */
170: protected boolean isTemporaryFile() {
171: return isTemporary;
172: }
173:
174: /**
175: * Returns {@code true} since image readers backed by {@link File}
176: * object usually supports random access efficiently.
177: */
178: //@Override
179: public boolean isRandomAccessEasy(final int imageIndex)
180: throws IOException {
181: return true;
182: }
183:
184: /**
185: * Deletes the temporary file, if any.
186: */
187: //@Override
188: protected void close() throws IOException {
189: if (inputFile != null) {
190: if (isTemporary) {
191: inputFile.delete();
192: }
193: inputFile = null;
194: }
195: isTemporary = false;
196: super.close();
197: }
198: }
|