rt/emul/compact/src/main/java/java/io/BufferedReader.java
changeset 772 d382dacfd73f
parent 636 8d0be6a9a809
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/java/io/BufferedReader.java	Tue Feb 26 16:54:16 2013 +0100
     1.3 @@ -0,0 +1,523 @@
     1.4 +/*
     1.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package java.io;
    1.30 +
    1.31 +
    1.32 +
    1.33 +/**
    1.34 + * Reads text from a character-input stream, buffering characters so as to
    1.35 + * provide for the efficient reading of characters, arrays, and lines.
    1.36 + *
    1.37 + * <p> The buffer size may be specified, or the default size may be used.  The
    1.38 + * default is large enough for most purposes.
    1.39 + *
    1.40 + * <p> In general, each read request made of a Reader causes a corresponding
    1.41 + * read request to be made of the underlying character or byte stream.  It is
    1.42 + * therefore advisable to wrap a BufferedReader around any Reader whose read()
    1.43 + * operations may be costly, such as FileReaders and InputStreamReaders.  For
    1.44 + * example,
    1.45 + *
    1.46 + * <pre>
    1.47 + * BufferedReader in
    1.48 + *   = new BufferedReader(new FileReader("foo.in"));
    1.49 + * </pre>
    1.50 + *
    1.51 + * will buffer the input from the specified file.  Without buffering, each
    1.52 + * invocation of read() or readLine() could cause bytes to be read from the
    1.53 + * file, converted into characters, and then returned, which can be very
    1.54 + * inefficient.
    1.55 + *
    1.56 + * <p> Programs that use DataInputStreams for textual input can be localized by
    1.57 + * replacing each DataInputStream with an appropriate BufferedReader.
    1.58 + *
    1.59 + * @see FileReader
    1.60 + * @see InputStreamReader
    1.61 + * @see java.nio.file.Files#newBufferedReader
    1.62 + *
    1.63 + * @author      Mark Reinhold
    1.64 + * @since       JDK1.1
    1.65 + */
    1.66 +
    1.67 +public class BufferedReader extends Reader {
    1.68 +
    1.69 +    private Reader in;
    1.70 +
    1.71 +    private char cb[];
    1.72 +    private int nChars, nextChar;
    1.73 +
    1.74 +    private static final int INVALIDATED = -2;
    1.75 +    private static final int UNMARKED = -1;
    1.76 +    private int markedChar = UNMARKED;
    1.77 +    private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
    1.78 +
    1.79 +    /** If the next character is a line feed, skip it */
    1.80 +    private boolean skipLF = false;
    1.81 +
    1.82 +    /** The skipLF flag when the mark was set */
    1.83 +    private boolean markedSkipLF = false;
    1.84 +
    1.85 +    private static int defaultCharBufferSize = 8192;
    1.86 +    private static int defaultExpectedLineLength = 80;
    1.87 +
    1.88 +    /**
    1.89 +     * Creates a buffering character-input stream that uses an input buffer of
    1.90 +     * the specified size.
    1.91 +     *
    1.92 +     * @param  in   A Reader
    1.93 +     * @param  sz   Input-buffer size
    1.94 +     *
    1.95 +     * @exception  IllegalArgumentException  If sz is <= 0
    1.96 +     */
    1.97 +    public BufferedReader(Reader in, int sz) {
    1.98 +        super(in);
    1.99 +        if (sz <= 0)
   1.100 +            throw new IllegalArgumentException("Buffer size <= 0");
   1.101 +        this.in = in;
   1.102 +        cb = new char[sz];
   1.103 +        nextChar = nChars = 0;
   1.104 +    }
   1.105 +
   1.106 +    /**
   1.107 +     * Creates a buffering character-input stream that uses a default-sized
   1.108 +     * input buffer.
   1.109 +     *
   1.110 +     * @param  in   A Reader
   1.111 +     */
   1.112 +    public BufferedReader(Reader in) {
   1.113 +        this(in, defaultCharBufferSize);
   1.114 +    }
   1.115 +
   1.116 +    /** Checks to make sure that the stream has not been closed */
   1.117 +    private void ensureOpen() throws IOException {
   1.118 +        if (in == null)
   1.119 +            throw new IOException("Stream closed");
   1.120 +    }
   1.121 +
   1.122 +    /**
   1.123 +     * Fills the input buffer, taking the mark into account if it is valid.
   1.124 +     */
   1.125 +    private void fill() throws IOException {
   1.126 +        int dst;
   1.127 +        if (markedChar <= UNMARKED) {
   1.128 +            /* No mark */
   1.129 +            dst = 0;
   1.130 +        } else {
   1.131 +            /* Marked */
   1.132 +            int delta = nextChar - markedChar;
   1.133 +            if (delta >= readAheadLimit) {
   1.134 +                /* Gone past read-ahead limit: Invalidate mark */
   1.135 +                markedChar = INVALIDATED;
   1.136 +                readAheadLimit = 0;
   1.137 +                dst = 0;
   1.138 +            } else {
   1.139 +                if (readAheadLimit <= cb.length) {
   1.140 +                    /* Shuffle in the current buffer */
   1.141 +                    System.arraycopy(cb, markedChar, cb, 0, delta);
   1.142 +                    markedChar = 0;
   1.143 +                    dst = delta;
   1.144 +                } else {
   1.145 +                    /* Reallocate buffer to accommodate read-ahead limit */
   1.146 +                    char ncb[] = new char[readAheadLimit];
   1.147 +                    System.arraycopy(cb, markedChar, ncb, 0, delta);
   1.148 +                    cb = ncb;
   1.149 +                    markedChar = 0;
   1.150 +                    dst = delta;
   1.151 +                }
   1.152 +                nextChar = nChars = delta;
   1.153 +            }
   1.154 +        }
   1.155 +
   1.156 +        int n;
   1.157 +        do {
   1.158 +            n = in.read(cb, dst, cb.length - dst);
   1.159 +        } while (n == 0);
   1.160 +        if (n > 0) {
   1.161 +            nChars = dst + n;
   1.162 +            nextChar = dst;
   1.163 +        }
   1.164 +    }
   1.165 +
   1.166 +    /**
   1.167 +     * Reads a single character.
   1.168 +     *
   1.169 +     * @return The character read, as an integer in the range
   1.170 +     *         0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
   1.171 +     *         end of the stream has been reached
   1.172 +     * @exception  IOException  If an I/O error occurs
   1.173 +     */
   1.174 +    public int read() throws IOException {
   1.175 +        synchronized (lock) {
   1.176 +            ensureOpen();
   1.177 +            for (;;) {
   1.178 +                if (nextChar >= nChars) {
   1.179 +                    fill();
   1.180 +                    if (nextChar >= nChars)
   1.181 +                        return -1;
   1.182 +                }
   1.183 +                if (skipLF) {
   1.184 +                    skipLF = false;
   1.185 +                    if (cb[nextChar] == '\n') {
   1.186 +                        nextChar++;
   1.187 +                        continue;
   1.188 +                    }
   1.189 +                }
   1.190 +                return cb[nextChar++];
   1.191 +            }
   1.192 +        }
   1.193 +    }
   1.194 +
   1.195 +    /**
   1.196 +     * Reads characters into a portion of an array, reading from the underlying
   1.197 +     * stream if necessary.
   1.198 +     */
   1.199 +    private int read1(char[] cbuf, int off, int len) throws IOException {
   1.200 +        if (nextChar >= nChars) {
   1.201 +            /* If the requested length is at least as large as the buffer, and
   1.202 +               if there is no mark/reset activity, and if line feeds are not
   1.203 +               being skipped, do not bother to copy the characters into the
   1.204 +               local buffer.  In this way buffered streams will cascade
   1.205 +               harmlessly. */
   1.206 +            if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
   1.207 +                return in.read(cbuf, off, len);
   1.208 +            }
   1.209 +            fill();
   1.210 +        }
   1.211 +        if (nextChar >= nChars) return -1;
   1.212 +        if (skipLF) {
   1.213 +            skipLF = false;
   1.214 +            if (cb[nextChar] == '\n') {
   1.215 +                nextChar++;
   1.216 +                if (nextChar >= nChars)
   1.217 +                    fill();
   1.218 +                if (nextChar >= nChars)
   1.219 +                    return -1;
   1.220 +            }
   1.221 +        }
   1.222 +        int n = Math.min(len, nChars - nextChar);
   1.223 +        System.arraycopy(cb, nextChar, cbuf, off, n);
   1.224 +        nextChar += n;
   1.225 +        return n;
   1.226 +    }
   1.227 +
   1.228 +    /**
   1.229 +     * Reads characters into a portion of an array.
   1.230 +     *
   1.231 +     * <p> This method implements the general contract of the corresponding
   1.232 +     * <code>{@link Reader#read(char[], int, int) read}</code> method of the
   1.233 +     * <code>{@link Reader}</code> class.  As an additional convenience, it
   1.234 +     * attempts to read as many characters as possible by repeatedly invoking
   1.235 +     * the <code>read</code> method of the underlying stream.  This iterated
   1.236 +     * <code>read</code> continues until one of the following conditions becomes
   1.237 +     * true: <ul>
   1.238 +     *
   1.239 +     *   <li> The specified number of characters have been read,
   1.240 +     *
   1.241 +     *   <li> The <code>read</code> method of the underlying stream returns
   1.242 +     *   <code>-1</code>, indicating end-of-file, or
   1.243 +     *
   1.244 +     *   <li> The <code>ready</code> method of the underlying stream
   1.245 +     *   returns <code>false</code>, indicating that further input requests
   1.246 +     *   would block.
   1.247 +     *
   1.248 +     * </ul> If the first <code>read</code> on the underlying stream returns
   1.249 +     * <code>-1</code> to indicate end-of-file then this method returns
   1.250 +     * <code>-1</code>.  Otherwise this method returns the number of characters
   1.251 +     * actually read.
   1.252 +     *
   1.253 +     * <p> Subclasses of this class are encouraged, but not required, to
   1.254 +     * attempt to read as many characters as possible in the same fashion.
   1.255 +     *
   1.256 +     * <p> Ordinarily this method takes characters from this stream's character
   1.257 +     * buffer, filling it from the underlying stream as necessary.  If,
   1.258 +     * however, the buffer is empty, the mark is not valid, and the requested
   1.259 +     * length is at least as large as the buffer, then this method will read
   1.260 +     * characters directly from the underlying stream into the given array.
   1.261 +     * Thus redundant <code>BufferedReader</code>s will not copy data
   1.262 +     * unnecessarily.
   1.263 +     *
   1.264 +     * @param      cbuf  Destination buffer
   1.265 +     * @param      off   Offset at which to start storing characters
   1.266 +     * @param      len   Maximum number of characters to read
   1.267 +     *
   1.268 +     * @return     The number of characters read, or -1 if the end of the
   1.269 +     *             stream has been reached
   1.270 +     *
   1.271 +     * @exception  IOException  If an I/O error occurs
   1.272 +     */
   1.273 +    public int read(char cbuf[], int off, int len) throws IOException {
   1.274 +        synchronized (lock) {
   1.275 +            ensureOpen();
   1.276 +            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
   1.277 +                ((off + len) > cbuf.length) || ((off + len) < 0)) {
   1.278 +                throw new IndexOutOfBoundsException();
   1.279 +            } else if (len == 0) {
   1.280 +                return 0;
   1.281 +            }
   1.282 +
   1.283 +            int n = read1(cbuf, off, len);
   1.284 +            if (n <= 0) return n;
   1.285 +            while ((n < len) && in.ready()) {
   1.286 +                int n1 = read1(cbuf, off + n, len - n);
   1.287 +                if (n1 <= 0) break;
   1.288 +                n += n1;
   1.289 +            }
   1.290 +            return n;
   1.291 +        }
   1.292 +    }
   1.293 +
   1.294 +    /**
   1.295 +     * Reads a line of text.  A line is considered to be terminated by any one
   1.296 +     * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
   1.297 +     * followed immediately by a linefeed.
   1.298 +     *
   1.299 +     * @param      ignoreLF  If true, the next '\n' will be skipped
   1.300 +     *
   1.301 +     * @return     A String containing the contents of the line, not including
   1.302 +     *             any line-termination characters, or null if the end of the
   1.303 +     *             stream has been reached
   1.304 +     *
   1.305 +     * @see        java.io.LineNumberReader#readLine()
   1.306 +     *
   1.307 +     * @exception  IOException  If an I/O error occurs
   1.308 +     */
   1.309 +    String readLine(boolean ignoreLF) throws IOException {
   1.310 +        StringBuffer s = null;
   1.311 +        int startChar;
   1.312 +
   1.313 +        synchronized (lock) {
   1.314 +            ensureOpen();
   1.315 +            boolean omitLF = ignoreLF || skipLF;
   1.316 +
   1.317 +        bufferLoop:
   1.318 +            for (;;) {
   1.319 +
   1.320 +                if (nextChar >= nChars)
   1.321 +                    fill();
   1.322 +                if (nextChar >= nChars) { /* EOF */
   1.323 +                    if (s != null && s.length() > 0)
   1.324 +                        return s.toString();
   1.325 +                    else
   1.326 +                        return null;
   1.327 +                }
   1.328 +                boolean eol = false;
   1.329 +                char c = 0;
   1.330 +                int i;
   1.331 +
   1.332 +                /* Skip a leftover '\n', if necessary */
   1.333 +                if (omitLF && (cb[nextChar] == '\n'))
   1.334 +                    nextChar++;
   1.335 +                skipLF = false;
   1.336 +                omitLF = false;
   1.337 +
   1.338 +            charLoop:
   1.339 +                for (i = nextChar; i < nChars; i++) {
   1.340 +                    c = cb[i];
   1.341 +                    if ((c == '\n') || (c == '\r')) {
   1.342 +                        eol = true;
   1.343 +                        break charLoop;
   1.344 +                    }
   1.345 +                }
   1.346 +
   1.347 +                startChar = nextChar;
   1.348 +                nextChar = i;
   1.349 +
   1.350 +                if (eol) {
   1.351 +                    String str;
   1.352 +                    if (s == null) {
   1.353 +                        str = new String(cb, startChar, i - startChar);
   1.354 +                    } else {
   1.355 +                        s.append(cb, startChar, i - startChar);
   1.356 +                        str = s.toString();
   1.357 +                    }
   1.358 +                    nextChar++;
   1.359 +                    if (c == '\r') {
   1.360 +                        skipLF = true;
   1.361 +                    }
   1.362 +                    return str;
   1.363 +                }
   1.364 +
   1.365 +                if (s == null)
   1.366 +                    s = new StringBuffer(defaultExpectedLineLength);
   1.367 +                s.append(cb, startChar, i - startChar);
   1.368 +            }
   1.369 +        }
   1.370 +    }
   1.371 +
   1.372 +    /**
   1.373 +     * Reads a line of text.  A line is considered to be terminated by any one
   1.374 +     * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
   1.375 +     * followed immediately by a linefeed.
   1.376 +     *
   1.377 +     * @return     A String containing the contents of the line, not including
   1.378 +     *             any line-termination characters, or null if the end of the
   1.379 +     *             stream has been reached
   1.380 +     *
   1.381 +     * @exception  IOException  If an I/O error occurs
   1.382 +     *
   1.383 +     * @see java.nio.file.Files#readAllLines
   1.384 +     */
   1.385 +    public String readLine() throws IOException {
   1.386 +        return readLine(false);
   1.387 +    }
   1.388 +
   1.389 +    /**
   1.390 +     * Skips characters.
   1.391 +     *
   1.392 +     * @param  n  The number of characters to skip
   1.393 +     *
   1.394 +     * @return    The number of characters actually skipped
   1.395 +     *
   1.396 +     * @exception  IllegalArgumentException  If <code>n</code> is negative.
   1.397 +     * @exception  IOException  If an I/O error occurs
   1.398 +     */
   1.399 +    public long skip(long n) throws IOException {
   1.400 +        if (n < 0L) {
   1.401 +            throw new IllegalArgumentException("skip value is negative");
   1.402 +        }
   1.403 +        synchronized (lock) {
   1.404 +            ensureOpen();
   1.405 +            long r = n;
   1.406 +            while (r > 0) {
   1.407 +                if (nextChar >= nChars)
   1.408 +                    fill();
   1.409 +                if (nextChar >= nChars) /* EOF */
   1.410 +                    break;
   1.411 +                if (skipLF) {
   1.412 +                    skipLF = false;
   1.413 +                    if (cb[nextChar] == '\n') {
   1.414 +                        nextChar++;
   1.415 +                    }
   1.416 +                }
   1.417 +                long d = nChars - nextChar;
   1.418 +                if (r <= d) {
   1.419 +                    nextChar += r;
   1.420 +                    r = 0;
   1.421 +                    break;
   1.422 +                }
   1.423 +                else {
   1.424 +                    r -= d;
   1.425 +                    nextChar = nChars;
   1.426 +                }
   1.427 +            }
   1.428 +            return n - r;
   1.429 +        }
   1.430 +    }
   1.431 +
   1.432 +    /**
   1.433 +     * Tells whether this stream is ready to be read.  A buffered character
   1.434 +     * stream is ready if the buffer is not empty, or if the underlying
   1.435 +     * character stream is ready.
   1.436 +     *
   1.437 +     * @exception  IOException  If an I/O error occurs
   1.438 +     */
   1.439 +    public boolean ready() throws IOException {
   1.440 +        synchronized (lock) {
   1.441 +            ensureOpen();
   1.442 +
   1.443 +            /*
   1.444 +             * If newline needs to be skipped and the next char to be read
   1.445 +             * is a newline character, then just skip it right away.
   1.446 +             */
   1.447 +            if (skipLF) {
   1.448 +                /* Note that in.ready() will return true if and only if the next
   1.449 +                 * read on the stream will not block.
   1.450 +                 */
   1.451 +                if (nextChar >= nChars && in.ready()) {
   1.452 +                    fill();
   1.453 +                }
   1.454 +                if (nextChar < nChars) {
   1.455 +                    if (cb[nextChar] == '\n')
   1.456 +                        nextChar++;
   1.457 +                    skipLF = false;
   1.458 +                }
   1.459 +            }
   1.460 +            return (nextChar < nChars) || in.ready();
   1.461 +        }
   1.462 +    }
   1.463 +
   1.464 +    /**
   1.465 +     * Tells whether this stream supports the mark() operation, which it does.
   1.466 +     */
   1.467 +    public boolean markSupported() {
   1.468 +        return true;
   1.469 +    }
   1.470 +
   1.471 +    /**
   1.472 +     * Marks the present position in the stream.  Subsequent calls to reset()
   1.473 +     * will attempt to reposition the stream to this point.
   1.474 +     *
   1.475 +     * @param readAheadLimit   Limit on the number of characters that may be
   1.476 +     *                         read while still preserving the mark. An attempt
   1.477 +     *                         to reset the stream after reading characters
   1.478 +     *                         up to this limit or beyond may fail.
   1.479 +     *                         A limit value larger than the size of the input
   1.480 +     *                         buffer will cause a new buffer to be allocated
   1.481 +     *                         whose size is no smaller than limit.
   1.482 +     *                         Therefore large values should be used with care.
   1.483 +     *
   1.484 +     * @exception  IllegalArgumentException  If readAheadLimit is < 0
   1.485 +     * @exception  IOException  If an I/O error occurs
   1.486 +     */
   1.487 +    public void mark(int readAheadLimit) throws IOException {
   1.488 +        if (readAheadLimit < 0) {
   1.489 +            throw new IllegalArgumentException("Read-ahead limit < 0");
   1.490 +        }
   1.491 +        synchronized (lock) {
   1.492 +            ensureOpen();
   1.493 +            this.readAheadLimit = readAheadLimit;
   1.494 +            markedChar = nextChar;
   1.495 +            markedSkipLF = skipLF;
   1.496 +        }
   1.497 +    }
   1.498 +
   1.499 +    /**
   1.500 +     * Resets the stream to the most recent mark.
   1.501 +     *
   1.502 +     * @exception  IOException  If the stream has never been marked,
   1.503 +     *                          or if the mark has been invalidated
   1.504 +     */
   1.505 +    public void reset() throws IOException {
   1.506 +        synchronized (lock) {
   1.507 +            ensureOpen();
   1.508 +            if (markedChar < 0)
   1.509 +                throw new IOException((markedChar == INVALIDATED)
   1.510 +                                      ? "Mark invalid"
   1.511 +                                      : "Stream not marked");
   1.512 +            nextChar = markedChar;
   1.513 +            skipLF = markedSkipLF;
   1.514 +        }
   1.515 +    }
   1.516 +
   1.517 +    public void close() throws IOException {
   1.518 +        synchronized (lock) {
   1.519 +            if (in == null)
   1.520 +                return;
   1.521 +            in.close();
   1.522 +            in = null;
   1.523 +            cb = null;
   1.524 +        }
   1.525 +    }
   1.526 +}