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 18package java.io; 19 20import java.util.Arrays; 21 22/** 23 * A specialized {@link InputStream } for reading the contents of a byte array. 24 * 25 * @see ByteArrayOutputStream 26 */ 27public 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