1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 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.ByteArrayOutputStream; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.nio.ByteBuffer; 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.List; 40 41 /** 42 * Reads and decodes protocol message fields. 43 * 44 * This class contains two kinds of methods: methods that read specific 45 * protocol message constructs and field types (e.g. {@link #readTag()} and 46 * {@link #readInt32()}) and methods that read low-level values (e.g. 47 * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading 48 * encoded protocol messages, you should use the former methods, but if you are 49 * reading some other format of your own design, use the latter. 50 * 51 * @author kenton@google.com Kenton Varda 52 */ 53 public final class CodedInputStream { 54 /** 55 * Create a new CodedInputStream wrapping the given InputStream. 56 */ newInstance(final InputStream input)57 public static CodedInputStream newInstance(final InputStream input) { 58 return new CodedInputStream(input, BUFFER_SIZE); 59 } 60 61 /** 62 * Create a new CodedInputStream wrapping the given InputStream. 63 */ newInstance(final InputStream input, int bufferSize)64 static CodedInputStream newInstance(final InputStream input, int bufferSize) { 65 return new CodedInputStream(input, bufferSize); 66 } 67 68 /** 69 * Create a new CodedInputStream wrapping the given byte array. 70 */ newInstance(final byte[] buf)71 public static CodedInputStream newInstance(final byte[] buf) { 72 return newInstance(buf, 0, buf.length); 73 } 74 75 /** 76 * Create a new CodedInputStream wrapping the given byte array slice. 77 */ newInstance(final byte[] buf, final int off, final int len)78 public static CodedInputStream newInstance(final byte[] buf, final int off, 79 final int len) { 80 return newInstance(buf, off, len, false /* bufferIsImmutable */); 81 } 82 83 /** 84 * Create a new CodedInputStream wrapping the given byte array slice. 85 */ newInstance( final byte[] buf, final int off, final int len, final boolean bufferIsImmutable)86 static CodedInputStream newInstance( 87 final byte[] buf, final int off, final int len, final boolean bufferIsImmutable) { 88 CodedInputStream result = new CodedInputStream(buf, off, len, bufferIsImmutable); 89 try { 90 // Some uses of CodedInputStream can be more efficient if they know 91 // exactly how many bytes are available. By pushing the end point of the 92 // buffer as a limit, we allow them to get this information via 93 // getBytesUntilLimit(). Pushing a limit that we know is at the end of 94 // the stream can never hurt, since we can never past that point anyway. 95 result.pushLimit(len); 96 } catch (InvalidProtocolBufferException ex) { 97 // The only reason pushLimit() might throw an exception here is if len 98 // is negative. Normally pushLimit()'s parameter comes directly off the 99 // wire, so it's important to catch exceptions in case of corrupt or 100 // malicious data. However, in this case, we expect that len is not a 101 // user-supplied value, so we can assume that it being negative indicates 102 // a programming error. Therefore, throwing an unchecked exception is 103 // appropriate. 104 throw new IllegalArgumentException(ex); 105 } 106 return result; 107 } 108 109 /** 110 * Create a new CodedInputStream wrapping the given ByteBuffer. The data 111 * starting from the ByteBuffer's current position to its limit will be read. 112 * The returned CodedInputStream may or may not share the underlying data 113 * in the ByteBuffer, therefore the ByteBuffer cannot be changed while the 114 * CodedInputStream is in use. 115 * Note that the ByteBuffer's position won't be changed by this function. 116 * Concurrent calls with the same ByteBuffer object are safe if no other 117 * thread is trying to alter the ByteBuffer's status. 118 */ newInstance(ByteBuffer buf)119 public static CodedInputStream newInstance(ByteBuffer buf) { 120 if (buf.hasArray()) { 121 return newInstance(buf.array(), buf.arrayOffset() + buf.position(), 122 buf.remaining()); 123 } else { 124 ByteBuffer temp = buf.duplicate(); 125 byte[] buffer = new byte[temp.remaining()]; 126 temp.get(buffer); 127 return newInstance(buffer); 128 } 129 } 130 131 // ----------------------------------------------------------------- 132 133 /** 134 * Attempt to read a field tag, returning zero if we have reached EOF. 135 * Protocol message parsers use this to read tags, since a protocol message 136 * may legally end wherever a tag occurs, and zero is not a valid tag number. 137 */ readTag()138 public int readTag() throws IOException { 139 if (isAtEnd()) { 140 lastTag = 0; 141 return 0; 142 } 143 144 lastTag = readRawVarint32(); 145 if (WireFormat.getTagFieldNumber(lastTag) == 0) { 146 // If we actually read zero (or any tag number corresponding to field 147 // number zero), that's not a valid tag. 148 throw InvalidProtocolBufferException.invalidTag(); 149 } 150 return lastTag; 151 } 152 153 /** 154 * Verifies that the last call to readTag() returned the given tag value. 155 * This is used to verify that a nested group ended with the correct 156 * end tag. 157 * 158 * @throws InvalidProtocolBufferException {@code value} does not match the 159 * last tag. 160 */ checkLastTagWas(final int value)161 public void checkLastTagWas(final int value) 162 throws InvalidProtocolBufferException { 163 if (lastTag != value) { 164 throw InvalidProtocolBufferException.invalidEndTag(); 165 } 166 } 167 getLastTag()168 public int getLastTag() { 169 return lastTag; 170 } 171 172 /** 173 * Reads and discards a single field, given its tag value. 174 * 175 * @return {@code false} if the tag is an endgroup tag, in which case 176 * nothing is skipped. Otherwise, returns {@code true}. 177 */ skipField(final int tag)178 public boolean skipField(final int tag) throws IOException { 179 switch (WireFormat.getTagWireType(tag)) { 180 case WireFormat.WIRETYPE_VARINT: 181 skipRawVarint(); 182 return true; 183 case WireFormat.WIRETYPE_FIXED64: 184 skipRawBytes(8); 185 return true; 186 case WireFormat.WIRETYPE_LENGTH_DELIMITED: 187 skipRawBytes(readRawVarint32()); 188 return true; 189 case WireFormat.WIRETYPE_START_GROUP: 190 skipMessage(); 191 checkLastTagWas( 192 WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), 193 WireFormat.WIRETYPE_END_GROUP)); 194 return true; 195 case WireFormat.WIRETYPE_END_GROUP: 196 return false; 197 case WireFormat.WIRETYPE_FIXED32: 198 skipRawBytes(4); 199 return true; 200 default: 201 throw InvalidProtocolBufferException.invalidWireType(); 202 } 203 } 204 205 /** 206 * Reads a single field and writes it to output in wire format, 207 * given its tag value. 208 * 209 * @return {@code false} if the tag is an endgroup tag, in which case 210 * nothing is skipped. Otherwise, returns {@code true}. 211 */ skipField(final int tag, final CodedOutputStream output)212 public boolean skipField(final int tag, final CodedOutputStream output) 213 throws IOException { 214 switch (WireFormat.getTagWireType(tag)) { 215 case WireFormat.WIRETYPE_VARINT: { 216 long value = readInt64(); 217 output.writeRawVarint32(tag); 218 output.writeUInt64NoTag(value); 219 return true; 220 } 221 case WireFormat.WIRETYPE_FIXED64: { 222 long value = readRawLittleEndian64(); 223 output.writeRawVarint32(tag); 224 output.writeFixed64NoTag(value); 225 return true; 226 } 227 case WireFormat.WIRETYPE_LENGTH_DELIMITED: { 228 ByteString value = readBytes(); 229 output.writeRawVarint32(tag); 230 output.writeBytesNoTag(value); 231 return true; 232 } 233 case WireFormat.WIRETYPE_START_GROUP: { 234 output.writeRawVarint32(tag); 235 skipMessage(output); 236 int endtag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), 237 WireFormat.WIRETYPE_END_GROUP); 238 checkLastTagWas(endtag); 239 output.writeRawVarint32(endtag); 240 return true; 241 } 242 case WireFormat.WIRETYPE_END_GROUP: { 243 return false; 244 } 245 case WireFormat.WIRETYPE_FIXED32: { 246 int value = readRawLittleEndian32(); 247 output.writeRawVarint32(tag); 248 output.writeFixed32NoTag(value); 249 return true; 250 } 251 default: 252 throw InvalidProtocolBufferException.invalidWireType(); 253 } 254 } 255 256 /** 257 * Reads and discards an entire message. This will read either until EOF 258 * or until an endgroup tag, whichever comes first. 259 */ skipMessage()260 public void skipMessage() throws IOException { 261 while (true) { 262 final int tag = readTag(); 263 if (tag == 0 || !skipField(tag)) { 264 return; 265 } 266 } 267 } 268 269 /** 270 * Reads an entire message and writes it to output in wire format. 271 * This will read either until EOF or until an endgroup tag, 272 * whichever comes first. 273 */ skipMessage(CodedOutputStream output)274 public void skipMessage(CodedOutputStream output) throws IOException { 275 while (true) { 276 final int tag = readTag(); 277 if (tag == 0 || !skipField(tag, output)) { 278 return; 279 } 280 } 281 } 282 283 /** 284 * Collects the bytes skipped and returns the data in a ByteBuffer. 285 */ 286 private class SkippedDataSink implements RefillCallback { 287 private int lastPos = bufferPos; 288 private ByteArrayOutputStream byteArrayStream; 289 290 @Override onRefill()291 public void onRefill() { 292 if (byteArrayStream == null) { 293 byteArrayStream = new ByteArrayOutputStream(); 294 } 295 byteArrayStream.write(buffer, lastPos, bufferPos - lastPos); 296 lastPos = 0; 297 } 298 299 /** 300 * Gets skipped data in a ByteBuffer. This method should only be 301 * called once. 302 */ getSkippedData()303 ByteBuffer getSkippedData() { 304 if (byteArrayStream == null) { 305 return ByteBuffer.wrap(buffer, lastPos, bufferPos - lastPos); 306 } else { 307 byteArrayStream.write(buffer, lastPos, bufferPos); 308 return ByteBuffer.wrap(byteArrayStream.toByteArray()); 309 } 310 } 311 } 312 313 314 // ----------------------------------------------------------------- 315 316 /** Read a {@code double} field value from the stream. */ readDouble()317 public double readDouble() throws IOException { 318 return Double.longBitsToDouble(readRawLittleEndian64()); 319 } 320 321 /** Read a {@code float} field value from the stream. */ readFloat()322 public float readFloat() throws IOException { 323 return Float.intBitsToFloat(readRawLittleEndian32()); 324 } 325 326 /** Read a {@code uint64} field value from the stream. */ readUInt64()327 public long readUInt64() throws IOException { 328 return readRawVarint64(); 329 } 330 331 /** Read an {@code int64} field value from the stream. */ readInt64()332 public long readInt64() throws IOException { 333 return readRawVarint64(); 334 } 335 336 /** Read an {@code int32} field value from the stream. */ readInt32()337 public int readInt32() throws IOException { 338 return readRawVarint32(); 339 } 340 341 /** Read a {@code fixed64} field value from the stream. */ readFixed64()342 public long readFixed64() throws IOException { 343 return readRawLittleEndian64(); 344 } 345 346 /** Read a {@code fixed32} field value from the stream. */ readFixed32()347 public int readFixed32() throws IOException { 348 return readRawLittleEndian32(); 349 } 350 351 /** Read a {@code bool} field value from the stream. */ readBool()352 public boolean readBool() throws IOException { 353 return readRawVarint64() != 0; 354 } 355 356 /** 357 * Read a {@code string} field value from the stream. 358 * If the stream contains malformed UTF-8, 359 * replace the offending bytes with the standard UTF-8 replacement character. 360 */ readString()361 public String readString() throws IOException { 362 final int size = readRawVarint32(); 363 if (size <= (bufferSize - bufferPos) && size > 0) { 364 // Fast path: We already have the bytes in a contiguous buffer, so 365 // just copy directly from it. 366 final String result = new String(buffer, bufferPos, size, Internal.UTF_8); 367 bufferPos += size; 368 return result; 369 } else if (size == 0) { 370 return ""; 371 } else if (size <= bufferSize) { 372 refillBuffer(size); 373 String result = new String(buffer, bufferPos, size, Internal.UTF_8); 374 bufferPos += size; 375 return result; 376 } else { 377 // Slow path: Build a byte array first then copy it. 378 return new String(readRawBytesSlowPath(size), Internal.UTF_8); 379 } 380 } 381 382 /** 383 * Read a {@code string} field value from the stream. 384 * If the stream contains malformed UTF-8, 385 * throw exception {@link InvalidProtocolBufferException}. 386 */ readStringRequireUtf8()387 public String readStringRequireUtf8() throws IOException { 388 final int size = readRawVarint32(); 389 final byte[] bytes; 390 final int oldPos = bufferPos; 391 final int pos; 392 if (size <= (bufferSize - oldPos) && size > 0) { 393 // Fast path: We already have the bytes in a contiguous buffer, so 394 // just copy directly from it. 395 bytes = buffer; 396 bufferPos = oldPos + size; 397 pos = oldPos; 398 } else if (size == 0) { 399 return ""; 400 } else if (size <= bufferSize) { 401 refillBuffer(size); 402 bytes = buffer; 403 pos = 0; 404 bufferPos = pos + size; 405 } else { 406 // Slow path: Build a byte array first then copy it. 407 bytes = readRawBytesSlowPath(size); 408 pos = 0; 409 } 410 // TODO(martinrb): We could save a pass by validating while decoding. 411 if (!Utf8.isValidUtf8(bytes, pos, pos + size)) { 412 throw InvalidProtocolBufferException.invalidUtf8(); 413 } 414 return new String(bytes, pos, size, Internal.UTF_8); 415 } 416 417 /** Read a {@code group} field value from the stream. */ readGroup(final int fieldNumber, final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)418 public void readGroup(final int fieldNumber, 419 final MessageLite.Builder builder, 420 final ExtensionRegistryLite extensionRegistry) 421 throws IOException { 422 if (recursionDepth >= recursionLimit) { 423 throw InvalidProtocolBufferException.recursionLimitExceeded(); 424 } 425 ++recursionDepth; 426 builder.mergeFrom(this, extensionRegistry); 427 checkLastTagWas( 428 WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); 429 --recursionDepth; 430 } 431 432 433 /** Read a {@code group} field value from the stream. */ readGroup( final int fieldNumber, final Parser<T> parser, final ExtensionRegistryLite extensionRegistry)434 public <T extends MessageLite> T readGroup( 435 final int fieldNumber, 436 final Parser<T> parser, 437 final ExtensionRegistryLite extensionRegistry) 438 throws IOException { 439 if (recursionDepth >= recursionLimit) { 440 throw InvalidProtocolBufferException.recursionLimitExceeded(); 441 } 442 ++recursionDepth; 443 T result = parser.parsePartialFrom(this, extensionRegistry); 444 checkLastTagWas( 445 WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); 446 --recursionDepth; 447 return result; 448 } 449 450 /** 451 * Reads a {@code group} field value from the stream and merges it into the 452 * given {@link UnknownFieldSet}. 453 * 454 * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so 455 * you can just call {@link #readGroup}. 456 */ 457 @Deprecated readUnknownGroup(final int fieldNumber, final MessageLite.Builder builder)458 public void readUnknownGroup(final int fieldNumber, 459 final MessageLite.Builder builder) 460 throws IOException { 461 // We know that UnknownFieldSet will ignore any ExtensionRegistry so it 462 // is safe to pass null here. (We can't call 463 // ExtensionRegistry.getEmptyRegistry() because that would make this 464 // class depend on ExtensionRegistry, which is not part of the lite 465 // library.) 466 readGroup(fieldNumber, builder, null); 467 } 468 469 /** Read an embedded message field value from the stream. */ readMessage(final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)470 public void readMessage(final MessageLite.Builder builder, 471 final ExtensionRegistryLite extensionRegistry) 472 throws IOException { 473 final int length = readRawVarint32(); 474 if (recursionDepth >= recursionLimit) { 475 throw InvalidProtocolBufferException.recursionLimitExceeded(); 476 } 477 final int oldLimit = pushLimit(length); 478 ++recursionDepth; 479 builder.mergeFrom(this, extensionRegistry); 480 checkLastTagWas(0); 481 --recursionDepth; 482 popLimit(oldLimit); 483 } 484 485 486 /** Read an embedded message field value from the stream. */ readMessage( final Parser<T> parser, final ExtensionRegistryLite extensionRegistry)487 public <T extends MessageLite> T readMessage( 488 final Parser<T> parser, 489 final ExtensionRegistryLite extensionRegistry) 490 throws IOException { 491 int length = readRawVarint32(); 492 if (recursionDepth >= recursionLimit) { 493 throw InvalidProtocolBufferException.recursionLimitExceeded(); 494 } 495 final int oldLimit = pushLimit(length); 496 ++recursionDepth; 497 T result = parser.parsePartialFrom(this, extensionRegistry); 498 checkLastTagWas(0); 499 --recursionDepth; 500 popLimit(oldLimit); 501 return result; 502 } 503 504 /** Read a {@code bytes} field value from the stream. */ readBytes()505 public ByteString readBytes() throws IOException { 506 final int size = readRawVarint32(); 507 if (size <= (bufferSize - bufferPos) && size > 0) { 508 // Fast path: We already have the bytes in a contiguous buffer, so 509 // just copy directly from it. 510 final ByteString result = bufferIsImmutable && enableAliasing 511 ? ByteString.wrap(buffer, bufferPos, size) 512 : ByteString.copyFrom(buffer, bufferPos, size); 513 bufferPos += size; 514 return result; 515 } else if (size == 0) { 516 return ByteString.EMPTY; 517 } else { 518 // Slow path: Build a byte array first then copy it. 519 return ByteString.wrap(readRawBytesSlowPath(size)); 520 } 521 } 522 523 /** Read a {@code bytes} field value from the stream. */ readByteArray()524 public byte[] readByteArray() throws IOException { 525 final int size = readRawVarint32(); 526 if (size <= (bufferSize - bufferPos) && size > 0) { 527 // Fast path: We already have the bytes in a contiguous buffer, so 528 // just copy directly from it. 529 final byte[] result = 530 Arrays.copyOfRange(buffer, bufferPos, bufferPos + size); 531 bufferPos += size; 532 return result; 533 } else { 534 // Slow path: Build a byte array first then copy it. 535 return readRawBytesSlowPath(size); 536 } 537 } 538 539 /** Read a {@code bytes} field value from the stream. */ readByteBuffer()540 public ByteBuffer readByteBuffer() throws IOException { 541 final int size = readRawVarint32(); 542 if (size <= (bufferSize - bufferPos) && size > 0) { 543 // Fast path: We already have the bytes in a contiguous buffer. 544 // When aliasing is enabled, we can return a ByteBuffer pointing directly 545 // into the underlying byte array without copy if the CodedInputStream is 546 // constructed from a byte array. If aliasing is disabled or the input is 547 // from an InputStream or ByteString, we have to make a copy of the bytes. 548 ByteBuffer result = input == null && !bufferIsImmutable && enableAliasing 549 ? ByteBuffer.wrap(buffer, bufferPos, size).slice() 550 : ByteBuffer.wrap(Arrays.copyOfRange( 551 buffer, bufferPos, bufferPos + size)); 552 bufferPos += size; 553 return result; 554 } else if (size == 0) { 555 return Internal.EMPTY_BYTE_BUFFER; 556 } else { 557 // Slow path: Build a byte array first then copy it. 558 return ByteBuffer.wrap(readRawBytesSlowPath(size)); 559 } 560 } 561 562 /** Read a {@code uint32} field value from the stream. */ readUInt32()563 public int readUInt32() throws IOException { 564 return readRawVarint32(); 565 } 566 567 /** 568 * Read an enum field value from the stream. Caller is responsible 569 * for converting the numeric value to an actual enum. 570 */ readEnum()571 public int readEnum() throws IOException { 572 return readRawVarint32(); 573 } 574 575 /** Read an {@code sfixed32} field value from the stream. */ readSFixed32()576 public int readSFixed32() throws IOException { 577 return readRawLittleEndian32(); 578 } 579 580 /** Read an {@code sfixed64} field value from the stream. */ readSFixed64()581 public long readSFixed64() throws IOException { 582 return readRawLittleEndian64(); 583 } 584 585 /** Read an {@code sint32} field value from the stream. */ readSInt32()586 public int readSInt32() throws IOException { 587 return decodeZigZag32(readRawVarint32()); 588 } 589 590 /** Read an {@code sint64} field value from the stream. */ readSInt64()591 public long readSInt64() throws IOException { 592 return decodeZigZag64(readRawVarint64()); 593 } 594 595 // ================================================================= 596 597 /** 598 * Read a raw Varint from the stream. If larger than 32 bits, discard the 599 * upper bits. 600 */ readRawVarint32()601 public int readRawVarint32() throws IOException { 602 // See implementation notes for readRawVarint64 603 fastpath: { 604 int pos = bufferPos; 605 606 if (bufferSize == pos) { 607 break fastpath; 608 } 609 610 final byte[] buffer = this.buffer; 611 int x; 612 if ((x = buffer[pos++]) >= 0) { 613 bufferPos = pos; 614 return x; 615 } else if (bufferSize - pos < 9) { 616 break fastpath; 617 } else if ((x ^= (buffer[pos++] << 7)) < 0) { 618 x ^= (~0 << 7); 619 } else if ((x ^= (buffer[pos++] << 14)) >= 0) { 620 x ^= (~0 << 7) ^ (~0 << 14); 621 } else if ((x ^= (buffer[pos++] << 21)) < 0) { 622 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); 623 } else { 624 int y = buffer[pos++]; 625 x ^= y << 28; 626 x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); 627 if (y < 0 && 628 buffer[pos++] < 0 && 629 buffer[pos++] < 0 && 630 buffer[pos++] < 0 && 631 buffer[pos++] < 0 && 632 buffer[pos++] < 0) { 633 break fastpath; // Will throw malformedVarint() 634 } 635 } 636 bufferPos = pos; 637 return x; 638 } 639 return (int) readRawVarint64SlowPath(); 640 } 641 skipRawVarint()642 private void skipRawVarint() throws IOException { 643 if (bufferSize - bufferPos >= 10) { 644 final byte[] buffer = this.buffer; 645 int pos = bufferPos; 646 for (int i = 0; i < 10; i++) { 647 if (buffer[pos++] >= 0) { 648 bufferPos = pos; 649 return; 650 } 651 } 652 } 653 skipRawVarintSlowPath(); 654 } 655 skipRawVarintSlowPath()656 private void skipRawVarintSlowPath() throws IOException { 657 for (int i = 0; i < 10; i++) { 658 if (readRawByte() >= 0) { 659 return; 660 } 661 } 662 throw InvalidProtocolBufferException.malformedVarint(); 663 } 664 665 /** 666 * Reads a varint from the input one byte at a time, so that it does not 667 * read any bytes after the end of the varint. If you simply wrapped the 668 * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)} 669 * then you would probably end up reading past the end of the varint since 670 * CodedInputStream buffers its input. 671 */ readRawVarint32(final InputStream input)672 static int readRawVarint32(final InputStream input) throws IOException { 673 final int firstByte = input.read(); 674 if (firstByte == -1) { 675 throw InvalidProtocolBufferException.truncatedMessage(); 676 } 677 return readRawVarint32(firstByte, input); 678 } 679 680 /** 681 * Like {@link #readRawVarint32(InputStream)}, but expects that the caller 682 * has already read one byte. This allows the caller to determine if EOF 683 * has been reached before attempting to read. 684 */ readRawVarint32( final int firstByte, final InputStream input)685 public static int readRawVarint32( 686 final int firstByte, final InputStream input) throws IOException { 687 if ((firstByte & 0x80) == 0) { 688 return firstByte; 689 } 690 691 int result = firstByte & 0x7f; 692 int offset = 7; 693 for (; offset < 32; offset += 7) { 694 final int b = input.read(); 695 if (b == -1) { 696 throw InvalidProtocolBufferException.truncatedMessage(); 697 } 698 result |= (b & 0x7f) << offset; 699 if ((b & 0x80) == 0) { 700 return result; 701 } 702 } 703 // Keep reading up to 64 bits. 704 for (; offset < 64; offset += 7) { 705 final int b = input.read(); 706 if (b == -1) { 707 throw InvalidProtocolBufferException.truncatedMessage(); 708 } 709 if ((b & 0x80) == 0) { 710 return result; 711 } 712 } 713 throw InvalidProtocolBufferException.malformedVarint(); 714 } 715 716 /** Read a raw Varint from the stream. */ readRawVarint64()717 public long readRawVarint64() throws IOException { 718 // Implementation notes: 719 // 720 // Optimized for one-byte values, expected to be common. 721 // The particular code below was selected from various candidates 722 // empirically, by winning VarintBenchmark. 723 // 724 // Sign extension of (signed) Java bytes is usually a nuisance, but 725 // we exploit it here to more easily obtain the sign of bytes read. 726 // Instead of cleaning up the sign extension bits by masking eagerly, 727 // we delay until we find the final (positive) byte, when we clear all 728 // accumulated bits with one xor. We depend on javac to constant fold. 729 fastpath: { 730 int pos = bufferPos; 731 732 if (bufferSize == pos) { 733 break fastpath; 734 } 735 736 final byte[] buffer = this.buffer; 737 long x; 738 int y; 739 if ((y = buffer[pos++]) >= 0) { 740 bufferPos = pos; 741 return y; 742 } else if (bufferSize - pos < 9) { 743 break fastpath; 744 } else if ((y ^= (buffer[pos++] << 7)) < 0) { 745 x = y ^ (~0 << 7); 746 } else if ((y ^= (buffer[pos++] << 14)) >= 0) { 747 x = y ^ ((~0 << 7) ^ (~0 << 14)); 748 } else if ((y ^= (buffer[pos++] << 21)) < 0) { 749 x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); 750 } else if ((x = ((long) y) ^ ((long) buffer[pos++] << 28)) >= 0L) { 751 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); 752 } else if ((x ^= ((long) buffer[pos++] << 35)) < 0L) { 753 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); 754 } else if ((x ^= ((long) buffer[pos++] << 42)) >= 0L) { 755 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42); 756 } else if ((x ^= ((long) buffer[pos++] << 49)) < 0L) { 757 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42) 758 ^ (~0L << 49); 759 } else { 760 x ^= ((long) buffer[pos++] << 56); 761 x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42) 762 ^ (~0L << 49) ^ (~0L << 56); 763 if (x < 0L) { 764 if (buffer[pos++] < 0L) { 765 break fastpath; // Will throw malformedVarint() 766 } 767 } 768 } 769 bufferPos = pos; 770 return x; 771 } 772 return readRawVarint64SlowPath(); 773 } 774 775 /** Variant of readRawVarint64 for when uncomfortably close to the limit. */ 776 /* Visible for testing */ readRawVarint64SlowPath()777 long readRawVarint64SlowPath() throws IOException { 778 long result = 0; 779 for (int shift = 0; shift < 64; shift += 7) { 780 final byte b = readRawByte(); 781 result |= (long) (b & 0x7F) << shift; 782 if ((b & 0x80) == 0) { 783 return result; 784 } 785 } 786 throw InvalidProtocolBufferException.malformedVarint(); 787 } 788 789 /** Read a 32-bit little-endian integer from the stream. */ readRawLittleEndian32()790 public int readRawLittleEndian32() throws IOException { 791 int pos = bufferPos; 792 793 // hand-inlined ensureAvailable(4); 794 if (bufferSize - pos < 4) { 795 refillBuffer(4); 796 pos = bufferPos; 797 } 798 799 final byte[] buffer = this.buffer; 800 bufferPos = pos + 4; 801 return (((buffer[pos] & 0xff)) | 802 ((buffer[pos + 1] & 0xff) << 8) | 803 ((buffer[pos + 2] & 0xff) << 16) | 804 ((buffer[pos + 3] & 0xff) << 24)); 805 } 806 807 /** Read a 64-bit little-endian integer from the stream. */ readRawLittleEndian64()808 public long readRawLittleEndian64() throws IOException { 809 int pos = bufferPos; 810 811 // hand-inlined ensureAvailable(8); 812 if (bufferSize - pos < 8) { 813 refillBuffer(8); 814 pos = bufferPos; 815 } 816 817 final byte[] buffer = this.buffer; 818 bufferPos = pos + 8; 819 return ((((long) buffer[pos] & 0xffL)) | 820 (((long) buffer[pos + 1] & 0xffL) << 8) | 821 (((long) buffer[pos + 2] & 0xffL) << 16) | 822 (((long) buffer[pos + 3] & 0xffL) << 24) | 823 (((long) buffer[pos + 4] & 0xffL) << 32) | 824 (((long) buffer[pos + 5] & 0xffL) << 40) | 825 (((long) buffer[pos + 6] & 0xffL) << 48) | 826 (((long) buffer[pos + 7] & 0xffL) << 56)); 827 } 828 829 /** 830 * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers 831 * into values that can be efficiently encoded with varint. (Otherwise, 832 * negative values must be sign-extended to 64 bits to be varint encoded, 833 * thus always taking 10 bytes on the wire.) 834 * 835 * @param n An unsigned 32-bit integer, stored in a signed int because 836 * Java has no explicit unsigned support. 837 * @return A signed 32-bit integer. 838 */ decodeZigZag32(final int n)839 public static int decodeZigZag32(final int n) { 840 return (n >>> 1) ^ -(n & 1); 841 } 842 843 /** 844 * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers 845 * into values that can be efficiently encoded with varint. (Otherwise, 846 * negative values must be sign-extended to 64 bits to be varint encoded, 847 * thus always taking 10 bytes on the wire.) 848 * 849 * @param n An unsigned 64-bit integer, stored in a signed int because 850 * Java has no explicit unsigned support. 851 * @return A signed 64-bit integer. 852 */ decodeZigZag64(final long n)853 public static long decodeZigZag64(final long n) { 854 return (n >>> 1) ^ -(n & 1); 855 } 856 857 // ----------------------------------------------------------------- 858 859 private final byte[] buffer; 860 private final boolean bufferIsImmutable; 861 private int bufferSize; 862 private int bufferSizeAfterLimit; 863 private int bufferPos; 864 private final InputStream input; 865 private int lastTag; 866 private boolean enableAliasing = false; 867 868 /** 869 * The total number of bytes read before the current buffer. The total 870 * bytes read up to the current position can be computed as 871 * {@code totalBytesRetired + bufferPos}. This value may be negative if 872 * reading started in the middle of the current buffer (e.g. if the 873 * constructor that takes a byte array and an offset was used). 874 */ 875 private int totalBytesRetired; 876 877 /** The absolute position of the end of the current message. */ 878 private int currentLimit = Integer.MAX_VALUE; 879 880 /** See setRecursionLimit() */ 881 private int recursionDepth; 882 private int recursionLimit = DEFAULT_RECURSION_LIMIT; 883 884 /** See setSizeLimit() */ 885 private int sizeLimit = DEFAULT_SIZE_LIMIT; 886 887 private static final int DEFAULT_RECURSION_LIMIT = 100; 888 private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB 889 private static final int BUFFER_SIZE = 4096; 890 CodedInputStream( final byte[] buffer, final int off, final int len, boolean bufferIsImmutable)891 private CodedInputStream( 892 final byte[] buffer, final int off, final int len, boolean bufferIsImmutable) { 893 this.buffer = buffer; 894 bufferSize = off + len; 895 bufferPos = off; 896 totalBytesRetired = -off; 897 input = null; 898 this.bufferIsImmutable = bufferIsImmutable; 899 } 900 CodedInputStream(final InputStream input, int bufferSize)901 private CodedInputStream(final InputStream input, int bufferSize) { 902 buffer = new byte[bufferSize]; 903 bufferSize = 0; 904 bufferPos = 0; 905 totalBytesRetired = 0; 906 this.input = input; 907 bufferIsImmutable = false; 908 } 909 enableAliasing(boolean enabled)910 public void enableAliasing(boolean enabled) { 911 this.enableAliasing = enabled; 912 } 913 914 /** 915 * Set the maximum message recursion depth. In order to prevent malicious 916 * messages from causing stack overflows, {@code CodedInputStream} limits 917 * how deeply messages may be nested. The default limit is 64. 918 * 919 * @return the old limit. 920 */ setRecursionLimit(final int limit)921 public int setRecursionLimit(final int limit) { 922 if (limit < 0) { 923 throw new IllegalArgumentException( 924 "Recursion limit cannot be negative: " + limit); 925 } 926 final int oldLimit = recursionLimit; 927 recursionLimit = limit; 928 return oldLimit; 929 } 930 931 /** 932 * Set the maximum message size. In order to prevent malicious 933 * messages from exhausting memory or causing integer overflows, 934 * {@code CodedInputStream} limits how large a message may be. 935 * The default limit is 64MB. You should set this limit as small 936 * as you can without harming your app's functionality. Note that 937 * size limits only apply when reading from an {@code InputStream}, not 938 * when constructed around a raw byte array (nor with 939 * {@link ByteString#newCodedInput}). 940 * <p> 941 * If you want to read several messages from a single CodedInputStream, you 942 * could call {@link #resetSizeCounter()} after each one to avoid hitting the 943 * size limit. 944 * 945 * @return the old limit. 946 */ setSizeLimit(final int limit)947 public int setSizeLimit(final int limit) { 948 if (limit < 0) { 949 throw new IllegalArgumentException( 950 "Size limit cannot be negative: " + limit); 951 } 952 final int oldLimit = sizeLimit; 953 sizeLimit = limit; 954 return oldLimit; 955 } 956 957 /** 958 * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). 959 */ resetSizeCounter()960 public void resetSizeCounter() { 961 totalBytesRetired = -bufferPos; 962 } 963 964 /** 965 * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This 966 * is called when descending into a length-delimited embedded message. 967 * 968 * <p>Note that {@code pushLimit()} does NOT affect how many bytes the 969 * {@code CodedInputStream} reads from an underlying {@code InputStream} when 970 * refreshing its buffer. If you need to prevent reading past a certain 971 * point in the underlying {@code InputStream} (e.g. because you expect it to 972 * contain more data after the end of the message which you need to handle 973 * differently) then you must place a wrapper around your {@code InputStream} 974 * which limits the amount of data that can be read from it. 975 * 976 * @return the old limit. 977 */ pushLimit(int byteLimit)978 public int pushLimit(int byteLimit) throws InvalidProtocolBufferException { 979 if (byteLimit < 0) { 980 throw InvalidProtocolBufferException.negativeSize(); 981 } 982 byteLimit += totalBytesRetired + bufferPos; 983 final int oldLimit = currentLimit; 984 if (byteLimit > oldLimit) { 985 throw InvalidProtocolBufferException.truncatedMessage(); 986 } 987 currentLimit = byteLimit; 988 989 recomputeBufferSizeAfterLimit(); 990 991 return oldLimit; 992 } 993 recomputeBufferSizeAfterLimit()994 private void recomputeBufferSizeAfterLimit() { 995 bufferSize += bufferSizeAfterLimit; 996 final int bufferEnd = totalBytesRetired + bufferSize; 997 if (bufferEnd > currentLimit) { 998 // Limit is in current buffer. 999 bufferSizeAfterLimit = bufferEnd - currentLimit; 1000 bufferSize -= bufferSizeAfterLimit; 1001 } else { 1002 bufferSizeAfterLimit = 0; 1003 } 1004 } 1005 1006 /** 1007 * Discards the current limit, returning to the previous limit. 1008 * 1009 * @param oldLimit The old limit, as returned by {@code pushLimit}. 1010 */ popLimit(final int oldLimit)1011 public void popLimit(final int oldLimit) { 1012 currentLimit = oldLimit; 1013 recomputeBufferSizeAfterLimit(); 1014 } 1015 1016 /** 1017 * Returns the number of bytes to be read before the current limit. 1018 * If no limit is set, returns -1. 1019 */ getBytesUntilLimit()1020 public int getBytesUntilLimit() { 1021 if (currentLimit == Integer.MAX_VALUE) { 1022 return -1; 1023 } 1024 1025 final int currentAbsolutePosition = totalBytesRetired + bufferPos; 1026 return currentLimit - currentAbsolutePosition; 1027 } 1028 1029 /** 1030 * Returns true if the stream has reached the end of the input. This is the 1031 * case if either the end of the underlying input source has been reached or 1032 * if the stream has reached a limit created using {@link #pushLimit(int)}. 1033 */ isAtEnd()1034 public boolean isAtEnd() throws IOException { 1035 return bufferPos == bufferSize && !tryRefillBuffer(1); 1036 } 1037 1038 /** 1039 * The total bytes read up to the current position. Calling 1040 * {@link #resetSizeCounter()} resets this value to zero. 1041 */ getTotalBytesRead()1042 public int getTotalBytesRead() { 1043 return totalBytesRetired + bufferPos; 1044 } 1045 1046 private interface RefillCallback { onRefill()1047 void onRefill(); 1048 } 1049 1050 private RefillCallback refillCallback = null; 1051 1052 /** 1053 * Reads more bytes from the input, making at least {@code n} bytes available 1054 * in the buffer. Caller must ensure that the requested space is not yet 1055 * available, and that the requested space is less than BUFFER_SIZE. 1056 * 1057 * @throws InvalidProtocolBufferException The end of the stream or the current 1058 * limit was reached. 1059 */ refillBuffer(int n)1060 private void refillBuffer(int n) throws IOException { 1061 if (!tryRefillBuffer(n)) { 1062 throw InvalidProtocolBufferException.truncatedMessage(); 1063 } 1064 } 1065 1066 /** 1067 * Tries to read more bytes from the input, making at least {@code n} bytes 1068 * available in the buffer. Caller must ensure that the requested space is 1069 * not yet available, and that the requested space is less than BUFFER_SIZE. 1070 * 1071 * @return {@code true} if the bytes could be made available; {@code false} 1072 * if the end of the stream or the current limit was reached. 1073 */ tryRefillBuffer(int n)1074 private boolean tryRefillBuffer(int n) throws IOException { 1075 if (bufferPos + n <= bufferSize) { 1076 throw new IllegalStateException( 1077 "refillBuffer() called when " + n + 1078 " bytes were already available in buffer"); 1079 } 1080 1081 if (totalBytesRetired + bufferPos + n > currentLimit) { 1082 // Oops, we hit a limit. 1083 return false; 1084 } 1085 1086 if (refillCallback != null) { 1087 refillCallback.onRefill(); 1088 } 1089 1090 if (input != null) { 1091 int pos = bufferPos; 1092 if (pos > 0) { 1093 if (bufferSize > pos) { 1094 System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos); 1095 } 1096 totalBytesRetired += pos; 1097 bufferSize -= pos; 1098 bufferPos = 0; 1099 } 1100 1101 int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize); 1102 if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) { 1103 throw new IllegalStateException( 1104 "InputStream#read(byte[]) returned invalid result: " + bytesRead + 1105 "\nThe InputStream implementation is buggy."); 1106 } 1107 if (bytesRead > 0) { 1108 bufferSize += bytesRead; 1109 // Integer-overflow-conscious check against sizeLimit 1110 if (totalBytesRetired + n - sizeLimit > 0) { 1111 throw InvalidProtocolBufferException.sizeLimitExceeded(); 1112 } 1113 recomputeBufferSizeAfterLimit(); 1114 return (bufferSize >= n) ? true : tryRefillBuffer(n); 1115 } 1116 } 1117 1118 return false; 1119 } 1120 1121 /** 1122 * Read one byte from the input. 1123 * 1124 * @throws InvalidProtocolBufferException The end of the stream or the current 1125 * limit was reached. 1126 */ readRawByte()1127 public byte readRawByte() throws IOException { 1128 if (bufferPos == bufferSize) { 1129 refillBuffer(1); 1130 } 1131 return buffer[bufferPos++]; 1132 } 1133 1134 /** 1135 * Read a fixed size of bytes from the input. 1136 * 1137 * @throws InvalidProtocolBufferException The end of the stream or the current 1138 * limit was reached. 1139 */ readRawBytes(final int size)1140 public byte[] readRawBytes(final int size) throws IOException { 1141 final int pos = bufferPos; 1142 if (size <= (bufferSize - pos) && size > 0) { 1143 bufferPos = pos + size; 1144 return Arrays.copyOfRange(buffer, pos, pos + size); 1145 } else { 1146 return readRawBytesSlowPath(size); 1147 } 1148 } 1149 1150 /** 1151 * Exactly like readRawBytes, but caller must have already checked the fast 1152 * path: (size <= (bufferSize - pos) && size > 0) 1153 */ readRawBytesSlowPath(final int size)1154 private byte[] readRawBytesSlowPath(final int size) throws IOException { 1155 if (size <= 0) { 1156 if (size == 0) { 1157 return Internal.EMPTY_BYTE_ARRAY; 1158 } else { 1159 throw InvalidProtocolBufferException.negativeSize(); 1160 } 1161 } 1162 1163 // Verify that the message size so far has not exceeded sizeLimit. 1164 int currentMessageSize = totalBytesRetired + bufferPos + size; 1165 if (currentMessageSize > sizeLimit) { 1166 throw InvalidProtocolBufferException.sizeLimitExceeded(); 1167 } 1168 1169 // Verify that the message size so far has not exceeded currentLimit. 1170 if (currentMessageSize > currentLimit) { 1171 // Read to the end of the stream anyway. 1172 skipRawBytes(currentLimit - totalBytesRetired - bufferPos); 1173 throw InvalidProtocolBufferException.truncatedMessage(); 1174 } 1175 1176 // We need the input stream to proceed. 1177 if (input == null) { 1178 throw InvalidProtocolBufferException.truncatedMessage(); 1179 } 1180 1181 final int originalBufferPos = bufferPos; 1182 final int bufferedBytes = bufferSize - bufferPos; 1183 1184 // Mark the current buffer consumed. 1185 totalBytesRetired += bufferSize; 1186 bufferPos = 0; 1187 bufferSize = 0; 1188 1189 // Determine the number of bytes we need to read from the input stream. 1190 int sizeLeft = size - bufferedBytes; 1191 // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE. 1192 if (sizeLeft < BUFFER_SIZE || sizeLeft <= input.available()) { 1193 // Either the bytes we need are known to be available, or the required buffer is 1194 // within an allowed threshold - go ahead and allocate the buffer now. 1195 final byte[] bytes = new byte[size]; 1196 1197 // Copy all of the buffered bytes to the result buffer. 1198 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); 1199 1200 // Fill the remaining bytes from the input stream. 1201 int pos = bufferedBytes; 1202 while (pos < bytes.length) { 1203 int n = input.read(bytes, pos, size - pos); 1204 if (n == -1) { 1205 throw InvalidProtocolBufferException.truncatedMessage(); 1206 } 1207 totalBytesRetired += n; 1208 pos += n; 1209 } 1210 1211 return bytes; 1212 } 1213 1214 // The size is very large. For security reasons, we can't allocate the 1215 // entire byte array yet. The size comes directly from the input, so a 1216 // maliciously-crafted message could provide a bogus very large size in 1217 // order to trick the app into allocating a lot of memory. We avoid this 1218 // by allocating and reading only a small chunk at a time, so that the 1219 // malicious message must actually *be* extremely large to cause 1220 // problems. Meanwhile, we limit the allowed size of a message elsewhere. 1221 final List<byte[]> chunks = new ArrayList<byte[]>(); 1222 1223 while (sizeLeft > 0) { 1224 // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE. 1225 final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)]; 1226 int pos = 0; 1227 while (pos < chunk.length) { 1228 final int n = input.read(chunk, pos, chunk.length - pos); 1229 if (n == -1) { 1230 throw InvalidProtocolBufferException.truncatedMessage(); 1231 } 1232 totalBytesRetired += n; 1233 pos += n; 1234 } 1235 sizeLeft -= chunk.length; 1236 chunks.add(chunk); 1237 } 1238 1239 // OK, got everything. Now concatenate it all into one buffer. 1240 final byte[] bytes = new byte[size]; 1241 1242 // Start by copying the leftover bytes from this.buffer. 1243 System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); 1244 1245 // And now all the chunks. 1246 int pos = bufferedBytes; 1247 for (final byte[] chunk : chunks) { 1248 System.arraycopy(chunk, 0, bytes, pos, chunk.length); 1249 pos += chunk.length; 1250 } 1251 1252 // Done. 1253 return bytes; 1254 } 1255 1256 /** 1257 * Reads and discards {@code size} bytes. 1258 * 1259 * @throws InvalidProtocolBufferException The end of the stream or the current 1260 * limit was reached. 1261 */ skipRawBytes(final int size)1262 public void skipRawBytes(final int size) throws IOException { 1263 if (size <= (bufferSize - bufferPos) && size >= 0) { 1264 // We have all the bytes we need already. 1265 bufferPos += size; 1266 } else { 1267 skipRawBytesSlowPath(size); 1268 } 1269 } 1270 1271 /** 1272 * Exactly like skipRawBytes, but caller must have already checked the fast 1273 * path: (size <= (bufferSize - pos) && size >= 0) 1274 */ skipRawBytesSlowPath(final int size)1275 private void skipRawBytesSlowPath(final int size) throws IOException { 1276 if (size < 0) { 1277 throw InvalidProtocolBufferException.negativeSize(); 1278 } 1279 1280 if (totalBytesRetired + bufferPos + size > currentLimit) { 1281 // Read to the end of the stream anyway. 1282 skipRawBytes(currentLimit - totalBytesRetired - bufferPos); 1283 // Then fail. 1284 throw InvalidProtocolBufferException.truncatedMessage(); 1285 } 1286 1287 // Skipping more bytes than are in the buffer. First skip what we have. 1288 int pos = bufferSize - bufferPos; 1289 bufferPos = bufferSize; 1290 1291 // Keep refilling the buffer until we get to the point we wanted to skip to. 1292 // This has the side effect of ensuring the limits are updated correctly. 1293 refillBuffer(1); 1294 while (size - pos > bufferSize) { 1295 pos += bufferSize; 1296 bufferPos = bufferSize; 1297 refillBuffer(1); 1298 } 1299 1300 bufferPos = size - pos; 1301 } 1302 } 1303