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