1/*
2 * Copyright (c) 1994, 2011, 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
26package 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 */
51public
52class 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     */
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 size is <= 0
89     * @since  JDK1.1
90     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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