X-Git-Url: http://git.nikiroo.be/?p=nikiroo-utils.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2FNextableInputStream.java;h=37322c9e8e0d7c5f7b651f44a817aecbe6469e5b;hp=b5374a1329b88ce4944412830f4edb552c818b17;hb=33895a7b06d1a8a7c3555da06b215ab1085ac4df;hpb=473e5f319a4cacc584b5daaf8f0c5d1f18bbf5d0 diff --git a/src/be/nikiroo/utils/NextableInputStream.java b/src/be/nikiroo/utils/NextableInputStream.java index b5374a1..37322c9 100644 --- a/src/be/nikiroo/utils/NextableInputStream.java +++ b/src/be/nikiroo/utils/NextableInputStream.java @@ -2,7 +2,6 @@ package be.nikiroo.utils; import java.io.IOException; import java.io.InputStream; -import java.util.Arrays; /** * This {@link InputStream} can be separated into sub-streams (you can process @@ -13,26 +12,10 @@ import java.util.Arrays; * * @author niki */ -public class NextableInputStream extends InputStream { +public class NextableInputStream extends BufferedInputStream { private NextableInputStreamStep step; private boolean started; private boolean stopped; - private boolean closed; - - private InputStream in; - private int openCounter; - private boolean eof; - private int pos; - private int len; - private byte[] buffer; - - // special use, prefetched next buffer - private byte[] buffer2; - private int pos2; - private int len2; - private byte[] originalBuffer; - - private long bytesRead; /** * Create a new {@link NextableInputStream} that wraps the given @@ -45,13 +28,8 @@ 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; - - this.buffer = new byte[4096]; - this.originalBuffer = this.buffer; - this.pos = 0; - this.len = 0; } /** @@ -90,45 +68,11 @@ public class NextableInputStream extends InputStream { */ public NextableInputStream(byte[] in, NextableInputStreamStep step, int offset, int length) { - if (in == null) { - throw new NullPointerException(); - } else if (offset < 0 || length < 0 || length > in.length - offset) { - throw new IndexOutOfBoundsException(); - } - - this.in = null; + super(in, offset, length); this.step = step; - - this.buffer = in; - this.originalBuffer = this.buffer; - this.pos = offset; - this.len = length; - checkBuffer(true); } - /** - * Return this very same {@link NextableInputStream}, but keep a counter of - * how many streams were open this way. When calling - * {@link NextableInputStream#close()}, decrease this counter if it is not - * already zero instead of actually closing the stream. - *

- * You are now responsible for it — you must close it. - *

