allow a digest in Stream
[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 import org.ibex.crypto.*;
8
9 /** package-private class */
10 abstract class ByteBufInputStream extends InputStream {
11
12     private InputStream is;
13     public  Stream next = null;
14     private byte[] buf = new byte[8192];
15     private int start = 0;
16     private int end = 0;
17     public  Digest digest = null;
18     
19     public ByteBufInputStream(InputStream is) {
20         this.is = is;
21     }
22
23     public void appendStream(Stream next) {
24         if (this.next == null) this.next = next;
25         else this.next.appendStream(next);
26     }
27     private int bufSize() { if (end==start) { end = start = 0; } return end-start; }
28     private int fillBufIfEmpty() {
29         try {
30             if (bufSize() > 0) return bufSize();
31             if (is == null) return -1;
32             if (prereading) return -1;
33             start = 0;
34             do {
35                 end = is.read(buf, 0, buf.length);
36                 if (end == -1) {
37                     is.close();
38                     is = null;
39                     if (next != null) {
40                         // FIXME: append to a stream that has already run out?
41                         is = next.getInputStream();
42                         next = null;
43                         start = end = 0;
44                         continue;
45                     }
46                 } else {
47                     if (digest != null) digest.update(buf, 0, end);
48                 }
49             } while(end==0);
50             if (end == -1) { end = 0; return -1; }
51             return end;
52         } catch (IOException e) { Stream.ioe(e); return -1; }
53     }
54
55     public int available() { return end-start; }
56     public void close() {
57         try {
58             if (is != null) is.close();
59             if (next != null) next.close();
60         } catch (IOException e) { Stream.ioe(e); }
61     }
62
63     private boolean prereading = false;
64     public abstract void preread();
65     public int read() { byte[] b = new byte[0]; if (read(b, 0, 1)<=0) return -1; return b[0] & 0xff; }
66     public int read(byte[] c, int pos, int len) {
67         if (prereading) return -1;
68         prereading = true;
69         try {
70             preread();
71         } finally { prereading = false; }
72         if (fillBufIfEmpty() == -1) return -1;
73         if (len > end - start) len = end - start;
74         System.arraycopy(buf, start, c, pos, len);
75         start += len;
76         return len;
77     }
78
79     public void pushback(byte[] b, int off, int len) {
80         if (len <= 0) return;
81         if (start-len < 0) {
82             /* FIXME, this allocates too often */
83             byte[] newbuf = new byte[len+(end-start)];
84             System.arraycopy(buf, start, newbuf, len, (end-start));
85             buf = newbuf;
86             end = len + (end-start);
87             start = len;
88         }
89         System.arraycopy(b, off, buf, start-len, len);
90         start -= len;
91     }
92 }