1 /* 2 * Copyright (c) 1996, 2013, 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 JDK1.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 */ read(char cbuf[], int off, int len)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 */ unread(int c)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 */ unread(char cbuf[], int off, int len)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 */ unread(char cbuf[])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 */ ready()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 */ mark(int readAheadLimit)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 */ reset()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 */ markSupported()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 */ close()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 */ skip(long n)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 } 282