massive bugfixes in stream library
[org.ibex.io.git] / src / org / ibex / io / ByteBufInputStream.java
1 // Copyright 2000-2007 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.io;
6 import java.io.*;
7
8 /** package-private class */
9 abstract class ByteBufInputStream extends InputStream {
10
11     private InputStream is;
12     public  Stream next = null;
13     private byte[] buf = new byte[8192];
14     private int start = 0;
15     private int end = 0;
16     
17     public ByteBufInputStream(InputStream is) {
18         this.is = is;
19     }
20
21     public void appendStream(Stream next) {
22         if (this.next == null) this.next = next;
23         else this.next.appendStream(next);
24     }
25     private int bufSize() { if (end==start) { end = start = 0; } return end-start; }
26     private int fillBufIfEmpty() {
27         try {
28             if (bufSize() > 0) return bufSize();
29             if (is == null) return -1;
30             if (prereading) return -1;
31             start = 0;
32             do {
33                 end = is.read(buf, 0, buf.length);
34                 if (end == -1) {
35                     is.close();
36                     is = null;
37                     if (next != null) {
38                         // FIXME: append to a stream that has already run out?
39                         is = next.getInputStream();
40                         next = null;
41                         start = end = 0;
42                         continue;
43                     }
44                 }
45             } while(end==0);
46             if (end == -1) { end = 0; return -1; }
47             return end;
48         } catch (IOException e) { Stream.ioe(e); return -1; }
49     }
50
51     public int available() { return end-start; }
52     public void close() {
53         try {
54             if (is != null) is.close();
55             if (next != null) next.close();
56         } catch (IOException e) { Stream.ioe(e); }
57     }
58
59     private boolean prereading = false;
60     public abstract void preread();
61     public int read() { byte[] b = new byte[0]; if (read(b, 0, 1)<=0) return -1; return b[0] & 0xff; }
62     public int read(byte[] c, int pos, int len) {
63         if (prereading) return -1;
64         prereading = true;
65         try {
66             preread();
67         } finally { prereading = false; }
68         if (fillBufIfEmpty() == -1) return -1;
69         if (len > end - start) len = end - start;
70         System.arraycopy(buf, start, c, pos, len);
71         start += len;
72         return len;
73     }
74
75     public void pushback(byte[] b, int off, int len) {
76         if (len <= 0) return;
77         if (start-len < 0) {
78             /* FIXME, this allocates too often */
79             byte[] newbuf = new byte[len+(end-start)];
80             System.arraycopy(buf, start, newbuf, len, (end-start));
81             buf = newbuf;
82             end = len + (end-start);
83             start = len;
84         }
85         System.arraycopy(b, off, buf, start-len, len);
86         start -= len;
87     }
88 }