New: BufferedOutputStream
[nikiroo-utils.git] / src / be / nikiroo / utils / BufferedInputStream.java
index 9b95574b8165ea8d093cafe4869b8b307886a8ac..aa455a2426d0b96d2534f27c0740c545510c858f 100644 (file)
@@ -14,9 +14,13 @@ import java.util.Arrays;
  * @author niki
  */
 public class BufferedInputStream extends InputStream {
-       protected int pos;
-       protected int len;
+       /** The current position in the buffer. */
+       protected int start;
+       /** The index of the last usable position of the buffer. */
+       protected int stop;
+       /** The buffer itself. */
        protected byte[] buffer;
+       /** An End-Of-File (or buffer, here) marker. */
        protected boolean eof;
 
        private boolean closed;
@@ -43,8 +47,8 @@ public class BufferedInputStream extends InputStream {
 
                this.buffer = new byte[4096];
                this.originalBuffer = this.buffer;
-               this.pos = 0;
-               this.len = 0;
+               this.start = 0;
+               this.stop = 0;
        }
 
        /**
@@ -86,8 +90,8 @@ public class BufferedInputStream extends InputStream {
 
                this.buffer = in;
                this.originalBuffer = this.buffer;
-               this.pos = offset;
-               this.len = length;
+               this.start = offset;
+               this.stop = length;
        }
 
        /**
@@ -112,12 +116,42 @@ public class BufferedInputStream extends InputStream {
                return this;
        }
 
-       // max is buffer.size !
+       /**
+        * Check if the current content (what will be read next) starts with the
+        * given search term.
+        * <p>
+        * Note: the search term size <b>must</b> be smaller or equal the internal
+        * buffer size.
+        * 
+        * @param search
+        *            the term to search for
+        * 
+        * @return TRUE if the content that will be read starts with it
+        * 
+        * @throws IOException
+        *             in case of I/O error or if the size of the search term is
+        *             greater than the internal buffer
+        */
        public boolean startsWiths(String search) throws IOException {
                return startsWith(search.getBytes("UTF-8"));
        }
 
-       // max is buffer.size !
+       /**
+        * Check if the current content (what will be read next) starts with the
+        * given search term.
+        * <p>
+        * Note: the search term size <b>must</b> be smaller or equal the internal
+        * buffer size.
+        * 
+        * @param search
+        *            the term to search for
+        * 
+        * @return TRUE if the content that will be read starts with it
+        * 
+        * @throws IOException
+        *             in case of I/O error or if the size of the search term is
+        *             greater than the internal buffer
+        */
        public boolean startsWith(byte[] search) throws IOException {
                if (search.length > originalBuffer.length) {
                        throw new IOException(
@@ -133,7 +167,7 @@ public class BufferedInputStream extends InputStream {
 
                if (available() >= search.length) {
                        // Easy path
-                       return startsWith(search, buffer, pos);
+                       return startsWith(search, buffer, start, stop);
                } else if (!eof) {
                        // Harder path
                        if (buffer2 == null && buffer.length == originalBuffer.length) {
@@ -149,9 +183,7 @@ public class BufferedInputStream extends InputStream {
                                len2 += pos2;
                        }
 
-                       if (available() + (len2 - pos2) >= search.length) {
-                               return startsWith(search, buffer2, pos2);
-                       }
+                       return startsWith(search, buffer2, pos2, len2);
                }
 
                return false;
@@ -169,14 +201,11 @@ public class BufferedInputStream extends InputStream {
        /**
         * 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.
         * 
         * @return TRUE if it is
         */
        public boolean eof() {
-               return closed || (len < 0 && !hasMoreData());
+               return closed || (stop < 0 && !hasMoreData());
        }
 
        @Override
@@ -188,7 +217,7 @@ public class BufferedInputStream extends InputStream {
                        return -1;
                }
 
-               return buffer[pos++];
+               return buffer[start++];
        }
 
        @Override
@@ -212,10 +241,10 @@ public class BufferedInputStream extends InputStream {
                while (hasMoreData() && done < blen) {
                        preRead();
                        if (hasMoreData()) {
-                               int now = Math.min(blen, len) - pos;
+                               int now = Math.min(blen, stop) - start;
                                if (now > 0) {
-                                       System.arraycopy(buffer, pos, b, boff, now);
-                                       pos += now;
+                                       System.arraycopy(buffer, start, b, boff + done, now);
+                                       start += now;
                                        done += now;
                                }
                        }
@@ -235,7 +264,7 @@ public class BufferedInputStream extends InputStream {
                        preRead();
 
                        long inBuffer = Math.min(n, available());
-                       pos += inBuffer;
+                       start += inBuffer;
                        n -= inBuffer;
                        skipped += inBuffer;
                }
@@ -249,7 +278,7 @@ public class BufferedInputStream extends InputStream {
                        return 0;
                }
 
-               return Math.max(0, len - pos);
+               return Math.max(0, stop - start);
        }
 
        /**
@@ -288,6 +317,9 @@ public class BufferedInputStream extends InputStream {
         * closed when you have called {@link BufferedInputStream#close()} once more
         * than {@link BufferedInputStream#open()}.
         * 
+        * @param includingSubStream
+        *            also close the under-laying stream
+        * 
         * @exception IOException
         *                in case of I/O error
         */
@@ -316,12 +348,12 @@ public class BufferedInputStream extends InputStream {
         */
        protected boolean preRead() throws IOException {
                boolean hasRead = false;
-               if (!eof && in != null && pos >= len) {
-                       pos = 0;
+               if (!eof && in != null && start >= stop) {
+                       start = 0;
                        if (buffer2 != null) {
                                buffer = buffer2;
-                               pos = pos2;
-                               len = len2;
+                               start = pos2;
+                               stop = len2;
 
                                buffer2 = null;
                                pos2 = 0;
@@ -329,16 +361,16 @@ public class BufferedInputStream extends InputStream {
                        } else {
                                buffer = originalBuffer;
 
-                               len = read(in, buffer);
-                               if (len > 0) {
-                                       bytesRead += len;
+                               stop = read(in, buffer);
+                               if (stop > 0) {
+                                       bytesRead += stop;
                                }
                        }
 
                        hasRead = true;
                }
 
-               if (pos >= len) {
+               if (start >= stop) {
                        eof = true;
                }
 
@@ -368,7 +400,7 @@ public class BufferedInputStream extends InputStream {
         * @return TRUE if it is the case, FALSE if not
         */
        protected boolean hasMoreData() {
-               return !closed && !(eof && pos >= len);
+               return !closed && !(eof && start >= stop);
        }
 
        /**
@@ -381,12 +413,41 @@ public class BufferedInputStream extends InputStream {
        protected void checkClose() throws IOException {
                if (closed) {
                        throw new IOException(
-                                       "This NextableInputStream was closed, you cannot use it anymore.");
+                                       "This BufferedInputStream was closed, you cannot use it anymore.");
                }
        }
 
-       // buffer must be > search
-       static protected boolean startsWith(byte[] search, byte[] buffer, int offset) {
+       /**
+        * Check if the buffer starts with the given search term (given as an array,
+        * a start position and a end position).
+        * <p>
+        * Note: the parameter <tt>len</tt> is the <b>index</b> of the last
+        * position, <b>not</b> the length.
+        * <p>
+        * Note: the search term size <b>must</b> be smaller or equal the internal
+        * buffer size.
+        * 
+        * @param search
+        *            the term to search for
+        * @param buffer
+        *            the buffer to look into
+        * @param offset
+        *            the offset at which to start the search
+        * @param len
+        *            the maximum index of the data to check (this is <b>not</b> a
+        *            length, but an index)
+        * 
+        * @return TRUE if the search content is present at the given location and
+        *         does not exceed the <tt>len</tt> index
+        */
+       static protected boolean startsWith(byte[] search, byte[] buffer,
+                       int offset, int len) {
+
+               // Check if there even is enough space for it
+               if (search.length > (len - offset)) {
+                       return false;
+               }
+
                boolean same = true;
                for (int i = 0; i < search.length; i++) {
                        if (search[i] != buffer[offset + i]) {