2003/09/30 21:30:49
[org.ibex.core.git] / src / org / xwt / util / CachedInputStream.java
diff --git a/src/org/xwt/util/CachedInputStream.java b/src/org/xwt/util/CachedInputStream.java
new file mode 100644 (file)
index 0000000..1c2cffd
--- /dev/null
@@ -0,0 +1,56 @@
+package org.xwt.util;
+import java.io.*;
+
+/**
+ *  Wraps around an InputStream, caching the stream in a byte[] as it
+ *  is read and permitting multiple simultaneous readers
+ */
+public class CachedInputStream {
+
+    boolean filling = false;               ///< true iff some thread is blocked on us waiting for input
+    boolean eof = false;                   ///< true iff end of stream has been reached
+    byte[] cache = new byte[1024 * 128];
+    int size = 0;
+    final InputStream is;
+
+    public CachedInputStream(InputStream is) { this.is = is; }
+    public InputStream getInputStream() { return new SubStream(); }
+
+    public void grow(int newLength) {
+        if (newLength < cache.length) return;
+        byte[] newCache = new byte[cache.length + 2 * (newLength - cache.length)];
+        System.arraycopy(cache, 0, newCache, 0, size);
+        cache = newCache;
+    }
+
+    synchronized void fillCache(int howMuch) throws IOException {
+        if (filling) { try { wait(); } catch (InterruptedException e) { }; return; }
+        filling = true;
+        grow(size + howMuch);
+        int ret = is.read(cache, size, howMuch);
+        if (ret == -1) eof = true;
+        else size += ret;
+        filling = false;
+        notifyAll();
+    }
+
+    private class SubStream extends InputStream {
+        int pos = 0;
+        public int available() { return Math.max(0, size - pos); }
+        public long skip(long n) throws IOException { pos += (int)n; return n; }     // FEATURE: don't skip past EOF
+        public int read() throws IOException {                                       // FEATURE: be smarter here
+            byte[] b = new byte[1];
+            int ret = read(b, 0, 1);
+            return ret == -1 ? -1 : b[0];
+        }
+        public int read(byte[] b, int off, int len) throws IOException {
+            synchronized(CachedInputStream.this) {
+                while (pos >= size && !eof) fillCache(pos + len - size);
+                if (eof && pos == size) return -1;
+                int count = Math.min(size - pos, len);
+                System.arraycopy(cache, pos, b, off, count);
+                return count;
+            }
+        }
+    }
+}