KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > io > TCByteBufferInputStream


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.io;
5
6 import com.tc.bytes.TCByteBuffer;
7
8 import java.io.DataInputStream JavaDoc;
9 import java.io.EOFException JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.io.InputStream JavaDoc;
12 import java.util.ArrayList JavaDoc;
13 import java.util.List JavaDoc;
14
15 public class TCByteBufferInputStream extends InputStream JavaDoc implements TCDataInput {
16   private static final int EOF = -1;
17   private static final TCByteBuffer[] EMPTY_BYTE_BUFFER_ARRAY = new TCByteBuffer[] {};
18
19   private TCByteBuffer[] data;
20   private int totalLength;
21   private int numBufs;
22   private boolean closed = false;
23   private int position = 0;
24   private int index = 0;
25   private Mark mark = null;
26
27   private TCByteBufferInputStream(TCByteBuffer[] sourceData, int dupeLength, int sourceIndex) {
28     this(sourceData, dupeLength, sourceIndex, true);
29   }
30
31   public TCByteBufferInputStream(TCByteBuffer data) {
32     this(new TCByteBuffer[] { data });
33   }
34
35   public TCByteBufferInputStream(TCByteBuffer[] data) {
36     if (data == null) { throw new NullPointerException JavaDoc(); }
37
38     long length = 0;
39
40     this.data = new TCByteBuffer[data.length];
41
42     for (int i = 0, n = data.length; i < n; i++) {
43       TCByteBuffer buf = data[i];
44       if (buf == null) { throw new NullPointerException JavaDoc("null buffer at index " + i); }
45
46       this.data[i] = buf.duplicate().rewind();
47       length += buf.limit();
48     }
49
50     if (length > Integer.MAX_VALUE) { throw new IllegalArgumentException JavaDoc("too much data: " + length); }
51
52     this.numBufs = this.data.length;
53     this.totalLength = (int) length;
54   }
55
56   private TCByteBufferInputStream(TCByteBuffer[] sourceData, int dupeLength, int sourceIndex, boolean duplicate) {
57     // skipping checks. Invariants should hold since this is a private cstr()
58

59     if (duplicate) {
60       this.data = new TCByteBuffer[sourceData.length - sourceIndex];
61     } else {
62       this.data = sourceData;
63     }
64
65     this.numBufs = this.data.length;
66
67     if (duplicate) {
68       for (int i = 0, n = this.data.length; i < n; i++) {
69         this.data[i] = sourceData[sourceIndex + i].duplicate();
70       }
71     }
72
73     this.totalLength = dupeLength;
74     this.position = 0;
75     this.index = 0;
76   }
77
78   /**
79    * Duplicate this stream. The resulting stream will share data with the source stream (ie. no copying), but the two
80    * streams will have independent read positions. The read position of the result stream will initially be the same as
81    * the source stream
82    */

83   public TCByteBufferInputStream duplicate() {
84     checkClosed();
85     return new TCByteBufferInputStream(data, available(), index);
86   }
87
88   /**
89    * Effectively the same thing as calling duplicate().limit(int), but potentially creating far less garbage (depending
90    * on the size difference between the original stream and the slice you want)
91    */

92   public TCByteBufferInputStream duplicateAndLimit(final int limit) {
93     checkClosed();
94
95     if (limit > available()) { throw new IllegalArgumentException JavaDoc("Not enough data left in stream: " + limit + " > "
96                                                                   + available()); }
97
98     if (limit == 0) { return new TCByteBufferInputStream(EMPTY_BYTE_BUFFER_ARRAY); }
99
100     int numBytesNeeded = limit;
101     int dataIndex = this.index;
102     int lastLimit = -1;
103     while (numBytesNeeded > 0) {
104       TCByteBuffer buf = this.data[dataIndex];
105       int numFromThisBuffer = Math.min(numBytesNeeded, buf.remaining());
106       lastLimit = buf.position() + numFromThisBuffer;
107       numBytesNeeded -= numFromThisBuffer;
108       if (numBytesNeeded > 0) {
109         dataIndex++;
110       }
111     }
112
113     int size = (dataIndex - this.index) + 1;
114     TCByteBuffer[] limitedData = new TCByteBuffer[size];
115     for (int i = 0, n = limitedData.length; i < n; i++) {
116       limitedData[i] = this.data[this.index + i].duplicate();
117     }
118
119     limitedData[limitedData.length - 1].limit(lastLimit);
120
121     return new TCByteBufferInputStream(limitedData, limit, 0, false);
122   }
123
124   public TCByteBuffer[] toArray() {
125     checkClosed();
126
127     if (available() == 0) { return EMPTY_BYTE_BUFFER_ARRAY; }
128
129     TCByteBuffer[] rv = new TCByteBuffer[numBufs - index];
130     rv[0] = data[index].slice();
131     for (int i = 1, n = rv.length; i < n; i++) {
132       rv[i] = data[index + i].duplicate();
133     }
134
135     return rv;
136   }
137
138   /**
139    * Artificially limit the length of this input stream starting at the current read position. This operation is
140    * destructive to the stream contents (ie. data trimmed off by setting limit can never be read with this stream).
141    */

142   public TCDataInput limit(int limit) {
143     checkClosed();
144
145     if (available() < limit) { throw new IllegalArgumentException JavaDoc("Not enough data left in stream: " + limit + " > "
146                                                                   + available()); }
147
148     List JavaDoc newData = new ArrayList JavaDoc();
149     int num = limit;
150     while (num > 0) {
151       TCByteBuffer current = data[index];
152       int avail = current.remaining();
153       int take = Math.min(avail, num);
154       if (take > 0) {
155         newData.add(current.slice().limit(take));
156         num -= take;
157       }
158       nextBuffer();
159     }
160
161     this.data = new TCByteBuffer[newData.size()];
162     this.data = (TCByteBuffer[]) newData.toArray(this.data);
163     this.numBufs = this.data.length;
164     this.totalLength = limit;
165     this.position = 0;
166     this.index = 0;
167
168     return this;
169   }
170
171   public int getTotalLength() {
172     return totalLength;
173   }
174
175   public int available() {
176     return totalLength - position;
177   }
178
179   public void close() {
180     if (!closed) {
181       closed = true;
182       this.data = null;
183     }
184   }
185
186   public void mark(int readlimit) {
187     throw new UnsupportedOperationException JavaDoc();
188   }
189
190   // XXX: This is a TC special version of mark() to be used in conjunction with tcReset()...We should eventually
191
// implement the general purpose mark(int) method as specified by InputStream. NOTE: It has some unusual semantics
192
// that make it a little trickier to implement (in our case) than you might think (specifially the readLimit field)
193
public void mark() {
194     checkClosed();
195     mark = new Mark(index, data[index].position(), position);
196   }
197
198   public boolean markSupported() {
199     return false;
200   }
201
202   public final int read(byte[] b, int off, int len) {
203     checkClosed();
204
205     if (b == null) { throw new NullPointerException JavaDoc(); }
206     if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException JavaDoc(); }
207     if (len == 0) { return 0; }
208
209     if (available() == 0) { return EOF; }
210
211     int bytesRead = 0;
212     int numToRead = Math.min(available(), len);
213
214     while (index < numBufs) {
215       TCByteBuffer buf = data[index];
216       if (buf.hasRemaining()) {
217         int read = Math.min(buf.remaining(), numToRead);
218         buf.get(b, off, read);
219         off += read;
220         position += read;
221         bytesRead += read;
222         numToRead -= read;
223         if (numToRead == 0) break;
224       }
225       nextBuffer();
226     }
227
228     return bytesRead;
229   }
230
231   public final int read(byte[] b) {
232     return read(b, 0, b.length);
233   }
234
235   public final int read() {
236     checkClosed();
237
238     while (index < numBufs) {
239       if (this.data[index].hasRemaining()) {
240         position++;
241         return this.data[index].get() & 0xFF;
242       }
243       nextBuffer();
244     }
245     return EOF;
246   }
247
248   private void nextBuffer() {
249     if (mark == null) {
250       this.data[index] = null;
251     }
252     index++;
253   }
254
255   public void reset() {
256     throw new UnsupportedOperationException JavaDoc();
257   }
258
259   /**
260    * Reset this input stream to the position recorded by the last call to mark(). This method discards the previous
261    * value of the mark
262    *
263    * @throws IOException if mark() has never been called on this stream
264    */

