Frames | No Frames |
1: /* PushbackInputStream.java -- An input stream that can unread bytes 2: Copyright (C) 1998, 1999, 2001, 2002, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package java.io; 39: 40: /** 41: * This subclass of <code>FilterInputStream</code> provides the ability to 42: * unread data from a stream. It maintains an internal buffer of unread 43: * data that is supplied to the next read operation. This is conceptually 44: * similar to mark/reset functionality, except that in this case the 45: * position to reset the stream to does not need to be known in advance. 46: * <p> 47: * The default pushback buffer size one byte, but this can be overridden 48: * by the creator of the stream. 49: * <p> 50: * 51: * @author Aaron M. Renn (arenn@urbanophile.com) 52: * @author Warren Levy (warrenl@cygnus.com) 53: */ 54: public class PushbackInputStream extends FilterInputStream 55: { 56: /** 57: * This is the default buffer size 58: */ 59: private static final int DEFAULT_BUFFER_SIZE = 1; 60: 61: /** 62: * This is the buffer that is used to store the pushed back data 63: */ 64: protected byte[] buf; 65: 66: /** 67: * This is the position in the buffer from which the next byte will be 68: * read. Bytes are stored in reverse order in the buffer, starting from 69: * <code>buf[buf.length - 1]</code> to <code>buf[0]</code>. Thus when 70: * <code>pos</code> is 0 the buffer is full and <code>buf.length</code> when 71: * it is empty 72: */ 73: protected int pos; 74: 75: /** 76: * This method initializes a <code>PushbackInputStream</code> to 77: * read from the specified subordinate <code>InputStream</code> 78: * with a default pushback buffer size of 1. 79: * 80: * @param in The subordinate stream to read from 81: */ 82: public PushbackInputStream(InputStream in) 83: { 84: this(in, DEFAULT_BUFFER_SIZE); 85: } 86: 87: /** 88: * This method initializes a <code>PushbackInputStream</code> to 89: * read from the specified subordinate <code>InputStream</code> with 90: * the specified buffer size 91: * 92: * @param in The subordinate <code>InputStream</code> to read from 93: * @param size The pushback buffer size to use 94: */ 95: public PushbackInputStream(InputStream in, int size) 96: { 97: super(in); 98: if (size < 0) 99: throw new IllegalArgumentException(); 100: buf = new byte[size]; 101: pos = buf.length; 102: } 103: 104: /** 105: * This method returns the number of bytes that can be read from this 106: * stream before a read can block. A return of 0 indicates that blocking 107: * might (or might not) occur on the very next read attempt. 108: * <p> 109: * This method will return the number of bytes available from the 110: * pushback buffer plus the number of bytes available from the 111: * underlying stream. 112: * 113: * @return The number of bytes that can be read before blocking could occur 114: * 115: * @exception IOException If an error occurs 116: */ 117: public int available() throws IOException 118: { 119: try 120: { 121: return (buf.length - pos) + super.available(); 122: } 123: catch (NullPointerException npe) 124: { 125: throw new IOException ("Stream closed"); 126: } 127: } 128: 129: /** 130: * This method closes the stream and releases any associated resources. 131: * 132: * @exception IOException If an error occurs. 133: */ 134: public synchronized void close() throws IOException 135: { 136: buf = null; 137: super.close(); 138: } 139: 140: /** 141: * This method returns <code>false</code> to indicate that it does 142: * not support mark/reset functionality. 143: * 144: * @return This method returns <code>false</code> to indicate that 145: * this class does not support mark/reset functionality 146: */ 147: public boolean markSupported() 148: { 149: return false; 150: } 151: 152: /** 153: * This method always throws an IOException in this class because 154: * mark/reset functionality is not supported. 155: * 156: * @exception IOException Always thrown for this class 157: */ 158: public void reset() throws IOException 159: { 160: throw new IOException("Mark not supported in this class"); 161: } 162: 163: /** 164: * This method reads an unsigned byte from the input stream and returns it 165: * as an int in the range of 0-255. This method also will return -1 if 166: * the end of the stream has been reached. The byte returned will be read 167: * from the pushback buffer, unless the buffer is empty, in which case 168: * the byte will be read from the underlying stream. 169: * <p> 170: * This method will block until the byte can be read. 171: * 172: * @return The byte read or -1 if end of stream 173: * 174: * @exception IOException If an error occurs 175: */ 176: public synchronized int read() throws IOException 177: { 178: if (pos < buf.length) 179: return ((int) buf[pos++]) & 0xFF; 180: 181: return super.read(); 182: } 183: 184: /** 185: * This method read bytes from a stream and stores them into a 186: * caller supplied buffer. It starts storing the data at index 187: * <code>offset</code> into the buffer and attempts to read 188: * <code>len</code> bytes. This method can return before reading the 189: * number of bytes requested. The actual number of bytes read is 190: * returned as an int. A -1 is returned to indicate the end of the 191: * stream. 192: * <p> 193: * This method will block until some data can be read. 194: * <p> 195: * This method first reads bytes from the pushback buffer in order to 196: * satisfy the read request. If the pushback buffer cannot provide all 197: * of the bytes requested, the remaining bytes are read from the 198: * underlying stream. 199: * 200: * @param b The array into which the bytes read should be stored 201: * @param off The offset into the array to start storing bytes 202: * @param len The requested number of bytes to read 203: * 204: * @return The actual number of bytes read, or -1 if end of stream. 205: * 206: * @exception IOException If an error occurs. 207: */ 208: public synchronized int read(byte[] b, int off, int len) throws IOException 209: { 210: int numBytes = Math.min(buf.length - pos, len); 211: 212: if (numBytes > 0) 213: { 214: System.arraycopy (buf, pos, b, off, numBytes); 215: pos += numBytes; 216: len -= numBytes; 217: off += numBytes; 218: } 219: 220: if (len > 0) 221: { 222: len = super.read(b, off, len); 223: if (len == -1) //EOF 224: return numBytes > 0 ? numBytes : -1; 225: numBytes += len; 226: } 227: return numBytes; 228: } 229: 230: /** 231: * This method pushes a single byte of data into the pushback buffer. 232: * The byte pushed back is the one that will be returned as the first byte 233: * of the next read. 234: * <p> 235: * If the pushback buffer is full, this method throws an exception. 236: * <p> 237: * The argument to this method is an <code>int</code>. Only the low 238: * eight bits of this value are pushed back. 239: * 240: * @param b The byte to be pushed back, passed as an int 241: * 242: * @exception IOException If the pushback buffer is full. 243: */ 244: public synchronized void unread(int b) throws IOException 245: { 246: if (pos <= 0) 247: throw new IOException("Insufficient space in pushback buffer"); 248: 249: buf[--pos] = (byte) b; 250: } 251: 252: /** 253: * This method pushes all of the bytes in the passed byte array into 254: * the pushback bfer. These bytes are pushed in reverse order so that 255: * the next byte read from the stream after this operation will be 256: * <code>b[0]</code> followed by <code>b[1]</code>, etc. 257: * <p> 258: * If the pushback buffer cannot hold all of the requested bytes, an 259: * exception is thrown. 260: * 261: * @param b The byte array to be pushed back 262: * 263: * @exception IOException If the pushback buffer is full 264: */ 265: public synchronized void unread(byte[] b) throws IOException 266: { 267: unread(b, 0, b.length); 268: } 269: 270: /** 271: * This method pushed back bytes from the passed in array into the 272: * pushback buffer. The bytes from <code>b[offset]</code> to 273: * <code>b[offset + len]</code> are pushed in reverse order so that 274: * the next byte read from the stream after this operation will be 275: * <code>b[offset]</code> followed by <code>b[offset + 1]</code>, 276: * etc. 277: * <p> 278: * If the pushback buffer cannot hold all of the requested bytes, an 279: * exception is thrown. 280: * 281: * @param b The byte array to be pushed back 282: * @param off The index into the array where the bytes to be push start 283: * @param len The number of bytes to be pushed. 284: * 285: * @exception IOException If the pushback buffer is full 286: */ 287: public synchronized void unread(byte[] b, int off, int len) 288: throws IOException 289: { 290: if (pos < len) 291: throw new IOException("Insufficient space in pushback buffer"); 292: 293: // Note the order that these bytes are being added is the opposite 294: // of what would be done if they were added to the buffer one at a time. 295: // See the Java Class Libraries book p. 1390. 296: System.arraycopy(b, off, buf, pos - len, len); 297: 298: // Don't put this into the arraycopy above, an exception might be thrown 299: // and in that case we don't want to modify pos. 300: pos -= len; 301: } 302: 303: /** 304: * This method skips the specified number of bytes in the stream. It 305: * returns the actual number of bytes skipped, which may be less than the 306: * requested amount. 307: * <p> 308: * This method first discards bytes from the buffer, then calls the 309: * <code>skip</code> method on the underlying <code>InputStream</code> to 310: * skip additional bytes if necessary. 311: * 312: * @param n The requested number of bytes to skip 313: * 314: * @return The actual number of bytes skipped. 315: * 316: * @exception IOException If an error occurs 317: * 318: * @since 1.2 319: */ 320: public synchronized long skip(long n) throws IOException 321: { 322: final long origN = n; 323: 324: if (n > 0L) 325: { 326: int numread = (int) Math.min((long) (buf.length - pos), n); 327: pos += numread; 328: n -= numread; 329: if (n > 0) 330: n -= super.skip(n); 331: } 332: 333: return origN - n; 334: } 335: }