1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // http://code.google.com/p/protobuf/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import java.io.IOException; 34 import java.io.InputStream; 35 import java.util.ArrayList; 36 import java.util.List; 37 38 /** 39 * Reads and decodes protocol message fields. 40 * 41 * This class contains two kinds of methods: methods that read specific 42 * protocol message constructs and field types (e.g. {@link #readTag()} and 43 * {@link #readInt32()}) and methods that read low-level values (e.g. 44 * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading 45 * encoded protocol messages, you should use the former methods, but if you are 46 * reading some other format of your own design, use the latter. 47 * 48 * @author kenton (at) google.com Kenton Varda 49 */ 50 public final class CodedInputStream { 51 /** 52 * Create a new CodedInputStream wrapping the given InputStream. 53 */ 54 public static CodedInputStream newInstance(final InputStream input) { 55 return new CodedInputStream(input); 56 } 57 58 /** 59 * Create a new CodedInputStream wrapping the given byte array. 60 */ 61 public static CodedInputStream newInstance(final byte[] buf) { 62 return newInstance(buf, 0, buf.length); 63 } 64 65 /** 66 * Create a new CodedInputStream wrapping the given byte array slice. 67 */ 68 public static CodedInputStream newInstance(final byte[] buf, final int off, 69 final int len) { 70 return new CodedInputStream(buf, off, len); 71 } 72 73 // ----------------------------------------------------------------- 74 75 /** 76 * Attempt to read a field tag, returning zero if we have reached EOF. 77 * Protocol message parsers use this to read tags, since a protocol message 78 * may legally end wherever a tag occurs, and zero is not a valid tag number. 79 */ 80 public int readTag() throws IOException { 81 if (isAtEnd()) { 82 lastTag = 0; 83 return 0; 84 } 85 86 lastTag = readRawVarint32(); 87 if (WireFormat.getTagFieldNumber(lastTag) == 0) { 88 // If we actually read zero (or any tag number corresponding to field 89 // number zero), that's not a valid tag. 90 throw InvalidProtocolBufferException.invalidTag(); 91 } 92 return lastTag; 93 } 94 95 /** 96 * Verifies that the last call to readTag() returned the given tag value. 97 * This is used to verify that a nested group ended with the correct 98 * end tag. 99 * 100 * @throws InvalidProtocolBufferException {@code value} does not match the 101 * last tag. 102 */ 103 public void checkLastTagWas(final int value) 104 throws InvalidProtocolBufferException { 105 if (lastTag != value) { 106 throw InvalidProtocolBufferException.invalidEndTag(); 107 } 108 } 109 110 /** 111 * Reads and discards a single field, given its tag value. 112 * 113 * @return {@code false} if the tag is an endgroup tag, in which case 114 * nothing is skipped. Otherwise, returns {@code true}. 115 */ 116 public boolean skipField(final int tag) throws IOException { 117 switch (WireFormat.getTagWireType(tag)) { 118 case WireFormat.WIRETYPE_VARINT: 119 readInt32(); 120 return true; 121 case WireFormat.WIRETYPE_FIXED64: 122 readRawLittleEndian64(); 123 return true; 124 case WireFormat.WIRETYPE_LENGTH_DELIMITED: 125 skipRawBytes(readRawVarint32()); 126 return true; 127 case WireFormat.WIRETYPE_START_GROUP: 128 skipMessage(); 129 checkLastTagWas( 130 WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), 131 WireFormat.WIRETYPE_END_GROUP)); 132 return true; 133 case WireFormat.WIRETYPE_END_GROUP: 134 return false; 135 case WireFormat.WIRETYPE_FIXED32: 136 readRawLittleEndian32(); 137 return true; 138 default: 139 throw InvalidProtocolBufferException.invalidWireType(); 140 } 141 } 142 143 /** 144 * Reads and discards an entire message. This will read either until EOF 145 * or until an endgroup tag, whichever comes first. 146 */ 147 public void skipMessage() throws IOException { 148 while (true) { 149 final int tag = readTag(); 150 if (tag == 0 || !skipField(tag)) { 151 return; 152 } 153 } 154 } 155 156 // ----------------------------------------------------------------- 157 158 /** Read a {@code double} field value from the stream. */ 159 public double readDouble() throws IOException { 160 return Double.longBitsToDouble(readRawLittleEndian64()); 161 } 162 163 /** Read a {@code float} field value from the stream. */ 164 public float readFloat() throws IOException { 165 return Float.intBitsToFloat(readRawLittleEndian32()); 166 } 167 168 /** Read a {@code uint64} field value from the stream. */ 169 public long readUInt64() throws IOException { 170 return readRawVarint64(); 171 } 172 173 /** Read an {@code int64} field value from the stream. */ 174 public long readInt64() throws IOException { 175 return readRawVarint64(); 176 } 177 178 /** Read an {@code int32} field value from the stream. */ 179 public int readInt32() throws IOException { 180 return readRawVarint32(); 181 } 182 183 /** Read a {@code fixed64} field value from the stream. */ 184 public long readFixed64() throws IOException { 185 return readRawLittleEndian64(); 186 } 187 188 /** Read a {@code fixed32} field value from the stream. */ 189 public int readFixed32() throws IOException { 190 return readRawLittleEndian32(); 191 } 192 193 /** Read a {@code bool} field value from the stream. */ 194 public boolean readBool() throws IOException { 195 return readRawVarint32() != 0; 196 } 197 198 /** Read a {@code string} field value from the stream. */ 199 public String readString() throws IOException { 200 final int size = readRawVarint32(); 201 if (size <= (bufferSize - bufferPos) && size > 0) { 202 // Fast path: We already have the bytes in a contiguous buffer, so 203 // just copy directly from it. 204 final String result = new String(buffer, bufferPos, size, "UTF-8"); 205 bufferPos += size; 206 return result; 207 } else { 208 // Slow path: Build a byte array first then copy it. 209 return new String(readRawBytes(size), "UTF-8"); 210 } 211 } 212 213 /** Read a {@code group} field value from the stream. */ 214 public void readGroup(final int fieldNumber, 215 final MessageLite.Builder builder, 216 final ExtensionRegistryLite extensionRegistry) 217 throws IOException { 218 if (recursionDepth >= recursionLimit) { 219 throw InvalidProtocolBufferException.recursionLimitExceeded(); 220 } 221 ++recursionDepth; 222 builder.mergeFrom(this, extensionRegistry); 223 checkLastTagWas( 224 WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); 225 --recursionDepth; 226 } 227 228 /** 229 * Reads a {@code group} field value from the stream and merges it into the 230 * given {@link UnknownFieldSet}. 231 * 232 * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so 233 * you can just call {@link #readGroup}. 234 */ 235 @Deprecated 236 public void readUnknownGroup(final int fieldNumber, 237 final MessageLite.Builder builder) 238 throws IOException { 239 // We know that UnknownFieldSet will ignore any ExtensionRegistry so it 240 // is safe to pass null here. (We can't call 241 // ExtensionRegistry.getEmptyRegistry() because that would make this 242 // class depend on ExtensionRegistry, which is not part of the lite 243 // library.) 244 readGroup(fieldNumber, builder, null); 245 } 246 247 /** Read an embedded message field value from the stream. */ 248 public void readMessage(final MessageLite.Builder builder, 249 final ExtensionRegistryLite extensionRegistry) 250 throws IOException { 251 final int length = readRawVarint32(); 252 if (recursionDepth >= recursionLimit) { 253 throw InvalidProtocolBufferException.recursionLimitExceeded(); 254 } 255 final int oldLimit = pushLimit(length); 256 ++recursionDepth; 257 builder.mergeFrom(this, extensionRegistry); 258 checkLastTagWas(0); 259 --recursionDepth; 260 popLimit(oldLimit); 261 } 262 263 /** Read a {@code bytes} field value from the stream. */ 264 public ByteString readBytes() throws IOException { 265 final int size = readRawVarint32(); 266 if (size <= (bufferSize - bufferPos) && size > 0) { 267 // Fast path: We already have the bytes in a contiguous buffer, so 268 // just copy directly from it. 269 final ByteString result = ByteString.copyFrom(buffer, bufferPos, size); 270 bufferPos += size; 271 return result; 272 } else { 273 // Slow path: Build a byte array first then copy it. 274 return ByteString.copyFrom(readRawBytes(size)); 275 } 276 } 277 278 /** Read a {@code uint32} field value from the stream. */ 279 public int readUInt32() throws IOException { 280 return readRawVarint32(); 281 } 282 283 /** 284 * Read an enum field value from the stream. Caller is responsible 285 * for converting the numeric value to an actual enum. 286 */ 287 public int readEnum() throws IOException { 288 return readRawVarint32(); 289 } 290 291 /** Read an {@code sfixed32} field value from the stream. */ 292 public int readSFixed32() throws IOException { 293 return readRawLittleEndian32(); 294 } 295 296 /** Read an {@code sfixed64} field value from the stream. */ 297 public long readSFixed64() throws IOException { 298 return readRawLittleEndian64(); 299 } 300 301 /** Read an {@code sint32} field value from the stream. */ 302 public int readSInt32() throws IOException { 303 return decodeZigZag32(readRawVarint32()); 304 } 305 306 /** Read an {@code sint64} field value from the stream. */ 307 public long readSInt64() throws IOException { 308 return decodeZigZag64(readRawVarint64()); 309 } 310 311 // ================================================================= 312 313 /** 314 * Read a raw Varint from the stream. If larger than 32 bits, discard the 315 * upper bits. 316 */ 317 public int readRawVarint32() throws IOException { 318 byte tmp = readRawByte(); 319 if (tmp >= 0) { 320 return tmp; 321 } 322 int result = tmp & 0x7f; 323 if ((tmp = readRawByte()) >= 0) { 324 result |= tmp << 7; 325 } else { 326 result |= (tmp & 0x7f) << 7; 327 if ((tmp = readRawByte()) >= 0) { 328 result |= tmp << 14; 329 } else { 330 result |= (tmp & 0x7f) << 14; 331 if ((tmp = readRawByte()) >= 0) { 332 result |= tmp << 21; 333 } else { 334 result |= (tmp & 0x7f) << 21; 335 result |= (tmp = readRawByte()) << 28; 336 if (tmp < 0) { 337 // Discard upper 32 bits. 338 for (int i = 0; i < 5; i++) { 339 if (readRawByte() >= 0) { 340 return result; 341 } 342 } 343 throw InvalidProtocolBufferException.malformedVarint(); 344 } 345 } 346 } 347 } 348 return result; 349 } 350 351 /** 352 * Reads a varint from the input one byte at a time, so that it does not 353 * read any bytes after the end of the varint. If you simply wrapped the 354 * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)} 355 * then you would probably end up reading past the end of the varint since 356 * CodedInputStream buffers its input. 357 */ 358 static int readRawVarint32(final InputStream input) throws IOException { 359 final int firstByte = input.read(); 360 if (firstByte == -1) { 361 throw InvalidProtocolBufferException.truncatedMessage(); 362 } 363 return readRawVarint32(firstByte, input); 364 } 365 366 /** 367 * Like {@link #readRawVarint32(InputStream)}, but expects that the caller 368 * has already read one byte. This allows the caller to determine if EOF 369 * has been reached before attempting to read. 370 */ 371 static int readRawVarint32(final int firstByte, 372 final InputStream input) throws IOException { 373 if ((firstByte & 0x80) == 0) { 374 return firstByte; 375 } 376 377 int result = firstByte & 0x7f; 378 int offset = 7; 379 for (; offset < 32; offset += 7) { 380 final int b = input.read(); 381 if (b == -1) { 382 throw InvalidProtocolBufferException.truncatedMessage(); 383 } 384 result |= (b & 0x7f) << offset; 385 if ((b & 0x80) == 0) { 386 return result; 387 } 388 } 389 // Keep reading up to 64 bits. 390 for (; offset < 64; offset += 7) { 391 final int b = input.read(); 392 if (b == -1) { 393 throw InvalidProtocolBufferException.truncatedMessage(); 394 } 395 if ((b & 0x80) == 0) { 396 return result; 397 } 398 } 399 throw InvalidProtocolBufferException.malformedVarint(); 400 } 401 402 /** Read a raw Varint from the stream. */ 403 public long readRawVarint64() throws IOException { 404 int shift = 0; 405 long result = 0; 406 while (shift < 64) { 407 final byte b = readRawByte(); 408 result |= (long)(b & 0x7F) << shift; 409 if ((b & 0x80) == 0) { 410 return result; 411 } 412 shift += 7; 413 } 414 throw InvalidProtocolBufferException.malformedVarint(); 415 } 416 417 /** Read a 32-bit little-endian integer from the stream. */ 418 public int readRawLittleEndian32() throws IOException { 419 final byte b1 = readRawByte(); 420 final byte b2 = readRawByte(); 421 final byte b3 = readRawByte(); 422 final byte b4 = readRawByte(); 423 return (((int)b1 & 0xff) ) | 424 (((int)b2 & 0xff) << 8) | 425 (((int)b3 & 0xff) << 16) | 426 (((int)b4 & 0xff) << 24); 427 } 428 429 /** Read a 64-bit little-endian integer from the stream. */ 430 public long readRawLittleEndian64() throws IOException { 431 final byte b1 = readRawByte(); 432 final byte b2 = readRawByte(); 433 final byte b3 = readRawByte(); 434 final byte b4 = readRawByte(); 435 final byte b5 = readRawByte(); 436 final byte b6 = readRawByte(); 437 final byte b7 = readRawByte(); 438 final byte b8 = readRawByte(); 439 return (((long)b1 & 0xff) ) | 440 (((long)b2 & 0xff) << 8) | 441 (((long)b3 & 0xff) << 16) | 442 (((long)b4 & 0xff) << 24) | 443 (((long)b5 & 0xff) << 32) | 444 (((long)b6 & 0xff) << 40) | 445 (((long)b7 & 0xff) << 48) | 446 (((long)b8 & 0xff) << 56); 447 } 448 449 /** 450 * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers 451 * into values that can be efficiently encoded with varint. (Otherwise, 452 * negative values must be sign-extended to 64 bits to be varint encoded, 453 * thus always taking 10 bytes on the wire.) 454 * 455 * @param n An unsigned 32-bit integer, stored in a signed int because 456 * Java has no explicit unsigned support. 457 * @return A signed 32-bit integer. 458 */ 459 public static int decodeZigZag32(final int n) { 460 return (n >>> 1) ^ -(n & 1); 461 } 462 463 /** 464 * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers 465 * into values that can be efficiently encoded with varint. (Otherwise, 466 * negative values must be sign-extended to 64 bits to be varint encoded, 467 * thus always taking 10 bytes on the wire.) 468 * 469 * @param n An unsigned 64-bit integer, stored in a signed int because 470 * Java has no explicit unsigned support. 471 * @return A signed 64-bit integer. 472 */ 473 public static long decodeZigZag64(final long n) { 474 return (n >>> 1) ^ -(n & 1); 475 } 476 477 // ----------------------------------------------------------------- 478 479 private final byte[] buffer; 480 private int bufferSize; 481 private int bufferSizeAfterLimit; 482 private int bufferPos; 483 private final InputStream input; 484 private int lastTag; 485 486 /** 487 * The total number of bytes read before the current buffer. The total 488 * bytes read up to the current position can be computed as 489 * {@code totalBytesRetired + bufferPos}. This value may be negative if 490 * reading started in the middle of the current buffer (e.g. if the 491 * constructor that takes a byte array and an offset was used). 492 */ 493 private int totalBytesRetired; 494 495 /** The absolute position of the end of the current message. */ 496 private int currentLimit = Integer.MAX_VALUE; 497 498 /** See setRecursionLimit() */ 499 private int recursionDepth; 500 private int recursionLimit = DEFAULT_RECURSION_LIMIT; 501 502 /** See setSizeLimit() */ 503 private int sizeLimit = DEFAULT_SIZE_LIMIT; 504 505 private static final int DEFAULT_RECURSION_LIMIT = 64; 506 private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB 507 private static final int BUFFER_SIZE = 4096; 508 509 private CodedInputStream(final byte[] buffer, final int off, final int len) { 510 this.buffer = buffer; 511 bufferSize = off + len; 512 bufferPos = off; 513 totalBytesRetired = -off; 514 input = null; 515 } 516 517 private CodedInputStream(final InputStream input) { 518 buffer = new byte[BUFFER_SIZE]; 519 bufferSize = 0; 520 bufferPos = 0; 521 totalBytesRetired = 0; 522 this.input = input; 523 } 524 525 /** 526 * Set the maximum message recursion depth. In order to prevent malicious 527 * messages from causing stack overflows, {@code CodedInputStream} limits 528 * how deeply messages may be nested. The default limit is 64. 529 * 530 * @return the old limit. 531 */ 532 public int setRecursionLimit(final int limit) { 533 if (limit < 0) { 534 throw new IllegalArgumentException( 535 "Recursion limit cannot be negative: " + limit); 536 } 537 final int oldLimit = recursionLimit; 538 recursionLimit = limit; 539 return oldLimit; 540 } 541 542 /** 543 * Set the maximum message size. In order to prevent malicious 544 * messages from exhausting memory or causing integer overflows, 545 * {@code CodedInputStream} limits how large a message may be. 546 * The default limit is 64MB. You should set this limit as small 547 * as you can without harming your app's functionality. Note that 548 * size limits only apply when reading from an {@code InputStream}, not 549 * when constructed around a raw byte array (nor with 550 * {@link ByteString#newCodedInput}). 551 * <p> 552 * If you want to read several messages from a single CodedInputStream, you 553 * could call {@link #resetSizeCounter()} after each one to avoid hitting the 554 * size limit. 555 * 556 * @return the old limit. 557 */ 558 public int setSizeLimit(final int limit) { 559 if (limit < 0) { 560 throw new IllegalArgumentException( 561 "Size limit cannot be negative: " + limit); 562 } 563 final int oldLimit = sizeLimit; 564 sizeLimit = limit; 565 return oldLimit; 566 } 567 568 /** 569 * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). 570 */ 571 public void resetSizeCounter() { 572 totalBytesRetired = -bufferPos; 573 } 574 575 /** 576 * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This 577 * is called when descending into a length-delimited embedded message. 578 * 579 * <p>Note that {@code pushLimit()} does NOT affect how many bytes the 580 * {@code CodedInputStream} reads from an underlying {@code InputStream} when 581 * refreshing its buffer. If you need to prevent reading past a certain 582 * point in the underlying {@code InputStream} (e.g. because you expect it to 583 * contain more data after the end of the message which you need to handle 584 * differently) then you must place a wrapper around you {@code InputStream} 585 * which limits the amount of data that can be read from it. 586 * 587 * @return the old limit. 588 */ 589 public int pushLimit(int byteLimit) throws InvalidProtocolBufferException { 590 if (byteLimit < 0) { 591 throw InvalidProtocolBufferException.negativeSize(); 592 } 593 byteLimit += totalBytesRetired + bufferPos; 594 final int oldLimit = currentLimit; 595 if (byteLimit > oldLimit) { 596 throw InvalidProtocolBufferException.truncatedMessage(); 597 } 598 currentLimit = byteLimit; 599 600 recomputeBufferSizeAfterLimit(); 601 602 return oldLimit; 603 } 604 605 private void recomputeBufferSizeAfterLimit() { 606 bufferSize += bufferSizeAfterLimit; 607 final int bufferEnd = totalBytesRetired + bufferSize; 608 if (bufferEnd > currentLimit) { 609 // Limit is in current buffer. 610 bufferSizeAfterLimit = bufferEnd - currentLimit; 611 bufferSize -= bufferSizeAfterLimit; 612 } else { 613 bufferSizeAfterLimit = 0; 614 } 615 } 616 617 /** 618 * Discards the current limit, returning to the previous limit. 619 * 620 * @param oldLimit The old limit, as returned by {@code pushLimit}. 621 */ 622 public void popLimit(final int oldLimit) { 623 currentLimit = oldLimit; 624 recomputeBufferSizeAfterLimit(); 625 } 626 627 /** 628 * Returns the number of bytes to be read before the current limit. 629 * If no limit is set, returns -1. 630 */ 631 public int getBytesUntilLimit() { 632 if (currentLimit == Integer.MAX_VALUE) { 633 return -1; 634 } 635 636 final int currentAbsolutePosition = totalBytesRetired + bufferPos; 637 return currentLimit - currentAbsolutePosition; 638 } 639 640 /** 641 * Returns true if the stream has reached the end of the input. This is the 642 * case if either the end of the underlying input source has been reached or 643 * if the stream has reached a limit created using {@link #pushLimit(int)}. 644 */ 645 public boolean isAtEnd() throws IOException { 646 return bufferPos == bufferSize && !refillBuffer(false); 647 } 648 649 /** 650 * The total bytes read up to the current position. Calling 651 * {@link #resetSizeCounter()} resets this value to zero. 652 */ 653 public int getTotalBytesRead() { 654 return totalBytesRetired + bufferPos; 655 } 656 657 /** 658 * Called with {@code this.buffer} is empty to read more bytes from the 659 * input. If {@code mustSucceed} is true, refillBuffer() gurantees that 660 * either there will be at least one byte in the buffer when it returns 661 * or it will throw an exception. If {@code mustSucceed} is false, 662 * refillBuffer() returns false if no more bytes were available. 663 */ 664 private boolean refillBuffer(final boolean mustSucceed) throws IOException { 665 if (bufferPos < bufferSize) { 666 throw new IllegalStateException( 667 "refillBuffer() called when buffer wasn't empty."); 668 } 669 670 if (totalBytesRetired + bufferSize == currentLimit) { 671 // Oops, we hit a limit. 672 if (mustSucceed) { 673 throw InvalidProtocolBufferException.truncatedMessage(); 674 } else { 675 return false; 676 } 677 } 678 679 totalBytesRetired += bufferSize; 680 681 bufferPos = 0; 682 bufferSize = (input == null) ? -1 : input.read(buffer); 683 if (bufferSize == 0 || bufferSize < -1) { 684 throw new IllegalStateException( 685 "InputStream#read(byte[]) returned invalid result: " + bufferSize + 686 "\nThe InputStream implementation is buggy."); 687 } 688 if (bufferSize == -1) { 689 bufferSize = 0; 690 if (mustSucceed) { 691 throw InvalidProtocolBufferException.truncatedMessage(); 692 } else { 693 return false; 694 } 695 } else { 696 recomputeBufferSizeAfterLimit(); 697 final int totalBytesRead = 698 totalBytesRetired + bufferSize + bufferSizeAfterLimit; 699 if (totalBytesRead > sizeLimit || totalBytesRead < 0) { 700 throw InvalidProtocolBufferException.sizeLimitExceeded(); 701 } 702 return true; 703 } 704 } 705 706 /** 707 * Read one byte from the input. 708 * 709 * @throws InvalidProtocolBufferException The end of the stream or the current 710 * limit was reached. 711 */ 712 public byte readRawByte() throws IOException { 713 if (bufferPos == bufferSize) { 714 refillBuffer(true); 715 } 716 return buffer[bufferPos++]; 717 } 718 719 /** 720 * Read a fixed size of bytes from the input. 721 * 722 * @throws InvalidProtocolBufferException The end of the stream or the current 723 * limit was reached. 724 */ 725 public byte[] readRawBytes(final int size) throws IOException { 726 if (size < 0) { 727 throw InvalidProtocolBufferException.negativeSize(); 728 } 729 730 if (totalBytesRetired + bufferPos + size > currentLimit) { 731 // Read to the end of the stream anyway. 732 skipRawBytes(currentLimit - totalBytesRetired - bufferPos); 733 // Then fail. 734 throw InvalidProtocolBufferException.truncatedMessage(); 735 } 736 737 if (size <= bufferSize - bufferPos) { 738 // We have all the bytes we need already. 739 final byte[] bytes = new byte[size]; 740 System.arraycopy(buffer, bufferPos, bytes, 0, size); 741 bufferPos += size; 742 return bytes; 743 } else if (size < BUFFER_SIZE) { 744 // Reading more bytes than are in the buffer, but not an excessive number 745 // of bytes. We can safely allocate the resulting array ahead of time. 746 747 // First copy what we have. 748 final byte[] bytes = new byte[size]; 749 int pos = bufferSize - bufferPos; 750 System.arraycopy(buffer, bufferPos, bytes, 0, pos); 751 bufferPos = bufferSize; 752 753 // We want to use refillBuffer() and then copy from the buffer into our 754 // byte array rather than reading directly into our byte array because 755 // the input may be unbuffered. 756 refillBuffer(true); 757 758 while (size - pos > bufferSize) { 759 System.arraycopy(buffer, 0, bytes, pos, bufferSize); 760 pos += bufferSize; 761 bufferPos = bufferSize; 762 refillBuffer(true); 763 } 764 765 System.arraycopy(buffer, 0, bytes, pos, size - pos); 766 bufferPos = size - pos; 767 768 return bytes; 769 } else { 770 // The size is very large. For security reasons, we can't allocate the 771 // entire byte array yet. The size comes directly from the input, so a 772 // maliciously-crafted message could provide a bogus very large size in 773 // order to trick the app into allocating a lot of memory. We avoid this 774 // by allocating and reading only a small chunk at a time, so that the 775 // malicious message must actually *be* extremely large to cause 776 // problems. Meanwhile, we limit the allowed size of a message elsewhere. 777 778 // Remember the buffer markers since we'll have to copy the bytes out of 779 // it later. 780 final int originalBufferPos = bufferPos; 781 final int originalBufferSize = bufferSize; 782 783 // Mark the current buffer consumed. 784 totalBytesRetired += bufferSize; 785 bufferPos = 0; 786 bufferSize = 0; 787 788 // Read all the rest of the bytes we need. 789 int sizeLeft = size - (originalBufferSize - originalBufferPos); 790 final List<byte[]> chunks = new ArrayList<byte[]>(); 791 792 while (sizeLeft > 0) { 793 final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)]; 794 int pos = 0; 795 while (pos < chunk.length) { 796 final int n = (input == null) ? -1 : 797 input.read(chunk, pos, chunk.length - pos); 798 if (n == -1) { 799 throw InvalidProtocolBufferException.truncatedMessage(); 800 } 801 totalBytesRetired += n; 802 pos += n; 803 } 804 sizeLeft -= chunk.length; 805 chunks.add(chunk); 806 } 807 808 // OK, got everything. Now concatenate it all into one buffer. 809 final byte[] bytes = new byte[size]; 810 811 // Start by copying the leftover bytes from this.buffer. 812 int pos = originalBufferSize - originalBufferPos; 813 System.arraycopy(buffer, originalBufferPos, bytes, 0, pos); 814 815 // And now all the chunks. 816 for (final byte[] chunk : chunks) { 817 System.arraycopy(chunk, 0, bytes, pos, chunk.length); 818 pos += chunk.length; 819 } 820 821 // Done. 822 return bytes; 823 } 824 } 825 826 /** 827 * Reads and discards {@code size} bytes. 828 * 829 * @throws InvalidProtocolBufferException The end of the stream or the current 830 * limit was reached. 831 */ 832 public void skipRawBytes(final int size) throws IOException { 833 if (size < 0) { 834 throw InvalidProtocolBufferException.negativeSize(); 835 } 836 837 if (totalBytesRetired + bufferPos + size > currentLimit) { 838 // Read to the end of the stream anyway. 839 skipRawBytes(currentLimit - totalBytesRetired - bufferPos); 840 // Then fail. 841 throw InvalidProtocolBufferException.truncatedMessage(); 842 } 843 844 if (size <= bufferSize - bufferPos) { 845 // We have all the bytes we need already. 846 bufferPos += size; 847 } else { 848 // Skipping more bytes than are in the buffer. First skip what we have. 849 int pos = bufferSize - bufferPos; 850 totalBytesRetired += bufferSize; 851 bufferPos = 0; 852 bufferSize = 0; 853 854 // Then skip directly from the InputStream for the rest. 855 while (pos < size) { 856 final int n = (input == null) ? -1 : (int) input.skip(size - pos); 857 if (n <= 0) { 858 throw InvalidProtocolBufferException.truncatedMessage(); 859 } 860 pos += n; 861 totalBytesRetired += n; 862 } 863 } 864 } 865 } 866