1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package java.io;
28 
29 
30 import java.util.Iterator;
31 import java.util.NoSuchElementException;
32 import java.util.Spliterator;
33 import java.util.Spliterators;
34 import java.util.stream.Stream;
35 import java.util.stream.StreamSupport;
36 
37 /**
38  * Reads text from a character-input stream, buffering characters so as to
39  * provide for the efficient reading of characters, arrays, and lines.
40  *
41  * <p> The buffer size may be specified, or the default size may be used.  The
42  * default is large enough for most purposes.
43  *
44  * <p> In general, each read request made of a Reader causes a corresponding
45  * read request to be made of the underlying character or byte stream.  It is
46  * therefore advisable to wrap a BufferedReader around any Reader whose read()
47  * operations may be costly, such as FileReaders and InputStreamReaders.  For
48  * example,
49  *
50  * <pre>
51  * BufferedReader in
52  *   = new BufferedReader(new FileReader("foo.in"));
53  * </pre>
54  *
55  * will buffer the input from the specified file.  Without buffering, each
56  * invocation of read() or readLine() could cause bytes to be read from the
57  * file, converted into characters, and then returned, which can be very
58  * inefficient.
59  *
60  * <p> Programs that use DataInputStreams for textual input can be localized by
61  * replacing each DataInputStream with an appropriate BufferedReader.
62  *
63  * @see FileReader
64  * @see InputStreamReader
65  * @see java.nio.file.Files#newBufferedReader
66  *
67  * @author      Mark Reinhold
68  * @since       1.1
69  */
70 
71 public class BufferedReader extends Reader {
72 
73     private Reader in;
74 
75     private char cb[];
76     private int nChars, nextChar;
77 
78     private static final int INVALIDATED = -2;
79     private static final int UNMARKED = -1;
80     private int markedChar = UNMARKED;
81     private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
82 
83     /** If the next character is a line feed, skip it */
84     private boolean skipLF = false;
85 
86     /** The skipLF flag when the mark was set */
87     private boolean markedSkipLF = false;
88 
89     private static int defaultCharBufferSize = 8192;
90     private static int defaultExpectedLineLength = 80;
91 
92     /**
93      * Creates a buffering character-input stream that uses an input buffer of
94      * the specified size.
95      *
96      * @param  in   A Reader
97      * @param  sz   Input-buffer size
98      *
99      * @exception  IllegalArgumentException  If {@code sz <= 0}
100      */
BufferedReader(Reader in, int sz)101     public BufferedReader(Reader in, int sz) {
102         super(in);
103         if (sz <= 0)
104             throw new IllegalArgumentException("Buffer size <= 0");
105         this.in = in;
106         cb = new char[sz];
107         nextChar = nChars = 0;
108     }
109 
110     /**
111      * Creates a buffering character-input stream that uses a default-sized
112      * input buffer.
113      *
114      * @param  in   A Reader
115      */
BufferedReader(Reader in)116     public BufferedReader(Reader in) {
117         this(in, defaultCharBufferSize);
118     }
119 
120     /** Checks to make sure that the stream has not been closed */
ensureOpen()121     private void ensureOpen() throws IOException {
122         if (in == null)
123             throw new IOException("Stream closed");
124     }
125 
126     /**
127      * Fills the input buffer, taking the mark into account if it is valid.
128      */
fill()129     private void fill() throws IOException {
130         int dst;
131         if (markedChar <= UNMARKED) {
132             /* No mark */
133             dst = 0;
134         } else {
135             /* Marked */
136             int delta = nextChar - markedChar;
137             if (delta >= readAheadLimit) {
138                 /* Gone past read-ahead limit: Invalidate mark */
139                 markedChar = INVALIDATED;
140                 readAheadLimit = 0;
141                 dst = 0;
142             } else {
143                 if (readAheadLimit <= cb.length) {
144                     /* Shuffle in the current buffer */
145                     System.arraycopy(cb, markedChar, cb, 0, delta);
146                     markedChar = 0;
147                     dst = delta;
148                 } else {
149                     /* Reallocate buffer to accommodate read-ahead limit */
150                     //
151                     // Android-changed: Use the same strategy as BufferedInputStream,
152                     // i.e, double the size of the buffer on each fill. Do not directly
153                     // size the buffer to the readAheadLimit.
154                     //
155                     // char ncb[] = new char[readAheadLimit];
156                     int nlength = cb.length * 2;
157                     if (nlength > readAheadLimit) {
158                         nlength = readAheadLimit;
159                     }
160                     char ncb[] = new char[nlength];
161                     System.arraycopy(cb, markedChar, ncb, 0, delta);
162                     cb = ncb;
163                     markedChar = 0;
164                     dst = delta;
165                 }
166                 nextChar = nChars = delta;
167             }
168         }
169 
170         int n;
171         do {
172             n = in.read(cb, dst, cb.length - dst);
173         } while (n == 0);
174         if (n > 0) {
175             nChars = dst + n;
176             nextChar = dst;
177         }
178     }
179 
180     /**
181      * Reads a single character.
182      *
183      * @return The character read, as an integer in the range
184      *         0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
185      *         end of the stream has been reached
186      * @exception  IOException  If an I/O error occurs
187      */
read()188     public int read() throws IOException {
189         synchronized (lock) {
190             ensureOpen();
191             for (;;) {
192                 if (nextChar >= nChars) {
193                     fill();
194                     if (nextChar >= nChars)
195                         return -1;
196                 }
197                 if (skipLF) {
198                     skipLF = false;
199                     if (cb[nextChar] == '\n') {
200                         nextChar++;
201                         continue;
202                     }
203                 }
204                 return cb[nextChar++];
205             }
206         }
207     }
208 
209     /**
210      * Reads characters into a portion of an array, reading from the underlying
211      * stream if necessary.
212      */
read1(char[] cbuf, int off, int len)213     private int read1(char[] cbuf, int off, int len) throws IOException {
214         if (nextChar >= nChars) {
215             /* If the requested length is at least as large as the buffer, and
216                if there is no mark/reset activity, and if line feeds are not
217                being skipped, do not bother to copy the characters into the
218                local buffer.  In this way buffered streams will cascade
219                harmlessly. */
220             if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
221                 return in.read(cbuf, off, len);
222             }
223             fill();
224         }
225         if (nextChar >= nChars) return -1;
226         if (skipLF) {
227             skipLF = false;
228             if (cb[nextChar] == '\n') {
229                 nextChar++;
230                 if (nextChar >= nChars)
231                     fill();
232                 if (nextChar >= nChars)
233                     return -1;
234             }
235         }
236         int n = Math.min(len, nChars - nextChar);
237         System.arraycopy(cb, nextChar, cbuf, off, n);
238         nextChar += n;
239         return n;
240     }
241 
242     /**
243      * Reads characters into a portion of an array.
244      *
245      * <p> This method implements the general contract of the corresponding
246      * <code>{@link Reader#read(char[], int, int) read}</code> method of the
247      * <code>{@link Reader}</code> class.  As an additional convenience, it
248      * attempts to read as many characters as possible by repeatedly invoking
249      * the <code>read</code> method of the underlying stream.  This iterated
250      * <code>read</code> continues until one of the following conditions becomes
251      * true: <ul>
252      *
253      *   <li> The specified number of characters have been read,
254      *
255      *   <li> The <code>read</code> method of the underlying stream returns
256      *   <code>-1</code>, indicating end-of-file, or
257      *
258      *   <li> The <code>ready</code> method of the underlying stream
259      *   returns <code>false</code>, indicating that further input requests
260      *   would block.
261      *
262      * </ul> If the first <code>read</code> on the underlying stream returns
263      * <code>-1</code> to indicate end-of-file then this method returns
264      * <code>-1</code>.  Otherwise this method returns the number of characters
265      * actually read.
266      *
267      * <p> Subclasses of this class are encouraged, but not required, to
268      * attempt to read as many characters as possible in the same fashion.
269      *
270      * <p> Ordinarily this method takes characters from this stream's character
271      * buffer, filling it from the underlying stream as necessary.  If,
272      * however, the buffer is empty, the mark is not valid, and the requested
273      * length is at least as large as the buffer, then this method will read
274      * characters directly from the underlying stream into the given array.
275      * Thus redundant <code>BufferedReader</code>s will not copy data
276      * unnecessarily.
277      *
278      * @param      cbuf  Destination buffer
279      * @param      off   Offset at which to start storing characters
280      * @param      len   Maximum number of characters to read
281      *
282      * @return     The number of characters read, or -1 if the end of the
283      *             stream has been reached
284      *
285      * @exception  IOException  If an I/O error occurs
286      * @exception  IndexOutOfBoundsException {@inheritDoc}
287      */
read(char cbuf[], int off, int len)288     public int read(char cbuf[], int off, int len) throws IOException {
289         synchronized (lock) {
290             ensureOpen();
291             if ((off < 0) || (off > cbuf.length) || (len < 0) ||
292                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
293                 throw new IndexOutOfBoundsException();
294             } else if (len == 0) {
295                 return 0;
296             }
297 
298             int n = read1(cbuf, off, len);
299             if (n <= 0) return n;
300             while ((n < len) && in.ready()) {
301                 int n1 = read1(cbuf, off + n, len - n);
302                 if (n1 <= 0) break;
303                 n += n1;
304             }
305             return n;
306         }
307     }
308 
309     /**
310      * Reads a line of text.  A line is considered to be terminated by any one
311      * of a line feed ('\n'), a carriage return ('\r'), a carriage return
312      * followed immediately by a line feed, or by reaching the end-of-file
313      * (EOF).
314      *
315      * @param      ignoreLF  If true, the next '\n' will be skipped
316      *
317      * @return     A String containing the contents of the line, not including
318      *             any line-termination characters, or null if the end of the
319      *             stream has been reached without reading any characters
320      *
321      * @see        java.io.LineNumberReader#readLine()
322      *
323      * @exception  IOException  If an I/O error occurs
324      */
readLine(boolean ignoreLF)325     String readLine(boolean ignoreLF) throws IOException {
326         StringBuilder s = null;
327         int startChar;
328 
329         synchronized (lock) {
330             ensureOpen();
331             boolean omitLF = ignoreLF || skipLF;
332 
333         bufferLoop:
334             for (;;) {
335 
336                 if (nextChar >= nChars)
337                     fill();
338                 if (nextChar >= nChars) { /* EOF */
339                     if (s != null && s.length() > 0)
340                         return s.toString();
341                     else
342                         return null;
343                 }
344                 boolean eol = false;
345                 char c = 0;
346                 int i;
347 
348                 /* Skip a leftover '\n', if necessary */
349                 if (omitLF && (cb[nextChar] == '\n'))
350                     nextChar++;
351                 skipLF = false;
352                 omitLF = false;
353 
354             charLoop:
355                 for (i = nextChar; i < nChars; i++) {
356                     c = cb[i];
357                     if ((c == '\n') || (c == '\r')) {
358                         eol = true;
359                         break charLoop;
360                     }
361                 }
362 
363                 startChar = nextChar;
364                 nextChar = i;
365 
366                 if (eol) {
367                     String str;
368                     if (s == null) {
369                         str = new String(cb, startChar, i - startChar);
370                     } else {
371                         s.append(cb, startChar, i - startChar);
372                         str = s.toString();
373                     }
374                     nextChar++;
375                     if (c == '\r') {
376                         skipLF = true;
377                     }
378                     return str;
379                 }
380 
381                 if (s == null)
382                     s = new StringBuilder(defaultExpectedLineLength);
383                 s.append(cb, startChar, i - startChar);
384             }
385         }
386     }
387 
388     /**
389      * Reads a line of text.  A line is considered to be terminated by any one
390      * of a line feed ('\n'), a carriage return ('\r'), a carriage return
391      * followed immediately by a line feed, or by reaching the end-of-file
392      * (EOF).
393      *
394      * @return     A String containing the contents of the line, not including
395      *             any line-termination characters, or null if the end of the
396      *             stream has been reached without reading any characters
397      *
398      * @exception  IOException  If an I/O error occurs
399      *
400      * @see java.nio.file.Files#readAllLines
401      */
readLine()402     public String readLine() throws IOException {
403         return readLine(false);
404     }
405 
406     /**
407      * Skips characters.
408      *
409      * @param  n  The number of characters to skip
410      *
411      * @return    The number of characters actually skipped
412      *
413      * @exception  IllegalArgumentException  If <code>n</code> is negative.
414      * @exception  IOException  If an I/O error occurs
415      */
skip(long n)416     public long skip(long n) throws IOException {
417         if (n < 0L) {
418             throw new IllegalArgumentException("skip value is negative");
419         }
420         synchronized (lock) {
421             ensureOpen();
422             long r = n;
423             while (r > 0) {
424                 if (nextChar >= nChars)
425                     fill();
426                 if (nextChar >= nChars) /* EOF */
427                     break;
428                 if (skipLF) {
429                     skipLF = false;
430                     if (cb[nextChar] == '\n') {
431                         nextChar++;
432                     }
433                 }
434                 long d = nChars - nextChar;
435                 if (r <= d) {
436                     nextChar += r;
437                     r = 0;
438                     break;
439                 }
440                 else {
441                     r -= d;
442                     nextChar = nChars;
443                 }
444             }
445             return n - r;
446         }
447     }
448 
449     /**
450      * Tells whether this stream is ready to be read.  A buffered character
451      * stream is ready if the buffer is not empty, or if the underlying
452      * character stream is ready.
453      *
454      * @exception  IOException  If an I/O error occurs
455      */
ready()456     public boolean ready() throws IOException {
457         synchronized (lock) {
458             ensureOpen();
459 
460             /*
461              * If newline needs to be skipped and the next char to be read
462              * is a newline character, then just skip it right away.
463              */
464             if (skipLF) {
465                 /* Note that in.ready() will return true if and only if the next
466                  * read on the stream will not block.
467                  */
468                 if (nextChar >= nChars && in.ready()) {
469                     fill();
470                 }
471                 if (nextChar < nChars) {
472                     if (cb[nextChar] == '\n')
473                         nextChar++;
474                     skipLF = false;
475                 }
476             }
477             return (nextChar < nChars) || in.ready();
478         }
479     }
480 
481     /**
482      * Tells whether this stream supports the mark() operation, which it does.
483      */
markSupported()484     public boolean markSupported() {
485         return true;
486     }
487 
488     /**
489      * Marks the present position in the stream.  Subsequent calls to reset()
490      * will attempt to reposition the stream to this point.
491      *
492      * @param readAheadLimit   Limit on the number of characters that may be
493      *                         read while still preserving the mark. An attempt
494      *                         to reset the stream after reading characters
495      *                         up to this limit or beyond may fail.
496      *                         A limit value larger than the size of the input
497      *                         buffer will cause a new buffer to be allocated
498      *                         whose size is no smaller than limit.
499      *                         Therefore large values should be used with care.
500      *
501      * @exception  IllegalArgumentException  If {@code readAheadLimit < 0}
502      * @exception  IOException  If an I/O error occurs
503      */
mark(int readAheadLimit)504     public void mark(int readAheadLimit) throws IOException {
505         if (readAheadLimit < 0) {
506             throw new IllegalArgumentException("Read-ahead limit < 0");
507         }
508         synchronized (lock) {
509             ensureOpen();
510             this.readAheadLimit = readAheadLimit;
511             markedChar = nextChar;
512             markedSkipLF = skipLF;
513         }
514     }
515 
516     /**
517      * Resets the stream to the most recent mark.
518      *
519      * @exception  IOException  If the stream has never been marked,
520      *                          or if the mark has been invalidated
521      */
reset()522     public void reset() throws IOException {
523         synchronized (lock) {
524             ensureOpen();
525             if (markedChar < 0)
526                 throw new IOException((markedChar == INVALIDATED)
527                                       ? "Mark invalid"
528                                       : "Stream not marked");
529             nextChar = markedChar;
530             skipLF = markedSkipLF;
531         }
532     }
533 
close()534     public void close() throws IOException {
535         synchronized (lock) {
536             if (in == null)
537                 return;
538             try {
539                 in.close();
540             } finally {
541                 in = null;
542                 cb = null;
543             }
544         }
545     }
546 
547     /**
548      * Returns a {@code Stream}, the elements of which are lines read from
549      * this {@code BufferedReader}.  The {@link Stream} is lazily populated,
550      * i.e., read only occurs during the
551      * <a href="../util/stream/package-summary.html#StreamOps">terminal
552      * stream operation</a>.
553      *
554      * <p> The reader must not be operated on during the execution of the
555      * terminal stream operation. Otherwise, the result of the terminal stream
556      * operation is undefined.
557      *
558      * <p> After execution of the terminal stream operation there are no
559      * guarantees that the reader will be at a specific position from which to
560      * read the next character or line.
561      *
562      * <p> If an {@link IOException} is thrown when accessing the underlying
563      * {@code BufferedReader}, it is wrapped in an {@link
564      * UncheckedIOException} which will be thrown from the {@code Stream}
565      * method that caused the read to take place. This method will return a
566      * Stream if invoked on a BufferedReader that is closed. Any operation on
567      * that stream that requires reading from the BufferedReader after it is
568      * closed, will cause an UncheckedIOException to be thrown.
569      *
570      * @return a {@code Stream<String>} providing the lines of text
571      *         described by this {@code BufferedReader}
572      *
573      * @since 1.8
574      */
lines()575     public Stream<String> lines() {
576         Iterator<String> iter = new Iterator<>() {
577             String nextLine = null;
578 
579             @Override
580             public boolean hasNext() {
581                 if (nextLine != null) {
582                     return true;
583                 } else {
584                     try {
585                         nextLine = readLine();
586                         return (nextLine != null);
587                     } catch (IOException e) {
588                         throw new UncheckedIOException(e);
589                     }
590                 }
591             }
592 
593             @Override
594             public String next() {
595                 if (nextLine != null || hasNext()) {
596                     String line = nextLine;
597                     nextLine = null;
598                     return line;
599                 } else {
600                     throw new NoSuchElementException();
601                 }
602             }
603         };
604         return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
605                 iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
606     }
607 }
608