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