KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > io > PushbackInputStream


1 /*
2  * @(#)PushbackInputStream.java 1.36 04/02/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.io;
9
10 /**
11  * A <code>PushbackInputStream</code> adds
12  * functionality to another input stream, namely
13  * the ability to "push back" or "unread"
14  * one byte. This is useful in situations where
15  * it is convenient for a fragment of code
16  * to read an indefinite number of data bytes
17  * that are delimited by a particular byte
18  * value; after reading the terminating byte,
19  * the code fragment can "unread" it, so that
20  * the next read operation on the input stream
21  * will reread the byte that was pushed back.
22  * For example, bytes representing the characters
23  * constituting an identifier might be terminated
24  * by a byte representing an operator character;
25  * a method whose job is to read just an identifier
26  * can read until it sees the operator and
27  * then push the operator back to be re-read.
28  *
29  * @author David Connelly
30  * @author Jonathan Payne
31  * @version 1.36, 02/19/04
32  * @since JDK1.0
33  */

34 public
35 class PushbackInputStream extends FilterInputStream JavaDoc {
36     /**
37      * The pushback buffer.
38      * @since JDK1.1
39      */

40     protected byte[] buf;
41
42     /**
43      * The position within the pushback buffer from which the next byte will
44      * be read. When the buffer is empty, <code>pos</code> is equal to
45      * <code>buf.length</code>; when the buffer is full, <code>pos</code> is
46      * equal to zero.
47      *
48      * @since JDK1.1
49      */

50     protected int pos;
51
52     /**
53      * Check to make sure that this stream has not been closed
54      */

55     private void ensureOpen() throws IOException JavaDoc {
56     if (in == null)
57         throw new IOException JavaDoc("Stream closed");
58     }
59
60     /**
61      * Creates a <code>PushbackInputStream</code>
62      * with a pushback buffer of the specified <code>size</code>,
63      * and saves its argument, the input stream
64      * <code>in</code>, for later use. Initially,
65      * there is no pushed-back byte (the field
66      * <code>pushBack</code> is initialized to
67      * <code>-1</code>).
68      *
69      * @param in the input stream from which bytes will be read.
70      * @param size the size of the pushback buffer.
71      * @exception IllegalArgumentException if size is <= 0
72      * @since JDK1.1
73      */

74     public PushbackInputStream(InputStream JavaDoc in, int size) {
75     super(in);
76         if (size <= 0) {
77             throw new IllegalArgumentException JavaDoc("size <= 0");
78         }
79     this.buf = new byte[size];
80     this.pos = size;
81     }
82
83     /**
84      * Creates a <code>PushbackInputStream</code>
85      * and saves its argument, the input stream
86      * <code>in</code>, for later use. Initially,
87      * there is no pushed-back byte (the field
88      * <code>pushBack</code> is initialized to
89      * <code>-1</code>).
90      *
91      * @param in the input stream from which bytes will be read.
92      */

93     public PushbackInputStream(InputStream JavaDoc in) {
94     this(in, 1);
95     }
96
97     /**
98      * Reads the next byte of data from this input stream. The value
99      * byte is returned as an <code>int</code> in the range
100      * <code>0</code> to <code>255</code>. If no byte is available
101      * because the end of the stream has been reached, the value
102      * <code>-1</code> is returned. This method blocks until input data
103      * is available, the end of the stream is detected, or an exception
104      * is thrown.
105      *
106      * <p> This method returns the most recently pushed-back byte, if there is
107      * one, and otherwise calls the <code>read</code> method of its underlying
108      * input stream and returns whatever value that method returns.
109      *
110      * @return the next byte of data, or <code>-1</code> if the end of the
111      * stream has been reached.
112      * @exception IOException if an I/O error occurs.
113      * @see java.io.InputStream#read()
114      */

115     public int read() throws IOException JavaDoc {
116         ensureOpen();
117     if (pos < buf.length) {
118         return buf[pos++] & 0xff;
119     }
120     return super.read();
121     }
122
123     /**
124      * Reads up to <code>len</code> bytes of data from this input stream into
125      * an array of bytes. This method first reads any pushed-back bytes; after
126      * that, if fewer than <code>len</code> bytes have been read then it
127      * reads from the underlying input stream. This method blocks until at
128      * least 1 byte of input is available.
129      *
130      * @param b the buffer into which the data is read.
131      * @param off the start offset of the data.
132      * @param len the maximum number of bytes read.
133      * @return the total number of bytes read into the buffer, or
134      * <code>-1</code> if there is no more data because the end of
135      * the stream has been reached.
136      * @exception IOException if an I/O error occurs.
137      * @see java.io.InputStream#read(byte[], int, int)
138      */

139     public int read(byte[] b, int off, int len) throws IOException JavaDoc {
140         ensureOpen();
141         if ((off < 0) || (off > b.length) || (len < 0) ||
142             ((off + len) > b.length) || ((off + len) < 0)) {
143             throw new IndexOutOfBoundsException JavaDoc();
144         }
145
146     if (len == 0) {
147         return 0;
148     }
149
150     int avail = buf.length - pos;
151     if (avail > 0) {
152         if (len < avail) {
153         avail = len;
154         }
155         System.arraycopy(buf, pos, b, off, avail);
156         pos += avail;
157         off += avail;
158         len -= avail;
159     }
160     if (len > 0) {
161         len = super.read(b, off, len);
162         if (len == -1) {
163         return avail == 0 ? -1 : avail;
164         }
165         return avail + len;
166     }
167     return avail;
168     }
169
170     /**
171      * Pushes back a byte by copying it to the front of the pushback buffer.
172      * After this method returns, the next byte to be read will have the value
173      * <code>(byte)b</code>.
174      *
175      * @param b the <code>int</code> value whose low-order
176      * byte is to be pushed back.
177      * @exception IOException If there is not enough room in the pushback
178      * buffer for the byte.
179      */

180     public void unread(int b) throws IOException JavaDoc {
181         ensureOpen();
182     if (pos == 0) {
183         throw new IOException JavaDoc("Push back buffer is full");
184     }
185     buf[--pos] = (byte)b;
186     }
187
188     /**
189      * Pushes back a portion of an array of bytes by copying it to the front
190      * of the pushback buffer. After this method returns, the next byte to be
191      * read will have the value <code>b[off]</code>, the byte after that will
192      * have the value <code>b[off+1]</code>, and so forth.
193      *
194      * @param b the byte array to push back.
195      * @param off the start offset of the data.
196      * @param len the number of bytes to push back.
197      * @exception IOException If there is not enough room in the pushback
198      * buffer for the specified number of bytes.
199      * @since JDK1.1
200      */

201     public void unread(byte[] b, int off, int len) throws IOException JavaDoc {
202         ensureOpen();
203     if (len > pos) {
204         throw new IOException JavaDoc("Push back buffer is full");
205     }
206     pos -= len;
207     System.arraycopy(b, off, buf, pos, len);
208     }
209
210     /**
211      * Pushes back an array of bytes by copying it to the front of the
212      * pushback buffer. After this method returns, the next byte to be read
213      * will have the value <code>b[0]</code>, the byte after that will have the
214      * value <code>b[1]</code>, and so forth.
215      *
216      * @param b the byte array to push back
217      * @exception IOException If there is not enough room in the pushback
218      * buffer for the specified number of bytes.
219      * @since JDK1.1
220      */

221     public void unread(byte[] b) throws IOException JavaDoc {
222     unread(b, 0, b.length);
223     }
224
225     /**
226      * Returns the number of bytes that can be read from this input stream
227      * without blocking. This method calls the <code>available</code> method
228      * of the underlying input stream; it returns that value plus the number of
229      * bytes that have been pushed back.
230      *
231      * @return the number of bytes that can be read from the input stream
232      * without blocking.
233      * @exception IOException if an I/O error occurs.
234      * @see java.io.FilterInputStream#in
235      * @see java.io.InputStream#available()
236      */

237     public int available() throws IOException JavaDoc {
238         ensureOpen();
239     return (buf.length - pos) + super.available();
240     }
241
242     /**
243      * Skips over and discards <code>n</code> bytes of data from this
244      * input stream. The <code>skip</code> method may, for a variety of
245      * reasons, end up skipping over some smaller number of bytes,
246      * possibly zero. If <code>n</code> is negative, no bytes are skipped.
247      *
248      * <p> The <code>skip</code> method of <code>PushbackInputStream</code>
249      * first skips over the bytes in the pushback buffer, if any. It then
250      * calls the <code>skip</code> method of the underlying input stream if
251      * more bytes need to be skipped. The actual number of bytes skipped
252      * is returned.
253      *
254      * @param n the number of bytes to be skipped.
255      * @return the actual number of bytes skipped.
256      * @exception IOException if an I/O error occurs.
257      * @see java.io.FilterInputStream#in
258      * @see java.io.InputStream#skip(long n)
259      * @since 1.2
260      */

261     public long skip(long n) throws IOException JavaDoc {
262         ensureOpen();
263     if (n <= 0) {
264         return 0;
265     }
266
267     long pskip = buf.length - pos;
268     if (pskip > 0) {
269         if (n < pskip) {
270         pskip = n;
271         }
272         pos += pskip;
273         n -= pskip;
274     }
275     if (n > 0) {
276         pskip += super.skip(n);
277     }
278     return pskip;
279     }
280
281     /**
282      * Tests if this input stream supports the <code>mark</code> and
283      * <code>reset</code> methods, which it does not.
284      *
285      * @return <code>false</code>, since this class does not support the
286      * <code>mark</code> and <code>reset</code> methods.
287      * @see java.io.InputStream#mark(int)
288      * @see java.io.InputStream#reset()
289      */

290     public boolean markSupported() {
291     return false;
292     }
293
294     /**
295      * Marks the current position in this input stream.
296      *
297      * <p> The <code>mark</code> method of <code>PushbackInputStream</code>
298      * does nothing.
299      *
300      * @param readlimit the maximum limit of bytes that can be read before
301      * the mark position becomes invalid.
302      * @see java.io.InputStream#reset()
303      */

304     public synchronized void mark(int readlimit) {
305     }
306  
307     /**
308      * Repositions this stream to the position at the time the
309      * <code>mark</code> method was last called on this input stream.
310      *
311      * <p> The method <code>reset</code> for class
312      * <code>PushbackInputStream</code> does nothing except throw an
313      * <code>IOException</code>.
314      *
315      * @exception IOException if this method is invoked.
316      * @see java.io.InputStream#mark(int)
317      * @see java.io.IOException
318      */

319     public synchronized void reset() throws IOException JavaDoc {
320         throw new IOException JavaDoc("mark/reset not supported");
321     }
322
323     /**
324      * Closes this input stream and releases any system resources
325      * associated with the stream.
326      *
327      * @exception IOException if an I/O error occurs.
328      */

329     public synchronized void close() throws IOException JavaDoc {
330         if (in == null)
331             return;
332         in.close();
333         in = null;
334         buf = null;
335     }
336
337 }
338
Popular Tags