1 package be
.nikiroo
.utils
.streams
;
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 this stream is totally spent (no more data to read or to
118 * Note: an empty stream that is still not started will return FALSE, as we
119 * don't know yet if it is empty.
121 * @return TRUE if it is
124 public boolean eof() {
129 * Check if we still have some data in the buffer and, if not, fetch some.
131 * @return TRUE if we fetched some data, FALSE if there are still some in
134 * @throws IOException
135 * in case of I/O error
138 protected boolean preRead() throws IOException
{
140 boolean bufferChanged
= super.preRead();
142 return bufferChanged
;
153 * We have more data available in the buffer or we can fetch more.
155 * @return TRUE if it is the case, FALSE if not
158 protected boolean hasMoreData() {
159 return started
&& super.hasMoreData();
163 * Check that the buffer didn't overshot to the next item, and fix
164 * {@link NextableInputStream#stop} if needed.
166 * If {@link NextableInputStream#stop} is fixed,
167 * {@link NextableInputStream#eof} and {@link NextableInputStream#stopped}
171 * we changed the buffer, we need to clear some information in
172 * the {@link NextableInputStreamStep}
174 private void checkBuffer(boolean newBuffer
) {
175 if (step
!= null && stop
> 0) {
180 int stopAt
= step
.stop(buffer
, start
, stop
);
190 * The implementation of {@link NextableInputStream#next()} and
191 * {@link NextableInputStream#nextAll()}.
194 * TRUE for {@link NextableInputStream#nextAll()}, FALSE for
195 * {@link NextableInputStream#next()}
197 * @return TRUE if we unblocked the next sub-stream, FALSE if not
199 * @throws IOException
200 * in case of I/O error or if the stream is closed
202 private boolean next(boolean all
) throws IOException
{
206 // First call before being allowed to read
216 if (step
!= null && !hasMoreData() && stopped
) {
217 stop
= step
.getResumeLen();
218 start
+= step
.getResumeSkip();
229 // consider that if EOF, there is no next
230 return hasMoreData();