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&nbsp;- 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 }