Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package java.io;
     27 
     28 /**
     29  * This class implements a character buffer that can be used as a
     30  * character-input stream.
     31  *
     32  * @author      Herb Jellinek
     33  * @since       JDK1.1
     34  */
     35 public class CharArrayReader extends Reader {
     36     /** The character buffer. */
     37     protected char buf[];
     38 
     39     /** The current buffer position. */
     40     protected int pos;
     41 
     42     /** The position of mark in buffer. */
     43     protected int markedPos = 0;
     44 
     45     /**
     46      *  The index of the end of this buffer.  There is not valid
     47      *  data at or beyond this index.
     48      */
     49     protected int count;
     50 
     51     /**
     52      * Creates a CharArrayReader from the specified array of chars.
     53      * @param buf       Input buffer (not copied)
     54      */
     55     public CharArrayReader(char buf[]) {
     56         this.buf = buf;
     57         this.pos = 0;
     58         this.count = buf.length;
     59     }
     60 
     61     /**
     62      * Creates a CharArrayReader from the specified array of chars.
     63      *
     64      * <p> The resulting reader will start reading at the given
     65      * <tt>offset</tt>.  The total number of <tt>char</tt> values that can be
     66      * read from this reader will be either <tt>length</tt> or
     67      * <tt>buf.length-offset</tt>, whichever is smaller.
     68      *
     69      * @throws IllegalArgumentException
     70      *         If <tt>offset</tt> is negative or greater than
     71      *         <tt>buf.length</tt>, or if <tt>length</tt> is negative, or if
     72      *         the sum of these two values is negative.
     73      *
     74      * @param buf       Input buffer (not copied)
     75      * @param offset    Offset of the first char to read
     76      * @param length    Number of chars to read
     77      */
     78     public CharArrayReader(char buf[], int offset, int length) {
     79         if ((offset < 0) || (offset > buf.length) || (length < 0) ||
     80             ((offset + length) < 0)) {
     81             throw new IllegalArgumentException();
     82         }
     83         this.buf = buf;
     84         this.pos = offset;
     85         this.count = Math.min(offset + length, buf.length);
     86         this.markedPos = offset;
     87     }
     88 
     89     /** Checks to make sure that the stream has not been closed */
     90     private void ensureOpen() throws IOException {
     91         if (buf == null)
     92             throw new IOException("Stream closed");
     93     }
     94 
     95     /**
     96      * Reads a single character.
     97      *
     98      * @exception   IOException  If an I/O error occurs
     99      */
    100     public int read() throws IOException {
    101         synchronized (lock) {
    102             ensureOpen();
    103             if (pos >= count)
    104                 return -1;
    105             else
    106                 return buf[pos++];
    107         }
    108     }
    109 
    110     /**
    111      * Reads characters into a portion of an array.
    112      * @param b  Destination buffer
    113      * @param off  Offset at which to start storing characters
    114      * @param len   Maximum number of characters to read
    115      * @return  The actual number of characters read, or -1 if
    116      *          the end of the stream has been reached
    117      *
    118      * @exception   IOException  If an I/O error occurs
    119      */
    120     public int read(char b[], int off, int len) throws IOException {
    121         synchronized (lock) {
    122             ensureOpen();
    123             if ((off < 0) || (off > b.length) || (len < 0) ||
    124                 ((off + len) > b.length) || ((off + len) < 0)) {
    125                 throw new IndexOutOfBoundsException();
    126             } else if (len == 0) {
    127                 return 0;
    128             }
    129 
    130             if (pos >= count) {
    131                 return -1;
    132             }
    133             // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
    134             int avail = count - pos;
    135             if (len > avail) {
    136                 len = avail;
    137             }
    138             // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
    139             if (len <= 0) {
    140                 return 0;
    141             }
    142             System.arraycopy(buf, pos, b, off, len);
    143             pos += len;
    144             return len;
    145         }
    146     }
    147 
    148     /**
    149      * Skips characters.  Returns the number of characters that were skipped.
    150      *
    151      * <p>The <code>n</code> parameter may be negative, even though the
    152      * <code>skip</code> method of the {@link Reader} superclass throws
    153      * an exception in this case. If <code>n</code> is negative, then
    154      * this method does nothing and returns <code>0</code>.
    155      *
    156      * @param n The number of characters to skip
    157      * @return       The number of characters actually skipped
    158      * @exception  IOException If the stream is closed, or an I/O error occurs
    159      */
    160     public long skip(long n) throws IOException {
    161         synchronized (lock) {
    162             ensureOpen();
    163             // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
    164             long avail = count - pos;
    165             if (n > avail) {
    166                 n = avail;
    167             }
    168             // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
    169             if (n < 0) {
    170                 return 0;
    171             }
    172             pos += n;
    173             return n;
    174         }
    175     }
    176 
    177     /**
    178      * Tells whether this stream is ready to be read.  Character-array readers
    179      * are always ready to be read.
    180      *
    181      * @exception  IOException  If an I/O error occurs
    182      */
    183     public boolean ready() throws IOException {
    184         synchronized (lock) {
    185             ensureOpen();
    186             return (count - pos) > 0;
    187         }
    188     }
    189 
    190     /**
    191      * Tells whether this stream supports the mark() operation, which it does.
    192      */
    193     public boolean markSupported() {
    194         return true;
    195     }
    196 
    197     /**
    198      * Marks the present position in the stream.  Subsequent calls to reset()
    199      * will reposition the stream to this point.
    200      *
    201      * @param  readAheadLimit  Limit on the number of characters that may be
    202      *                         read while still preserving the mark.  Because
    203      *                         the stream's input comes from a character array,
    204      *                         there is no actual limit; hence this argument is
    205      *                         ignored.
    206      *
    207      * @exception  IOException  If an I/O error occurs
    208      */
    209     public void mark(int readAheadLimit) throws IOException {
    210         synchronized (lock) {
    211             ensureOpen();
    212             markedPos = pos;
    213         }
    214     }
    215 
    216     /**
    217      * Resets the stream to the most recent mark, or to the beginning if it has
    218      * never been marked.
    219      *
    220      * @exception  IOException  If an I/O error occurs
    221      */
    222     public void reset() throws IOException {
    223         synchronized (lock) {
    224             ensureOpen();
    225             pos = markedPos;
    226         }
    227     }
    228 
    229     /**
    230      * Closes the stream and releases any system resources associated with
    231      * it.  Once the stream has been closed, further read(), ready(),
    232      * mark(), reset(), or skip() invocations will throw an IOException.
    233      * Closing a previously closed stream has no effect.
    234      */
    235     public void close() {
    236         buf = null;
    237     }
    238 }
    239