1 /* 2 * Copyright (c) 1996, 2015, 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 /** 30 * A character-stream reader that allows characters to be pushed back into the 31 * stream. 32 * 33 * @author Mark Reinhold 34 * @since 1.1 35 */ 36 37 public 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 {@code size <= 0} 51 */ PushbackReader(Reader in, int size)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 */ PushbackReader(Reader in)66 public PushbackReader(Reader in) { 67 this(in, 1); 68 } 69 70 /** Checks to make sure that the stream has not been closed. */ ensureOpen()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 */ read()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 * @exception IndexOutOfBoundsException {@inheritDoc} 106 */ read(char cbuf[], int off, int len)107 public int read(char cbuf[], int off, int len) throws IOException { 108 synchronized (lock) { 109 ensureOpen(); 110 try { 111 if (len <= 0) { 112 if (len < 0) { 113 throw new IndexOutOfBoundsException(); 114 } else if ((off < 0) || (off > cbuf.length)) { 115 throw new IndexOutOfBoundsException(); 116 } 117 return 0; 118 } 119 int avail = buf.length - pos; 120 if (avail > 0) { 121 if (len < avail) 122 avail = len; 123 System.arraycopy(buf, pos, cbuf, off, avail); 124 pos += avail; 125 off += avail; 126 len -= avail; 127 } 128 if (len > 0) { 129 len = super.read(cbuf, off, len); 130 if (len == -1) { 131 return (avail == 0) ? -1 : avail; 132 } 133 return avail + len; 134 } 135 return avail; 136 } catch (ArrayIndexOutOfBoundsException e) { 137 throw new IndexOutOfBoundsException(); 138 } 139 } 140 } 141 142 /** 143 * Pushes back a single character by copying it to the front of the 144 * pushback buffer. After this method returns, the next character to be read 145 * will have the value <code>(char)c</code>. 146 * 147 * @param c The int value representing a character to be pushed back 148 * 149 * @exception IOException If the pushback buffer is full, 150 * or if some other I/O error occurs 151 */ unread(int c)152 public void unread(int c) throws IOException { 153 synchronized (lock) { 154 ensureOpen(); 155 if (pos == 0) 156 throw new IOException("Pushback buffer overflow"); 157 buf[--pos] = (char) c; 158 } 159 } 160 161 /** 162 * Pushes back a portion of an array of characters by copying it to the 163 * front of the pushback buffer. After this method returns, the next 164 * character to be read will have the value <code>cbuf[off]</code>, the 165 * character after that will have the value <code>cbuf[off+1]</code>, and 166 * so forth. 167 * 168 * @param cbuf Character array 169 * @param off Offset of first character to push back 170 * @param len Number of characters to push back 171 * 172 * @exception IOException If there is insufficient room in the pushback 173 * buffer, or if some other I/O error occurs 174 */ unread(char cbuf[], int off, int len)175 public void unread(char cbuf[], int off, int len) throws IOException { 176 synchronized (lock) { 177 ensureOpen(); 178 if (len > pos) 179 throw new IOException("Pushback buffer overflow"); 180 pos -= len; 181 System.arraycopy(cbuf, off, buf, pos, len); 182 } 183 } 184 185 /** 186 * Pushes back an array of characters by copying it to the front of the 187 * pushback buffer. After this method returns, the next character to be 188 * read will have the value <code>cbuf[0]</code>, the character after that 189 * will have the value <code>cbuf[1]</code>, and so forth. 190 * 191 * @param cbuf Character array to push back 192 * 193 * @exception IOException If there is insufficient room in the pushback 194 * buffer, or if some other I/O error occurs 195 */ unread(char cbuf[])196 public void unread(char cbuf[]) throws IOException { 197 unread(cbuf, 0, cbuf.length); 198 } 199 200 /** 201 * Tells whether this stream is ready to be read. 202 * 203 * @exception IOException If an I/O error occurs 204 */ ready()205 public boolean ready() throws IOException { 206 synchronized (lock) { 207 ensureOpen(); 208 return (pos < buf.length) || super.ready(); 209 } 210 } 211 212 /** 213 * Marks the present position in the stream. The <code>mark</code> 214 * for class <code>PushbackReader</code> always throws an exception. 215 * 216 * @exception IOException Always, since mark is not supported 217 */ mark(int readAheadLimit)218 public void mark(int readAheadLimit) throws IOException { 219 throw new IOException("mark/reset not supported"); 220 } 221 222 /** 223 * Resets the stream. The <code>reset</code> method of 224 * <code>PushbackReader</code> always throws an exception. 225 * 226 * @exception IOException Always, since reset is not supported 227 */ reset()228 public void reset() throws IOException { 229 throw new IOException("mark/reset not supported"); 230 } 231 232 /** 233 * Tells whether this stream supports the mark() operation, which it does 234 * not. 235 */ markSupported()236 public boolean markSupported() { 237 return false; 238 } 239 240 /** 241 * Closes the stream and releases any system resources associated with 242 * it. Once the stream has been closed, further read(), 243 * unread(), ready(), or skip() invocations will throw an IOException. 244 * Closing a previously closed stream has no effect. This method will block 245 * while there is another thread blocking on the reader. 246 * 247 * @exception IOException If an I/O error occurs 248 */ close()249 public void close() throws IOException { 250 synchronized (lock) { 251 super.close(); 252 buf = null; 253 } 254 } 255 256 /** 257 * Skips characters. This method will block until some characters are 258 * available, an I/O error occurs, or the end of the stream is reached. 259 * 260 * @param n The number of characters to skip 261 * 262 * @return The number of characters actually skipped 263 * 264 * @exception IllegalArgumentException If <code>n</code> is negative. 265 * @exception IOException If an I/O error occurs 266 */ skip(long n)267 public long skip(long n) throws IOException { 268 if (n < 0L) 269 throw new IllegalArgumentException("skip value is negative"); 270 synchronized (lock) { 271 ensureOpen(); 272 int avail = buf.length - pos; 273 if (avail > 0) { 274 if (n <= avail) { 275 pos += n; 276 return n; 277 } else { 278 pos = buf.length; 279 n -= avail; 280 } 281 } 282 return avail + super.skip(n); 283 } 284 } 285 } 286