1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package net
.multiphasicapps
.io
;
12 import cc
.squirreljme
.runtime
.cldc
.annotation
.Exported
;
13 import cc
.squirreljme
.runtime
.cldc
.debug
.Debugging
;
14 import java
.io
.IOException
;
15 import java
.io
.InputStream
;
18 * This is an input stream which allows any future data in the stream to be
19 * cached for later actual reading. This class should be used in situations
20 * where it is needed to read future bytes in the stream and react to those
23 * This class is not thread safe.
28 public class DynamicHistoryInputStream
31 /** The backing buffer. */
32 protected final ByteDeque buffer
;
34 /** The source input stream. */
35 protected final InputStream input
;
38 private volatile boolean _closed
;
41 private volatile boolean _eof
;
44 * Initializes a dynamic history stream which sources data from the given
47 * @param __is The stream to read data from.
48 * @throws NullPointerException On null arguments.
52 public DynamicHistoryInputStream(InputStream __is
)
53 throws NullPointerException
57 throw new NullPointerException("NARG");
61 this.buffer
= new ByteDeque();
75 // Clear the buffer since it is not needed
78 // Close wrapped stream
83 * Grabs the specified number of bytes and loads them into an internal
84 * queue where they may then be obtained using another method.
86 * @param __i The number of bytes to read ahead and buffer.
87 * @return The number of bytes which are available for input, this may
88 * be less than or greater than the input parameter.
89 * @throws IndexOutOfBoundsException If the count is negative.
90 * @throws IOException On read errors.
94 public int grab(int __i
)
95 throws IndexOutOfBoundsException
, IOException
97 // {@squirreljme.error BD0m A negative number of bytes cannot be
98 // grabbed. (The number of bytes to grab)}
100 throw new IndexOutOfBoundsException(String
.format("BD0m %s", __i
));
103 ByteDeque buffer
= this.buffer
;
105 // {@squirreljme.error BD0n Cannot grab bytes because the stream
108 throw new IOException("BD0n");
110 // Already have this number of bytes grabbed
111 int cursize
= buffer
.available();
115 // The number of bytes that need to be read
116 int diff
= __i
- cursize
;
118 // Read them from the input
119 byte[] qq
= new byte[diff
];
124 int rc
= this.input
.read(qq
);
126 // If EOF was read, stop
130 // Add them to the end of the buffer
131 buffer
.addLast(qq
, 0, rc
);
133 // The number of available bytes is the current and the read
139 return cursize
+ total
;
143 * Reads a single byte that is ahead of the current read position.
145 * @param __a The position of the byte ahead of the current read position
147 * @return The read value or a negative value if the byte to be read
148 * exceeds the end of the stream.
149 * @throws IndexOutOfBoundsException If the requested read ahead position
151 * @throws IOException On read errors.
155 public int peek(int __a
)
156 throws IndexOutOfBoundsException
, IOException
158 // {@squirreljme.error BD0o Cannot a peek byte which have already been
159 // read. (The requested index)}
161 throw new IndexOutOfBoundsException(String
.format("BD0o %d", __a
));
164 ByteDeque buffer
= this.buffer
;
166 // {@squirreljme.error BD0p Cannot peek a single byte because the
167 // stream is closed.}
169 throw new IOException("BD0p");
171 // Grab bytes, stop if none are available
172 int avail
= this.grab(__a
+ 1);
176 throw Debugging
.todo();
180 * Reads multiple bytes which are ahead of the current read position.
182 * @param __a The start position of the bytes ahead of the current read
184 * @param __b The array which receives the bytes being read.
185 * @return The number of bytes read or a negative value if there are no
186 * bytes to be read because they exceed the end of the stream.
187 * @throws IndexOutOfBoundsException If the requested read ahead position
189 * @throws IOException On read errors.
190 * @throws NullPointerException On null arguments.
194 public int peek(int __a
, byte[] __b
)
195 throws IndexOutOfBoundsException
, IOException
, NullPointerException
197 return this.peek(__a
, __b
, 0, __b
.length
);
201 * Reads multiple bytes which are ahead of the current read position.
203 * @param __a The start position of the bytes ahead of the current read
205 * @param __b The array which receives the bytes being read.
206 * @param __o The starting offset into the array to write into.
207 * @param __l The number of bytes to read.
208 * @return The number of bytes read or a negative value if there are no
209 * bytes to be read because they exceed the end of the stream.
210 * @throws IndexOutOfBoundsException If the requested read ahead position
211 * is negative; or the offset and or length exceed the array size.
212 * @throws IOException On read errors.
213 * @throws NullPointerException On null arguments.
217 public int peek(int __a
, byte[] __b
, int __o
, int __l
)
218 throws IndexOutOfBoundsException
, IOException
, NullPointerException
220 // {@squirreljme.error BD0q Cannot peek bytes which have already been
221 // read. (The requested index)}
223 throw new IndexOutOfBoundsException(String
.format("BD0q %d", __a
));
227 throw new NullPointerException("NARG");
229 if (__o
< 0 || __l
< 0 || (__o
+ __l
) > n
)
230 throw new IndexOutOfBoundsException("IOOB");
233 ByteDeque buffer
= this.buffer
;
235 // {@squirreljme.error BD0r Cannot peek multiple bytes because
236 // the stream is closed.}
238 throw new IOException("BD0r");
240 // Grab bytes, stop if none are available
241 int avail
= this.grab(__a
+ __l
);
245 // Not reading anything?
246 int rc
= Math
.min(__l
, avail
);
250 // Read from the buffer
251 buffer
.get(__a
, __b
, __o
, rc
);
263 // {@squirreljme.error BD0s Cannot read a single byte because the
264 // stream has been closed.}
266 throw new IOException("BD0s");
268 // Grab a single byte
269 int gc
= this.grab(1);
276 return (this.buffer
.removeFirst() & 0xFF);
284 public int read(byte[] __b
, int __o
, int __l
)
285 throws IndexOutOfBoundsException
, IOException
, NullPointerException
289 throw new NullPointerException("NARG");
291 if (__o
< 0 || __l
< 0 || (__o
+ __l
) > n
)
292 throw new IndexOutOfBoundsException("IOOB");
295 ByteDeque buffer
= this.buffer
;
297 // {@squirreljme BI08 Cannot read multiple bytes because the
298 // stream is closed.}
300 throw new IOException("BI08");
302 // Grab multiple bytes
303 int gc
= this.grab(__l
);
310 int dc
= Math
.min(gc
, __l
);
314 // Remove the early bytes
315 buffer
.removeFirst(__b
, __o
, dc
);