1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2013 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.nano;
32 
33 import java.io.IOException;
34 
35 /**
36  * Reads and decodes protocol message fields.
37  *
38  * This class contains two kinds of methods:  methods that read specific
39  * protocol message constructs and field types (e.g. {@link #readTag()} and
40  * {@link #readInt32()}) and methods that read low-level values (e.g.
41  * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
42  * encoded protocol messages, you should use the former methods, but if you are
43  * reading some other format of your own design, use the latter.
44  *
45  * @author kenton@google.com Kenton Varda
46  */
47 public final class CodedInputByteBufferNano {
48   /**
49    * Create a new CodedInputStream wrapping the given byte array.
50    */
newInstance(final byte[] buf)51   public static CodedInputByteBufferNano newInstance(final byte[] buf) {
52     return newInstance(buf, 0, buf.length);
53   }
54 
55   /**
56    * Create a new CodedInputStream wrapping the given byte array slice.
57    */
newInstance(final byte[] buf, final int off, final int len)58   public static CodedInputByteBufferNano newInstance(final byte[] buf, final int off,
59                                              final int len) {
60     return new CodedInputByteBufferNano(buf, off, len);
61   }
62 
63   // -----------------------------------------------------------------
64 
65   /**
66    * Attempt to read a field tag, returning zero if we have reached EOF.
67    * Protocol message parsers use this to read tags, since a protocol message
68    * may legally end wherever a tag occurs, and zero is not a valid tag number.
69    */
readTag()70   public int readTag() throws IOException {
71     if (isAtEnd()) {
72       lastTag = 0;
73       return 0;
74     }
75 
76     lastTag = readRawVarint32();
77     if (lastTag == 0) {
78       // If we actually read zero, that's not a valid tag.
79       throw InvalidProtocolBufferNanoException.invalidTag();
80     }
81     return lastTag;
82   }
83 
84   /**
85    * Verifies that the last call to readTag() returned the given tag value.
86    * This is used to verify that a nested group ended with the correct
87    * end tag.
88    *
89    * @throws InvalidProtocolBufferNanoException {@code value} does not match the
90    *                                        last tag.
91    */
checkLastTagWas(final int value)92   public void checkLastTagWas(final int value)
93                               throws InvalidProtocolBufferNanoException {
94     if (lastTag != value) {
95       throw InvalidProtocolBufferNanoException.invalidEndTag();
96     }
97   }
98 
99   /**
100    * Reads and discards a single field, given its tag value.
101    *
102    * @return {@code false} if the tag is an endgroup tag, in which case
103    *         nothing is skipped.  Otherwise, returns {@code true}.
104    */
skipField(final int tag)105   public boolean skipField(final int tag) throws IOException {
106     switch (WireFormatNano.getTagWireType(tag)) {
107       case WireFormatNano.WIRETYPE_VARINT:
108         readInt32();
109         return true;
110       case WireFormatNano.WIRETYPE_FIXED64:
111         readRawLittleEndian64();
112         return true;
113       case WireFormatNano.WIRETYPE_LENGTH_DELIMITED:
114         skipRawBytes(readRawVarint32());
115         return true;
116       case WireFormatNano.WIRETYPE_START_GROUP:
117         skipMessage();
118         checkLastTagWas(
119           WireFormatNano.makeTag(WireFormatNano.getTagFieldNumber(tag),
120                              WireFormatNano.WIRETYPE_END_GROUP));
121         return true;
122       case WireFormatNano.WIRETYPE_END_GROUP:
123         return false;
124       case WireFormatNano.WIRETYPE_FIXED32:
125         readRawLittleEndian32();
126         return true;
127       default:
128         throw InvalidProtocolBufferNanoException.invalidWireType();
129     }
130   }
131 
132   /**
133    * Reads and discards an entire message.  This will read either until EOF
134    * or until an endgroup tag, whichever comes first.
135    */
skipMessage()136   public void skipMessage() throws IOException {
137     while (true) {
138       final int tag = readTag();
139       if (tag == 0 || !skipField(tag)) {
140         return;
141       }
142     }
143   }
144 
145   // -----------------------------------------------------------------
146 
147   /** Read a {@code double} field value from the stream. */
readDouble()148   public double readDouble() throws IOException {
149     return Double.longBitsToDouble(readRawLittleEndian64());
150   }
151 
152   /** Read a {@code float} field value from the stream. */
readFloat()153   public float readFloat() throws IOException {
154     return Float.intBitsToFloat(readRawLittleEndian32());
155   }
156 
157   /** Read a {@code uint64} field value from the stream. */
readUInt64()158   public long readUInt64() throws IOException {
159     return readRawVarint64();
160   }
161 
162   /** Read an {@code int64} field value from the stream. */
readInt64()163   public long readInt64() throws IOException {
164     return readRawVarint64();
165   }
166 
167   /** Read an {@code int32} field value from the stream. */
readInt32()168   public int readInt32() throws IOException {
169     return readRawVarint32();
170   }
171 
172   /** Read a {@code fixed64} field value from the stream. */
readFixed64()173   public long readFixed64() throws IOException {
174     return readRawLittleEndian64();
175   }
176 
177   /** Read a {@code fixed32} field value from the stream. */
readFixed32()178   public int readFixed32() throws IOException {
179     return readRawLittleEndian32();
180   }
181 
182   /** Read a {@code bool} field value from the stream. */
readBool()183   public boolean readBool() throws IOException {
184     return readRawVarint32() != 0;
185   }
186 
187   /** Read a {@code string} field value from the stream. */
readString()188   public String readString() throws IOException {
189     final int size = readRawVarint32();
190     if (size <= (bufferSize - bufferPos) && size > 0) {
191       // Fast path:  We already have the bytes in a contiguous buffer, so
192       //   just copy directly from it.
193       final String result = new String(buffer, bufferPos, size, InternalNano.UTF_8);
194       bufferPos += size;
195       return result;
196     } else {
197       // Slow path:  Build a byte array first then copy it.
198       return new String(readRawBytes(size), InternalNano.UTF_8);
199     }
200   }
201 
202   /** Read a {@code group} field value from the stream. */
readGroup(final MessageNano msg, final int fieldNumber)203   public void readGroup(final MessageNano msg, final int fieldNumber)
204       throws IOException {
205     if (recursionDepth >= recursionLimit) {
206       throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
207     }
208     ++recursionDepth;
209     msg.mergeFrom(this);
210     checkLastTagWas(
211       WireFormatNano.makeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP));
212     --recursionDepth;
213   }
214 
readMessage(final MessageNano msg)215   public void readMessage(final MessageNano msg)
216       throws IOException {
217     final int length = readRawVarint32();
218     if (recursionDepth >= recursionLimit) {
219       throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
220     }
221     final int oldLimit = pushLimit(length);
222     ++recursionDepth;
223     msg.mergeFrom(this);
224     checkLastTagWas(0);
225     --recursionDepth;
226     popLimit(oldLimit);
227   }
228 
229   /** Read a {@code bytes} field value from the stream. */
readBytes()230   public byte[] readBytes() throws IOException {
231     final int size = readRawVarint32();
232     if (size <= (bufferSize - bufferPos) && size > 0) {
233       // Fast path:  We already have the bytes in a contiguous buffer, so
234       //   just copy directly from it.
235       final byte[] result = new byte[size];
236       System.arraycopy(buffer, bufferPos, result, 0, size);
237       bufferPos += size;
238       return result;
239     } else if (size == 0) {
240       return WireFormatNano.EMPTY_BYTES;
241     } else {
242       // Slow path:  Build a byte array first then copy it.
243       return readRawBytes(size);
244     }
245   }
246 
247   /** Read a {@code uint32} field value from the stream. */
readUInt32()248   public int readUInt32() throws IOException {
249     return readRawVarint32();
250   }
251 
252   /**
253    * Read an enum field value from the stream.  Caller is responsible
254    * for converting the numeric value to an actual enum.
255    */
readEnum()256   public int readEnum() throws IOException {
257     return readRawVarint32();
258   }
259 
260   /** Read an {@code sfixed32} field value from the stream. */
readSFixed32()261   public int readSFixed32() throws IOException {
262     return readRawLittleEndian32();
263   }
264 
265   /** Read an {@code sfixed64} field value from the stream. */
readSFixed64()266   public long readSFixed64() throws IOException {
267     return readRawLittleEndian64();
268   }
269 
270   /** Read an {@code sint32} field value from the stream. */
readSInt32()271   public int readSInt32() throws IOException {
272     return decodeZigZag32(readRawVarint32());
273   }
274 
275   /** Read an {@code sint64} field value from the stream. */
readSInt64()276   public long readSInt64() throws IOException {
277     return decodeZigZag64(readRawVarint64());
278   }
279 
280   // =================================================================
281 
282   /**
283    * Read a raw Varint from the stream.  If larger than 32 bits, discard the
284    * upper bits.
285    */
readRawVarint32()286   public int readRawVarint32() throws IOException {
287     byte tmp = readRawByte();
288     if (tmp >= 0) {
289       return tmp;
290     }
291     int result = tmp & 0x7f;
292     if ((tmp = readRawByte()) >= 0) {
293       result |= tmp << 7;
294     } else {
295       result |= (tmp & 0x7f) << 7;
296       if ((tmp = readRawByte()) >= 0) {
297         result |= tmp << 14;
298       } else {
299         result |= (tmp & 0x7f) << 14;
300         if ((tmp = readRawByte()) >= 0) {
301           result |= tmp << 21;
302         } else {
303           result |= (tmp & 0x7f) << 21;
304           result |= (tmp = readRawByte()) << 28;
305           if (tmp < 0) {
306             // Discard upper 32 bits.
307             for (int i = 0; i < 5; i++) {
308               if (readRawByte() >= 0) {
309                 return result;
310               }
311             }
312             throw InvalidProtocolBufferNanoException.malformedVarint();
313           }
314         }
315       }
316     }
317     return result;
318   }
319 
320   /** Read a raw Varint from the stream. */
readRawVarint64()321   public long readRawVarint64() throws IOException {
322     int shift = 0;
323     long result = 0;
324     while (shift < 64) {
325       final byte b = readRawByte();
326       result |= (long)(b & 0x7F) << shift;
327       if ((b & 0x80) == 0) {
328         return result;
329       }
330       shift += 7;
331     }
332     throw InvalidProtocolBufferNanoException.malformedVarint();
333   }
334 
335   /** Read a 32-bit little-endian integer from the stream. */
readRawLittleEndian32()336   public int readRawLittleEndian32() throws IOException {
337     final byte b1 = readRawByte();
338     final byte b2 = readRawByte();
339     final byte b3 = readRawByte();
340     final byte b4 = readRawByte();
341     return ((b1 & 0xff)      ) |
342            ((b2 & 0xff) <<  8) |
343            ((b3 & 0xff) << 16) |
344            ((b4 & 0xff) << 24);
345   }
346 
347   /** Read a 64-bit little-endian integer from the stream. */
readRawLittleEndian64()348   public long readRawLittleEndian64() throws IOException {
349     final byte b1 = readRawByte();
350     final byte b2 = readRawByte();
351     final byte b3 = readRawByte();
352     final byte b4 = readRawByte();
353     final byte b5 = readRawByte();
354     final byte b6 = readRawByte();
355     final byte b7 = readRawByte();
356     final byte b8 = readRawByte();
357     return (((long)b1 & 0xff)      ) |
358            (((long)b2 & 0xff) <<  8) |
359            (((long)b3 & 0xff) << 16) |
360            (((long)b4 & 0xff) << 24) |
361            (((long)b5 & 0xff) << 32) |
362            (((long)b6 & 0xff) << 40) |
363            (((long)b7 & 0xff) << 48) |
364            (((long)b8 & 0xff) << 56);
365   }
366 
367   /**
368    * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
369    * into values that can be efficiently encoded with varint.  (Otherwise,
370    * negative values must be sign-extended to 64 bits to be varint encoded,
371    * thus always taking 10 bytes on the wire.)
372    *
373    * @param n An unsigned 32-bit integer, stored in a signed int because
374    *          Java has no explicit unsigned support.
375    * @return A signed 32-bit integer.
376    */
decodeZigZag32(final int n)377   public static int decodeZigZag32(final int n) {
378     return (n >>> 1) ^ -(n & 1);
379   }
380 
381   /**
382    * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
383    * into values that can be efficiently encoded with varint.  (Otherwise,
384    * negative values must be sign-extended to 64 bits to be varint encoded,
385    * thus always taking 10 bytes on the wire.)
386    *
387    * @param n An unsigned 64-bit integer, stored in a signed int because
388    *          Java has no explicit unsigned support.
389    * @return A signed 64-bit integer.
390    */
decodeZigZag64(final long n)391   public static long decodeZigZag64(final long n) {
392     return (n >>> 1) ^ -(n & 1);
393   }
394 
395   // -----------------------------------------------------------------
396 
397   private final byte[] buffer;
398   private int bufferStart;
399   private int bufferSize;
400   private int bufferSizeAfterLimit;
401   private int bufferPos;
402   private int lastTag;
403 
404   /** The absolute position of the end of the current message. */
405   private int currentLimit = Integer.MAX_VALUE;
406 
407   /** See setRecursionLimit() */
408   private int recursionDepth;
409   private int recursionLimit = DEFAULT_RECURSION_LIMIT;
410 
411   /** See setSizeLimit() */
412   private int sizeLimit = DEFAULT_SIZE_LIMIT;
413 
414   private static final int DEFAULT_RECURSION_LIMIT = 64;
415   private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
416 
CodedInputByteBufferNano(final byte[] buffer, final int off, final int len)417   private CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) {
418     this.buffer = buffer;
419     bufferStart = off;
420     bufferSize = off + len;
421     bufferPos = off;
422   }
423 
424   /**
425    * Set the maximum message recursion depth.  In order to prevent malicious
426    * messages from causing stack overflows, {@code CodedInputStream} limits
427    * how deeply messages may be nested.  The default limit is 64.
428    *
429    * @return the old limit.
430    */
setRecursionLimit(final int limit)431   public int setRecursionLimit(final int limit) {
432     if (limit < 0) {
433       throw new IllegalArgumentException(
434         "Recursion limit cannot be negative: " + limit);
435     }
436     final int oldLimit = recursionLimit;
437     recursionLimit = limit;
438     return oldLimit;
439   }
440 
441   /**
442    * Set the maximum message size.  In order to prevent malicious
443    * messages from exhausting memory or causing integer overflows,
444    * {@code CodedInputStream} limits how large a message may be.
445    * The default limit is 64MB.  You should set this limit as small
446    * as you can without harming your app's functionality.  Note that
447    * size limits only apply when reading from an {@code InputStream}, not
448    * when constructed around a raw byte array.
449    * <p>
450    * If you want to read several messages from a single CodedInputStream, you
451    * could call {@link #resetSizeCounter()} after each one to avoid hitting the
452    * size limit.
453    *
454    * @return the old limit.
455    */
setSizeLimit(final int limit)456   public int setSizeLimit(final int limit) {
457     if (limit < 0) {
458       throw new IllegalArgumentException(
459         "Size limit cannot be negative: " + limit);
460     }
461     final int oldLimit = sizeLimit;
462     sizeLimit = limit;
463     return oldLimit;
464   }
465 
466   /**
467    * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
468    */
resetSizeCounter()469   public void resetSizeCounter() {
470   }
471 
472   /**
473    * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
474    * is called when descending into a length-delimited embedded message.
475    *
476    * @return the old limit.
477    */
pushLimit(int byteLimit)478   public int pushLimit(int byteLimit) throws InvalidProtocolBufferNanoException {
479     if (byteLimit < 0) {
480       throw InvalidProtocolBufferNanoException.negativeSize();
481     }
482     byteLimit += bufferPos;
483     final int oldLimit = currentLimit;
484     if (byteLimit > oldLimit) {
485       throw InvalidProtocolBufferNanoException.truncatedMessage();
486     }
487     currentLimit = byteLimit;
488 
489     recomputeBufferSizeAfterLimit();
490 
491     return oldLimit;
492   }
493 
recomputeBufferSizeAfterLimit()494   private void recomputeBufferSizeAfterLimit() {
495     bufferSize += bufferSizeAfterLimit;
496     final int bufferEnd = bufferSize;
497     if (bufferEnd > currentLimit) {
498       // Limit is in current buffer.
499       bufferSizeAfterLimit = bufferEnd - currentLimit;
500       bufferSize -= bufferSizeAfterLimit;
501     } else {
502       bufferSizeAfterLimit = 0;
503     }
504   }
505 
506   /**
507    * Discards the current limit, returning to the previous limit.
508    *
509    * @param oldLimit The old limit, as returned by {@code pushLimit}.
510    */
popLimit(final int oldLimit)511   public void popLimit(final int oldLimit) {
512     currentLimit = oldLimit;
513     recomputeBufferSizeAfterLimit();
514   }
515 
516   /**
517    * Returns the number of bytes to be read before the current limit.
518    * If no limit is set, returns -1.
519    */
getBytesUntilLimit()520   public int getBytesUntilLimit() {
521     if (currentLimit == Integer.MAX_VALUE) {
522       return -1;
523     }
524 
525     final int currentAbsolutePosition = bufferPos;
526     return currentLimit - currentAbsolutePosition;
527   }
528 
529   /**
530    * Returns true if the stream has reached the end of the input.  This is the
531    * case if either the end of the underlying input source has been reached or
532    * if the stream has reached a limit created using {@link #pushLimit(int)}.
533    */
isAtEnd()534   public boolean isAtEnd() {
535     return bufferPos == bufferSize;
536   }
537 
538   /**
539    * Get current position in buffer relative to beginning offset.
540    */
getPosition()541   public int getPosition() {
542     return bufferPos - bufferStart;
543   }
544 
545   /**
546    * Get current (absolute) position in buffer.
547    */
getAbsolutePosition()548   public int getAbsolutePosition() {
549     return bufferPos;
550   }
551 
552   /**
553    * Return the raw underlying data in the buffer, directly.
554    */
getBuffer()555   public byte[] getBuffer() {
556     return buffer;
557   }
558 
559   /**
560    * Retrieves a subset of data in the buffer. The returned array is not backed by the original
561    * buffer array.
562    *
563    * @param offset the position (relative to the buffer start position) to start at.
564    * @param length the number of bytes to retrieve.
565    */
getData(int offset, int length)566   public byte[] getData(int offset, int length) {
567     if (length == 0) {
568       return WireFormatNano.EMPTY_BYTES;
569     }
570     byte[] copy = new byte[length];
571     int start = bufferStart + offset;
572     System.arraycopy(buffer, start, copy, 0, length);
573     return copy;
574   }
575 
576   /**
577    * Rewind to previous position. Cannot go forward.
578    */
rewindToPosition(int position)579   public void rewindToPosition(int position) {
580     if (position > bufferPos - bufferStart) {
581       throw new IllegalArgumentException(
582               "Position " + position + " is beyond current " + (bufferPos - bufferStart));
583     }
584     if (position < 0) {
585       throw new IllegalArgumentException("Bad position " + position);
586     }
587     bufferPos = bufferStart + position;
588   }
589 
590   /**
591    * Read one byte from the input.
592    *
593    * @throws InvalidProtocolBufferNanoException The end of the stream or the current
594    *                                        limit was reached.
595    */
readRawByte()596   public byte readRawByte() throws IOException {
597     if (bufferPos == bufferSize) {
598       throw InvalidProtocolBufferNanoException.truncatedMessage();
599     }
600     return buffer[bufferPos++];
601   }
602 
603   /**
604    * Read a fixed size of bytes from the input.
605    *
606    * @throws InvalidProtocolBufferNanoException The end of the stream or the current
607    *                                        limit was reached.
608    */
readRawBytes(final int size)609   public byte[] readRawBytes(final int size) throws IOException {
610     if (size < 0) {
611       throw InvalidProtocolBufferNanoException.negativeSize();
612     }
613 
614     if (bufferPos + size > currentLimit) {
615       // Read to the end of the stream anyway.
616       skipRawBytes(currentLimit - bufferPos);
617       // Then fail.
618       throw InvalidProtocolBufferNanoException.truncatedMessage();
619     }
620 
621     if (size <= bufferSize - bufferPos) {
622       // We have all the bytes we need already.
623       final byte[] bytes = new byte[size];
624       System.arraycopy(buffer, bufferPos, bytes, 0, size);
625       bufferPos += size;
626       return bytes;
627     } else {
628       throw InvalidProtocolBufferNanoException.truncatedMessage();
629     }
630   }
631 
632   /**
633    * Reads and discards {@code size} bytes.
634    *
635    * @throws InvalidProtocolBufferNanoException The end of the stream or the current
636    *                                        limit was reached.
637    */
skipRawBytes(final int size)638   public void skipRawBytes(final int size) throws IOException {
639     if (size < 0) {
640       throw InvalidProtocolBufferNanoException.negativeSize();
641     }
642 
643     if (bufferPos + size > currentLimit) {
644       // Read to the end of the stream anyway.
645       skipRawBytes(currentLimit - bufferPos);
646       // Then fail.
647       throw InvalidProtocolBufferNanoException.truncatedMessage();
648     }
649 
650     if (size <= bufferSize - bufferPos) {
651       // We have all the bytes we need already.
652       bufferPos += size;
653     } else {
654       throw InvalidProtocolBufferNanoException.truncatedMessage();
655     }
656   }
657 
658   // Read a primitive type.
readPrimitiveField(int type)659   Object readPrimitiveField(int type) throws IOException {
660     switch (type) {
661       case InternalNano.TYPE_DOUBLE:
662           return readDouble();
663       case InternalNano.TYPE_FLOAT:
664           return readFloat();
665       case InternalNano.TYPE_INT64:
666           return readInt64();
667       case InternalNano.TYPE_UINT64:
668           return readUInt64();
669       case InternalNano.TYPE_INT32:
670           return readInt32();
671       case InternalNano.TYPE_FIXED64:
672           return readFixed64();
673       case InternalNano.TYPE_FIXED32:
674           return readFixed32();
675       case InternalNano.TYPE_BOOL:
676           return readBool();
677       case InternalNano.TYPE_STRING:
678           return readString();
679       case InternalNano.TYPE_BYTES:
680           return readBytes();
681       case InternalNano.TYPE_UINT32:
682           return readUInt32();
683       case InternalNano.TYPE_ENUM:
684           return readEnum();
685       case InternalNano.TYPE_SFIXED32:
686           return readSFixed32();
687       case InternalNano.TYPE_SFIXED64:
688           return readSFixed64();
689       case InternalNano.TYPE_SINT32:
690           return readSInt32();
691       case InternalNano.TYPE_SINT64:
692           return readSInt64();
693       default:
694           throw new IllegalArgumentException("Unknown type " + type);
695     }
696   }
697 }
698