1 /* 2 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.io; 27 28 /** 29 * A <code>PushbackInputStream</code> adds 30 * functionality to another input stream, namely 31 * the ability to "push back" or "unread" 32 * one byte. This is useful in situations where 33 * it is convenient for a fragment of code 34 * to read an indefinite number of data bytes 35 * that are delimited by a particular byte 36 * value; after reading the terminating byte, 37 * the code fragment can "unread" it, so that 38 * the next read operation on the input stream 39 * will reread the byte that was pushed back. 40 * For example, bytes representing the characters 41 * constituting an identifier might be terminated 42 * by a byte representing an operator character; 43 * a method whose job is to read just an identifier 44 * can read until it sees the operator and 45 * then push the operator back to be re-read. 46 * 47 * @author David Connelly 48 * @author Jonathan Payne 49 * @since JDK1.0 50 */ 51 public 52 class PushbackInputStream extends FilterInputStream { 53 /** 54 * The pushback buffer. 55 * @since JDK1.1 56 */ 57 protected byte[] buf; 58 59 /** 60 * The position within the pushback buffer from which the next byte will 61 * be read. When the buffer is empty, <code>pos</code> is equal to 62 * <code>buf.length</code>; when the buffer is full, <code>pos</code> is 63 * equal to zero. 64 * 65 * @since JDK1.1 66 */ 67 protected int pos; 68 69 /** 70 * Check to make sure that this stream has not been closed 71 */ ensureOpen()72 private void ensureOpen() throws IOException { 73 if (in == null) 74 throw new IOException("Stream closed"); 75 } 76 77 /** 78 * Creates a <code>PushbackInputStream</code> 79 * with a pushback buffer of the specified <code>size</code>, 80 * and saves its argument, the input stream 81 * <code>in</code>, for later use. Initially, 82 * there is no pushed-back byte (the field 83 * <code>pushBack</code> is initialized to 84 * <code>-1</code>). 85 * 86 * @param in the input stream from which bytes will be read. 87 * @param size the size of the pushback buffer. 88 * @exception IllegalArgumentException if {@code size <= 0} 89 * @since JDK1.1 90 */ PushbackInputStream(InputStream in, int size)91 public PushbackInputStream(InputStream in, int size) { 92 super(in); 93 if (size <= 0) { 94 throw new IllegalArgumentException("size <= 0"); 95 } 96 this.buf = new byte[size]; 97 this.pos = size; 98 } 99 100 /** 101 * Creates a <code>PushbackInputStream</code> 102 * and saves its argument, the input stream 103 * <code>in</code>, for later use. Initially, 104 * there is no pushed-back byte (the field 105 * <code>pushBack</code> is initialized to 106 * <code>-1</code>). 107 * 108 * @param in the input stream from which bytes will be read. 109 */ PushbackInputStream(InputStream in)110 public PushbackInputStream(InputStream in) { 111 this(in, 1); 112 } 113 114 /** 115 * Reads the next byte of data from this input stream. The value 116 * byte is returned as an <code>int</code> in the range 117 * <code>0</code> to <code>255</code>. If no byte is available 118 * because the end of the stream has been reached, the value 119 * <code>-1</code> is returned. This method blocks until input data 120 * is available, the end of the stream is detected, or an exception 121 * is thrown. 122 * 123 * <p> This method returns the most recently pushed-back byte, if there is 124 * one, and otherwise calls the <code>read</code> method of its underlying 125 * input stream and returns whatever value that method returns. 126 * 127 * @return the next byte of data, or <code>-1</code> if the end of the 128 * stream has been reached. 129 * @exception IOException if this input stream has been closed by 130 * invoking its {@link #close()} method, 131 * or an I/O error occurs. 132 * @see java.io.InputStream#read() 133 */ read()134 public int read() throws IOException { 135 ensureOpen(); 136 if (pos < buf.length) { 137 return buf[pos++] & 0xff; 138 } 139 return super.read(); 140 } 141 142 /** 143 * Reads up to <code>len</code> bytes of data from this input stream into 144 * an array of bytes. This method first reads any pushed-back bytes; after 145 * that, if fewer than <code>len</code> bytes have been read then it 146 * reads from the underlying input stream. If <code>len</code> is not zero, the method 147 * blocks until at least 1 byte of input is available; otherwise, no 148 * bytes are read and <code>0</code> is returned. 149 * 150 * @param b the buffer into which the data is read. 151 * @param off the start offset in the destination array <code>b</code> 152 * @param len the maximum number of bytes read. 153 * @return the total number of bytes read into the buffer, or 154 * <code>-1</code> if there is no more data because the end of 155 * the stream has been reached. 156 * @exception NullPointerException If <code>b</code> is <code>null</code>. 157 * @exception IndexOutOfBoundsException If <code>off</code> is negative, 158 * <code>len</code> is negative, or <code>len</code> is greater than 159 * <code>b.length - off</code> 160 * @exception IOException if this input stream has been closed by 161 * invoking its {@link #close()} method, 162 * or an I/O error occurs. 163 * @see java.io.InputStream#read(byte[], int, int) 164 */ read(byte[] b, int off, int len)165 public int read(byte[] b, int off, int len) throws IOException { 166 ensureOpen(); 167 if (b == null) { 168 throw new NullPointerException(); 169 } else if (off < 0 || len < 0 || len > b.length - off) { 170 throw new IndexOutOfBoundsException(); 171 } else if (len == 0) { 172 return 0; 173 } 174 175 int avail = buf.length - pos; 176 if (avail > 0) { 177 if (len < avail) { 178 avail = len; 179 } 180 System.arraycopy(buf, pos, b, off, avail); 181 pos += avail; 182 off += avail; 183 len -= avail; 184 } 185 if (len > 0) { 186 len = super.read(b, off, len); 187 if (len == -1) { 188 return avail == 0 ? -1 : avail; 189 } 190 return avail + len; 191 } 192 return avail; 193 } 194 195 /** 196 * Pushes back a byte by copying it to the front of the pushback buffer. 197 * After this method returns, the next byte to be read will have the value 198 * <code>(byte)b</code>. 199 * 200 * @param b the <code>int</code> value whose low-order 201 * byte is to be pushed back. 202 * @exception IOException If there is not enough room in the pushback 203 * buffer for the byte, or this input stream has been closed by 204 * invoking its {@link #close()} method. 205 */ unread(int b)206 public void unread(int b) throws IOException { 207 ensureOpen(); 208 if (pos == 0) { 209 throw new IOException("Push back buffer is full"); 210 } 211 buf[--pos] = (byte)b; 212 } 213 214 /** 215 * Pushes back a portion of an array of bytes by copying it to the front 216 * of the pushback buffer. After this method returns, the next byte to be 217 * read will have the value <code>b[off]</code>, the byte after that will 218 * have the value <code>b[off+1]</code>, and so forth. 219 * 220 * @param b the byte array to push back. 221 * @param off the start offset of the data. 222 * @param len the number of bytes to push back. 223 * @exception IOException If there is not enough room in the pushback 224 * buffer for the specified number of bytes, 225 * or this input stream has been closed by 226 * invoking its {@link #close()} method. 227 * @since JDK1.1 228 */ unread(byte[] b, int off, int len)229 public void unread(byte[] b, int off, int len) throws IOException { 230 ensureOpen(); 231 if (len > pos) { 232 throw new IOException("Push back buffer is full"); 233 } 234 pos -= len; 235 System.arraycopy(b, off, buf, pos, len); 236 } 237 238 /** 239 * Pushes back an array of bytes by copying it to the front of the 240 * pushback buffer. After this method returns, the next byte to be read 241 * will have the value <code>b[0]</code>, the byte after that will have the 242 * value <code>b[1]</code>, and so forth. 243 * 244 * @param b the byte array to push back 245 * @exception IOException If there is not enough room in the pushback 246 * buffer for the specified number of bytes, 247 * or this input stream has been closed by 248 * invoking its {@link #close()} method. 249 * @since JDK1.1 250 */ unread(byte[] b)251 public void unread(byte[] b) throws IOException { 252 unread(b, 0, b.length); 253 } 254 255 /** 256 * Returns an estimate of the number of bytes that can be read (or 257 * skipped over) from this input stream without blocking by the next 258 * invocation of a method for this input stream. The next invocation might be 259 * the same thread or another thread. A single read or skip of this 260 * many bytes will not block, but may read or skip fewer bytes. 261 * 262 * <p> The method returns the sum of the number of bytes that have been 263 * pushed back and the value returned by {@link 264 * java.io.FilterInputStream#available available}. 265 * 266 * @return the number of bytes that can be read (or skipped over) from 267 * the input stream without blocking. 268 * @exception IOException if this input stream has been closed by 269 * invoking its {@link #close()} method, 270 * or an I/O error occurs. 271 * @see java.io.FilterInputStream#in 272 * @see java.io.InputStream#available() 273 */ available()274 public int available() throws IOException { 275 ensureOpen(); 276 int n = buf.length - pos; 277 int avail = super.available(); 278 return n > (Integer.MAX_VALUE - avail) 279 ? Integer.MAX_VALUE 280 : n + avail; 281 } 282 283 /** 284 * Skips over and discards <code>n</code> bytes of data from this 285 * input stream. The <code>skip</code> method may, for a variety of 286 * reasons, end up skipping over some smaller number of bytes, 287 * possibly zero. If <code>n</code> is negative, no bytes are skipped. 288 * 289 * <p> The <code>skip</code> method of <code>PushbackInputStream</code> 290 * first skips over the bytes in the pushback buffer, if any. It then 291 * calls the <code>skip</code> method of the underlying input stream if 292 * more bytes need to be skipped. The actual number of bytes skipped 293 * is returned. 294 * 295 * @param n {@inheritDoc} 296 * @return {@inheritDoc} 297 * @exception IOException if the stream does not support seek, 298 * or the stream has been closed by 299 * invoking its {@link #close()} method, 300 * or an I/O error occurs. 301 * @see java.io.FilterInputStream#in 302 * @see java.io.InputStream#skip(long n) 303 * @since 1.2 304 */ skip(long n)305 public long skip(long n) throws IOException { 306 ensureOpen(); 307 if (n <= 0) { 308 return 0; 309 } 310 311 long pskip = buf.length - pos; 312 if (pskip > 0) { 313 if (n < pskip) { 314 pskip = n; 315 } 316 pos += pskip; 317 n -= pskip; 318 } 319 if (n > 0) { 320 pskip += super.skip(n); 321 } 322 return pskip; 323 } 324 325 /** 326 * Tests if this input stream supports the <code>mark</code> and 327 * <code>reset</code> methods, which it does not. 328 * 329 * @return <code>false</code>, since this class does not support the 330 * <code>mark</code> and <code>reset</code> methods. 331 * @see java.io.InputStream#mark(int) 332 * @see java.io.InputStream#reset() 333 */ markSupported()334 public boolean markSupported() { 335 return false; 336 } 337 338 /** 339 * Marks the current position in this input stream. 340 * 341 * <p> The <code>mark</code> method of <code>PushbackInputStream</code> 342 * does nothing. 343 * 344 * @param readlimit the maximum limit of bytes that can be read before 345 * the mark position becomes invalid. 346 * @see java.io.InputStream#reset() 347 */ mark(int readlimit)348 public synchronized void mark(int readlimit) { 349 } 350 351 /** 352 * Repositions this stream to the position at the time the 353 * <code>mark</code> method was last called on this input stream. 354 * 355 * <p> The method <code>reset</code> for class 356 * <code>PushbackInputStream</code> does nothing except throw an 357 * <code>IOException</code>. 358 * 359 * @exception IOException if this method is invoked. 360 * @see java.io.InputStream#mark(int) 361 * @see java.io.IOException 362 */ reset()363 public synchronized void reset() throws IOException { 364 throw new IOException("mark/reset not supported"); 365 } 366 367 /** 368 * Closes this input stream and releases any system resources 369 * associated with the stream. 370 * Once the stream has been closed, further read(), unread(), 371 * available(), reset(), or skip() invocations will throw an IOException. 372 * Closing a previously closed stream has no effect. 373 * 374 * @exception IOException if an I/O error occurs. 375 */ close()376 public synchronized void close() throws IOException { 377 if (in == null) 378 return; 379 in.close(); 380 in = null; 381 buf = null; 382 } 383 } 384