From 028ff7c29a8fb07c702ffd34913a5dd22b688211 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 28 Apr 2019 11:31:19 +0200 Subject: [PATCH] Streams: bug fixes --- src/be/nikiroo/utils/IOUtils.java | 2 +- .../utils/streams/BufferedInputStream.java | 36 ++++++++++++++----- .../utils/streams/BufferedOutputStream.java | 6 ++-- .../utils/streams/NextableInputStream.java | 24 +++++++------ .../streams/NextableInputStreamStep.java | 32 ++++++++++++----- .../utils/streams/ReplaceInputStream.java | 12 ++++--- 6 files changed, 76 insertions(+), 36 deletions(-) diff --git a/src/be/nikiroo/utils/IOUtils.java b/src/be/nikiroo/utils/IOUtils.java index 5a7e179b..9ab638af 100644 --- a/src/be/nikiroo/utils/IOUtils.java +++ b/src/be/nikiroo/utils/IOUtils.java @@ -56,7 +56,7 @@ public class IOUtils { throws IOException { byte buffer[] = new byte[4096]; int len = in.read(buffer); - while (len > 0) { + while (len > -1) { out.write(buffer, 0, len); len = in.read(buffer); } diff --git a/src/be/nikiroo/utils/streams/BufferedInputStream.java b/src/be/nikiroo/utils/streams/BufferedInputStream.java index be4b24d2..af1e2ac9 100644 --- a/src/be/nikiroo/utils/streams/BufferedInputStream.java +++ b/src/be/nikiroo/utils/streams/BufferedInputStream.java @@ -174,7 +174,7 @@ public class BufferedInputStream extends InputStream { buffer2 = Arrays.copyOf(buffer, buffer.length * 2); pos2 = buffer.length; - len2 = in.read(buffer2, pos2, buffer.length); + len2 = read(in, buffer2, pos2, buffer.length); if (len2 > 0) { bytesRead += len2; } @@ -203,9 +203,17 @@ public class BufferedInputStream extends InputStream { * process). * * @return TRUE if it is + * + * @throws IOException + * in case of I/O error */ - public boolean eof() { - return closed || (stop < 0 && !hasMoreData()); + public boolean eof() throws IOException { + if (closed) { + return true; + } + + preRead(); + return !hasMoreData(); } @Override @@ -348,7 +356,7 @@ public class BufferedInputStream extends InputStream { */ protected boolean preRead() throws IOException { boolean hasRead = false; - if (!eof && in != null && start >= stop) { + if (in != null && !eof && start >= stop) { start = 0; if (buffer2 != null) { buffer = buffer2; @@ -361,7 +369,7 @@ public class BufferedInputStream extends InputStream { } else { buffer = originalBuffer; - stop = read(in, buffer); + stop = read(in, buffer, 0, buffer.length); if (stop > 0) { bytesRead += stop; } @@ -384,23 +392,33 @@ public class BufferedInputStream extends InputStream { * the under-laying {@link InputStream} * @param buffer * the buffer we use in this {@link BufferedInputStream} + * @param off + * the offset + * @param len + * the length in bytes * * @return the number of bytes read * * @throws IOException * in case of I/O error */ - protected int read(InputStream in, byte[] buffer) throws IOException { - return in.read(buffer); + protected int read(InputStream in, byte[] buffer, int off, int len) + throws IOException { + return in.read(buffer, off, len); } /** - * We have more data available in the buffer or we can fetch more. + * We have more data available in the buffer or we can, maybe, fetch + * more. * * @return TRUE if it is the case, FALSE if not */ protected boolean hasMoreData() { - return !closed && !(eof && start >= stop); + if (closed) { + return false; + } + + return (start < stop) || !eof; } /** diff --git a/src/be/nikiroo/utils/streams/BufferedOutputStream.java b/src/be/nikiroo/utils/streams/BufferedOutputStream.java index 5f7e6ebc..2071d0c3 100644 --- a/src/be/nikiroo/utils/streams/BufferedOutputStream.java +++ b/src/be/nikiroo/utils/streams/BufferedOutputStream.java @@ -184,8 +184,10 @@ public class BufferedOutputStream extends OutputStream { * in case of I/O error */ protected void flush(boolean includingSubStream) throws IOException { - out.write(buffer, start, stop - start); - bytesWritten += (stop - start); + if (stop > start) { + out.write(buffer, start, stop - start); + bytesWritten += (stop - start); + } start = 0; stop = 0; diff --git a/src/be/nikiroo/utils/streams/NextableInputStream.java b/src/be/nikiroo/utils/streams/NextableInputStream.java index 4a6e0abc..d023ad34 100644 --- a/src/be/nikiroo/utils/streams/NextableInputStream.java +++ b/src/be/nikiroo/utils/streams/NextableInputStream.java @@ -115,16 +115,19 @@ public class NextableInputStream extends BufferedInputStream { * 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. + * Note: when the stream is divided into sub-streams, each sub-stream will + * report it is eof when emptied. * * @return TRUE if it is + * + * @throws IOException + * in case of I/O error */ @Override - public boolean eof() { + public boolean eof() throws IOException { return super.eof(); } - + /** * Check if we still have some data in the buffer and, if not, fetch some. * @@ -138,7 +141,7 @@ public class NextableInputStream extends BufferedInputStream { protected boolean preRead() throws IOException { if (!stopped) { boolean bufferChanged = super.preRead(); - checkBuffer(true); + checkBuffer(bufferChanged); return bufferChanged; } @@ -172,12 +175,12 @@ public class NextableInputStream extends BufferedInputStream { * the {@link NextableInputStreamStep} */ private void checkBuffer(boolean newBuffer) { - if (step != null && stop > 0) { + if (step != null && stop >= 0) { if (newBuffer) { step.clearBuffer(); } - int stopAt = step.stop(buffer, start, stop); + int stopAt = step.stop(buffer, start, stop, eof); if (stopAt >= 0) { stop = stopAt; eof = true; @@ -216,15 +219,14 @@ public class NextableInputStream extends BufferedInputStream { if (step != null && !hasMoreData() && stopped) { stop = step.getResumeLen(); start += step.getResumeSkip(); - eof = false; + eof = step.getResumeEof(); + stopped = false; if (all) { step = null; } - if (!preRead()) { - checkBuffer(false); - } + checkBuffer(false); // consider that if EOF, there is no next return hasMoreData(); diff --git a/src/be/nikiroo/utils/streams/NextableInputStreamStep.java b/src/be/nikiroo/utils/streams/NextableInputStreamStep.java index 818abf5a..fda998d1 100755 --- a/src/be/nikiroo/utils/streams/NextableInputStreamStep.java +++ b/src/be/nikiroo/utils/streams/NextableInputStreamStep.java @@ -9,9 +9,10 @@ import java.io.InputStream; */ public class NextableInputStreamStep { private int stopAt; - private int resumeLen; private int last = -1; - private int skip; + private int resumeLen; + private int resumeSkip; + private boolean resumeEof; /** * Create a new divider that will separate the sub-streams each time it sees @@ -43,17 +44,20 @@ public class NextableInputStreamStep { * @param len * the maximum index to use in the buffer (anything above that is * not to be used) + * @param eof + * the current state of the under-laying stream * * @return the index at which to stop, or -1 */ - public int stop(byte[] buffer, int pos, int len) { + public int stop(byte[] buffer, int pos, int len, boolean eof) { for (int i = pos; i < len; i++) { if (buffer[i] == stopAt) { if (i > this.last) { // we skip the sep - this.skip = 1; + this.resumeSkip = 1; this.resumeLen = len; + this.resumeEof = eof; this.last = i; return i; } @@ -65,7 +69,8 @@ public class NextableInputStreamStep { /** * Get the maximum index to use in the buffer used in - * {@link NextableInputStreamStep#stop(byte[], int, int)} at resume time. + * {@link NextableInputStreamStep#stop(byte[], int, int, boolean)} at resume + * time. * * @return the index */ @@ -79,18 +84,29 @@ public class NextableInputStreamStep { * @return the number of bytes to skip */ public int getResumeSkip() { - return skip; + return resumeSkip; + } + + /** + * Get the under-laying stream state at resume time. + * + * @return the EOF state + */ + public boolean getResumeEof() { + return resumeEof; } /** * Clear the information we may have kept about the current buffer *

* You should call this method each time you change the content of the - * buffer used in {@link NextableInputStreamStep#stop(byte[], int, int)}. + * buffer used in + * {@link NextableInputStreamStep#stop(byte[], int, int, boolean)}. */ public void clearBuffer() { this.last = -1; - this.skip = 0; + this.resumeSkip = 0; this.resumeLen = 0; + this.resumeEof = false; } } diff --git a/src/be/nikiroo/utils/streams/ReplaceInputStream.java b/src/be/nikiroo/utils/streams/ReplaceInputStream.java index eea3a1ab..b2187af0 100644 --- a/src/be/nikiroo/utils/streams/ReplaceInputStream.java +++ b/src/be/nikiroo/utils/streams/ReplaceInputStream.java @@ -101,8 +101,9 @@ public class ReplaceInputStream extends BufferedInputStream { } @Override - protected int read(InputStream in, byte[] buffer) throws IOException { - if (buffer.length < maxToSize || source.length < maxToSize * 2) { + protected int read(InputStream in, byte[] buffer, int off, int len) + throws IOException { + if (len < maxToSize || source.length < maxToSize * 2) { throw new IOException( "An underlaying buffer is too small for these replace values"); } @@ -114,13 +115,14 @@ public class ReplaceInputStream extends BufferedInputStream { // Note: very simple, not efficient implementation, sorry. int count = 0; - while (spos < slen && count < buffer.length - maxToSize) { + while (spos < slen && count < len - maxToSize) { boolean replaced = false; for (int i = 0; i < froms.length; i++) { if (froms[i] != null && froms[i].length > 0 && StreamUtils.startsWith(froms[i], source, spos, slen)) { if (tos[i] != null && tos[i].length > 0) { - System.arraycopy(tos[i], 0, buffer, spos, tos[i].length); + System.arraycopy(tos[i], 0, buffer, off + spos, + tos[i].length); count += tos[i].length; } @@ -131,7 +133,7 @@ public class ReplaceInputStream extends BufferedInputStream { } if (!replaced) { - buffer[count++] = source[spos++]; + buffer[off + count++] = source[spos++]; } } -- 2.27.0