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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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