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.commons.io.input; 18 19 import java.io.EOFException; 20 import java.io.IOException; 21 import java.io.Reader; 22 23 /** 24 * A functional, light weight {@link Reader} that emulates 25 * a reader of a specified size. 26 * <p> 27 * This implementation provides a light weight 28 * object for testing with an {@link Reader} 29 * where the contents don't matter. 30 * <p> 31 * One use case would be for testing the handling of 32 * large {@link Reader} as it can emulate that 33 * scenario without the overhead of actually processing 34 * large numbers of characters - significantly speeding up 35 * test execution times. 36 * <p> 37 * This implementation returns a space from the method that 38 * reads a character and leaves the array unchanged in the read 39 * methods that are passed a character array. 40 * If alternative data is required the <code>processChar()</code> and 41 * <code>processChars()</code> methods can be implemented to generate 42 * data, for example: 43 * 44 * <pre> 45 * public class TestReader extends NullReader { 46 * public TestReader(int size) { 47 * super(size); 48 * } 49 * protected char processChar() { 50 * return ... // return required value here 51 * } 52 * protected void processChars(char[] chars, int offset, int length) { 53 * for (int i = offset; i < length; i++) { 54 * chars[i] = ... // set array value here 55 * } 56 * } 57 * } 58 * </pre> 59 * 60 * @since Commons IO 1.3 61 * @version $Revision: 463529 $ 62 */ 63 public class NullReader extends Reader { 64 65 private long size; 66 private long position; 67 private long mark = -1; 68 private long readlimit; 69 private boolean eof; 70 private boolean throwEofException; 71 private boolean markSupported; 72 73 /** 74 * Create a {@link Reader} that emulates a specified size 75 * which supports marking and does not throw EOFException. 76 * 77 * @param size The size of the reader to emulate. 78 */ NullReader(long size)79 public NullReader(long size) { 80 this(size, true, false); 81 } 82 83 /** 84 * Create a {@link Reader} that emulates a specified 85 * size with option settings. 86 * 87 * @param size The size of the reader to emulate. 88 * @param markSupported Whether this instance will support 89 * the <code>mark()</code> functionality. 90 * @param throwEofException Whether this implementation 91 * will throw an {@link EOFException} or return -1 when the 92 * end of file is reached. 93 */ NullReader(long size, boolean markSupported, boolean throwEofException)94 public NullReader(long size, boolean markSupported, boolean throwEofException) { 95 this.size = size; 96 this.markSupported = markSupported; 97 this.throwEofException = throwEofException; 98 } 99 100 /** 101 * Return the current position. 102 * 103 * @return the current position. 104 */ getPosition()105 public long getPosition() { 106 return position; 107 } 108 109 /** 110 * Return the size this {@link Reader} emulates. 111 * 112 * @return The size of the reader to emulate. 113 */ getSize()114 public long getSize() { 115 return size; 116 } 117 118 /** 119 * Close this Reader - resets the internal state to 120 * the initial values. 121 * 122 * @throws IOException If an error occurs. 123 */ close()124 public void close() throws IOException { 125 eof = false; 126 position = 0; 127 mark = -1; 128 } 129 130 /** 131 * Mark the current position. 132 * 133 * @param readlimit The number of characters before this marked position 134 * is invalid. 135 * @throws UnsupportedOperationException if mark is not supported. 136 */ mark(int readlimit)137 public synchronized void mark(int readlimit) { 138 if (!markSupported) { 139 throw new UnsupportedOperationException("Mark not supported"); 140 } 141 mark = position; 142 this.readlimit = readlimit; 143 } 144 145 /** 146 * Indicates whether <i>mark</i> is supported. 147 * 148 * @return Whether <i>mark</i> is supported or not. 149 */ markSupported()150 public boolean markSupported() { 151 return markSupported; 152 } 153 154 /** 155 * Read a character. 156 * 157 * @return Either The character value returned by <code>processChar()</code> 158 * or <code>-1</code> if the end of file has been reached and 159 * <code>throwEofException</code> is set to <code>false</code>. 160 * @throws EOFException if the end of file is reached and 161 * <code>throwEofException</code> is set to <code>true</code>. 162 * @throws IOException if trying to read past the end of file. 163 */ read()164 public int read() throws IOException { 165 if (eof) { 166 throw new IOException("Read after end of file"); 167 } 168 if (position == size) { 169 return doEndOfFile(); 170 } 171 position++; 172 return processChar(); 173 } 174 175 /** 176 * Read some characters into the specified array. 177 * 178 * @param chars The character array to read into 179 * @return The number of characters read or <code>-1</code> 180 * if the end of file has been reached and 181 * <code>throwEofException</code> is set to <code>false</code>. 182 * @throws EOFException if the end of file is reached and 183 * <code>throwEofException</code> is set to <code>true</code>. 184 * @throws IOException if trying to read past the end of file. 185 */ read(char[] chars)186 public int read(char[] chars) throws IOException { 187 return read(chars, 0, chars.length); 188 } 189 190 /** 191 * Read the specified number characters into an array. 192 * 193 * @param chars The character array to read into. 194 * @param offset The offset to start reading characters into. 195 * @param length The number of characters to read. 196 * @return The number of characters read or <code>-1</code> 197 * if the end of file has been reached and 198 * <code>throwEofException</code> is set to <code>false</code>. 199 * @throws EOFException if the end of file is reached and 200 * <code>throwEofException</code> is set to <code>true</code>. 201 * @throws IOException if trying to read past the end of file. 202 */ read(char[] chars, int offset, int length)203 public int read(char[] chars, int offset, int length) throws IOException { 204 if (eof) { 205 throw new IOException("Read after end of file"); 206 } 207 if (position == size) { 208 return doEndOfFile(); 209 } 210 position += length; 211 int returnLength = length; 212 if (position > size) { 213 returnLength = length - (int)(position - size); 214 position = size; 215 } 216 processChars(chars, offset, returnLength); 217 return returnLength; 218 } 219 220 /** 221 * Reset the stream to the point when mark was last called. 222 * 223 * @throws UnsupportedOperationException if mark is not supported. 224 * @throws IOException If no position has been marked 225 * or the read limit has been exceed since the last position was 226 * marked. 227 */ reset()228 public synchronized void reset() throws IOException { 229 if (!markSupported) { 230 throw new UnsupportedOperationException("Mark not supported"); 231 } 232 if (mark < 0) { 233 throw new IOException("No position has been marked"); 234 } 235 if (position > (mark + readlimit)) { 236 throw new IOException("Marked position [" + mark + 237 "] is no longer valid - passed the read limit [" + 238 readlimit + "]"); 239 } 240 position = mark; 241 eof = false; 242 } 243 244 /** 245 * Skip a specified number of characters. 246 * 247 * @param numberOfChars The number of characters to skip. 248 * @return The number of characters skipped or <code>-1</code> 249 * if the end of file has been reached and 250 * <code>throwEofException</code> is set to <code>false</code>. 251 * @throws EOFException if the end of file is reached and 252 * <code>throwEofException</code> is set to <code>true</code>. 253 * @throws IOException if trying to read past the end of file. 254 */ skip(long numberOfChars)255 public long skip(long numberOfChars) throws IOException { 256 if (eof) { 257 throw new IOException("Skip after end of file"); 258 } 259 if (position == size) { 260 return doEndOfFile(); 261 } 262 position += numberOfChars; 263 long returnLength = numberOfChars; 264 if (position > size) { 265 returnLength = numberOfChars - (position - size); 266 position = size; 267 } 268 return returnLength; 269 } 270 271 /** 272 * Return a character value for the <code>read()</code> method. 273 * <p> 274 * This implementation returns zero. 275 * 276 * @return This implementation always returns zero. 277 */ processChar()278 protected int processChar() { 279 // do nothing - overridable by subclass 280 return 0; 281 } 282 283 /** 284 * Process the characters for the <code>read(char[], offset, length)</code> 285 * method. 286 * <p> 287 * This implementation leaves the character array unchanged. 288 * 289 * @param chars The character array 290 * @param offset The offset to start at. 291 * @param length The number of characters. 292 */ processChars(char[] chars, int offset, int length)293 protected void processChars(char[] chars, int offset, int length) { 294 // do nothing - overridable by subclass 295 } 296 297 /** 298 * Handle End of File. 299 * 300 * @return <code>-1</code> if <code>throwEofException</code> is 301 * set to <code>false</code> 302 * @throws EOFException if <code>throwEofException</code> is set 303 * to <code>true</code>. 304 */ doEndOfFile()305 private int doEndOfFile() throws EOFException { 306 eof = true; 307 if (throwEofException) { 308 throw new EOFException(); 309 } 310 return -1; 311 } 312 313 } 314