2003/09/30 21:30:49
[org.ibex.core.git] / src / org / xwt / util / CachedInputStream.java
1 package org.xwt.util;
2 import java.io.*;
3
4 /**
5  *  Wraps around an InputStream, caching the stream in a byte[] as it
6  *  is read and permitting multiple simultaneous readers
7  */
8 public class CachedInputStream {
9
10     boolean filling = false;               ///< true iff some thread is blocked on us waiting for input
11     boolean eof = false;                   ///< true iff end of stream has been reached
12     byte[] cache = new byte[1024 * 128];
13     int size = 0;
14     final InputStream is;
15
16     public CachedInputStream(InputStream is) { this.is = is; }
17     public InputStream getInputStream() { return new SubStream(); }
18
19     public void grow(int newLength) {
20         if (newLength < cache.length) return;
21         byte[] newCache = new byte[cache.length + 2 * (newLength - cache.length)];
22         System.arraycopy(cache, 0, newCache, 0, size);
23         cache = newCache;
24     }
25
26     synchronized void fillCache(int howMuch) throws IOException {
27         if (filling) { try { wait(); } catch (InterruptedException e) { }; return; }
28         filling = true;
29         grow(size + howMuch);
30         int ret = is.read(cache, size, howMuch);
31         if (ret == -1) eof = true;
32         else size += ret;
33         filling = false;
34         notifyAll();
35     }
36
37     private class SubStream extends InputStream {
38         int pos = 0;
39         public int available() { return Math.max(0, size - pos); }
40         public long skip(long n) throws IOException { pos += (int)n; return n; }     // FEATURE: don't skip past EOF
41         public int read() throws IOException {                                       // FEATURE: be smarter here
42             byte[] b = new byte[1];
43             int ret = read(b, 0, 1);
44             return ret == -1 ? -1 : b[0];
45         }
46         public int read(byte[] b, int off, int len) throws IOException {
47             synchronized(CachedInputStream.this) {
48                 while (pos >= size && !eof) fillCache(pos + len - size);
49                 if (eof && pos == size) return -1;
50                 int count = Math.min(size - pos, len);
51                 System.arraycopy(cache, pos, b, off, count);
52                 return count;
53             }
54         }
55     }
56 }