X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2FNextableInputStream.java;h=f221cbbda9aa2ce9ad0eff7f215c725cbc886ab0;hb=a26188d393b11040b8ee8476338a73bfadabffb6;hp=0def936c4247ea5019898d0862481713e8620c2b;hpb=63b46ca9f1703134ef2979b72d474e9c9b8f5737;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/NextableInputStream.java b/src/be/nikiroo/utils/NextableInputStream.java index 0def936..f221cbb 100644 --- a/src/be/nikiroo/utils/NextableInputStream.java +++ b/src/be/nikiroo/utils/NextableInputStream.java @@ -12,16 +12,11 @@ import java.io.InputStream; * * @author niki */ -public class NextableInputStream extends InputStream { +public class NextableInputStream extends BufferedInputStream { private NextableInputStreamStep step; + private boolean started; private boolean stopped; - private InputStream in; - private boolean eof; - private int pos = 0; - private int len = 0; - private byte[] buffer = new byte[4096]; - /** * Create a new {@link NextableInputStream} that wraps the given * {@link InputStream}. @@ -33,10 +28,51 @@ public class NextableInputStream extends InputStream { * case it will behave as a normal {@link InputStream}) */ public NextableInputStream(InputStream in, NextableInputStreamStep step) { - this.in = in; + super(in); this.step = step; } + /** + * Create a new {@link NextableInputStream} that wraps the given bytes array + * as a data source. + * + * @param in + * the array to wrap, cannot be NULL + * @param step + * how to separate it into sub-streams (can be NULL, but in that + * case it will behave as a normal {@link InputStream}) + */ + public NextableInputStream(byte[] in, NextableInputStreamStep step) { + this(in, step, 0, in.length); + } + + /** + * Create a new {@link NextableInputStream} that wraps the given bytes array + * as a data source. + * + * @param in + * the array to wrap, cannot be NULL + * @param step + * how to separate it into sub-streams (can be NULL, but in that + * case it will behave as a normal {@link InputStream}) + * @param offset + * the offset to start the reading at + * @param length + * the number of bytes to take into account in the array, + * starting from the offset + * + * @throws NullPointerException + * if the array is NULL + * @throws IndexOutOfBoundsException + * if the offset and length do not correspond to the given array + */ + public NextableInputStream(byte[] in, NextableInputStreamStep step, + int offset, int length) { + super(in, offset, length); + this.step = step; + checkBuffer(true); + } + /** * Unblock the processing of the next sub-stream. *

@@ -53,70 +89,42 @@ public class NextableInputStream extends InputStream { * @return TRUE if we unblocked the next sub-stream, FALSE if not * * @throws IOException - * in case of I/O error + * in case of I/O error or if the stream is closed */ public boolean next() throws IOException { - if (!hasMoreData() && stopped) { - len = step.getResumeLen(); - pos += step.getResumeSkip(); - eof = false; - - if (!preRead()) { - checkBuffer(false); - } - - // consider that if EOF, there is no next - return hasMoreData(); - } - - return false; - } - - @Override - public int read() throws IOException { - preRead(); - if (eof) { - return -1; - } - - return buffer[pos++]; + return next(false); } - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - @Override - public int read(byte[] b, int boff, int blen) throws IOException { - if (b == null) { - throw new NullPointerException(); - } else if (boff < 0 || blen < 0 || blen > b.length - boff) { - throw new IndexOutOfBoundsException(); - } else if (blen == 0) { - return 0; - } - - int done = 0; - while (hasMoreData() && done < blen) { - preRead(); - if (hasMoreData()) { - for (int i = pos; i < blen && i < len; i++) { - b[boff + done] = buffer[i]; - pos++; - done++; - } - } - } - - return done > 0 ? done : -1; + /** + * Unblock the next sub-stream as would have done + * {@link NextableInputStream#next()}, but disable the sub-stream systems. + *

+ * That is, the next stream, if any, will be the last one and will not be + * subject to the {@link NextableInputStreamStep}. + * + * @return TRUE if we unblocked the next sub-stream, FALSE if not + * + * @throws IOException + * in case of I/O error or if the stream is closed + */ + public boolean nextAll() throws IOException { + return next(true); } + /** + * Check if this stream is totally spent (no more data to read or to + * process). + *

+ * Note: an empty stream that is still not started will return FALSE, as we + * don't know yet if it is empty. + * + * @return TRUE if it is + */ @Override - public int available() throws IOException { - return Math.max(0, len - pos); + public boolean eof() { + return super.eof(); } - + /** * Check if we still have some data in the buffer and, if not, fetch some. * @@ -126,20 +134,19 @@ public class NextableInputStream extends InputStream { * @throws IOException * in case of I/O error */ - private boolean preRead() throws IOException { - boolean hasRead = false; - if (!eof && in != null && pos >= len && !stopped) { - pos = 0; - len = in.read(buffer); + @Override + protected boolean preRead() throws IOException { + if (!stopped) { + boolean bufferChanged = super.preRead(); checkBuffer(true); - hasRead = true; + return bufferChanged; } - if (pos >= len) { + if (start >= stop) { eof = true; } - return hasRead; + return false; } /** @@ -147,15 +154,16 @@ public class NextableInputStream extends InputStream { * * @return TRUE if it is the case, FALSE if not */ - private boolean hasMoreData() { - return !(eof && pos >= len); + @Override + protected boolean hasMoreData() { + return started && super.hasMoreData(); } /** * Check that the buffer didn't overshot to the next item, and fix - * {@link NextableInputStream#len} if needed. + * {@link NextableInputStream#stop} if needed. *

- * If {@link NextableInputStream#len} is fixed, + * If {@link NextableInputStream#stop} is fixed, * {@link NextableInputStream#eof} and {@link NextableInputStream#stopped} * are set to TRUE. * @@ -164,17 +172,64 @@ public class NextableInputStream extends InputStream { * the {@link NextableInputStreamStep} */ private void checkBuffer(boolean newBuffer) { - if (step != null) { + if (step != null && stop > 0) { if (newBuffer) { step.clearBuffer(); } - int stopAt = step.stop(buffer, pos, len); + int stopAt = step.stop(buffer, start, stop); if (stopAt >= 0) { - len = stopAt; + stop = stopAt; eof = true; stopped = true; } } } + + /** + * The implementation of {@link NextableInputStream#next()} and + * {@link NextableInputStream#nextAll()}. + * + * @param all + * TRUE for {@link NextableInputStream#nextAll()}, FALSE for + * {@link NextableInputStream#next()} + * + * @return TRUE if we unblocked the next sub-stream, FALSE if not + * + * @throws IOException + * in case of I/O error or if the stream is closed + */ + private boolean next(boolean all) throws IOException { + checkClose(); + + if (!started) { + // First call before being allowed to read + started = true; + + if (all) { + step = null; + } + + return true; + } + + if (step != null && !hasMoreData() && stopped) { + stop = step.getResumeLen(); + start += step.getResumeSkip(); + eof = false; + + if (all) { + step = null; + } + + if (!preRead()) { + checkBuffer(false); + } + + // consider that if EOF, there is no next + return hasMoreData(); + } + + return false; + } }