Home | History | Annotate | Download | only in protobuf
      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 (at) google.com Kenton Varda
     52  */
     53 public final class CodedInputStream {
     54   /**
     55    * Create a new CodedInputStream wrapping the given InputStream.
     56    */
     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    */
     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    */
     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    */
     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    */
     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    */
    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    */
    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    */
    161   public void checkLastTagWas(final int value)
    162                               throws InvalidProtocolBufferException {
    163     if (lastTag != value) {
    164       throw InvalidProtocolBufferException.invalidEndTag();
    165     }
    166   }
    167 
    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    */
    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    */
    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    */
    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    */
    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
    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      */
    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. */
    317   public double readDouble() throws IOException {
    318     return Double.longBitsToDouble(readRawLittleEndian64());
    319   }
    320 
    321   /** Read a {@code float} field value from the stream. */
    322   public float readFloat() throws IOException {
    323     return Float.intBitsToFloat(readRawLittleEndian32());
    324   }
    325 
    326   /** Read a {@code uint64} field value from the stream. */
    327   public long readUInt64() throws IOException {
    328     return readRawVarint64();
    329   }
    330 
    331   /** Read an {@code int64} field value from the stream. */
    332   public long readInt64() throws IOException {
    333     return readRawVarint64();
    334   }
    335 
    336   /** Read an {@code int32} field value from the stream. */
    337   public int readInt32() throws IOException {
    338     return readRawVarint32();
    339   }
    340 
    341   /** Read a {@code fixed64} field value from the stream. */
    342   public long readFixed64() throws IOException {
    343     return readRawLittleEndian64();
    344   }
    345 
    346   /** Read a {@code fixed32} field value from the stream. */
    347   public int readFixed32() throws IOException {
    348     return readRawLittleEndian32();
    349   }
    350 
    351   /** Read a {@code bool} field value from the stream. */
    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    */
    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    */
    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. */
    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. */
    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
    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. */
    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. */
    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. */
    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. */
    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. */
    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. */
    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    */
    571   public int readEnum() throws IOException {
    572     return readRawVarint32();
    573   }
    574 
    575   /** Read an {@code sfixed32} field value from the stream. */
    576   public int readSFixed32() throws IOException {
    577     return readRawLittleEndian32();
    578   }
    579 
    580   /** Read an {@code sfixed64} field value from the stream. */
    581   public long readSFixed64() throws IOException {
    582     return readRawLittleEndian64();
    583   }
    584 
    585   /** Read an {@code sint32} field value from the stream. */
    586   public int readSInt32() throws IOException {
    587     return decodeZigZag32(readRawVarint32());
    588   }
    589 
    590   /** Read an {@code sint64} field value from the stream. */
    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    */
    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 
    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 
    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    */
    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    */
    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. */
    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 */
    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. */
    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. */
    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    */
    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    */
    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 
    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 
    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 
    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    */
    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    */
    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    */
    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    */
    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 
    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    */
   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    */
   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    */
   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    */
   1042   public int getTotalBytesRead() {
   1043       return totalBytesRetired + bufferPos;
   1044   }
   1045 
   1046   private interface RefillCallback {
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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