X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2FNextableInputStream.java;h=0def936c4247ea5019898d0862481713e8620c2b;hb=63b46ca9f1703134ef2979b72d474e9c9b8f5737;hp=6f3afc2b261fe439f65c79dbce20602be3bfdd53;hpb=4098af704dfa22ce4a60003940753c28030374fa;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/NextableInputStream.java b/src/be/nikiroo/utils/NextableInputStream.java index 6f3afc2..0def936 100644 --- a/src/be/nikiroo/utils/NextableInputStream.java +++ b/src/be/nikiroo/utils/NextableInputStream.java @@ -2,12 +2,19 @@ package be.nikiroo.utils; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; +/** + * This {@link InputStream} can be separated into sub-streams (you can process + * it as a normal {@link InputStream} but, when it is spent, you can call + * {@link NextableInputStream#next()} on it to unlock new data). + *

+ * The separation in sub-streams is done via {@link NextableInputStreamStep}. + * + * @author niki + */ public class NextableInputStream extends InputStream { - private List steps = new ArrayList(); - private NextableInputStreamStep step = null; + private NextableInputStreamStep step; + private boolean stopped; private InputStream in; private boolean eof; @@ -15,24 +22,51 @@ public class NextableInputStream extends InputStream { private int len = 0; private byte[] buffer = new byte[4096]; - public NextableInputStream(InputStream in) { + /** + * Create a new {@link NextableInputStream} that wraps the given + * {@link InputStream}. + * + * @param in + * the {@link InputStream} to wrap + * @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(InputStream in, NextableInputStreamStep step) { this.in = in; + this.step = step; } - public void addStep(NextableInputStreamStep step) { - steps.add(step); - } - - public boolean next() { - if (!hasMoreData() && step != null) { + /** + * Unblock the processing of the next sub-stream. + *

+ * It can only be called when the "current" stream is spent (i.e., you must + * first process the stream until it is spent). + *

+ * We consider that when the under-laying {@link InputStream} is also spent, + * we cannot have a next sub-stream (it will thus return FALSE). + *

+ * {@link IOException}s can happen when we have no data available in the + * buffer; in that case, we fetch more data to know if we can have a next + * sub-stream or not. + * + * @return TRUE if we unblocked the next sub-stream, FALSE if not + * + * @throws IOException + * in case of I/O error + */ + public boolean next() throws IOException { + if (!hasMoreData() && stopped) { len = step.getResumeLen(); - pos += step.getSkip(); + pos += step.getResumeSkip(); eof = false; - step = null; - - checkNexts(false); - return true; + if (!preRead()) { + checkBuffer(false); + } + + // consider that if EOF, there is no next + return hasMoreData(); } return false; @@ -83,36 +117,63 @@ public class NextableInputStream extends InputStream { return Math.max(0, len - pos); } - private void preRead() throws IOException { - if (!eof && in != null && pos >= len && step == null) { + /** + * Check if we still have some data in the buffer and, if not, fetch some. + * + * @return TRUE if we fetched some data, FALSE if there are still some in + * the buffer + * + * @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); - checkNexts(true); + checkBuffer(true); + hasRead = true; } if (pos >= len) { eof = true; } + + return hasRead; } + /** + * We have more data available in the buffer or we can fetch more. + * + * @return TRUE if it is the case, FALSE if not + */ private boolean hasMoreData() { return !(eof && pos >= len); } - private void checkNexts(boolean newBuffer) { - if (!eof) { - for (NextableInputStreamStep step : steps) { - if (newBuffer) { - step.clearBuffer(); - } + /** + * Check that the buffer didn't overshot to the next item, and fix + * {@link NextableInputStream#len} if needed. + *

+ * If {@link NextableInputStream#len} is fixed, + * {@link NextableInputStream#eof} and {@link NextableInputStream#stopped} + * are set to TRUE. + * + * @param newBuffer + * we changed the buffer, we need to clear some information in + * the {@link NextableInputStreamStep} + */ + private void checkBuffer(boolean newBuffer) { + if (step != null) { + if (newBuffer) { + step.clearBuffer(); + } - int stopAt = step.stop(buffer, pos, len); - if (stopAt >= 0) { - this.step = step; - len = stopAt; - eof = true; - break; - } + int stopAt = step.stop(buffer, pos, len); + if (stopAt >= 0) { + len = stopAt; + eof = true; + stopped = true; } } }