265   public void tcReset() {
266     checkClosed();
267     if (mark == null) { throw new IllegalStateException JavaDoc("no mark set"); }
268
269     int rewindToIndex = mark.getBufferIndex();
270     while (index > rewindToIndex) {
271       data[index].position(0);
272       index--;
273     }
274
275     index = rewindToIndex;
276     data[rewindToIndex].position(mark.getBufferPosition());
277     position = mark.getStreamPosition();
278     mark = null;
279   }
280
281   public long skip(long skip) {
282     checkClosed();
283
284     if (skip > Integer.MAX_VALUE) { throw new IllegalArgumentException JavaDoc("skip value too large: " + skip); }
285
286     if ((skip <= 0) || (available() == 0)) { return 0; } // per java.io.InputStream.skip() javadoc
287

288     int numToSkip = Math.min(available(), (int) skip);
289
290     int bytesSkipped = 0;
291     while (index < numBufs) {
292       TCByteBuffer buf = data[index];
293       int remaining = buf.remaining();
294       if (remaining > 0) {
295         int numToRead = Math.min(remaining, numToSkip);
296         buf.position(buf.position() + numToRead);
297         position += numToRead;
298         bytesSkipped += numToRead;
299         numToSkip -= numToRead;
300         if (numToSkip == 0) break;
301       }
302       nextBuffer();
303     }
304
305     return bytesSkipped;
306   }
307
308   private void checkClosed() {
309     if (closed) { throw new IllegalStateException JavaDoc("stream is closed"); }
310   }
311
312   private static class Mark {
313     private final int position;
314     private final int bufferIndex;
315     private final int streamPosition;
316
317     Mark(int bufferIndex, int bufferPosition, int streamPosition) {
318       this.bufferIndex = bufferIndex;
319       this.position = bufferPosition;
320       this.streamPosition = streamPosition;
321     }
322
323     int getBufferIndex() {
324       return bufferIndex;
325     }
326
327     int getBufferPosition() {
328       return position;
329     }
330
331     int getStreamPosition() {
332       return streamPosition;
333     }
334   }
335
336   public final int readInt() throws IOException JavaDoc {
337     int byte1 = read();
338     int byte2 = read();
339     int byte3 = read();
340     int byte4 = read();
341     if ((byte1 | byte2 | byte3 | byte4) < 0) throw new EOFException JavaDoc();
342     return ((byte1 << 24) + (byte2 << 16) + (byte3 << 8) + (byte4 << 0));
343   }
344
345   public final byte readByte() throws IOException JavaDoc {
346     int b = read();
347     if (b < 0) throw new EOFException JavaDoc();
348     return (byte) (b);
349   }
350
351   public final boolean readBoolean() throws IOException JavaDoc {
352     int b = read();
353     if (b < 0) throw new EOFException JavaDoc();
354     return (b != 0);
355   }
356
357   public final char readChar() throws IOException JavaDoc {
358     int byte1 = read();
359     int byte2 = read();
360     if ((byte1 | byte2) < 0) throw new EOFException JavaDoc();
361     return (char) ((byte1 << 8) + (byte2 << 0));
362   }
363
364   public final double readDouble() throws IOException JavaDoc {
365     return Double.longBitsToDouble(readLong());
366   }
367
368   public final long readLong() throws IOException JavaDoc {
369     int byte1 = read();
370     int byte2 = read();
371     int byte3 = read();
372     int byte4 = read();
373     int byte5 = read();
374     int byte6 = read();
375     int byte7 = read();
376     int byte8 = read();
377
378     if ((byte1 | byte2 | byte3 | byte4 | byte5 | byte6 | byte7 | byte8) < 0) throw new EOFException JavaDoc();
379
380     return (((long) byte1 << 56) + ((long) (byte2 & 255) << 48) + ((long) (byte3 & 255) << 40)
381             + ((long) (byte4 & 255) << 32) + ((long) (byte5 & 255) << 24) + ((byte6 & 255) << 16)
382             + ((byte7 & 255) << 8) + ((byte8 & 255) << 0));
383   }
384
385   public final float readFloat() throws IOException JavaDoc {
386     return Float.intBitsToFloat(readInt());
387   }
388
389   public final short readShort() throws IOException JavaDoc {
390     int byte1 = read();
391     int byte2 = read();
392     if ((byte1 | byte2) < 0) throw new EOFException JavaDoc();
393     return (short) ((byte1 << 8) + (byte2 << 0));
394   }
395
396   public final String JavaDoc readString() throws IOException JavaDoc {
397     boolean isNull = readBoolean();
398     if (isNull) { return null; }
399
400     int utf = read();
401     if (utf < 0) { throw new EOFException JavaDoc(); }
402
403     switch (utf) {
404       case 0: {
405         return readStringFromChars();
406       }
407       case 1: {
408         return DataInputStream.readUTF(this);
409       }
410       default:
411         throw new AssertionError JavaDoc("utf = " + utf);
412     }
413
414     // unreachable
415
}
416
417   private String JavaDoc readStringFromChars() throws IOException JavaDoc {
418     int len = readInt();
419     char[] chars = new char[len];
420     for (int i = 0, n = chars.length; i < n; i++) {
421       chars[i] = readChar();
422     }
423     return new String JavaDoc(chars);
424   }
425
426   public final void readFully(byte[] b) throws IOException JavaDoc {
427     readFully(b, 0, b.length);
428   }
429
430   public final void readFully(byte[] b, int off, int len) throws IOException JavaDoc {
431     if (len < 0) throw new IndexOutOfBoundsException JavaDoc();
432     int n = 0;
433     while (n < len) {
434       int count = read(b, off + n, len - n);
435       if (count < 0) throw new EOFException JavaDoc();
436       n += count;
437     }
438   }
439
440   public final int skipBytes(int n) {
441     return (int) skip(n);
442   }
443
444   public final int readUnsignedByte() throws IOException JavaDoc {
445     int b = read();
446     if (b < 0) throw new EOFException JavaDoc();
447     return b;
448   }
449
450   public final int readUnsignedShort() throws IOException JavaDoc {
451     int byte1 = read();
452     int byte2 = read();
453     if ((byte1 | byte2) < 0) throw new EOFException JavaDoc();
454     return (byte1 << 8) + (byte2 << 0);
455   }
456
457   public final String JavaDoc readLine() {
458     // Don't implement this method
459
throw new UnsupportedOperationException JavaDoc();
460   }
461
462   public final String JavaDoc readUTF() {
463     // Don't implement this method --> use readString() instead
464
throw new UnsupportedOperationException JavaDoc();
465   }
466
467 }
Popular Tags