1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.stream.ByteArrayInputStream; 13 14 import hunt.stream.Common; 15 16 import hunt.Exceptions; 17 import std.algorithm; 18 19 20 /** 21 * A <code>ByteArrayInputStream</code> contains 22 * an internal buffer that contains bytes that 23 * may be read from the stream. An internal 24 * counter keeps track of the next byte to 25 * be supplied by the <code>read</code> method. 26 * <p> 27 * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in 28 * this class can be called after the stream has been closed without 29 * generating an <tt>IOException</tt>. 30 * 31 */ 32 class ByteArrayInputStream : InputStream { 33 34 /** 35 * An array of bytes that was provided 36 * by the creator of the stream. Elements <code>buf[0]</code> 37 * through <code>buf[count-1]</code> are the 38 * only bytes that can ever be read from the 39 * stream; element <code>buf[pos]</code> is 40 * the next byte to be read. 41 */ 42 protected byte[] buf; 43 44 /** 45 * The index of the next character to read from the input stream buffer. 46 * This value should always be nonnegative 47 * and not larger than the value of <code>count</code>. 48 * The next byte to be read from the input stream buffer 49 * will be <code>buf[pos]</code>. 50 */ 51 protected int pos; 52 53 /** 54 * The currently marked position in the stream. 55 * ByteArrayInputStream objects are marked at position zero by 56 * default when constructed. They may be marked at another 57 * position within the buffer by the <code>mark()</code> method. 58 * The current buffer position is set to this point by the 59 * <code>reset()</code> method. 60 * <p> 61 * If no mark has been set, then the value of mark is the offset 62 * passed to the constructor (or 0 if the offset was not supplied). 63 * 64 */ 65 protected int _mark = 0; 66 67 /** 68 * The index one greater than the last valid character in the input 69 * stream buffer. 70 * This value should always be nonnegative 71 * and not larger than the length of <code>buf</code>. 72 * It is one greater than the position of 73 * the last byte within <code>buf</code> that 74 * can ever be read from the input stream buffer. 75 */ 76 protected int count; 77 78 alias read = InputStream.read; 79 80 /** 81 * Creates a <code>ByteArrayInputStream</code> 82 * so that it uses <code>buf</code> as its 83 * buffer array. 84 * The buffer array is not copied. 85 * The initial value of <code>pos</code> 86 * is <code>0</code> and the initial value 87 * of <code>count</code> is the length of 88 * <code>buf</code>. 89 * 90 * @param buf the input buffer. 91 */ 92 this(byte[] buf) { 93 this.buf = buf; 94 this.pos = 0; 95 this.count = cast(int)buf.length; 96 } 97 98 /** 99 * Creates <code>ByteArrayInputStream</code> 100 * that uses <code>buf</code> as its 101 * buffer array. The initial value of <code>pos</code> 102 * is <code>offset</code> and the initial value 103 * of <code>count</code> is the minimum of <code>offset+length</code> 104 * and <code>buf.length</code>. 105 * The buffer array is not copied. The buffer's mark is 106 * set to the specified offset. 107 * 108 * @param buf the input buffer. 109 * @param offset the offset in the buffer of the first byte to read. 110 * @param length the maximum number of bytes to read from the buffer. 111 */ 112 this(byte[] buf, int offset, size_t length) { 113 this.buf = buf; 114 this.pos = offset; 115 this.count = cast(int) min(offset + length, buf.length); 116 this._mark = offset; 117 } 118 119 byte[] getRawBuffer() 120 { 121 return buf; 122 } 123 124 /** 125 * Reads the next byte of data from this input stream. The value 126 * byte is returned as an <code>int</code> in the range 127 * <code>0</code> to <code>255</code>. If no byte is available 128 * because the end of the stream has been reached, the value 129 * <code>-1</code> is returned. 130 * <p> 131 * This <code>read</code> method 132 * cannot block. 133 * 134 * @return the next byte of data, or <code>-1</code> if the end of the 135 * stream has been reached. 136 */ 137 override int read() { 138 return (pos < count) ? (buf[pos++] & 0xff) : -1; 139 } 140 141 /** 142 * Reads up to <code>len</code> bytes of data into an array of bytes 143 * from this input stream. 144 * If <code>pos</code> equals <code>count</code>, 145 * then <code>-1</code> is returned to indicate 146 * end of file. Otherwise, the number <code>k</code> 147 * of bytes read is equal to the smaller of 148 * <code>len</code> and <code>count-pos</code>. 149 * If <code>k</code> is positive, then bytes 150 * <code>buf[pos]</code> through <code>buf[pos+k-1]</code> 151 * are copied into <code>b[off]</code> through 152 * <code>b[off+k-1]</code> in the manner performed 153 * by <code>System.arraycopy</code>. The 154 * value <code>k</code> is added into <code>pos</code> 155 * and <code>k</code> is returned. 156 * <p> 157 * This <code>read</code> method cannot block. 158 * 159 * @param b the buffer into which the data is read. 160 * @param off the start offset in the destination array <code>b</code> 161 * @param len the maximum number of bytes read. 162 * @return the total number of bytes read into the buffer, or 163 * <code>-1</code> if there is no more data because the end of 164 * the stream has been reached. 165 * @exception NullPointerException If <code>b</code> is <code>null</code>. 166 * @exception IndexOutOfBoundsException If <code>off</code> is negative, 167 * <code>len</code> is negative, or <code>len</code> is greater than 168 * <code>b.length - off</code> 169 */ 170 override int read(byte[] b, int off, int len) { 171 if (b is null) { 172 throw new NullPointerException(""); 173 } else if (off < 0 || len < 0 || len > b.length - off) { 174 throw new IndexOutOfBoundsException(""); 175 } 176 177 if (pos >= count) { 178 return -1; 179 } 180 181 int avail = count - pos; 182 if (len > avail) { 183 len = avail; 184 } 185 if (len <= 0) { 186 return 0; 187 } 188 // System.arraycopy(buf, pos, b, off, len); 189 b[off .. off+len] = buf[pos .. pos+len]; 190 pos += len; 191 return len; 192 } 193 194 /** 195 * Skips <code>n</code> bytes of input from this input stream. Fewer 196 * bytes might be skipped if the end of the input stream is reached. 197 * The actual number <code>k</code> 198 * of bytes to be skipped is equal to the smaller 199 * of <code>n</code> and <code>count-pos</code>. 200 * The value <code>k</code> is added into <code>pos</code> 201 * and <code>k</code> is returned. 202 * 203 * @param n the number of bytes to be skipped. 204 * @return the actual number of bytes skipped. 205 */ 206 override long skip(long n) { 207 long k = count - pos; 208 if (n < k) { 209 k = n < 0 ? 0 : n; 210 } 211 212 pos += k; 213 return k; 214 } 215 216 /** 217 * Returns the number of remaining bytes that can be read (or skipped over) 218 * from this input stream. 219 * <p> 220 * The value returned is <code>count - pos</code>, 221 * which is the number of bytes remaining to be read from the input buffer. 222 * 223 * @return the number of remaining bytes that can be read (or skipped 224 * over) from this input stream without blocking. 225 */ 226 override int available() @trusted nothrow { 227 return count - pos; 228 } 229 230 /** 231 * Tests if this <code>InputStream</code> supports mark/reset. The 232 * <code>markSupported</code> method of <code>ByteArrayInputStream</code> 233 * always returns <code>true</code>. 234 * 235 */ 236 override bool markSupported() { 237 return true; 238 } 239 240 /** 241 * Set the current marked position in the stream. 242 * ByteArrayInputStream objects are marked at position zero by 243 * default when constructed. They may be marked at another 244 * position within the buffer by this method. 245 * <p> 246 * If no mark has been set, then the value of the mark is the 247 * offset passed to the constructor (or 0 if the offset was not 248 * supplied). 249 * 250 * <p> Note: The <code>readAheadLimit</code> for this class 251 * has no meaning. 252 * 253 */ 254 override void mark(int readAheadLimit) { 255 _mark = pos; 256 } 257 258 /** 259 * Resets the buffer to the marked position. The marked position 260 * is 0 unless another position was marked or an offset was specified 261 * in the constructor. 262 */ 263 override void reset() { 264 pos = _mark; 265 } 266 267 override void position(int index) { 268 if(index < 0 || index>count) 269 throw new IOException("Out of range"); 270 pos = index; 271 } 272 /** 273 * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in 274 * this class can be called after the stream has been closed without 275 * generating an <tt>IOException</tt>. 276 */ 277 // void close(){ 278 // } 279 280 }