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