|
19 | 19 |
|
20 | 20 | import java.io.*;
|
21 | 21 |
|
22 |
| -import org.bson.io.BSONInput; |
23 | 22 | import org.bson.io.PoolOutputBuffer;
|
24 | 23 | import org.bson.types.ObjectId;
|
25 | 24 |
|
@@ -283,7 +282,245 @@ Object _readBasicObject()
|
283 | 282 | }
|
284 | 283 |
|
285 | 284 |
|
| 285 | + |
| 286 | + protected class BSONInput { |
| 287 | + |
| 288 | + public BSONInput(InputStream in){ |
| 289 | + _raw = in; |
| 290 | + _read = 0; |
| 291 | + |
| 292 | + _pos = 0; |
| 293 | + _len = 0; |
| 294 | + } |
| 295 | + |
| 296 | + /** |
| 297 | + * ensure that there are num bytes to read |
| 298 | + * _pos is where to start reading from |
| 299 | + * @return where to start reading from |
| 300 | + */ |
| 301 | + protected int _need( final int num ) |
| 302 | + throws IOException { |
| 303 | + |
| 304 | + //System.out.println( "p: " + _pos + " l: " + _len + " want: " + num ); |
| 305 | + |
| 306 | + if ( _len - _pos >= num ){ |
| 307 | + final int ret = _pos; |
| 308 | + _pos += num; |
| 309 | + _read += num; |
| 310 | + return ret; |
| 311 | + } |
| 312 | + |
| 313 | + if ( num >= _inputBuffer.length ) |
| 314 | + throw new IllegalArgumentException( "you can't need that much" ); |
| 315 | + |
| 316 | + final int remaining = _len - _pos; |
| 317 | + if ( _pos > 0 ){ |
| 318 | + System.arraycopy( _inputBuffer , _pos , _inputBuffer , 0 , remaining ); |
| 319 | + |
| 320 | + _pos = 0; |
| 321 | + _len = remaining; |
| 322 | + } |
| 323 | + |
| 324 | + // read as much as possible into buffer |
| 325 | + int maxToRead = Math.min( _max - _read - remaining , _inputBuffer.length - _len ); |
| 326 | + while ( maxToRead > 0 ){ |
| 327 | + int x = _raw.read( _inputBuffer , _len , maxToRead); |
| 328 | + if ( x <= 0 ) |
| 329 | + throw new IOException( "unexpected EOF" ); |
| 330 | + maxToRead -= x; |
| 331 | + _len += x; |
| 332 | + } |
| 333 | + |
| 334 | + int ret = _pos; |
| 335 | + _pos += num; |
| 336 | + _read += num; |
| 337 | + return ret; |
| 338 | + } |
| 339 | + |
| 340 | + public int readInt() |
| 341 | + throws IOException { |
| 342 | + return org.bson.io.Bits.readInt( _inputBuffer , _need(4) ); |
| 343 | + } |
| 344 | + |
| 345 | + public int readIntBE() |
| 346 | + throws IOException { |
| 347 | + return org.bson.io.Bits.readIntBE( _inputBuffer , _need(4) ); |
| 348 | + } |
| 349 | + |
| 350 | + public long readLong() |
| 351 | + throws IOException { |
| 352 | + return org.bson.io.Bits.readLong( _inputBuffer , _need(8) ); |
| 353 | + } |
| 354 | + |
| 355 | + public double readDouble() |
| 356 | + throws IOException { |
| 357 | + return Double.longBitsToDouble( readLong() ); |
| 358 | + } |
| 359 | + |
| 360 | + public byte read() |
| 361 | + throws IOException { |
| 362 | + if ( _pos < _len ){ |
| 363 | + ++_read; |
| 364 | + return _inputBuffer[_pos++]; |
| 365 | + } |
| 366 | + return _inputBuffer[_need(1)]; |
| 367 | + } |
| 368 | + |
| 369 | + public void fill( byte b[] ) |
| 370 | + throws IOException { |
| 371 | + fill( b , b.length ); |
| 372 | + } |
| 373 | + |
| 374 | + public void fill( byte b[] , int len ) |
| 375 | + throws IOException { |
| 376 | + // first use what we have |
| 377 | + int have = _len - _pos; |
| 378 | + int tocopy = Math.min( len , have ); |
| 379 | + System.arraycopy( _inputBuffer , _pos , b , 0 , tocopy ); |
| 380 | + |
| 381 | + _pos += tocopy; |
| 382 | + _read += tocopy; |
| 383 | + |
| 384 | + len -= tocopy; |
| 385 | + |
| 386 | + int off = tocopy; |
| 387 | + while ( len > 0 ){ |
| 388 | + int x = _raw.read( b , off , len ); |
| 389 | + if (x <= 0) |
| 390 | + throw new IOException( "unexpected EOF" ); |
| 391 | + _read += x; |
| 392 | + off += x; |
| 393 | + len -= x; |
| 394 | + } |
| 395 | + } |
| 396 | + |
| 397 | + protected boolean _isAscii( byte b ){ |
| 398 | + return b >=0 && b <= 127; |
| 399 | + } |
| 400 | + |
| 401 | + public String readCStr() |
| 402 | + throws IOException { |
| 403 | + |
| 404 | + boolean isAscii = true; |
| 405 | + |
| 406 | + // short circuit 1 byte strings |
| 407 | + _random[0] = read(); |
| 408 | + if (_random[0] == 0) { |
| 409 | + return ""; |
| 410 | + } |
| 411 | + |
| 412 | + _random[1] = read(); |
| 413 | + if (_random[1] == 0) { |
| 414 | + String out = ONE_BYTE_STRINGS[_random[0]]; |
| 415 | + if (out != null) { |
| 416 | + return out; |
| 417 | + } |
| 418 | + return new String(_random, 0, 1, "UTF-8"); |
| 419 | + } |
| 420 | + |
| 421 | + _stringBuffer.reset(); |
| 422 | + _stringBuffer.write(_random[0]); |
| 423 | + _stringBuffer.write(_random[1]); |
| 424 | + |
| 425 | + isAscii = _isAscii(_random[0]) && _isAscii(_random[1]); |
| 426 | + |
| 427 | + while ( true ){ |
| 428 | + byte b = read(); |
| 429 | + if ( b == 0 ) |
| 430 | + break; |
| 431 | + _stringBuffer.write( b ); |
| 432 | + isAscii = isAscii && _isAscii( b ); |
| 433 | + } |
| 434 | + |
| 435 | + String out = null; |
| 436 | + if ( isAscii ){ |
| 437 | + out = _stringBuffer.asAscii(); |
| 438 | + } |
| 439 | + else { |
| 440 | + try { |
| 441 | + out = _stringBuffer.asString( "UTF-8" ); |
| 442 | + } |
| 443 | + catch ( UnsupportedOperationException e ){ |
| 444 | + throw new BSONException( "impossible" , e ); |
| 445 | + } |
| 446 | + } |
| 447 | + _stringBuffer.reset(); |
| 448 | + return out; |
| 449 | + } |
| 450 | + |
| 451 | + public String readUTF8String() |
| 452 | + throws IOException { |
| 453 | + int size = readInt(); |
| 454 | + // this is just protection in case it's corrupted, to avoid huge strings |
| 455 | + if ( size <= 0 || size > ( 32 * 1024 * 1024 ) ) |
| 456 | + throw new BSONException( "bad string size: " + size ); |
| 457 | + |
| 458 | + if ( size < _inputBuffer.length / 2 ){ |
| 459 | + if ( size == 1 ){ |
| 460 | + read(); |
| 461 | + return ""; |
| 462 | + } |
| 463 | + |
| 464 | + return new String( _inputBuffer , _need(size) , size - 1 , "UTF-8" ); |
| 465 | + } |
| 466 | + |
| 467 | + byte[] b = size < _random.length ? _random : new byte[size]; |
| 468 | + |
| 469 | + fill( b , size ); |
| 470 | + |
| 471 | + try { |
| 472 | + return new String( b , 0 , size - 1 , "UTF-8" ); |
| 473 | + } |
| 474 | + catch ( java.io.UnsupportedEncodingException uee ){ |
| 475 | + throw new BSONException( "impossible" , uee ); |
| 476 | + } |
| 477 | + } |
| 478 | + |
| 479 | + public int numRead() { |
| 480 | + return _read; |
| 481 | + } |
| 482 | + |
| 483 | + public int getPos() { |
| 484 | + return _pos; |
| 485 | + } |
| 486 | + |
| 487 | + public int getMax() { |
| 488 | + return _max; |
| 489 | + } |
| 490 | + |
| 491 | + public void setMax(int _max) { |
| 492 | + this._max = _max; |
| 493 | + } |
| 494 | + |
| 495 | + int _read; |
| 496 | + final InputStream _raw; |
| 497 | + |
| 498 | + int _max = 4; // max number of total bytes allowed to ready |
| 499 | + |
| 500 | + } |
286 | 501 | protected BSONInput _in;
|
287 | 502 | protected BSONCallback _callback;
|
| 503 | + private byte[] _random = new byte[1024]; // has to be used within a single function |
| 504 | + private byte[] _inputBuffer = new byte[1024]; |
| 505 | + private PoolOutputBuffer _stringBuffer = new PoolOutputBuffer(); |
288 | 506 |
|
| 507 | + protected int _pos; // current offset into _inputBuffer |
| 508 | + protected int _len; // length of valid data in _inputBuffer |
| 509 | + |
| 510 | + |
| 511 | + |
| 512 | + static final String[] ONE_BYTE_STRINGS = new String[128]; |
| 513 | + static void _fillRange( byte min, byte max ){ |
| 514 | + while ( min < max ){ |
| 515 | + String s = ""; |
| 516 | + s += (char)min; |
| 517 | + ONE_BYTE_STRINGS[(int)min] = s; |
| 518 | + min++; |
| 519 | + } |
| 520 | + } |
| 521 | + static { |
| 522 | + _fillRange( (byte)'0' , (byte)'9' ); |
| 523 | + _fillRange( (byte)'a' , (byte)'z' ); |
| 524 | + _fillRange( (byte)'A' , (byte)'Z' ); |
| 525 | + } |
289 | 526 | }
|
0 commit comments