- * This method allows you to use a wrapping stream around this one and still - * close the wrapping stream. - * - * @return the same stream, but you are now responsible for closing it - * - * @throws IOException - * in case of I/O error or if the stream is closed - */ - public synchronized InputStream open() throws IOException { - checkClose(); - openCounter++; - return this; - } - /** * Unblock the processing of the next sub-stream. *

@@ -167,195 +111,6 @@ public class NextableInputStream extends InputStream { return next(true); } - // max is buffer.size ! - public boolean startsWiths(String search) throws IOException { - return startsWith(search.getBytes("UTF-8")); - } - - // max is buffer.size ! - public boolean startsWith(byte[] search) throws IOException { - if (search.length > originalBuffer.length) { - throw new IOException( - "This stream does not support searching for more than " - + buffer.length + " bytes"); - } - - checkClose(); - - if (available() < search.length) { - preRead(); - } - - if (available() >= search.length) { - // Easy path - return startsWith(search, buffer, pos); - } else if (!eof) { - // Harder path - if (buffer2 == null && buffer.length == originalBuffer.length) { - buffer2 = Arrays.copyOf(buffer, buffer.length * 2); - - pos2 = buffer.length; - len2 = in.read(buffer2, pos2, buffer.length); - if (len2 > 0) { - bytesRead += len2; - } - - // Note: here, len/len2 = INDEX of last good byte - len2 += pos2; - } - - if (available() + (len2 - pos2) >= search.length) { - return startsWith(search, buffer2, pos2); - } - } - - return false; - } - - /** - * The number of bytes read from the under-laying {@link InputStream}. - * - * @return the number of bytes - */ - public long getBytesRead() { - return bytesRead; - } - - /** - * Check if this stream is totally spent (no more data to read or to - * process). - * - * @return TRUE if it is - */ - public boolean eof() { - return closed || (len < 0 && !hasMoreData()); - } - - @Override - public int read() throws IOException { - checkClose(); - - preRead(); - if (eof) { - return -1; - } - - return buffer[pos++]; - } - - @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 { - checkClose(); - - 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; - } - - @Override - public long skip(long n) throws IOException { - if (n <= 0) { - return 0; - } - - long skipped = 0; - while (hasMoreData() && n > 0) { - preRead(); - - long inBuffer = Math.min(n, available()); - pos += inBuffer; - n -= inBuffer; - skipped += inBuffer; - } - - return skipped; - } - - @Override - public int available() { - if (closed) { - return 0; - } - - return Math.max(0, len - pos); - } - - /** - * Closes this stream and releases any system resources associated with the - * stream. - *

- * Including the under-laying {@link InputStream}. - *

- * Note: if you called the {@link NextableInputStream#open()} method - * prior to this one, it will just decrease the internal count of how many - * open streams it held and do nothing else. The stream will actually be - * closed when you have called {@link NextableInputStream#close()} once more - * than {@link NextableInputStream#open()}. - * - * @exception IOException - * in case of I/O error - */ - @Override - public synchronized void close() throws IOException { - close(true); - } - - /** - * Closes this stream and releases any system resources associated with the - * stream. - *

- * Including the under-laying {@link InputStream} if - * incudingSubStream is true. - *

- * You can call this method multiple times, it will not cause an - * {@link IOException} for subsequent calls. - *

- * Note: if you called the {@link NextableInputStream#open()} method - * prior to this one, it will just decrease the internal count of how many - * open streams it held and do nothing else. The stream will actually be - * closed when you have called {@link NextableInputStream#close()} once more - * than {@link NextableInputStream#open()}. - * - * @exception IOException - * in case of I/O error - */ - public synchronized void close(boolean includingSubStream) - throws IOException { - if (!closed) { - if (openCounter > 0) { - openCounter--; - } else { - closed = true; - if (includingSubStream && in != null) { - in.close(); - } - } - } - } - /** * Check if we still have some data in the buffer and, if not, fetch some. * @@ -365,35 +120,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; - if (buffer2 != null) { - buffer = buffer2; - pos = pos2; - len = len2; - - buffer2 = null; - pos2 = 0; - len2 = 0; - } else { - buffer = originalBuffer; - len = in.read(buffer); - if (len > 0) { - bytesRead += len; - } - } - + @Override + protected boolean preRead() throws IOException { + if (!stopped) { + boolean bufferChanged = super.preRead(); checkBuffer(true); - hasRead = true; + return bufferChanged; } if (pos >= len) { eof = true; } - return hasRead; + return false; } /** @@ -401,8 +140,9 @@ public class NextableInputStream extends InputStream { * * @return TRUE if it is the case, FALSE if not */ - private boolean hasMoreData() { - return !closed && started && !(eof && pos >= len); + @Override + protected boolean hasMoreData() { + return started && super.hasMoreData(); } /** @@ -478,32 +218,4 @@ public class NextableInputStream extends InputStream { return false; } - - /** - * Check that the stream was not closed, and throw an {@link IOException} if - * it was. - * - * @throws IOException - * if it was closed - */ - private void checkClose() throws IOException { - if (closed) { - throw new IOException( - "This NextableInputStream was closed, you cannot use it anymore."); - } - } - - // buffer must be > search - static private boolean startsWith(byte[] search, byte[] buffer, - int offset) { - boolean same = true; - for (int i = 0; i < search.length; i++) { - if (search[i] != buffer[offset + i]) { - same = false; - break; - } - } - - return same; - } }