• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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