blob: b9588cbec5c348942f5f506e732dae5ba5c413b1 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package java.io;
27
28
29/**
30 * A character-stream reader that allows characters to be pushed back into the
31 * stream.
32 *
33 * @author Mark Reinhold
34 * @since JDK1.1
35 */
36
37public class PushbackReader extends FilterReader {
38
39 /** Pushback buffer */
40 private char[] buf;
41
42 /** Current position in buffer */
43 private int pos;
44
45 /**
46 * Creates a new pushback reader with a pushback buffer of the given size.
47 *
48 * @param in The reader from which characters will be read
49 * @param size The size of the pushback buffer
50 * @exception IllegalArgumentException if size is <= 0
51 */
52 public PushbackReader(Reader in, int size) {
53 super(in);
54 if (size <= 0) {
55 throw new IllegalArgumentException("size <= 0");
56 }
57 this.buf = new char[size];
58 this.pos = size;
59 }
60
61 /**
62 * Creates a new pushback reader with a one-character pushback buffer.
63 *
64 * @param in The reader from which characters will be read
65 */
66 public PushbackReader(Reader in) {
67 this(in, 1);
68 }
69
70 /** Checks to make sure that the stream has not been closed. */
71 private void ensureOpen() throws IOException {
72 if (buf == null)
73 throw new IOException("Stream closed");
74 }
75
76 /**
77 * Reads a single character.
78 *
79 * @return The character read, or -1 if the end of the stream has been
80 * reached
81 *
82 * @exception IOException If an I/O error occurs
83 */
84 public int read() throws IOException {
85 synchronized (lock) {
86 ensureOpen();
87 if (pos < buf.length)
88 return buf[pos++];
89 else
90 return super.read();
91 }
92 }
93
94 /**
95 * Reads characters into a portion of an array.
96 *
97 * @param cbuf Destination buffer
98 * @param off Offset at which to start writing characters
99 * @param len Maximum number of characters to read
100 *
101 * @return The number of characters read, or -1 if the end of the
102 * stream has been reached
103 *
104 * @exception IOException If an I/O error occurs
105 */
106 public int read(char cbuf[], int off, int len) throws IOException {
107 synchronized (lock) {
108 ensureOpen();
109 try {
110 if (len <= 0) {
111 if (len < 0) {
112 throw new IndexOutOfBoundsException();
113 } else if ((off < 0) || (off > cbuf.length)) {
114 throw new IndexOutOfBoundsException();
115 }
116 return 0;
117 }
118 int avail = buf.length - pos;
119 if (avail > 0) {
120 if (len < avail)
121 avail = len;
122 System.arraycopy(buf, pos, cbuf, off, avail);
123 pos += avail;
124 off += avail;
125 len -= avail;
126 }
127 if (len > 0) {
128 len = super.read(cbuf, off, len);
129 if (len == -1) {
130 return (avail == 0) ? -1 : avail;
131 }
132 return avail + len;
133 }
134 return avail;
135 } catch (ArrayIndexOutOfBoundsException e) {
136 throw new IndexOutOfBoundsException();
137 }
138 }
139 }
140
141 /**
142 * Pushes back a single character by copying it to the front of the
143 * pushback buffer. After this method returns, the next character to be read
144 * will have the value <code>(char)c</code>.
145 *
146 * @param c The int value representing a character to be pushed back
147 *
148 * @exception IOException If the pushback buffer is full,
149 * or if some other I/O error occurs
150 */
151 public void unread(int c) throws IOException {
152 synchronized (lock) {
153 ensureOpen();
154 if (pos == 0)
155 throw new IOException("Pushback buffer overflow");
156 buf[--pos] = (char) c;
157 }
158 }
159
160 /**
161 * Pushes back a portion of an array of characters by copying it to the
162 * front of the pushback buffer. After this method returns, the next
163 * character to be read will have the value <code>cbuf[off]</code>, the
164 * character after that will have the value <code>cbuf[off+1]</code>, and
165 * so forth.
166 *
167 * @param cbuf Character array
168 * @param off Offset of first character to push back
169 * @param len Number of characters to push back
170 *
171 * @exception IOException If there is insufficient room in the pushback
172 * buffer, or if some other I/O error occurs
173 */
174 public void unread(char cbuf[], int off, int len) throws IOException {
175 synchronized (lock) {
176 ensureOpen();
177 if (len > pos)
178 throw new IOException("Pushback buffer overflow");
179 pos -= len;
180 System.arraycopy(cbuf, off, buf, pos, len);
181 }
182 }
183
184 /**
185 * Pushes back an array of characters by copying it to the front of the
186 * pushback buffer. After this method returns, the next character to be
187 * read will have the value <code>cbuf[0]</code>, the character after that
188 * will have the value <code>cbuf[1]</code>, and so forth.
189 *
190 * @param cbuf Character array to push back
191 *
192 * @exception IOException If there is insufficient room in the pushback
193 * buffer, or if some other I/O error occurs
194 */
195 public void unread(char cbuf[]) throws IOException {
196 unread(cbuf, 0, cbuf.length);
197 }
198
199 /**
200 * Tells whether this stream is ready to be read.
201 *
202 * @exception IOException If an I/O error occurs
203 */
204 public boolean ready() throws IOException {
205 synchronized (lock) {
206 ensureOpen();
207 return (pos < buf.length) || super.ready();
208 }
209 }
210
211 /**
212 * Marks the present position in the stream. The <code>mark</code>
213 * for class <code>PushbackReader</code> always throws an exception.
214 *
215 * @exception IOException Always, since mark is not supported
216 */
217 public void mark(int readAheadLimit) throws IOException {
218 throw new IOException("mark/reset not supported");
219 }
220
221 /**
222 * Resets the stream. The <code>reset</code> method of
223 * <code>PushbackReader</code> always throws an exception.
224 *
225 * @exception IOException Always, since reset is not supported
226 */
227 public void reset() throws IOException {
228 throw new IOException("mark/reset not supported");
229 }
230
231 /**
232 * Tells whether this stream supports the mark() operation, which it does
233 * not.
234 */
235 public boolean markSupported() {
236 return false;
237 }
238
239 /**
240 * Closes the stream and releases any system resources associated with
241 * it. Once the stream has been closed, further read(),
242 * unread(), ready(), or skip() invocations will throw an IOException.
243 * Closing a previously closed stream has no effect.
244 *
245 * @exception IOException If an I/O error occurs
246 */
247 public void close() throws IOException {
248 super.close();
249 buf = null;
250 }
251
252 /**
253 * Skips characters. This method will block until some characters are
254 * available, an I/O error occurs, or the end of the stream is reached.
255 *
256 * @param n The number of characters to skip
257 *
258 * @return The number of characters actually skipped
259 *
260 * @exception IllegalArgumentException If <code>n</code> is negative.
261 * @exception IOException If an I/O error occurs
262 */
263 public long skip(long n) throws IOException {
264 if (n < 0L)
265 throw new IllegalArgumentException("skip value is negative");
266 synchronized (lock) {
267 ensureOpen();
268 int avail = buf.length - pos;
269 if (avail > 0) {
270 if (n <= avail) {
271 pos += n;
272 return n;
273 } else {
274 pos = buf.length;
275 n -= avail;
276 }
277 }
278 return avail + super.skip(n);
279 }
280 }
281}