GNU Classpath (0.17) | ||
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: return (buf.length - pos) + super.available(); 120: } 121: 122: /** 123: * This method closes the stream and releases any associated resources. 124: * 125: * @exception IOException If an error occurs. 126: */ 127: public synchronized void close() throws IOException 128: { 129: buf = null; 130: super.close(); 131: } 132: 133: /** 134: * This method returns <code>false</code> to indicate that it does 135: * not support mark/reset functionality. 136: * 137: * @return This method returns <code>false</code> to indicate that 138: * this class does not support mark/reset functionality 139: */ 140: public boolean markSupported() 141: { 142: return false; 143: } 144: 145: /** 146: * This method always throws an IOException in this class because 147: * mark/reset functionality is not supported. 148: * 149: * @exception IOException Always thrown for this class 150: */ 151: public void reset() throws IOException 152: { 153: throw new IOException("Mark not supported in this class"); 154: } 155: 156: /** 157: * This method reads an unsigned byte from the input stream and returns it 158: * as an int in the range of 0-255. This method also will return -1 if 159: * the end of the stream has been reached. The byte returned will be read 160: * from the pushback buffer, unless the buffer is empty, in which case 161: * the byte will be read from the underlying stream. 162: * <p> 163: * This method will block until the byte can be read. 164: * 165: * @return The byte read or -1 if end of stream 166: * 167: * @exception IOException If an error occurs 168: */ 169: public synchronized int read() throws IOException 170: { 171: if (pos < buf.length) 172: return ((int) buf[pos++]) & 0xFF; 173: 174: return super.read(); 175: } 176: 177: /** 178: * This method read bytes from a stream and stores them into a 179: * caller supplied buffer. It starts storing the data at index 180: * <code>offset</code> into the buffer and attempts to read 181: * <code>len</code> bytes. This method can return before reading the 182: * number of bytes requested. The actual number of bytes read is 183: * returned as an int. A -1 is returned to indicate the end of the 184: * stream. 185: * <p> 186: * This method will block until some data can be read. 187: * <p> 188: * This method first reads bytes from the pushback buffer in order to 189: * satisfy the read request. If the pushback buffer cannot provide all 190: * of the bytes requested, the remaining bytes are read from the 191: * underlying stream. 192: * 193: * @param b The array into which the bytes read should be stored 194: * @param off The offset into the array to start storing bytes 195: * @param len The requested number of bytes to read 196: * 197: * @return The actual number of bytes read, or -1 if end of stream. 198: * 199: * @exception IOException If an error occurs. 200: */ 201: public synchronized int read(byte[] b, int off, int len) throws IOException 202: { 203: int numBytes = Math.min(buf.length - pos, len); 204: 205: if (numBytes > 0) 206: { 207: System.arraycopy (buf, pos, b, off, numBytes); 208: pos += numBytes; 209: len -= numBytes; 210: off += numBytes; 211: } 212: 213: if (len > 0) 214: { 215: len = super.read(b, off, len); 216: if (len == -1) //EOF 217: return numBytes > 0 ? numBytes : -1; 218: numBytes += len; 219: } 220: return numBytes; 221: } 222: 223: /** 224: * This method pushes a single byte of data into the pushback buffer. 225: * The byte pushed back is the one that will be returned as the first byte 226: * of the next read. 227: * <p> 228: * If the pushback buffer is full, this method throws an exception. 229: * <p> 230: * The argument to this method is an <code>int</code>. Only the low 231: * eight bits of this value are pushed back. 232: * 233: * @param b The byte to be pushed back, passed as an int 234: * 235: * @exception IOException If the pushback buffer is full. 236: */ 237: public synchronized void unread(int b) throws IOException 238: { 239: if (pos <= 0) 240: throw new IOException("Insufficient space in pushback buffer"); 241: 242: buf[--pos] = (byte) b; 243: } 244: 245: /** 246: * This method pushes all of the bytes in the passed byte array into 247: * the pushback bfer. These bytes are pushed in reverse order so that 248: * the next byte read from the stream after this operation will be 249: * <code>b[0]</code> followed by <code>b[1]</code>, etc. 250: * <p> 251: * If the pushback buffer cannot hold all of the requested bytes, an 252: * exception is thrown. 253: * 254: * @param b The byte array to be pushed back 255: * 256: * @exception IOException If the pushback buffer is full 257: */ 258: public synchronized void unread(byte[] b) throws IOException 259: { 260: unread(b, 0, b.length); 261: } 262: 263: /** 264: * This method pushed back bytes from the passed in array into the 265: * pushback buffer. The bytes from <code>b[offset]</code> to 266: * <code>b[offset + len]</code> are pushed in reverse order so that 267: * the next byte read from the stream after this operation will be 268: * <code>b[offset]</code> followed by <code>b[offset + 1]</code>, 269: * etc. 270: * <p> 271: * If the pushback buffer cannot hold all of the requested bytes, an 272: * exception is thrown. 273: * 274: * @param b The byte array to be pushed back 275: * @param off The index into the array where the bytes to be push start 276: * @param len The number of bytes to be pushed. 277: * 278: * @exception IOException If the pushback buffer is full 279: */ 280: public synchronized void unread(byte[] b, int off, int len) 281: throws IOException 282: { 283: if (pos < len) 284: throw new IOException("Insufficient space in pushback buffer"); 285: 286: // Note the order that these bytes are being added is the opposite 287: // of what would be done if they were added to the buffer one at a time. 288: // See the Java Class Libraries book p. 1390. 289: System.arraycopy(b, off, buf, pos - len, len); 290: 291: // Don't put this into the arraycopy above, an exception might be thrown 292: // and in that case we don't want to modify pos. 293: pos -= len; 294: } 295: 296: /** 297: * This method skips the specified number of bytes in the stream. It 298: * returns the actual number of bytes skipped, which may be less than the 299: * requested amount. 300: * <p> 301: * This method first discards bytes from the buffer, then calls the 302: * <code>skip</code> method on the underlying <code>InputStream</code> to 303: * skip additional bytes if necessary. 304: * 305: * @param n The requested number of bytes to skip 306: * 307: * @return The actual number of bytes skipped. 308: * 309: * @exception IOException If an error occurs 310: * 311: * @since 1.2 312: */ 313: public synchronized long skip(long n) throws IOException 314: { 315: final long origN = n; 316: 317: if (n > 0L) 318: { 319: int numread = (int) Math.min((long) (buf.length - pos), n); 320: pos += numread; 321: n -= numread; 322: if (n > 0) 323: n -= super.skip(n); 324: } 325: 326: return origN - n; 327: } 328: }
GNU Classpath (0.17) |