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