1 package be
.nikiroo
.utils
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
7 * This {@link InputStream} can be separated into sub-streams (you can process
8 * it as a normal {@link InputStream} but, when it is spent, you can call
9 * {@link NextableInputStream#next()} on it to unlock new data).
11 * The separation in sub-streams is done via {@link NextableInputStreamStep}.
15 public class NextableInputStream
extends BufferedInputStream
{
16 private NextableInputStreamStep step
;
17 private boolean started
;
18 private boolean stopped
;
21 * Create a new {@link NextableInputStream} that wraps the given
22 * {@link InputStream}.
25 * the {@link InputStream} to wrap
27 * how to separate it into sub-streams (can be NULL, but in that
28 * case it will behave as a normal {@link InputStream})
30 public NextableInputStream(InputStream in
, NextableInputStreamStep step
) {
36 * Create a new {@link NextableInputStream} that wraps the given bytes array
40 * the array to wrap, cannot be NULL
42 * how to separate it into sub-streams (can be NULL, but in that
43 * case it will behave as a normal {@link InputStream})
45 public NextableInputStream(byte[] in
, NextableInputStreamStep step
) {
46 this(in
, step
, 0, in
.length
);
50 * Create a new {@link NextableInputStream} that wraps the given bytes array
54 * the array to wrap, cannot be NULL
56 * how to separate it into sub-streams (can be NULL, but in that
57 * case it will behave as a normal {@link InputStream})
59 * the offset to start the reading at
61 * the number of bytes to take into account in the array,
62 * starting from the offset
64 * @throws NullPointerException
65 * if the array is NULL
66 * @throws IndexOutOfBoundsException
67 * if the offset and length do not correspond to the given array
69 public NextableInputStream(byte[] in
, NextableInputStreamStep step
,
70 int offset
, int length
) {
71 super(in
, offset
, length
);
77 * Unblock the processing of the next sub-stream.
79 * It can only be called when the "current" stream is spent (i.e., you must
80 * first process the stream until it is spent).
82 * We consider that when the under-laying {@link InputStream} is also spent,
83 * we cannot have a next sub-stream (it will thus return FALSE).
85 * {@link IOException}s can happen when we have no data available in the
86 * buffer; in that case, we fetch more data to know if we can have a next
89 * @return TRUE if we unblocked the next sub-stream, FALSE if not
92 * in case of I/O error or if the stream is closed
94 public boolean next() throws IOException
{
99 * Unblock the next sub-stream as would have done
100 * {@link NextableInputStream#next()}, but disable the sub-stream systems.
102 * That is, the next stream, if any, will be the last one and will not be
103 * subject to the {@link NextableInputStreamStep}.
105 * @return TRUE if we unblocked the next sub-stream, FALSE if not
107 * @throws IOException
108 * in case of I/O error or if the stream is closed
110 public boolean nextAll() throws IOException
{
115 * Check if we still have some data in the buffer and, if not, fetch some.
117 * @return TRUE if we fetched some data, FALSE if there are still some in
120 * @throws IOException
121 * in case of I/O error
124 protected boolean preRead() throws IOException
{
126 boolean bufferChanged
= super.preRead();
128 return bufferChanged
;
139 * We have more data available in the buffer or we can fetch more.
141 * @return TRUE if it is the case, FALSE if not
144 protected boolean hasMoreData() {
145 return started
&& super.hasMoreData();
149 * Check that the buffer didn't overshot to the next item, and fix
150 * {@link NextableInputStream#len} if needed.
152 * If {@link NextableInputStream#len} is fixed,
153 * {@link NextableInputStream#eof} and {@link NextableInputStream#stopped}
157 * we changed the buffer, we need to clear some information in
158 * the {@link NextableInputStreamStep}
160 private void checkBuffer(boolean newBuffer
) {
161 if (step
!= null && len
> 0) {
166 int stopAt
= step
.stop(buffer
, pos
, len
);
176 * The implementation of {@link NextableInputStream#next()} and
177 * {@link NextableInputStream#nextAll()}.
180 * TRUE for {@link NextableInputStream#nextAll()}, FALSE for
181 * {@link NextableInputStream#next()}
183 * @return TRUE if we unblocked the next sub-stream, FALSE if not
185 * @throws IOException
186 * in case of I/O error or if the stream is closed
188 private boolean next(boolean all
) throws IOException
{
192 // First call before being allowed to read
202 if (step
!= null && !hasMoreData() && stopped
) {
203 len
= step
.getResumeLen();
204 pos
+= step
.getResumeSkip();
215 // consider that if EOF, there is no next
216 return hasMoreData();