1/*
2 * Copyright (c) 1996, 2017, 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
26package java.io;
27
28
29import java.util.Iterator;
30import java.util.NoSuchElementException;
31import java.util.Spliterator;
32import java.util.Spliterators;
33import java.util.stream.Stream;
34import java.util.stream.StreamSupport;
35
36/**
37 * Reads text from a character-input stream, buffering characters so as to
38 * provide for the efficient reading of characters, arrays, and lines.
39 *
40 * <p> The buffer size may be specified, or the default size may be used.  The
41 * default is large enough for most purposes.
42 *
43 * <p> In general, each read request made of a Reader causes a corresponding
44 * read request to be made of the underlying character or byte stream.  It is
45 * therefore advisable to wrap a BufferedReader around any Reader whose read()
46 * operations may be costly, such as FileReaders and InputStreamReaders.  For
47 * example,
48 *
49 * <pre>
50 * BufferedReader in
51 *   = new BufferedReader(new FileReader("foo.in"));
52 * </pre>
53 *
54 * will buffer the input from the specified file.  Without buffering, each
55 * invocation of read() or readLine() could cause bytes to be read from the
56 * file, converted into characters, and then returned, which can be very
57 * inefficient.
58 *
59 * <p> Programs that use DataInputStreams for textual input can be localized by
60 * replacing each DataInputStream with an appropriate BufferedReader.
61 *
62 * @see FileReader
63 * @see InputStreamReader
64 * @see java.nio.file.Files#newBufferedReader
65 *
66 * @author      Mark Reinhold
67 * @since       1.1
68 */
69
70public class BufferedReader extends Reader {
71
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     * @exception  IllegalArgumentException  If {@code sz <= 0}
99     */
100    public BufferedReader(Reader in, int sz) {
101        super(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     * @exception  IOException  If an I/O error occurs
176     */
177    public int read() throws IOException {
178        synchronized (lock) {
179            ensureOpen();
180            for (;;) {
181                if (nextChar >= nChars) {
182                    fill();
183                    if (nextChar >= nChars)
184                        return -1;
185                }
186                if (skipLF) {
187                    skipLF = false;
188                    if (cb[nextChar] == '\n') {
189                        nextChar++;
190                        continue;
191                    }
192                }
193                return cb[nextChar++];
194            }
195        }
196    }
197
198    /**
199     * Reads characters into a portion of an array, reading from the underlying
200     * stream if necessary.
201     */
202    private int read1(char[] cbuf, int off, int len) throws IOException {
203        if (nextChar >= nChars) {
204            /* If the requested length is at least as large as the buffer, and
205               if there is no mark/reset activity, and if line feeds are not
206               being skipped, do not bother to copy the characters into the
207               local buffer.  In this way buffered streams will cascade
208               harmlessly. */
209            if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
210                return in.read(cbuf, off, len);
211            }
212            fill();
213        }
214        if (nextChar >= nChars) return -1;
215        if (skipLF) {
216            skipLF = false;
217            if (cb[nextChar] == '\n') {
218                nextChar++;
219                if (nextChar >= nChars)
220                    fill();
221                if (nextChar >= nChars)
222                    return -1;
223            }
224        }
225        int n = Math.min(len, nChars - nextChar);
226        System.arraycopy(cb, nextChar, cbuf, off, n);
227        nextChar += n;
228        return n;
229    }
230
231    /**
232     * Reads characters into a portion of an array.
233     *
234     * <p> This method implements the general contract of the corresponding
235     * <code>{@link Reader#read(char[], int, int) read}</code> method of the
236     * <code>{@link Reader}</code> class.  As an additional convenience, it
237     * attempts to read as many characters as possible by repeatedly invoking
238     * the <code>read</code> method of the underlying stream.  This iterated
239     * <code>read</code> continues until one of the following conditions becomes
240     * true: <ul>
241     *
242     *   <li> The specified number of characters have been read,
243     *
244     *   <li> The <code>read</code> method of the underlying stream returns
245     *   <code>-1</code>, indicating end-of-file, or
246     *
247     *   <li> The <code>ready</code> method of the underlying stream
248     *   returns <code>false</code>, indicating that further input requests
249     *   would block.
250     *
251     * </ul> If the first <code>read</code> on the underlying stream returns
252     * <code>-1</code> to indicate end-of-file then this method returns
253     * <code>-1</code>.  Otherwise this method returns the number of characters
254     * actually read.
255     *
256     * <p> Subclasses of this class are encouraged, but not required, to
257     * attempt to read as many characters as possible in the same fashion.
258     *
259     * <p> Ordinarily this method takes characters from this stream's character
260     * buffer, filling it from the underlying stream as necessary.  If,
261     * however, the buffer is empty, the mark is not valid, and the requested
262     * length is at least as large as the buffer, then this method will read
263     * characters directly from the underlying stream into the given array.
264     * Thus redundant <code>BufferedReader</code>s will not copy data
265     * unnecessarily.
266     *
267     * @param      cbuf  Destination buffer
268     * @param      off   Offset at which to start storing characters
269     * @param      len   Maximum number of characters to read
270     *
271     * @return     The number of characters read, or -1 if the end of the
272     *             stream has been reached
273     *
274     * @exception  IOException  If an I/O error occurs
275     * @exception  IndexOutOfBoundsException {@inheritDoc}
276     */
277    public int read(char cbuf[], int off, int len) throws IOException {
278        synchronized (lock) {
279            ensureOpen();
280            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
281                ((off + len) > cbuf.length) || ((off + len) < 0)) {
282                throw new IndexOutOfBoundsException();
283            } else if (len == 0) {
284                return 0;
285            }
286
287            int n = read1(cbuf, off, len);
288            if (n <= 0) return n;
289            while ((n < len) && in.ready()) {
290                int n1 = read1(cbuf, off + n, len - n);
291                if (n1 <= 0) break;
292                n += n1;
293            }
294            return n;
295        }
296    }
297
298    /**
299     * Reads a line of text.  A line is considered to be terminated by any one
300     * of a line feed ('\n'), a carriage return ('\r'), a carriage return
301     * followed immediately by a line feed, or by reaching the end-of-file
302     * (EOF).
303     *
304     * @param      ignoreLF  If true, the next '\n' will be skipped
305     *
306     * @return     A String containing the contents of the line, not including
307     *             any line-termination characters, or null if the end of the
308     *             stream has been reached without reading any characters
309     *
310     * @see        java.io.LineNumberReader#readLine()
311     *
312     * @exception  IOException  If an I/O error occurs
313     */
314    String readLine(boolean ignoreLF) throws IOException {
315        StringBuffer s = null;
316        int startChar;
317
318        synchronized (lock) {
319            ensureOpen();
320            boolean omitLF = ignoreLF || skipLF;
321
322        bufferLoop:
323            for (;;) {
324
325                if (nextChar >= nChars)
326                    fill();
327                if (nextChar >= nChars) { /* EOF */
328                    if (s != null && s.length() > 0)
329                        return s.toString();
330                    else
331                        return null;
332                }
333                boolean eol = false;
334                char c = 0;
335                int i;
336
337                /* Skip a leftover '\n', if necessary */
338                if (omitLF && (cb[nextChar] == '\n'))
339                    nextChar++;
340                skipLF = false;
341                omitLF = false;
342
343            charLoop:
344                for (i = nextChar; i < nChars; i++) {
345                    c = cb[i];
346                    if ((c == '\n') || (c == '\r')) {
347                        eol = true;
348                        break charLoop;
349                    }
350                }
351
352                startChar = nextChar;
353                nextChar = i;
354
355                if (eol) {
356                    String str;
357                    if (s == null) {
358                        str = new String(cb, startChar, i - startChar);
359                    } else {
360                        s.append(cb, startChar, i - startChar);
361                        str = s.toString();
362                    }
363                    nextChar++;
364                    if (c == '\r') {
365                        skipLF = true;
366                    }
367                    return str;
368                }
369
370                if (s == null)
371                    s = new StringBuffer(defaultExpectedLineLength);
372                s.append(cb, startChar, i - startChar);
373            }
374        }
375    }
376
377    /**
378     * Reads a line of text.  A line is considered to be terminated by any one
379     * of a line feed ('\n'), a carriage return ('\r'), a carriage return
380     * followed immediately by a line feed, or by reaching the end-of-file
381     * (EOF).
382     *
383     * @return     A String containing the contents of the line, not including
384     *             any line-termination characters, or null if the end of the
385     *             stream has been reached without reading any characters
386     *
387     * @exception  IOException  If an I/O error occurs
388     *
389     * @see java.nio.file.Files#readAllLines
390     */
391    public String readLine() throws IOException {
392        return readLine(false);
393    }
394
395    /**
396     * Skips characters.
397     *
398     * @param  n  The number of characters to skip
399     *
400     * @return    The number of characters actually skipped
401     *
402     * @exception  IllegalArgumentException  If <code>n</code> is negative.
403     * @exception  IOException  If an I/O error occurs
404     */
405    public long skip(long n) throws IOException {
406        if (n < 0L) {
407            throw new IllegalArgumentException("skip value is negative");
408        }
409        synchronized (lock) {
410            ensureOpen();
411            long r = n;
412            while (r > 0) {
413                if (nextChar >= nChars)
414                    fill();
415                if (nextChar >= nChars) /* EOF */
416                    break;
417                if (skipLF) {
418                    skipLF = false;
419                    if (cb[nextChar] == '\n') {
420                        nextChar++;
421                    }
422                }
423                long d = nChars - nextChar;
424                if (r <= d) {
425                    nextChar += r;
426                    r = 0;
427                    break;
428                }
429                else {
430                    r -= d;
431                    nextChar = nChars;
432                }
433            }
434            return n - r;
435        }
436    }
437
438    /**
439     * Tells whether this stream is ready to be read.  A buffered character
440     * stream is ready if the buffer is not empty, or if the underlying
441     * character stream is ready.
442     *
443     * @exception  IOException  If an I/O error occurs
444     */
445    public boolean ready() throws IOException {
446        synchronized (lock) {
447            ensureOpen();
448
449            /*
450             * If newline needs to be skipped and the next char to be read
451             * is a newline character, then just skip it right away.
452             */
453            if (skipLF) {
454                /* Note that in.ready() will return true if and only if the next
455                 * read on the stream will not block.
456                 */
457                if (nextChar >= nChars && in.ready()) {
458                    fill();
459                }
460                if (nextChar < nChars) {
461                    if (cb[nextChar] == '\n')
462                        nextChar++;
463                    skipLF = false;
464                }
465            }
466            return (nextChar < nChars) || in.ready();
467        }
468    }
469
470    /**
471     * Tells whether this stream supports the mark() operation, which it does.
472     */
473    public boolean markSupported() {
474        return true;
475    }
476
477    /**
478     * Marks the present position in the stream.  Subsequent calls to reset()
479     * will attempt to reposition the stream to this point.
480     *
481     * @param readAheadLimit   Limit on the number of characters that may be
482     *                         read while still preserving the mark. An attempt
483     *                         to reset the stream after reading characters
484     *                         up to this limit or beyond may fail.
485     *                         A limit value larger than the size of the input
486     *                         buffer will cause a new buffer to be allocated
487     *                         whose size is no smaller than limit.
488     *                         Therefore large values should be used with care.
489     *
490     * @exception  IllegalArgumentException  If {@code readAheadLimit < 0}
491     * @exception  IOException  If an I/O error occurs
492     */
493    public void mark(int readAheadLimit) throws IOException {
494        if (readAheadLimit < 0) {
495            throw new IllegalArgumentException("Read-ahead limit < 0");
496        }
497        synchronized (lock) {
498            ensureOpen();
499            this.readAheadLimit = readAheadLimit;
500            markedChar = nextChar;
501            markedSkipLF = skipLF;
502        }
503    }
504
505    /**
506     * Resets the stream to the most recent mark.
507     *
508     * @exception  IOException  If the stream has never been marked,
509     *                          or if the mark has been invalidated
510     */
511    public void reset() throws IOException {
512        synchronized (lock) {
513            ensureOpen();
514            if (markedChar < 0)
515                throw new IOException((markedChar == INVALIDATED)
516                                      ? "Mark invalid"
517                                      : "Stream not marked");
518            nextChar = markedChar;
519            skipLF = markedSkipLF;
520        }
521    }
522
523    public void close() throws IOException {
524        synchronized (lock) {
525            if (in == null)
526                return;
527            try {
528                in.close();
529            } finally {
530                in = null;
531                cb = null;
532            }
533        }
534    }
535
536    /**
537     * Returns a {@code Stream}, the elements of which are lines read from
538     * this {@code BufferedReader}.  The {@link Stream} is lazily populated,
539     * i.e., read only occurs during the
540     * <a href="../util/stream/package-summary.html#StreamOps">terminal
541     * stream operation</a>.
542     *
543     * <p> The reader must not be operated on during the execution of the
544     * terminal stream operation. Otherwise, the result of the terminal stream
545     * operation is undefined.
546     *
547     * <p> After execution of the terminal stream operation there are no
548     * guarantees that the reader will be at a specific position from which to
549     * read the next character or line.
550     *
551     * <p> If an {@link IOException} is thrown when accessing the underlying
552     * {@code BufferedReader}, it is wrapped in an {@link
553     * UncheckedIOException} which will be thrown from the {@code Stream}
554     * method that caused the read to take place. This method will return a
555     * Stream if invoked on a BufferedReader that is closed. Any operation on
556     * that stream that requires reading from the BufferedReader after it is
557     * closed, will cause an UncheckedIOException to be thrown.
558     *
559     * @return a {@code Stream<String>} providing the lines of text
560     *         described by this {@code BufferedReader}
561     *
562     * @since 1.8
563     */
564    public Stream<String> lines() {
565        Iterator<String> iter = new Iterator<>() {
566            String nextLine = null;
567
568            @Override
569            public boolean hasNext() {
570                if (nextLine != null) {
571                    return true;
572                } else {
573                    try {
574                        nextLine = readLine();
575                        return (nextLine != null);
576                    } catch (IOException e) {
577                        throw new UncheckedIOException(e);
578                    }
579                }
580            }
581
582            @Override
583            public String next() {
584                if (nextLine != null || hasNext()) {
585                    String line = nextLine;
586                    nextLine = null;
587                    return line;
588                } else {
589                    throw new NoSuchElementException();
590                }
591            }
592        };
593        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
594                iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
595    }
596}
597