KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > thaiopensource > validate > auto > RewindableInputStream


1 package com.thaiopensource.validate.auto;
2
3 import java.io.InputStream JavaDoc;
4 import java.io.IOException JavaDoc;
5
6 public class RewindableInputStream extends InputStream JavaDoc implements Rewindable {
7   static class Block {
8     Block next;
9     final byte[] buf;
10     int used = 0;
11     static final int MIN_SIZE = 1024;
12     Block(int minSize) {
13       buf = new byte[Math.max(MIN_SIZE, minSize)];
14     }
15
16     Block() {
17       this(0);
18     }
19
20     void append(byte b) {
21       buf[used++] = b;
22     }
23
24     void append(byte[] b, int off, int len) {
25       System.arraycopy(b, off, buf, used, len);
26       used += len;
27     }
28   }
29
30   private Block head;
31   /**
32    * If curBlockAvail > 0, then there are curBlockAvail bytes available to be
33    * returned starting at curBlockPos in curBlock.buf.
34    */

35   private int curBlockAvail;
36   private Block curBlock;
37   private int curBlockPos;
38   private Block lastBlock;
39   /**
40    * true unless willNotRewind has been called
41    */

42   private boolean saving = true;
43   private final InputStream JavaDoc in;
44   private boolean pretendClosed = false;
45   /**
46    * true if we have got an EOF from the underlying InputStream
47    */

48   private boolean eof;
49
50   public RewindableInputStream(InputStream JavaDoc in) {
51     if (in == null)
52       throw new NullPointerException JavaDoc();
53     this.in = in;
54   }
55
56   public void close() throws IOException JavaDoc {
57     if (saving) {
58       curBlockAvail = 0;
59       curBlock = null;
60       pretendClosed = true;
61     }
62     else {
63       head = null;
64       curBlock = null;
65       lastBlock = null;
66       saving = false;
67       curBlockAvail = 0;
68       in.close();
69     }
70   }
71
72   public void rewind() {
73     if (!saving)
74       throw new IllegalStateException JavaDoc("rewind() after willNotRewind()");
75     pretendClosed = false;
76     if (head == null)
77       return;
78     curBlock = head;
79     curBlockPos = 0;
80     curBlockAvail = curBlock.used;
81   }
82
83   public boolean canRewind() {
84     return saving;
85   }
86
87   public void willNotRewind() {
88     saving = false;
89     head = null;
90     lastBlock = null;
91     if (pretendClosed) {
92       pretendClosed = false;
93       try {
94         in.close();
95       }
96       catch (IOException JavaDoc e) { }
97     }
98   }
99
100   public int read() throws IOException JavaDoc {
101     if (curBlockAvail > 0) {
102       int c = curBlock.buf[curBlockPos++] & 0xFF;
103       --curBlockAvail;
104       if (curBlockAvail == 0) {
105         curBlock = curBlock.next;
106         if (curBlock != null) {
107           curBlockPos = 0;
108           curBlockAvail = curBlock.used;
109         }
110       }
111       return c;
112     }
113     int c = in.read();
114     if (saving && c != -1) {
115       if (lastBlock == null)
116         lastBlock = head = new Block();
117       else if (lastBlock.used == lastBlock.buf.length)
118         lastBlock = lastBlock.next = new Block();
119       lastBlock.append((byte)c);
120     }
121     return c;
122   }
123
124   public int read(byte b[], int off, int len) throws IOException JavaDoc {
125     if (curBlockAvail == 0 && !saving)
126       return in.read(b, off, len);
127     if (b == null)
128       throw new NullPointerException JavaDoc();
129     if (len < 0)
130       throw new IndexOutOfBoundsException JavaDoc();
131     int nRead = 0;
132     if (curBlockAvail != 0) {
133       for (;;) {
134         if (len == 0)
135           return nRead;
136         b[off++] = curBlock.buf[curBlockPos++];
137         --len;
138         nRead++;
139         --curBlockAvail;
140         if (curBlockAvail == 0) {
141           curBlock = curBlock.next;
142           if (curBlock == null)
143             break;
144           curBlockAvail = curBlock.used;
145           curBlockPos = 0;
146         }
147       }
148     }
149     if (len == 0)
150       return nRead;
151     if (eof)
152       return nRead > 0 ? nRead : -1;
153     try {
154       int n = in.read(b, off, len);
155       if (n < 0) {
156         eof = true;
157         return nRead > 0 ? nRead : -1;
158       }
159       nRead += n;
160       if (saving) {
161         if (lastBlock == null)
162           lastBlock = head = new Block(n);
163         else if (lastBlock.buf.length - lastBlock.used < n) {
164           if (lastBlock.used != lastBlock.buf.length) {
165             int free = lastBlock.buf.length - lastBlock.used;
166             lastBlock.append(b, off, free);
167             off += free;
168             n -= free;
169           }
170           lastBlock = lastBlock.next = new Block(n);
171         }
172         lastBlock.append(b, off, n);
173       }
174     }
175     catch (IOException JavaDoc e) {
176       eof = true;
177       if (nRead == 0)
178         throw e;
179     }
180     return nRead;
181   }
182
183   public int available() throws IOException JavaDoc {
184     if (curBlockAvail == 0)
185       return in.available();
186     int n = curBlockAvail;
187     for (Block b = curBlock.next; b != null; b = b.next)
188       n += b.used;
189     return n + in.available();
190   }
191
192 }
193
Popular Tags