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     @Override public synchronized int read(byte[] buffer, int byteOffset, int byteCount) {
    145         Arrays.checkOffsetAndCount(buffer.length, byteOffset, byteCount);
    146 
    147         // Are there any bytes available?
    148         if (this.pos >= this.count) {
    149             return -1;
    150         }
    151         if (byteCount == 0) {
    152             return 0;
    153         }
    154 
    155         int copylen = this.count - pos < byteCount ? this.count - pos : byteCount;
    156         System.arraycopy(this.buf, pos, buffer, byteOffset, copylen);
    157         pos += copylen;
    158         return copylen;
    159     }
    160 
    161     /**
    162      * Resets this stream to the last marked location. This implementation
    163      * resets the position to either the marked position, the start position
    164      * supplied in the constructor or 0 if neither has been provided.
    165      *
    166      * @see #mark(int)
    167      */
    168     @Override
    169     public synchronized void reset() {
    170         pos = mark;
    171     }
    172 
    173     /**
    174      * Skips {@code byteCount} bytes in this InputStream. Subsequent
    175      * calls to {@code read} will not return these bytes unless {@code reset} is
    176      * used. This implementation skips {@code byteCount} number of bytes in the
    177      * target stream. It does nothing and returns 0 if {@code byteCount} is negative.
    178      *
    179      * @return the number of bytes actually skipped.
    180      */
    181     @Override
    182     public synchronized long skip(long byteCount) {
    183         if (byteCount <= 0) {
    184             return 0;
    185         }
    186         int temp = pos;
    187         pos = this.count - pos < byteCount ? this.count : (int) (pos + byteCount);
    188         return pos - temp;
    189     }
    190 }
    191