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 InputStream } for reading the contents of a byte array.
     24  *
     25  * @see ByteArrayOutputStream
     26  */
     27 public class ByteArrayInputStream extends InputStream {
     28     /**
     29      * The {@code byte} array containing the bytes to stream over.
     30      */
     31     protected byte[] buf;
     32 
     33     /**
     34      * The current position within the byte array.
     35      */
     36     protected int pos;
     37 
     38     /**
     39      * The current mark position. Initially set to 0 or the <code>offset</code>
     40      * parameter within the constructor.
     41      */
     42     protected int mark;
     43 
     44     /**
     45      * The total number of bytes initially available in the byte array
     46      * {@code buf}.
     47      */
     48     protected int count;
     49 
     50     /**
     51      * Constructs a new {@code ByteArrayInputStream} on the byte array
     52      * {@code buf}.
     53      *
     54      * @param buf
     55      *            the byte array to stream over.
     56      */
     57     public ByteArrayInputStream(byte[] buf) {
     58         this.mark = 0;
     59         this.buf = buf;
     60         this.count = buf.length;
     61     }
     62 
     63     /**
     64      * Constructs a new {@code ByteArrayInputStream} on the byte array
     65      * {@code buf} with the initial position set to {@code offset} and the
     66      * number of bytes available set to {@code offset} + {@code length}.
     67      *
     68      * @param buf
     69      *            the byte array to stream over.
     70      * @param offset
     71      *            the initial position in {@code buf} to start streaming from.
     72      * @param length
     73      *            the number of bytes available for streaming.
     74      */
     75     public ByteArrayInputStream(byte[] buf, int offset, int length) {
     76         this.buf = buf;
     77         pos = offset;
     78         mark = offset;
     79         count = offset + length > buf.length ? buf.length : offset + length;
     80     }
     81 
     82     /**
     83      * Returns the number of remaining bytes.
     84      *
     85      * @return {@code count - pos}
     86      */
     87     @Override
     88     public synchronized int available() {
     89         return count - pos;
     90     }
     91 
     92     /**
     93      * Closes this stream and frees resources associated with this stream.
     94      *
     95      * @throws IOException
     96      *             if an I/O error occurs while closing this stream.
     97      */
     98     @Override
     99     public void close() throws IOException {
    100         // Do nothing on close, this matches JDK behavior.
    101     }
    102 
    103     /**
    104      * Sets a mark position in this ByteArrayInputStream. The parameter
    105      * {@code readlimit} is ignored. Sending {@code reset()} will reposition the
    106      * stream back to the marked position.
    107      *
    108      * @param readlimit
    109      *            ignored.
    110      * @see #markSupported()
    111      * @see #reset()
    112      */
    113     @Override
    114     public synchronized void mark(int readlimit) {
    115         mark = pos;
    116     }
    117 
    118     /**
    119      * Indicates whether this stream supports the {@code mark()} and
    120      * {@code reset()} methods. Returns {@code true} since this class supports
    121      * these methods.
    122      *
    123      * @return always {@code true}.
    124      * @see #mark(int)
    125      * @see #reset()
    126      */
    127     @Override
    128     public boolean markSupported() {
    129         return true;
    130     }
    131 
    132     /**
    133      * Reads a single byte from the source byte array and returns it as an
    134      * integer in the range from 0 to 255. Returns -1 if the end of the source
    135      * array has been reached.
    136      *
    137      * @return the byte read or -1 if the end of this stream has been reached.
    138      */
    139     @Override
    140     public synchronized int read() {
    141         return pos < count ? buf[pos++] & 0xFF : -1;
    142     }
    143 
    144     /**
    145      * Reads at most {@code len} bytes from this stream and stores
    146      * them in byte array {@code b} starting at {@code offset}. This
    147      * implementation reads bytes from the source byte array.
    148      *
    149      * @param buffer
    150      *            the byte array in which to store the bytes read.
    151      * @param offset
    152      *            the initial position in {@code b} to store the bytes read from
    153      *            this stream.
    154      * @param length
    155      *            the maximum number of bytes to store in {@code b}.
    156      * @return the number of bytes actually read or -1 if no bytes were read and
    157      *         the end of the stream was encountered.
    158      * @throws IndexOutOfBoundsException
    159      *             if {@code offset < 0} or {@code length < 0}, or if
    160      *             {@code offset + length} is greater than the size of
    161      *             {@code b}.
    162      * @throws NullPointerException
    163      *             if {@code b} is {@code null}.
    164      */
    165     @Override
    166     public synchronized int read(byte[] buffer, int offset, int length) {
    167         Arrays.checkOffsetAndCount(buffer.length, offset, length);
    168 
    169         // Are there any bytes available?
    170         if (this.pos >= this.count) {
    171             return -1;
    172         }
    173         if (length == 0) {
    174             return 0;
    175         }
    176 
    177         int copylen = this.count - pos < length ? this.count - pos : length;
    178         System.arraycopy(this.buf, pos, buffer, offset, copylen);
    179         pos += copylen;
    180         return copylen;
    181     }
    182 
    183     /**
    184      * Resets this stream to the last marked location. This implementation
    185      * resets the position to either the marked position, the start position
    186      * supplied in the constructor or 0 if neither has been provided.
    187      *
    188      * @see #mark(int)
    189      */
    190     @Override
    191     public synchronized void reset() {
    192         pos = mark;
    193     }
    194 
    195     /**
    196      * Skips {@code byteCount} bytes in this InputStream. Subsequent
    197      * calls to {@code read} will not return these bytes unless {@code reset} is
    198      * used. This implementation skips {@code byteCount} number of bytes in the
    199      * target stream. It does nothing and returns 0 if {@code byteCount} is negative.
    200      *
    201      * @return the number of bytes actually skipped.
    202      */
    203     @Override
    204     public synchronized long skip(long byteCount) {
    205         if (byteCount <= 0) {
    206             return 0;
    207         }
    208         int temp = pos;
    209         pos = this.count - pos < byteCount ? this.count : (int) (pos + byteCount);
    210         return pos - temp;
    211     }
    212 }
    213