fix "limit" and "skip" logic in io (still not very good, though)
[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 int limit = -1;
18     public  Digest digest = null;
19     
20     public ByteBufInputStream(InputStream is) {
21         this.is = is;
22     }
23
24     public void appendStream(Stream next) {
25         if (this.next == null) this.next = next;
26         else this.next.appendStream(next);
27     }
28     public void setLimit(int limit) { this.limit = limit; }
29     private int bufSize() { if (end==start) { end = start = 0; } return end-start; }
30     private int fillBufIfEmpty() {
31         try {
32             if (bufSize() > 0) return bufSize();
33             if (is == null) return -1;
34             if (prereading) return -1;
35             start = 0;
36             do {
37                 if      (limit == 0)  end = -1;
38                 else if (limit == -1) end = is.read(buf, 0, buf.length);
39                 else                  end = is.read(buf, 0, Math.min(buf.length, limit));
40                 if (end == -1) {
41                     is.close();
42                     is = null;
43                     if (next != null) {
44                         // FIXME: append to a stream that has already run out?
45                         is = next.getInputStream();
46                         next = null;
47                         start = end = 0;
48                         continue;
49                     }
50                 } else {
51                     if (limit >= 0) limit = Math.max(0, limit-end);
52                     if (digest != null) digest.update(buf, 0, end);
53                 }
54             } while(end==0);
55             if (end == -1) { end = 0; return -1; }
56             return end;
57         } catch (IOException e) { Stream.ioe(e); return -1; }
58     }
59
60     public int available() { return end-start; }
61     public void close() {
62         try {
63             if (is != null) is.close();
64             if (next != null) next.close();
65         } catch (IOException e) { Stream.ioe(e); }
66     }
67
68     private boolean prereading = false;
69     public abstract void preread();
70     public int read() { byte[] b = new byte[0]; if (read(b, 0, 1)<=0) return -1; return b[0] & 0xff; }
71     public int skip(int len) {
72         // FIXME ugly
73         return read(null, 0, len);
74     }
75     public int read(byte[] c, int pos, int len) {
76         if (prereading) return -1;
77         prereading = true;
78         try {
79             preread();
80         } finally { prereading = false; }
81         if (fillBufIfEmpty() == -1) return -1;
82         if (len > end - start) len = end - start;
83         if (c!=null) System.arraycopy(buf, start, c, pos, len);
84         start += len;
85         return len;
86     }
87
88     public void pushback(byte[] b, int off, int len) {
89         if (len <= 0) return;
90         if (start-len < 0) {
91             /* FIXME, this allocates too often */
92             byte[] newbuf = new byte[len+(end-start)];
93             System.arraycopy(buf, start, newbuf, len, (end-start));
94             buf = newbuf;
95             end = len + (end-start);
96             start = len;
97         }
98         System.arraycopy(b, off, buf, start-len, len);
99         start -= len;
100     }
101 }