1 /*
   2  * Copyright (c) 1996, 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 
  26 package java.io;
  27 
  28 
  29 /**
  30  * Reads text from a character-input stream, buffering characters so as to
  31  * provide for the efficient reading of characters, arrays, and lines.
  32  *
  33  * <p> The buffer size may be specified, or the default size may be used.  The
  34  * default is large enough for most purposes.
  35  *
  36  * <p> In general, each read request made of a Reader causes a corresponding
  37  * read request to be made of the underlying character or byte stream.  It is
  38  * therefore advisable to wrap a BufferedReader around any Reader whose read()
  39  * operations may be costly, such as FileReaders and InputStreamReaders.  For
  40  * example,
  41  *
  42  * <pre>
  43  * BufferedReader in
  44  *   = new BufferedReader(new FileReader("foo.in"));
  45  * </pre>
  46  *
  47  * will buffer the input from the specified file.  Without buffering, each
  48  * invocation of read() or readLine() could cause bytes to be read from the
  49  * file, converted into characters, and then returned, which can be very
  50  * inefficient.
  51  *
  52  * <p> Programs that use DataInputStreams for textual input can be localized by
  53  * replacing each DataInputStream with an appropriate BufferedReader.
  54  *
  55  * @see FileReader
  56  * @see InputStreamReader
  57  * @see java.nio.file.Files#newBufferedReader
  58  *
  59  * @author      Mark Reinhold
  60  * @since       JDK1.1
  61  */
  62 
  63 public class BufferedReader extends Reader {
  64 
  65     private Reader in;
  66 
  67     private char cb[];
  68     private int nChars, nextChar;
  69 
  70     private static final int INVALIDATED = -2;
  71     private static final int UNMARKED = -1;
  72     private int markedChar = UNMARKED;
  73     private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
  74 
  75     /** If the next character is a line feed, skip it */
  76     private boolean skipLF = false;
  77 
  78     /** The skipLF flag when the mark was set */
  79     private boolean markedSkipLF = false;
  80 
  81     private static int defaultCharBufferSize = 8192;
  82     private static int defaultExpectedLineLength = 80;
  83 
  84     /**
  85      * Creates a buffering character-input stream that uses an input buffer of
  86      * the specified size.
  87      *
  88      * @param  in   A Reader
  89      * @param  sz   Input-buffer size
  90      *
  91      * @exception  IllegalArgumentException  If sz is <= 0
  92      */
  93     public BufferedReader(Reader in, int sz) {
  94         super(in);
  95         if (sz <= 0)
  96             throw new IllegalArgumentException("Buffer size <= 0");
  97         this.in = in;
  98         cb = new char[sz];
  99         nextChar = nChars = 0;
 100     }
 101 
 102     /**
 103      * Creates a buffering character-input stream that uses a default-sized
 104      * input buffer.
 105      *
 106      * @param  in   A Reader
 107      */
 108     public BufferedReader(Reader in) {
 109         this(in, defaultCharBufferSize);
 110     }
 111 
 112     /** Checks to make sure that the stream has not been closed */
 113     private void ensureOpen() throws IOException {
 114         if (in == null)
 115             throw new IOException("Stream closed");
 116     }
 117 
 118     /**
 119      * Fills the input buffer, taking the mark into account if it is valid.
 120      */
 121     private void fill() throws IOException {
 122         int dst;
 123         if (markedChar <= UNMARKED) {
 124             /* No mark */
 125             dst = 0;
 126         } else {
 127             /* Marked */
 128             int delta = nextChar - markedChar;
 129             if (delta >= readAheadLimit) {
 130                 /* Gone past read-ahead limit: Invalidate mark */
 131                 markedChar = INVALIDATED;
 132                 readAheadLimit = 0;
 133                 dst = 0;
 134             } else {
 135                 if (readAheadLimit <= cb.length) {
 136                     /* Shuffle in the current buffer */
 137                     System.arraycopy(cb, markedChar, cb, 0, delta);
 138                     markedChar = 0;
 139                     dst = delta;
 140                 } else {
 141                     /* Reallocate buffer to accommodate read-ahead limit */
 142                     char ncb[] = new char[readAheadLimit];
 143                     System.arraycopy(cb, markedChar, ncb, 0, delta);
 144                     cb = ncb;
 145                     markedChar = 0;
 146                     dst = delta;
 147                 }
 148                 nextChar = nChars = delta;
 149             }
 150         }
 151 
 152         int n;
 153         do {
 154             n = in.read(cb, dst, cb.length - dst);
 155         } while (n == 0);
 156         if (n > 0) {
 157             nChars = dst + n;
 158             nextChar = dst;
 159         }
 160     }
 161 
 162     /**
 163      * Reads a single character.
 164      *
 165      * @return The character read, as an integer in the range
 166      *         0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
 167      *         end of the stream has been reached
 168      * @exception  IOException  If an I/O error occurs
 169      */
 170     public int read() throws IOException {
 171         synchronized (lock) {
 172             ensureOpen();
 173             for (;;) {
 174                 if (nextChar >= nChars) {
 175                     fill();
 176                     if (nextChar >= nChars)
 177                         return -1;
 178                 }
 179                 if (skipLF) {
 180                     skipLF = false;
 181                     if (cb[nextChar] == '\n') {
 182                         nextChar++;
 183                         continue;
 184                     }
 185                 }
 186                 return cb[nextChar++];
 187             }
 188         }
 189     }
 190 
 191     /**
 192      * Reads characters into a portion of an array, reading from the underlying
 193      * stream if necessary.
 194      */
 195     private int read1(char[] cbuf, int off, int len) throws IOException {
 196         if (nextChar >= nChars) {
 197             /* If the requested length is at least as large as the buffer, and
 198                if there is no mark/reset activity, and if line feeds are not
 199                being skipped, do not bother to copy the characters into the
 200                local buffer.  In this way buffered streams will cascade
 201                harmlessly. */
 202             if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
 203                 return in.read(cbuf, off, len);
 204             }
 205             fill();
 206         }
 207         if (nextChar >= nChars) return -1;
 208         if (skipLF) {
 209             skipLF = false;
 210             if (cb[nextChar] == '\n') {
 211                 nextChar++;
 212                 if (nextChar >= nChars)
 213                     fill();
 214                 if (nextChar >= nChars)
 215                     return -1;
 216             }
 217         }
 218         int n = Math.min(len, nChars - nextChar);
 219         System.arraycopy(cb, nextChar, cbuf, off, n);
 220         nextChar += n;
 221         return n;
 222     }
 223 
 224     /**
 225      * Reads characters into a portion of an array.
 226      *
 227      * <p> This method implements the general contract of the corresponding
 228      * <code>{@link Reader#read(char[], int, int) read}</code> method of the
 229      * <code>{@link Reader}</code> class.  As an additional convenience, it
 230      * attempts to read as many characters as possible by repeatedly invoking
 231      * the <code>read</code> method of the underlying stream.  This iterated
 232      * <code>read</code> continues until one of the following conditions becomes
 233      * true: <ul>
 234      *
 235      *   <li> The specified number of characters have been read,
 236      *
 237      *   <li> The <code>read</code> method of the underlying stream returns
 238      *   <code>-1</code>, indicating end-of-file, or
 239      *
 240      *   <li> The <code>ready</code> method of the underlying stream
 241      *   returns <code>false</code>, indicating that further input requests
 242      *   would block.
 243      *
 244      * </ul> If the first <code>read</code> on the underlying stream returns
 245      * <code>-1</code> to indicate end-of-file then this method returns
 246      * <code>-1</code>.  Otherwise this method returns the number of characters
 247      * actually read.
 248      *
 249      * <p> Subclasses of this class are encouraged, but not required, to
 250      * attempt to read as many characters as possible in the same fashion.
 251      *
 252      * <p> Ordinarily this method takes characters from this stream's character
 253      * buffer, filling it from the underlying stream as necessary.  If,
 254      * however, the buffer is empty, the mark is not valid, and the requested
 255      * length is at least as large as the buffer, then this method will read
 256      * characters directly from the underlying stream into the given array.
 257      * Thus redundant <code>BufferedReader</code>s will not copy data
 258      * unnecessarily.
 259      *
 260      * @param      cbuf  Destination buffer
 261      * @param      off   Offset at which to start storing characters
 262      * @param      len   Maximum number of characters to read
 263      *
 264      * @return     The number of characters read, or -1 if the end of the
 265      *             stream has been reached
 266      *
 267      * @exception  IOException  If an I/O error occurs
 268      */
 269     public int read(char cbuf[], int off, int len) throws IOException {
 270         synchronized (lock) {
 271             ensureOpen();
 272             if ((off < 0) || (off > cbuf.length) || (len < 0) ||
 273                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
 274                 throw new IndexOutOfBoundsException();
 275             } else if (len == 0) {
 276                 return 0;
 277             }
 278 
 279             int n = read1(cbuf, off, len);
 280             if (n <= 0) return n;
 281             while ((n < len) && in.ready()) {
 282                 int n1 = read1(cbuf, off + n, len - n);
 283                 if (n1 <= 0) break;
 284                 n += n1;
 285             }
 286             return n;
 287         }
 288     }
 289 
 290     /**
 291      * Reads a line of text.  A line is considered to be terminated by any one
 292      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
 293      * followed immediately by a linefeed.
 294      *
 295      * @param      ignoreLF  If true, the next '\n' will be skipped
 296      *
 297      * @return     A String containing the contents of the line, not including
 298      *             any line-termination characters, or null if the end of the
 299      *             stream has been reached
 300      *
 301      * @see        java.io.LineNumberReader#readLine()
 302      *
 303      * @exception  IOException  If an I/O error occurs
 304      */
 305     String readLine(boolean ignoreLF) throws IOException {
 306         StringBuffer s = null;
 307         int startChar;
 308 
 309         synchronized (lock) {
 310             ensureOpen();
 311             boolean omitLF = ignoreLF || skipLF;
 312 
 313         bufferLoop:
 314             for (;;) {
 315 
 316                 if (nextChar >= nChars)
 317                     fill();
 318                 if (nextChar >= nChars) { /* EOF */
 319                     if (s != null && s.length() > 0)
 320                         return s.toString();
 321                     else
 322                         return null;
 323                 }
 324                 boolean eol = false;
 325                 char c = 0;
 326                 int i;
 327 
 328                 /* Skip a leftover '\n', if necessary */
 329                 if (omitLF && (cb[nextChar] == '\n'))
 330                     nextChar++;
 331                 skipLF = false;
 332                 omitLF = false;
 333 
 334             charLoop:
 335                 for (i = nextChar; i < nChars; i++) {
 336                     c = cb[i];
 337                     if ((c == '\n') || (c == '\r')) {
 338                         eol = true;
 339                         break charLoop;
 340                     }
 341                 }
 342 
 343                 startChar = nextChar;
 344                 nextChar = i;
 345 
 346                 if (eol) {
 347                     String str;
 348                     if (s == null) {
 349                         str = new String(cb, startChar, i - startChar);
 350                     } else {
 351                         s.append(cb, startChar, i - startChar);
 352                         str = s.toString();
 353                     }
 354                     nextChar++;
 355                     if (c == '\r') {
 356                         skipLF = true;
 357                     }
 358                     return str;
 359                 }
 360 
 361                 if (s == null)
 362                     s = new StringBuffer(defaultExpectedLineLength);
 363                 s.append(cb, startChar, i - startChar);
 364             }
 365         }
 366     }
 367 
 368     /**
 369      * Reads a line of text.  A line is considered to be terminated by any one
 370      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
 371      * followed immediately by a linefeed.
 372      *
 373      * @return     A String containing the contents of the line, not including
 374      *             any line-termination characters, or null if the end of the
 375      *             stream has been reached
 376      *
 377      * @exception  IOException  If an I/O error occurs
 378      *
 379      * @see java.nio.file.Files#readAllLines
 380      */
 381     public String readLine() throws IOException {
 382         return readLine(false);
 383     }
 384 
 385     /**
 386      * Skips characters.
 387      *
 388      * @param  n  The number of characters to skip
 389      *
 390      * @return    The number of characters actually skipped
 391      *
 392      * @exception  IllegalArgumentException  If <code>n</code> is negative.
 393      * @exception  IOException  If an I/O error occurs
 394      */
 395     public long skip(long n) throws IOException {
 396         if (n < 0L) {
 397             throw new IllegalArgumentException("skip value is negative");
 398         }
 399         synchronized (lock) {
 400             ensureOpen();
 401             long r = n;
 402             while (r > 0) {
 403                 if (nextChar >= nChars)
 404                     fill();
 405                 if (nextChar >= nChars) /* EOF */
 406                     break;
 407                 if (skipLF) {
 408                     skipLF = false;
 409                     if (cb[nextChar] == '\n') {
 410                         nextChar++;
 411                     }
 412                 }
 413                 long d = nChars - nextChar;
 414                 if (r <= d) {
 415                     nextChar += r;
 416                     r = 0;
 417                     break;
 418                 }
 419                 else {
 420                     r -= d;
 421                     nextChar = nChars;
 422                 }
 423             }
 424             return n - r;
 425         }
 426     }
 427 
 428     /**
 429      * Tells whether this stream is ready to be read.  A buffered character
 430      * stream is ready if the buffer is not empty, or if the underlying
 431      * character stream is ready.
 432      *
 433      * @exception  IOException  If an I/O error occurs
 434      */
 435     public boolean ready() throws IOException {
 436         synchronized (lock) {
 437             ensureOpen();
 438 
 439             /*
 440              * If newline needs to be skipped and the next char to be read
 441              * is a newline character, then just skip it right away.
 442              */
 443             if (skipLF) {
 444                 /* Note that in.ready() will return true if and only if the next
 445                  * read on the stream will not block.
 446                  */
 447                 if (nextChar >= nChars && in.ready()) {
 448                     fill();
 449                 }
 450                 if (nextChar < nChars) {
 451                     if (cb[nextChar] == '\n')
 452                         nextChar++;
 453                     skipLF = false;
 454                 }
 455             }
 456             return (nextChar < nChars) || in.ready();
 457         }
 458     }
 459 
 460     /**
 461      * Tells whether this stream supports the mark() operation, which it does.
 462      */
 463     public boolean markSupported() {
 464         return true;
 465     }
 466 
 467     /**
 468      * Marks the present position in the stream.  Subsequent calls to reset()
 469      * will attempt to reposition the stream to this point.
 470      *
 471      * @param readAheadLimit   Limit on the number of characters that may be
 472      *                         read while still preserving the mark. An attempt
 473      *                         to reset the stream after reading characters
 474      *                         up to this limit or beyond may fail.
 475      *                         A limit value larger than the size of the input
 476      *                         buffer will cause a new buffer to be allocated
 477      *                         whose size is no smaller than limit.
 478      *                         Therefore large values should be used with care.
 479      *
 480      * @exception  IllegalArgumentException  If readAheadLimit is < 0
 481      * @exception  IOException  If an I/O error occurs
 482      */
 483     public void mark(int readAheadLimit) throws IOException {
 484         if (readAheadLimit < 0) {
 485             throw new IllegalArgumentException("Read-ahead limit < 0");
 486         }
 487         synchronized (lock) {
 488             ensureOpen();
 489             this.readAheadLimit = readAheadLimit;
 490             markedChar = nextChar;
 491             markedSkipLF = skipLF;
 492         }
 493     }
 494 
 495     /**
 496      * Resets the stream to the most recent mark.
 497      *
 498      * @exception  IOException  If the stream has never been marked,
 499      *                          or if the mark has been invalidated
 500      */
 501     public void reset() throws IOException {
 502         synchronized (lock) {
 503             ensureOpen();
 504             if (markedChar < 0)
 505                 throw new IOException((markedChar == INVALIDATED)
 506                                       ? "Mark invalid"
 507                                       : "Stream not marked");
 508             nextChar = markedChar;
 509             skipLF = markedSkipLF;
 510         }
 511     }
 512 
 513     public void close() throws IOException {
 514         synchronized (lock) {
 515             if (in == null)
 516                 return;
 517             try {
 518                 in.close();
 519             } finally {
 520                 in = null;
 521                 cb = null;
 522             }
 523         }
 524     }
 525 }