001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2001, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.image.io.text;
018:
019: // J2SE dependencies
020: import java.awt.image.BufferedImage;
021: import java.io.*; // Many imports, including some for javadoc only.
022: import java.text.ParseException;
023: import javax.imageio.ImageReadParam;
024:
025: // Geotools dependencies
026: import org.geotools.io.LineFormat;
027: import org.geotools.resources.XArray;
028:
029: /**
030: * A dummy implementation of {@link TextImageReader} used only by default implementation
031: * of {@link TextImageReader.Spi#canDecodeInput}. This class is more lightweight than
032: * loading the real image reader implementation.
033: *
034: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/coverageio/src/main/java/org/geotools/image/io/text/TestReader.java $
035: * @version $Id: TestReader.java 26576 2007-08-16 18:37:13Z desruisseaux $
036: * @author Martin Desruisseaux
037: */
038: final class TestReader extends TextImageReader {
039: /**
040: * The input stream to {@linkplain InputStream#reset reset} after
041: * {@linkplain InputStream#mark mark}.
042: */
043: private InputStream marked;
044:
045: /**
046: * Creates a new reader for the specified provider.
047: */
048: public TestReader(final TextImageReader.Spi provider) {
049: super (provider);
050: }
051:
052: /**
053: * Returns a null width.
054: */
055: public int getWidth(int imageIndex) {
056: return 0;
057: }
058:
059: /**
060: * Returns a null height.
061: */
062: public int getHeight(int imageIndex) {
063: return 0;
064: }
065:
066: /**
067: * Throws an {@link UnsupportedOperationException}.
068: */
069: public BufferedImage read(final int imageIndex,
070: final ImageReadParam param) {
071: throw new UnsupportedOperationException();
072: }
073:
074: /**
075: * Returns the {@linkplain #input input} as a {@linkplain Reader reader}, which doesn't need to
076: * be {@linkplain BufferedReader buffered}. If the reader is an instance supplied explicitly by
077: * the user, then it will be {@linkplain Reader#mark marked} with the specified read ahead limit.
078: *
079: * @return {@link #getInput} as a {@link Reader}, or {@code null} if this method
080: * can't provide a reader suitable for {@code canDecode}.
081: * @throws IllegalStateException if the {@linkplain #input input} is not set.
082: * @throws IOException If the input stream can't be created for an other reason.
083: */
084: private Reader getReader(final int readAheadLimit)
085: throws IllegalStateException, IOException {
086: final Object input = getInput();
087: if (input instanceof Reader) {
088: final Reader reader = (Reader) input;
089: if (!reader.markSupported()) {
090: return null;
091: }
092: reader.mark(readAheadLimit);
093: return reader;
094: // Do not set 'closeOnReset' since we don't own the reader.
095: }
096: final InputStream stream = getInputStream();
097: if (closeOnReset == null) {
098: // If we are not allowed to close and reopen a new stream on ImageReader.read, then
099: // we must be able to mark the stream otherwise we will not support canDecode(...).
100: if (!stream.markSupported()) {
101: return null;
102: }
103: stream.mark(readAheadLimit);
104: }
105: final Reader reader = getInputStreamReader(stream);
106: if (closeOnReset == stream) {
107: closeOnReset = reader;
108: }
109: return reader;
110: }
111:
112: /**
113: * Checks if the {@linkplain #getReader reader} seems to contains a readeable ASCII file.
114: * This method tries to read the first few lines. The caller is responsable for invoking
115: * {@link #close} after this method.
116: *
117: * @param readAheadLimit Maximum number of characters to read. If this amount is reached
118: * but this method still unable to make a choice, then it returns {@code null}.
119: * @return {@code true} if the source <em>seems</em> readable, {@code false} otherwise.
120: * @throws IOException If an error occured during reading.
121: */
122: final boolean canDecode(final int readAheadLimit)
123: throws IOException {
124: final Reader input = getReader(readAheadLimit);
125: if (input == null) {
126: return false;
127: }
128: final TextImageReader.Spi spi = (TextImageReader.Spi) originatingProvider;
129: final char[] buffer = new char[readAheadLimit];
130: final int length = input.read(buffer);
131: final LineFormat parser = getLineFormat(0);
132: double[][] rows = new double[16][];
133: int rowCount = 0;
134: int lower = 0;
135: scan: while (lower < readAheadLimit) {
136: // Skip line feeds at the begining of the line.
137: // They may be a rest from the previous line.
138: char c = buffer[lower];
139: if (c == '\r' || c == 'n') {
140: lower++;
141: continue;
142: }
143: // Search the end of line. If we reach the end of the buffer,
144: // do not attempt to parse that last line since it is incomplete.
145: int upper = lower;
146: while ((c = buffer[upper]) != '\r' && c != '\n') {
147: if (++upper >= readAheadLimit) {
148: break scan;
149: }
150: }
151: // Try to parse a line.
152: final String line = new String(buffer, lower, upper - lower);
153: if (!isComment(line)) {
154: try {
155: if (parser.setLine(line) != 0) {
156: if (rowCount == rows.length) {
157: rows = (double[][]) XArray.resize(rows,
158: rows.length * 2);
159: }
160: rows[rowCount] = parser
161: .getValues(rows[rowCount]);
162: rowCount++;
163: }
164: } catch (ParseException exception) {
165: return false;
166: }
167: }
168: lower = upper;
169: }
170: if (originatingProvider instanceof TextImageReader.Spi) {
171: rows = (double[][]) XArray.resize(rows, rowCount);
172: return ((TextImageReader.Spi) originatingProvider)
173: .isValidContent(rows);
174: }
175: return true;
176: }
177:
178: /**
179: * Closes the reader created by this class, or {@linkplain Reader#reset reset} the
180: * user's reader to its original position.
181: */
182: //@Override
183: protected void close() throws IOException {
184: if (marked != null) {
185: marked.reset();
186: marked = null;
187: }
188: super.close();
189: }
190: }
|