1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.tika.io; 18 19 import java.io.EOFException; 20 import java.io.IOException; 21 import java.io.InputStream; 22 23 /** 24 * A functional, light weight {@link InputStream} that emulates 25 * a stream of a specified size. 26 * <p> 27 * This implementation provides a light weight 28 * object for testing with an {@link InputStream} 29 * where the contents don't matter. 30 * <p> 31 * One use case would be for testing the handling of 32 * large {@link InputStream} as it can emulate that 33 * scenario without the overhead of actually processing 34 * large numbers of bytes - significantly speeding up 35 * test execution times. 36 * <p> 37 * This implementation returns zero from the method that 38 * reads a byte and leaves the array unchanged in the read 39 * methods that are passed a byte array. 40 * If alternative data is required the <code>processByte()</code> and 41 * <code>processBytes()</code> methods can be implemented to generate 42 * data, for example: 43 * 44 * <pre> 45 * public class TestInputStream extends NullInputStream { 46 * public TestInputStream(int size) { 47 * super(size); 48 * } 49 * protected int processByte() { 50 * return ... // return required value here 51 * } 52 * protected void processBytes(byte[] bytes, int offset, int length) { 53 * for (int i = offset; i < length; i++) { 54 * bytes[i] = ... // set array value here 55 * } 56 * } 57 * } 58 * </pre> 59 * 60 * @since Apache Tika 0.4, copied from Commons IO 1.4 61 */ 62 public class NullInputStream extends InputStream { 63 64 private final long size; 65 private long position; 66 private long mark = -1; 67 private long readlimit; 68 private boolean eof; 69 private final boolean throwEofException; 70 private final boolean markSupported; 71 72 /** 73 * Create an {@link InputStream} that emulates a specified size 74 * which supports marking and does not throw EOFException. 75 * 76 * @param size The size of the input stream to emulate. 77 */ 78 public NullInputStream(long size) { 79 this(size, true, false); 80 } 81 82 /** 83 * Create an {@link InputStream} that emulates a specified 84 * size with option settings. 85 * 86 * @param size The size of the input stream to emulate. 87 * @param markSupported Whether this instance will support 88 * the <code>mark()</code> functionality. 89 * @param throwEofException Whether this implementation 90 * will throw an {@link EOFException} or return -1 when the 91 * end of file is reached. 92 */ 93 public NullInputStream(long size, boolean markSupported, boolean throwEofException) { 94 this.size = size; 95 this.markSupported = markSupported; 96 this.throwEofException = throwEofException; 97 } 98 99 /** 100 * Return the current position. 101 * 102 * @return the current position. 103 */ 104 public long getPosition() { 105 return position; 106 } 107 108 /** 109 * Return the size this {@link InputStream} emulates. 110 * 111 * @return The size of the input stream to emulate. 112 */ 113 public long getSize() { 114 return size; 115 } 116 117 /** 118 * Return the number of bytes that can be read. 119 * 120 * @return The number of bytes that can be read. 121 */ 122 @Override 123 public int available() { 124 long avail = size - position; 125 if (avail <= 0) { 126 return 0; 127 } else if (avail > Integer.MAX_VALUE) { 128 return Integer.MAX_VALUE; 129 } else { 130 return (int)avail; 131 } 132 } 133 134 /** 135 * Close this input stream - resets the internal state to 136 * the initial values. 137 * 138 * @throws IOException If an error occurs. 139 */ 140 @Override 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 @Override 155 public synchronized void mark(int readlimit) { 156 if (!markSupported) { 157 throw new UnsupportedOperationException("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 @Override 169 public boolean markSupported() { 170 return markSupported; 171 } 172 173 /** 174 * Read a byte. 175 * 176 * @return Either The byte value returned by <code>processByte()</code> 177 * or <code>-1</code> if the end of file has been reached and 178 * <code>throwEofException</code> is set to <code>false</code>. 179 * @throws EOFException if the end of file is reached and 180 * <code>throwEofException</code> is set to <code>true</code>. 181 * @throws IOException if trying to read past the end of file. 182 */ 183 @Override 184 public int read() throws IOException { 185 if (eof) { 186 throw new IOException("Read after end of file"); 187 } 188 if (position == size) { 189 return doEndOfFile(); 190 } 191 position++; 192 return processByte(); 193 } 194 195 /** 196 * Read some bytes into the specified array. 197 * 198 * @param bytes The byte array to read into 199 * @return The number of bytes read or <code>-1</code> 200 * if the end of file has been reached and 201 * <code>throwEofException</code> is set to <code>false</code>. 202 * @throws EOFException if the end of file is reached and 203 * <code>throwEofException</code> is set to <code>true</code>. 204 * @throws IOException if trying to read past the end of file. 205 */ 206 @Override 207 public int read(byte[] bytes) throws IOException { 208 return read(bytes, 0, bytes.length); 209 } 210 211 /** 212 * Read the specified number bytes into an array. 213 * 214 * @param bytes The byte array to read into. 215 * @param offset The offset to start reading bytes into. 216 * @param length The number of bytes to read. 217 * @return The number of bytes read or <code>-1</code> 218 * if the end of file has been reached and 219 * <code>throwEofException</code> is set to <code>false</code>. 220 * @throws EOFException if the end of file is reached and 221 * <code>throwEofException</code> is set to <code>true</code>. 222 * @throws IOException if trying to read past the end of file. 223 */ 224 @Override 225 public int read(byte[] bytes, int offset, int length) throws IOException { 226 if (eof) { 227 throw new IOException("Read after end of file"); 228 } 229 if (position == size) { 230 return doEndOfFile(); 231 } 232 position += length; 233 int returnLength = length; 234 if (position > size) { 235 returnLength = length - (int)(position - size); 236 position = size; 237 } 238 processBytes(bytes, offset, returnLength); 239 return returnLength; 240 } 241 242 /** 243 * Reset the stream to the point when mark was last called. 244 * 245 * @throws UnsupportedOperationException if mark is not supported. 246 * @throws IOException If no position has been marked 247 * or the read limit has been exceed since the last position was 248 * marked. 249 */ 250 @Override 251 public synchronized void reset() throws IOException { 252 if (!markSupported) { 253 throw new UnsupportedOperationException("Mark not supported"); 254 } 255 if (mark < 0) { 256 throw new IOException("No position has been marked"); 257 } 258 if (position > (mark + readlimit)) { 259 throw new IOException("Marked position [" + mark + 260 "] is no longer valid - passed the read limit [" + 261 readlimit + "]"); 262 } 263 position = mark; 264 eof = false; 265 } 266 267 /** 268 * Skip a specified number of bytes. 269 * 270 * @param numberOfBytes The number of bytes to skip. 271 * @return The number of bytes skipped or <code>-1</code> 272 * if the end of file has been reached and 273 * <code>throwEofException</code> is set to <code>false</code>. 274 * @throws EOFException if the end of file is reached and 275 * <code>throwEofException</code> is set to <code>true</code>. 276 * @throws IOException if trying to read past the end of file. 277 */ 278 @Override 279 public long skip(long numberOfBytes) throws IOException { 280 if (eof) { 281 throw new IOException("Skip after end of file"); 282 } 283 if (position == size) { 284 return doEndOfFile(); 285 } 286 position += numberOfBytes; 287 long returnLength = numberOfBytes; 288 if (position > size) { 289 returnLength = numberOfBytes - (position - size); 290 position = size; 291 } 292 return returnLength; 293 } 294 295 /** 296 * Return a byte value for the <code>read()</code> method. 297 * <p> 298 * This implementation returns zero. 299 * 300 * @return This implementation always returns zero. 301 */ 302 protected int processByte() { 303 // do nothing - overridable by subclass 304 return 0; 305 } 306 307 /** 308 * Process the bytes for the <code>read(byte[], offset, length)</code> 309 * method. 310 * <p> 311 * This implementation leaves the byte array unchanged. 312 * 313 * @param bytes The byte array 314 * @param offset The offset to start at. 315 * @param length The number of bytes. 316 */ 317 protected void processBytes(byte[] bytes, int offset, int length) { 318 // do nothing - overridable by subclass 319 } 320 321 /** 322 * Handle End of File. 323 * 324 * @return <code>-1</code> if <code>throwEofException</code> is 325 * set to <code>false</code> 326 * @throws EOFException if <code>throwEofException</code> is set 327 * to <code>true</code>. 328 */ 329 private int doEndOfFile() throws EOFException { 330 eof = true; 331 if (throwEofException) { 332 throw new EOFException(); 333 } 334 return -1; 335 } 336 337 }