1 4 package com.tc.io; 5 6 import com.tc.bytes.TCByteBuffer; 7 8 import java.io.DataInputStream ; 9 import java.io.EOFException ; 10 import java.io.IOException ; 11 import java.io.InputStream ; 12 import java.util.ArrayList ; 13 import java.util.List ; 14 15 public class TCByteBufferInputStream extends InputStream 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 (); } 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 ("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 ("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 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 83 public TCByteBufferInputStream duplicate() { 84 checkClosed(); 85 return new TCByteBufferInputStream(data, available(), index); 86 } 87 88 92 public TCByteBufferInputStream duplicateAndLimit(final int limit) { 93 checkClosed(); 94 95 if (limit > available()) { throw new IllegalArgumentException ("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 142 public TCDataInput limit(int limit) { 143 checkClosed(); 144 145 if (available() < limit) { throw new IllegalArgumentException ("Not enough data left in stream: " + limit + " > " 146 + available()); } 147 148 List newData = new ArrayList (); 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 (); 188 } 189 190 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 (); } 206 if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException (); } 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 (); 257 } 258 259 265 public void tcReset() { 266 checkClosed(); 267 if (mark == null) { throw new IllegalStateException ("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 ("skip value too large: " + skip); } 285 286 if ((skip <= 0) || (available() == 0)) { return 0; } 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 ("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 { 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 (); 342 return ((byte1 << 24) + (byte2 << 16) + (byte3 << 8) + (byte4 << 0)); 343 } 344 345 public final byte readByte() throws IOException { 346 int b = read(); 347 if (b < 0) throw new EOFException (); 348 return (byte) (b); 349 } 350 351 public final boolean readBoolean() throws IOException { 352 int b = read(); 353 if (b < 0) throw new EOFException (); 354 return (b != 0); 355 } 356 357 public final char readChar() throws IOException { 358 int byte1 = read(); 359 int byte2 = read(); 360 if ((byte1 | byte2) < 0) throw new EOFException (); 361 return (char) ((byte1 << 8) + (byte2 << 0)); 362 } 363 364 public final double readDouble() throws IOException { 365 return Double.longBitsToDouble(readLong()); 366 } 367 368 public final long readLong() throws IOException { 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 (); 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 { 386 return Float.intBitsToFloat(readInt()); 387 } 388 389 public final short readShort() throws IOException { 390 int byte1 = read(); 391 int byte2 = read(); 392 if ((byte1 | byte2) < 0) throw new EOFException (); 393 return (short) ((byte1 << 8) + (byte2 << 0)); 394 } 395 396 public final String readString() throws IOException { 397 boolean isNull = readBoolean(); 398 if (isNull) { return null; } 399 400 int utf = read(); 401 if (utf < 0) { throw new EOFException (); } 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 ("utf = " + utf); 412 } 413 414 } 416 417 private String readStringFromChars() throws IOException { 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 (chars); 424 } 425 426 public final void readFully(byte[] b) throws IOException { 427 readFully(b, 0, b.length); 428 } 429 430 public final void readFully(byte[] b, int off, int len) throws IOException { 431 if (len < 0) throw new IndexOutOfBoundsException (); 432 int n = 0; 433 while (n < len) { 434 int count = read(b, off + n, len - n); 435 if (count < 0) throw new EOFException (); 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 { 445 int b = read(); 446 if (b < 0) throw new EOFException (); 447 return b; 448 } 449 450 public final int readUnsignedShort() throws IOException { 451 int byte1 = read(); 452 int byte2 = read(); 453 if ((byte1 | byte2) < 0) throw new EOFException (); 454 return (byte1 << 8) + (byte2 << 0); 455 } 456 457 public final String readLine() { 458 throw new UnsupportedOperationException (); 460 } 461 462 public final String readUTF() { 463 throw new UnsupportedOperationException (); 465 } 466 467 } | Popular Tags |