1 /*
  2  * Copyright (c) 1996, 2021, 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 import java.util.Iterator;
 29 import java.util.NoSuchElementException;
 30 import java.util.Objects;
 31 import java.util.Spliterator;
 32 import java.util.Spliterators;
 33 import java.util.stream.Stream;
 34 import java.util.stream.StreamSupport;
 35 import jdk.internal.misc.InternalLock;
 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     private Reader in;
 73 
 74     private char[] cb;
 75     private int nChars, nextChar;
 76 
 77     private static final int INVALIDATED = -2;
 78     private static final int UNMARKED = -1;
 79     private int markedChar = UNMARKED;
 80     private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
 81 
 82     /** If the next character is a line feed, skip it */
 83     private boolean skipLF = false;
 84 
 85     /** The skipLF flag when the mark was set */
 86     private boolean markedSkipLF = false;
 87 
 88     private static int defaultCharBufferSize = 8192;
 89     private static int defaultExpectedLineLength = 80;
 90     
 91     /**
 92      * Creates a buffering character-input stream that uses an input buffer of
 93      * the specified size.
 94      *
 95      * @param  in   A Reader
 96      * @param  sz   Input-buffer size
 97      *
 98      * @throws IllegalArgumentException  If {@code sz <= 0}
 99      */
100     public BufferedReader(Reader in, int sz) {
101         Objects.requireNonNull(in);
102         if (sz <= 0)
103             throw new IllegalArgumentException("Buffer size <= 0");
104         this.in = in;
105         cb = new char[sz];
106         nextChar = nChars = 0;
107     }
108 
109     /**
110      * Creates a buffering character-input stream that uses a default-sized
111      * input buffer.
112      *
113      * @param  in   A Reader
114      */
115     public BufferedReader(Reader in) {
116         this(in, defaultCharBufferSize);
117     }
118 
119     /** Checks to make sure that the stream has not been closed */
120     private void ensureOpen() throws IOException {
121         if (in == null)
122             throw new IOException("Stream closed");
123     }
124 
125     /**
126      * Fills the input buffer, taking the mark into account if it is valid.
127      */
128     private void fill() throws IOException {
129         int dst;
130         if (markedChar <= UNMARKED) {
131             /* No mark */
132             dst = 0;
133         } else {
134             /* Marked */
135             int delta = nextChar - markedChar;
136             if (delta >= readAheadLimit) {
137                 /* Gone past read-ahead limit: Invalidate mark */
138                 markedChar = INVALIDATED;
139                 readAheadLimit = 0;
140                 dst = 0;
141             } else {
142                 if (readAheadLimit <= cb.length) {
143                     /* Shuffle in the current buffer */
144                     System.arraycopy(cb, markedChar, cb, 0, delta);
145                     markedChar = 0;
146                     dst = delta;
147                 } else {
148                     /* Reallocate buffer to accommodate read-ahead limit */
149                     char[] ncb = new char[readAheadLimit];
150                     System.arraycopy(cb, markedChar, ncb, 0, delta);
151                     cb = ncb;
152                     markedChar = 0;
153                     dst = delta;
154                 }
155                 nextChar = nChars = delta;
156             }
157         }
158 
159         int n;
160         do {
161             n = in.read(cb, dst, cb.length - dst);
162         } while (n == 0);
163         if (n > 0) {
164             nChars = dst + n;
165             nextChar = dst;
166         }
167     }
168 
169     /**
170      * Reads a single character.
171      *
172      * @return The character read, as an integer in the range
173      *         0 to 65535 ({@code 0x00-0xffff}), or -1 if the
174      *         end of the stream has been reached
175      * @throws     IOException  If an I/O error occurs
176      */
177     public int read() throws IOException {
178         Object lock = this.lock;
179         if (lock instanceof InternalLock locker) {
180             locker.lock();
181             try {
182                 return lockedRead();
183             } finally {
184                 locker.unlock();
185             }
186         } else {
187             synchronized (lock) {
188                 return lockedRead();
189             }
190         }
191     }
192 
193     private int lockedRead() throws IOException {
194         ensureOpen();
195         for (;;) {
196             if (nextChar >= nChars) {
197                 fill();
198                 if (nextChar >= nChars)
199                     return -1;
200             }
201             if (skipLF) {
202                 skipLF = false;
203                 if (cb[nextChar] == '\n') {
204                     nextChar++;
205                     continue;
206                 }
207             }
208             return cb[nextChar++];
209         }
210     }
211 
212     /**
213      * Reads characters into a portion of an array, reading from the underlying
214      * stream if necessary.
215      */
216     private int read1(char[] cbuf, int off, int len) throws IOException {
217         if (nextChar >= nChars) {
218             /* If the requested length is at least as large as the buffer, and
219                if there is no mark/reset activity, and if line feeds are not
220                being skipped, do not bother to copy the characters into the
221                local buffer.  In this way buffered streams will cascade
222                harmlessly. */
223             if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
224                 return in.read(cbuf, off, len);
225             }
226             fill();
227         }
228         if (nextChar >= nChars) return -1;
229         if (skipLF) {
230             skipLF = false;
231             if (cb[nextChar] == '\n') {
232                 nextChar++;
233                 if (nextChar >= nChars)
234                     fill();
235                 if (nextChar >= nChars)
236                     return -1;
237             }
238         }
239         int n = Math.min(len, nChars - nextChar);
240         System.arraycopy(cb, nextChar, cbuf, off, n);
241         nextChar += n;
242         return n;
243     }
244 
245     /**
246      * Reads characters into a portion of an array.
247      *
248      * <p> This method implements the general contract of the corresponding
249      * {@link Reader#read(char[], int, int) read} method of the
250      * {@link Reader} class.  As an additional convenience, it
251      * attempts to read as many characters as possible by repeatedly invoking
252      * the {@code read} method of the underlying stream.  This iterated
253      * {@code read} continues until one of the following conditions becomes
254      * true:
255      * <ul>
256      *
257      *   <li> The specified number of characters have been read,
258      *
259      *   <li> The {@code read} method of the underlying stream returns
260      *   {@code -1}, indicating end-of-file, or
261      *
262      *   <li> The {@code ready} method of the underlying stream
263      *   returns {@code false}, indicating that further input requests
264      *   would block.
265      *
266      * </ul>
267      * If the first {@code read} on the underlying stream returns
268      * {@code -1} to indicate end-of-file then this method returns
269      * {@code -1}.  Otherwise this method returns the number of characters
270      * actually read.
271      *
272      * <p> Subclasses of this class are encouraged, but not required, to
273      * attempt to read as many characters as possible in the same fashion.
274      *
275      * <p> Ordinarily this method takes characters from this stream's character
276      * buffer, filling it from the underlying stream as necessary.  If,
277      * however, the buffer is empty, the mark is not valid, and the requested
278      * length is at least as large as the buffer, then this method will read
279      * characters directly from the underlying stream into the given array.
280      * Thus redundant {@code BufferedReader}s will not copy data
281      * unnecessarily.
282      *
283      * @param      cbuf  {@inheritDoc}
284      * @param      off   {@inheritDoc}
285      * @param      len   {@inheritDoc}
286      *
287      * @return     {@inheritDoc}
288      *
289      * @throws     IndexOutOfBoundsException {@inheritDoc}
290      * @throws     IOException  {@inheritDoc}
291      */
292     public int read(char[] cbuf, int off, int len) throws IOException {
293         Object lock = this.lock;
294         if (lock instanceof InternalLock locker) {
295             locker.lock();
296             try {
297                 return lockedRead(cbuf, off, len);
298             } finally {
299                 locker.unlock();
300             }
301         } else {
302             synchronized (lock) {
303                 return lockedRead(cbuf, off, len);
304             }
305         }
306     }
307 
308     private int lockedRead(char[] cbuf, int off, int len) throws IOException {
309         ensureOpen();
310         Objects.checkFromIndexSize(off, len, cbuf.length);
311         if (len == 0) {
312             return 0;
313         }
314 
315         int n = read1(cbuf, off, len);
316         if (n <= 0) return n;
317         while ((n < len) && in.ready()) {
318             int n1 = read1(cbuf, off + n, len - n);
319             if (n1 <= 0) break;
320             n += n1;
321         }
322         return n;
323     }
324 
325     /**
326      * Reads a line of text.  A line is considered to be terminated by any one
327      * of a line feed ('\n'), a carriage return ('\r'), a carriage return
328      * followed immediately by a line feed, or by reaching the end-of-file
329      * (EOF).
330      *
331      * @param      ignoreLF  If true, the next '\n' will be skipped
332      * @param      term      Output: Whether a line terminator was encountered
333      *                       while reading the line; may be {@code null}.
334      *
335      * @return     A String containing the contents of the line, not including
336      *             any line-termination characters, or null if the end of the
337      *             stream has been reached without reading any characters
338      *
339      * @see        java.io.LineNumberReader#readLine()
340      *
341      * @throws     IOException  If an I/O error occurs
342      */
343     String readLine(boolean ignoreLF, boolean[] term) throws IOException {
344         Object lock = this.lock;
345         if (lock instanceof InternalLock locker) {
346             locker.lock();
347             try {
348                 return lockedReadLine(ignoreLF, term);
349             } finally {
350                 locker.unlock();
351             }
352         } else {
353             synchronized (lock) {
354                 return lockedReadLine(ignoreLF, term);
355             }
356         }
357     }
358 
359     private String lockedReadLine(boolean ignoreLF, boolean[] term) throws IOException {
360         StringBuilder s = null;
361         int startChar;
362 
363         ensureOpen();
364         boolean omitLF = ignoreLF || skipLF;
365         if (term != null) term[0] = false;
366 
367       bufferLoop:
368         for (;;) {
369 
370             if (nextChar >= nChars)
371                 fill();
372             if (nextChar >= nChars) { /* EOF */
373                 if (s != null && s.length() > 0)
374                     return s.toString();
375                 else
376                     return null;
377             }
378             boolean eol = false;
379             char c = 0;
380             int i;
381 
382             /* Skip a leftover '\n', if necessary */
383             if (omitLF && (cb[nextChar] == '\n'))
384                 nextChar++;
385             skipLF = false;
386             omitLF = false;
387 
388           charLoop:
389             for (i = nextChar; i < nChars; i++) {
390                 c = cb[i];
391                 if ((c == '\n') || (c == '\r')) {
392                     if (term != null) term[0] = true;
393                     eol = true;
394                     break charLoop;
395                 }
396             }
397 
398             startChar = nextChar;
399             nextChar = i;
400 
401             if (eol) {
402                 String str;
403                 if (s == null) {
404                     str = new String(cb, startChar, i - startChar);
405                 } else {
406                     s.append(cb, startChar, i - startChar);
407                     str = s.toString();
408                 }
409                 nextChar++;
410                 if (c == '\r') {
411                     skipLF = true;
412                 }
413                 return str;
414             }
415 
416             if (s == null)
417                 s = new StringBuilder(defaultExpectedLineLength);
418             s.append(cb, startChar, i - startChar);
419         }
420     }
421 
422     /**
423      * Reads a line of text.  A line is considered to be terminated by any one
424      * of a line feed ('\n'), a carriage return ('\r'), a carriage return
425      * followed immediately by a line feed, or by reaching the end-of-file
426      * (EOF).
427      *
428      * @return     A String containing the contents of the line, not including
429      *             any line-termination characters, or null if the end of the
430      *             stream has been reached without reading any characters
431      *
432      * @throws     IOException  If an I/O error occurs
433      *
434      * @see java.nio.file.Files#readAllLines
435      */
436     public String readLine() throws IOException {
437         return readLine(false, null);
438     }
439 
440     /**
441      * {@inheritDoc}
442      */
443     public long skip(long n) throws IOException {
444         if (n < 0L) {
445             throw new IllegalArgumentException("skip value is negative");
446         }
447         Object lock = this.lock;
448         if (lock instanceof InternalLock locker) {
449             locker.lock();
450             try {
451                 return lockedSkip(n);
452             } finally {
453                 locker.unlock();
454             }
455         } else {
456             synchronized (lock) {
457                 return lockedSkip(n);
458             }
459         }
460     }
461 
462     private long lockedSkip(long n) throws IOException {
463         ensureOpen();
464         long r = n;
465         while (r > 0) {
466             if (nextChar >= nChars)
467                 fill();
468             if (nextChar >= nChars) /* EOF */
469                 break;
470             if (skipLF) {
471                 skipLF = false;
472                 if (cb[nextChar] == '\n') {
473                     nextChar++;
474                 }
475             }
476             long d = nChars - nextChar;
477             if (r <= d) {
478                 nextChar += r;
479                 r = 0;
480                 break;
481             }
482             else {
483                 r -= d;
484                 nextChar = nChars;
485             }
486         }
487         return n - r;
488     }
489 
490     /**
491      * Tells whether this stream is ready to be read.  A buffered character
492      * stream is ready if the buffer is not empty, or if the underlying
493      * character stream is ready.
494      *
495      * @throws     IOException  If an I/O error occurs
496      */
497     public boolean ready() throws IOException {
498         Object lock = this.lock;
499         if (lock instanceof InternalLock locker) {
500             locker.lock();
501             try {
502                 return lockedReady();
503             } finally {
504                 locker.unlock();
505             }
506         } else {
507             synchronized (lock) {
508                 return lockedReady();
509             }
510         }
511     }
512 
513     private boolean lockedReady() throws IOException {
514         ensureOpen();
515 
516         /*
517          * If newline needs to be skipped and the next char to be read
518          * is a newline character, then just skip it right away.
519          */
520         if (skipLF) {
521             /* Note that in.ready() will return true if and only if the next
522              * read on the stream will not block.
523              */
524             if (nextChar >= nChars && in.ready()) {
525                 fill();
526             }
527             if (nextChar < nChars) {
528                 if (cb[nextChar] == '\n')
529                     nextChar++;
530                 skipLF = false;
531             }
532         }
533         return (nextChar < nChars) || in.ready();
534     }
535 
536     /**
537      * Tells whether this stream supports the mark() operation, which it does.
538      */
539     public boolean markSupported() {
540         return true;
541     }
542 
543     /**
544      * Marks the present position in the stream.  Subsequent calls to reset()
545      * will attempt to reposition the stream to this point.
546      *
547      * @param readAheadLimit   Limit on the number of characters that may be
548      *                         read while still preserving the mark. An attempt
549      *                         to reset the stream after reading characters
550      *                         up to this limit or beyond may fail.
551      *                         A limit value larger than the size of the input
552      *                         buffer will cause a new buffer to be allocated
553      *                         whose size is no smaller than limit.
554      *                         Therefore large values should be used with care.
555      *
556      * @throws     IllegalArgumentException  If {@code readAheadLimit < 0}
557      * @throws     IOException  If an I/O error occurs
558      */
559     public void mark(int readAheadLimit) throws IOException {
560         if (readAheadLimit < 0) {
561             throw new IllegalArgumentException("Read-ahead limit < 0");
562         }
563         Object lock = this.lock;
564         if (lock instanceof InternalLock locker) {
565             locker.lock();
566             try {
567                 lockedMark(readAheadLimit);
568             } finally {
569                 locker.unlock();
570             }
571         } else {
572             synchronized (lock) {
573                 lockedMark(readAheadLimit);
574             }
575         }
576     }
577 
578     private void lockedMark(int readAheadLimit) throws IOException {
579         ensureOpen();
580         this.readAheadLimit = readAheadLimit;
581         markedChar = nextChar;
582         markedSkipLF = skipLF;
583     }
584 
585     /**
586      * Resets the stream to the most recent mark.
587      *
588      * @throws     IOException  If the stream has never been marked,
589      *                          or if the mark has been invalidated
590      */
591     public void reset() throws IOException {
592         Object lock = this.lock;
593         if (lock instanceof InternalLock locker) {
594             locker.lock();
595             try {
596                 lockedReset();
597             } finally {
598                 locker.unlock();
599             }
600         } else {
601             synchronized (lock) {
602                 lockedReset();
603             }
604         }
605     }
606 
607     private void lockedReset() throws IOException {
608         ensureOpen();
609         if (markedChar < 0)
610             throw new IOException((markedChar == INVALIDATED)
611                                   ? "Mark invalid"
612                                   : "Stream not marked");
613         nextChar = markedChar;
614         skipLF = markedSkipLF;
615     }
616 
617     public void close() throws IOException {
618         Object lock = this.lock;
619         if (lock instanceof InternalLock locker) {
620             locker.lock();
621             try {
622                 lockedClose();
623             } finally {
624                 locker.unlock();
625             }
626         } else {
627             synchronized (lock) {
628                 lockedClose();
629             }
630         }
631     }
632 
633     private void lockedClose() throws IOException {
634         if (in == null)
635             return;
636         try {
637             in.close();
638         } finally {
639             in = null;
640             cb = null;
641         }
642     }
643 
644     /**
645      * Returns a {@code Stream}, the elements of which are lines read from
646      * this {@code BufferedReader}.  The {@link Stream} is lazily populated,
647      * i.e., read only occurs during the
648      * <a href="../util/stream/package-summary.html#StreamOps">terminal
649      * stream operation</a>.
650      *
651      * <p> The reader must not be operated on during the execution of the
652      * terminal stream operation. Otherwise, the result of the terminal stream
653      * operation is undefined.
654      *
655      * <p> After execution of the terminal stream operation there are no
656      * guarantees that the reader will be at a specific position from which to
657      * read the next character or line.
658      *
659      * <p> If an {@link IOException} is thrown when accessing the underlying
660      * {@code BufferedReader}, it is wrapped in an {@link
661      * UncheckedIOException} which will be thrown from the {@code Stream}
662      * method that caused the read to take place. This method will return a
663      * Stream if invoked on a BufferedReader that is closed. Any operation on
664      * that stream that requires reading from the BufferedReader after it is
665      * closed, will cause an UncheckedIOException to be thrown.
666      *
667      * @return a {@code Stream<String>} providing the lines of text
668      *         described by this {@code BufferedReader}
669      *
670      * @since 1.8
671      */
672     public Stream<String> lines() {
673         Iterator<String> iter = new Iterator<>() {
674             String nextLine = null;
675 
676             @Override
677             public boolean hasNext() {
678                 if (nextLine != null) {
679                     return true;
680                 } else {
681                     try {
682                         nextLine = readLine();
683                         return (nextLine != null);
684                     } catch (IOException e) {
685                         throw new UncheckedIOException(e);
686                     }
687                 }
688             }
689 
690             @Override
691             public String next() {
692                 if (nextLine != null || hasNext()) {
693                     String line = nextLine;
694                     nextLine = null;
695                     return line;
696                 } else {
697                     throw new NoSuchElementException();
698                 }
699             }
700         };
701         return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
702                 iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
703     }
704 }