001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.io.input;
018:
019: import java.io.EOFException;
020: import java.io.IOException;
021: import java.io.InputStream;
022:
023: /**
024: * A functional, light weight {@link InputStream} that emulates
025: * a stream of a specified size.
026: * <p>
027: * This implementation provides a light weight
028: * object for testing with an {@link InputStream}
029: * where the contents don't matter.
030: * <p>
031: * One use case would be for testing the handling of
032: * large {@link InputStream} as it can emulate that
033: * scenario without the overhead of actually processing
034: * large numbers of bytes - significantly speeding up
035: * test execution times.
036: * <p>
037: * This implementation returns zero from the method that
038: * reads a byte and leaves the array unchanged in the read
039: * methods that are passed a byte array.
040: * If alternative data is required the <code>processByte()</code> and
041: * <code>processBytes()</code> methods can be implemented to generate
042: * data, for example:
043: *
044: * <pre>
045: * public class TestInputStream extends NullInputStream {
046: * public TestInputStream(int size) {
047: * super(size);
048: * }
049: * protected int processByte() {
050: * return ... // return required value here
051: * }
052: * protected void processBytes(byte[] bytes, int offset, int length) {
053: * for (int i = offset; i < length; i++) {
054: * bytes[i] = ... // set array value here
055: * }
056: * }
057: * }
058: * </pre>
059: *
060: * @since Commons IO 1.3
061: * @version $Revision: 463529 $
062: */
063: public class NullInputStream extends InputStream {
064:
065: private long size;
066: private long position;
067: private long mark = -1;
068: private long readlimit;
069: private boolean eof;
070: private boolean throwEofException;
071: private boolean markSupported;
072:
073: /**
074: * Create an {@link InputStream} that emulates a specified size
075: * which supports marking and does not throw EOFException.
076: *
077: * @param size The size of the input stream to emulate.
078: */
079: public NullInputStream(long size) {
080: this (size, true, false);
081: }
082:
083: /**
084: * Create an {@link InputStream} that emulates a specified
085: * size with option settings.
086: *
087: * @param size The size of the input stream to emulate.
088: * @param markSupported Whether this instance will support
089: * the <code>mark()</code> functionality.
090: * @param throwEofException Whether this implementation
091: * will throw an {@link EOFException} or return -1 when the
092: * end of file is reached.
093: */
094: public NullInputStream(long size, boolean markSupported,
095: boolean throwEofException) {
096: this .size = size;
097: this .markSupported = markSupported;
098: this .throwEofException = throwEofException;
099: }
100:
101: /**
102: * Return the current position.
103: *
104: * @return the current position.
105: */
106: public long getPosition() {
107: return position;
108: }
109:
110: /**
111: * Return the size this {@link InputStream} emulates.
112: *
113: * @return The size of the input stream to emulate.
114: */
115: public long getSize() {
116: return size;
117: }
118:
119: /**
120: * Return the number of bytes that can be read.
121: *
122: * @return The number of bytes that can be read.
123: */
124: public int available() {
125: long avail = size - position;
126: if (avail <= 0) {
127: return 0;
128: } else if (avail > Integer.MAX_VALUE) {
129: return Integer.MAX_VALUE;
130: } else {
131: return (int) avail;
132: }
133: }
134:
135: /**
136: * Close this input stream - resets the internal state to
137: * the initial values.
138: *
139: * @throws IOException If an error occurs.
140: */
141: public void close() throws IOException {
142: eof = false;
143: position = 0;
144: mark = -1;
145: }
146:
147: /**
148: * Mark the current position.
149: *
150: * @param readlimit The number of bytes before this marked position
151: * is invalid.
152: * @throws UnsupportedOperationException if mark is not supported.
153: */
154: public synchronized void mark(int readlimit) {
155: if (!markSupported) {
156: throw new UnsupportedOperationException(
157: "Mark not supported");
158: }
159: mark = position;
160: this .readlimit = readlimit;
161: }
162:
163: /**
164: * Indicates whether <i>mark</i> is supported.
165: *
166: * @return Whether <i>mark</i> is supported or not.
167: */
168: public boolean markSupported() {
169: return markSupported;
170: }
171:
172: /**
173: * Read a byte.
174: *
175: * @return Either The byte value returned by <code>processByte()</code>
176: * or <code>-1</code> if the end of file has been reached and
177: * <code>throwEofException</code> is set to <code>false</code>.
178: * @throws EOFException if the end of file is reached and
179: * <code>throwEofException</code> is set to <code>true</code>.
180: * @throws IOException if trying to read past the end of file.
181: */
182: public int read() throws IOException {
183: if (eof) {
184: throw new IOException("Read after end of file");
185: }
186: if (position == size) {
187: return doEndOfFile();
188: }
189: position++;
190: return processByte();
191: }
192:
193: /**
194: * Read some bytes into the specified array.
195: *
196: * @param bytes The byte array to read into
197: * @return The number of bytes read or <code>-1</code>
198: * if the end of file has been reached and
199: * <code>throwEofException</code> is set to <code>false</code>.
200: * @throws EOFException if the end of file is reached and
201: * <code>throwEofException</code> is set to <code>true</code>.
202: * @throws IOException if trying to read past the end of file.
203: */
204: public int read(byte[] bytes) throws IOException {
205: return read(bytes, 0, bytes.length);
206: }
207:
208: /**
209: * Read the specified number bytes into an array.
210: *
211: * @param bytes The byte array to read into.
212: * @param offset The offset to start reading bytes into.
213: * @param length The number of bytes to read.
214: * @return The number of bytes read or <code>-1</code>
215: * if the end of file has been reached and
216: * <code>throwEofException</code> is set to <code>false</code>.
217: * @throws EOFException if the end of file is reached and
218: * <code>throwEofException</code> is set to <code>true</code>.
219: * @throws IOException if trying to read past the end of file.
220: */
221: public int read(byte[] bytes, int offset, int length)
222: throws IOException {
223: if (eof) {
224: throw new IOException("Read after end of file");
225: }
226: if (position == size) {
227: return doEndOfFile();
228: }
229: position += length;
230: int returnLength = length;
231: if (position > size) {
232: returnLength = length - (int) (position - size);
233: position = size;
234: }
235: processBytes(bytes, offset, returnLength);
236: return returnLength;
237: }
238:
239: /**
240: * Reset the stream to the point when mark was last called.
241: *
242: * @throws UnsupportedOperationException if mark is not supported.
243: * @throws IOException If no position has been marked
244: * or the read limit has been exceed since the last position was
245: * marked.
246: */
247: public synchronized void reset() throws IOException {
248: if (!markSupported) {
249: throw new UnsupportedOperationException(
250: "Mark not supported");
251: }
252: if (mark < 0) {
253: throw new IOException("No position has been marked");
254: }
255: if (position > (mark + readlimit)) {
256: throw new IOException("Marked position [" + mark
257: + "] is no longer valid - passed the read limit ["
258: + readlimit + "]");
259: }
260: position = mark;
261: eof = false;
262: }
263:
264: /**
265: * Skip a specified number of bytes.
266: *
267: * @param numberOfBytes The number of bytes to skip.
268: * @return The number of bytes skipped or <code>-1</code>
269: * if the end of file has been reached and
270: * <code>throwEofException</code> is set to <code>false</code>.
271: * @throws EOFException if the end of file is reached and
272: * <code>throwEofException</code> is set to <code>true</code>.
273: * @throws IOException if trying to read past the end of file.
274: */
275: public long skip(long numberOfBytes) throws IOException {
276: if (eof) {
277: throw new IOException("Skip after end of file");
278: }
279: if (position == size) {
280: return doEndOfFile();
281: }
282: position += numberOfBytes;
283: long returnLength = numberOfBytes;
284: if (position > size) {
285: returnLength = numberOfBytes - (position - size);
286: position = size;
287: }
288: return returnLength;
289: }
290:
291: /**
292: * Return a byte value for the <code>read()</code> method.
293: * <p>
294: * This implementation returns zero.
295: *
296: * @return This implementation always returns zero.
297: */
298: protected int processByte() {
299: // do nothing - overridable by subclass
300: return 0;
301: }
302:
303: /**
304: * Process the bytes for the <code>read(byte[], offset, length)</code>
305: * method.
306: * <p>
307: * This implementation leaves the byte array unchanged.
308: *
309: * @param bytes The byte array
310: * @param offset The offset to start at.
311: * @param length The number of bytes.
312: */
313: protected void processBytes(byte[] bytes, int offset, int length) {
314: // do nothing - overridable by subclass
315: }
316:
317: /**
318: * Handle End of File.
319: *
320: * @return <code>-1</code> if <code>throwEofException</code> is
321: * set to <code>false</code>
322: * @throws EOFException if <code>throwEofException</code> is set
323: * to <code>true</code>.
324: */
325: private int doEndOfFile() throws EOFException {
326: eof = true;
327: if (throwEofException) {
328: throw new EOFException();
329: }
330: return -1;
331: }
332:
333: }
|