Home | History | Annotate | Download | only in io
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.io;
     19 
     20 import java.util.Arrays;
     21 
     22 /**
     23  * A specialized {@link Reader} for reading the contents of a char array.
     24  *
     25  * @see CharArrayWriter
     26  */
     27 public class CharArrayReader extends Reader {
     28     /**
     29      * The buffer for characters.
     30      */
     31     protected char[] buf;
     32 
     33     /**
     34      * The current buffer position.
     35      */
     36     protected int pos;
     37 
     38     /**
     39      * The current mark position.
     40      */
     41     protected int markedPos = -1;
     42 
     43     /**
     44      * The ending index of the buffer.
     45      */
     46     protected int count;
     47 
     48     /**
     49      * Constructs a CharArrayReader on the char array {@code buf}. The size of
     50      * the reader is set to the length of the buffer and the object to to read
     51      * from is set to {@code buf}.
     52      *
     53      * @param buf
     54      *            the char array from which to read.
     55      */
     56     public CharArrayReader(char[] buf) {
     57         this.buf = buf;
     58         this.count = buf.length;
     59     }
     60 
     61     /**
     62      * Constructs a CharArrayReader on the char array {@code buf}. The size of
     63      * the reader is set to {@code length} and the start position from which to
     64      * read the buffer is set to {@code offset}.
     65      *
     66      * @param buf
     67      *            the char array from which to read.
     68      * @param offset
     69      *            the index of the first character in {@code buf} to read.
     70      * @param length
     71      *            the number of characters that can be read from {@code buf}.
     72      * @throws IllegalArgumentException
     73      *             if {@code offset < 0} or {@code length < 0}, or if
     74      *             {@code offset} is greater than the size of {@code buf} .
     75      */
     76     public CharArrayReader(char[] buf, int offset, int length) {
     77         /*
     78          * The spec of this constructor is broken. In defining the legal values
     79          * of offset and length, it doesn't consider buffer's length. And to be
     80          * compatible with the broken spec, we must also test whether
     81          * (offset + length) overflows.
     82          */
     83         if (offset < 0 || offset > buf.length || length < 0 || offset + length < 0) {
     84             throw new IllegalArgumentException();
     85         }
     86         this.buf = buf;
     87         this.pos = offset;
     88         this.markedPos = offset;
     89 
     90         /* This is according to spec */
     91         int bufferLength = buf.length;
     92         this.count = offset + length < bufferLength ? length : bufferLength;
     93     }
     94 
     95     /**
     96      * This method closes this CharArrayReader. Once it is closed, you can no
     97      * longer read from it. Only the first invocation of this method has any
     98      * effect.
     99      */
    100     @Override
    101     public void close() {
    102         synchronized (lock) {
    103             if (isOpen()) {
    104                 buf = null;
    105             }
    106         }
    107     }
    108 
    109     /**
    110      * Indicates whether this reader is open.
    111      *
    112      * @return {@code true} if the reader is open, {@code false} otherwise.
    113      */
    114     private boolean isOpen() {
    115         return buf != null;
    116     }
    117 
    118     /**
    119      * Indicates whether this reader is closed.
    120      *
    121      * @return {@code true} if the reader is closed, {@code false} otherwise.
    122      */
    123     private boolean isClosed() {
    124         return buf == null;
    125     }
    126 
    127     /**
    128      * Sets a mark position in this reader. The parameter {@code readLimit} is
    129      * ignored for CharArrayReaders. Calling {@code reset()} will reposition the
    130      * reader back to the marked position provided the mark has not been
    131      * invalidated.
    132      *
    133      * @param readLimit
    134      *            ignored for CharArrayReaders.
    135      * @throws IOException
    136      *             if this reader is closed.
    137      */
    138     @Override
    139     public void mark(int readLimit) throws IOException {
    140         synchronized (lock) {
    141             checkNotClosed();
    142             markedPos = pos;
    143         }
    144     }
    145 
    146     private void checkNotClosed() throws IOException {
    147         if (isClosed()) {
    148             throw new IOException("CharArrayReader is closed");
    149         }
    150     }
    151 
    152     /**
    153      * Indicates whether this reader supports the {@code mark()} and
    154      * {@code reset()} methods.
    155      *
    156      * @return {@code true} for CharArrayReader.
    157      * @see #mark(int)
    158      * @see #reset()
    159      */
    160     @Override
    161     public boolean markSupported() {
    162         return true;
    163     }
    164 
    165     /**
    166      * Reads a single character from this reader and returns it as an integer
    167      * with the two higher-order bytes set to 0. Returns -1 if no more
    168      * characters are available from this reader.
    169      *
    170      * @return the character read as an int or -1 if the end of the reader has
    171      *         been reached.
    172      * @throws IOException
    173      *             if this reader is closed.
    174      */
    175     @Override
    176     public int read() throws IOException {
    177         synchronized (lock) {
    178             checkNotClosed();
    179             if (pos == count) {
    180                 return -1;
    181             }
    182             return buf[pos++];
    183         }
    184     }
    185 
    186     /**
    187      * Reads at most {@code count} characters from this CharArrayReader and
    188      * stores them at {@code offset} in the character array {@code buf}.
    189      * Returns the number of characters actually read or -1 if the end of reader
    190      * was encountered.
    191      *
    192      * @param buffer
    193      *            the character array to store the characters read.
    194      * @param offset
    195      *            the initial position in {@code buffer} to store the characters
    196      *            read from this reader.
    197      * @param len
    198      *            the maximum number of characters to read.
    199      * @return number of characters read or -1 if the end of the reader has been
    200      *         reached.
    201      * @throws IndexOutOfBoundsException
    202      *             if {@code offset < 0} or {@code len < 0}, or if
    203      *             {@code offset + len} is bigger than the size of
    204      *             {@code buffer}.
    205      * @throws IOException
    206      *             if this reader is closed.
    207      */
    208     @Override
    209     public int read(char[] buffer, int offset, int len) throws IOException {
    210         Arrays.checkOffsetAndCount(buffer.length, offset, len);
    211         synchronized (lock) {
    212             checkNotClosed();
    213             if (pos < this.count) {
    214                 int bytesRead = pos + len > this.count ? this.count - pos : len;
    215                 System.arraycopy(this.buf, pos, buffer, offset, bytesRead);
    216                 pos += bytesRead;
    217                 return bytesRead;
    218             }
    219             return -1;
    220         }
    221     }
    222 
    223     /**
    224      * Indicates whether this reader is ready to be read without blocking.
    225      * Returns {@code true} if the next {@code read} will not block. Returns
    226      * {@code false} if this reader may or may not block when {@code read} is
    227      * called. The implementation in CharArrayReader always returns {@code true}
    228      * even when it has been closed.
    229      *
    230      * @return {@code true} if this reader will not block when {@code read} is
    231      *         called, {@code false} if unknown or blocking will occur.
    232      * @throws IOException
    233      *             if this reader is closed.
    234      */
    235     @Override
    236     public boolean ready() throws IOException {
    237         synchronized (lock) {
    238             checkNotClosed();
    239             return pos != count;
    240         }
    241     }
    242 
    243     /**
    244      * Resets this reader's position to the last {@code mark()} location.
    245      * Invocations of {@code read()} and {@code skip()} will occur from this new
    246      * location. If this reader has not been marked, it is reset to the
    247      * beginning of the string.
    248      *
    249      * @throws IOException
    250      *             if this reader is closed.
    251      */
    252     @Override
    253     public void reset() throws IOException {
    254         synchronized (lock) {
    255             checkNotClosed();
    256             pos = markedPos != -1 ? markedPos : 0;
    257         }
    258     }
    259 
    260     /**
    261      * Skips {@code charCount} characters in this reader. Subsequent calls to
    262      * {@code read} will not return these characters unless {@code reset}
    263      * is used. This method does nothing and returns 0 if {@code charCount <= 0}.
    264      *
    265      * @return the number of characters actually skipped.
    266      * @throws IOException
    267      *             if this reader is closed.
    268      */
    269     @Override
    270     public long skip(long charCount) throws IOException {
    271         synchronized (lock) {
    272             checkNotClosed();
    273             if (charCount <= 0) {
    274                 return 0;
    275             }
    276             long skipped = 0;
    277             if (charCount < this.count - pos) {
    278                 pos = pos + (int) charCount;
    279                 skipped = charCount;
    280             } else {
    281                 skipped = this.count - pos;
    282                 pos = this.count;
    283             }
    284             return skipped;
    285         }
    286     }
    287 }
    288