Streams: bug fixes
authorNiki Roo <niki@nikiroo.be>
Sun, 28 Apr 2019 09:31:19 +0000 (11:31 +0200)
committerNiki Roo <niki@nikiroo.be>
Sun, 28 Apr 2019 09:31:19 +0000 (11:31 +0200)
src/be/nikiroo/utils/IOUtils.java
src/be/nikiroo/utils/streams/BufferedInputStream.java
src/be/nikiroo/utils/streams/BufferedOutputStream.java
src/be/nikiroo/utils/streams/NextableInputStream.java
src/be/nikiroo/utils/streams/NextableInputStreamStep.java
src/be/nikiroo/utils/streams/ReplaceInputStream.java

index 5a7e179b684d9423182c048376f2bf014c54077b..9ab638af06e1486122de1c059abec3eb5b0a4980 100644 (file)
@@ -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);
                }
index be4b24d2ec9b477b3556df34fd607923c8c30bf5..af1e2ac932a4abb7d46815d34963dfcf8dbf6305 100644 (file)
@@ -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 <b>or</b> 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;
        }
 
        /**
index 5f7e6ebc7011d4df33c10e95356ad1a91f08b925..2071d0c3b5d68623457808efb7167c9e265dc651 100644 (file)
@@ -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;
 
index 4a6e0abc672abf441ef6acf51f9db9ed1d625585..d023ad34482837b7896d75482d0bff85b98f9aa1 100644 (file)
@@ -115,16 +115,19 @@ public class NextableInputStream extends BufferedInputStream {
         * Check if this stream is totally spent (no more data to read or to
         * process).
         * <p>
-        * 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();
index 818abf5af730e8210d5151a12df0970758f694d3..fda998d1ce8990abe48539293e9a7d84613d0cf8 100755 (executable)
@@ -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
         * <p>
         * 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;
        }
 }
index eea3a1ab9b74b42158d5b40e565b59c839cb690a..b2187af09ce189dae52105733c10559f0db4aff0 100644 (file)
@@ -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++];
                        }
                }