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