1// Protocol Buffers - Google's data interchange format 2// Copyright 2013 Google Inc. All rights reserved. 3// http://code.google.com/p/protobuf/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31package com.google.protobuf.nano; 32 33import 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 */ 47public final class CodedInputByteBufferNano { 48 /** 49 * Create a new CodedInputStream wrapping the given byte array. 50 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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. */ 148 public double readDouble() throws IOException { 149 return Double.longBitsToDouble(readRawLittleEndian64()); 150 } 151 152 /** Read a {@code float} field value from the stream. */ 153 public float readFloat() throws IOException { 154 return Float.intBitsToFloat(readRawLittleEndian32()); 155 } 156 157 /** Read a {@code uint64} field value from the stream. */ 158 public long readUInt64() throws IOException { 159 return readRawVarint64(); 160 } 161 162 /** Read an {@code int64} field value from the stream. */ 163 public long readInt64() throws IOException { 164 return readRawVarint64(); 165 } 166 167 /** Read an {@code int32} field value from the stream. */ 168 public int readInt32() throws IOException { 169 return readRawVarint32(); 170 } 171 172 /** Read a {@code fixed64} field value from the stream. */ 173 public long readFixed64() throws IOException { 174 return readRawLittleEndian64(); 175 } 176 177 /** Read a {@code fixed32} field value from the stream. */ 178 public int readFixed32() throws IOException { 179 return readRawLittleEndian32(); 180 } 181 182 /** Read a {@code bool} field value from the stream. */ 183 public boolean readBool() throws IOException { 184 return readRawVarint32() != 0; 185 } 186 187 /** Read a {@code string} field value from the stream. */ 188 public String readString() throws IOException { 189 final int size = readRawVarint32(); 190 if (size < 0) { 191 throw InvalidProtocolBufferNanoException.negativeSize(); 192 } 193 if (size > (bufferSize - bufferPos)) { 194 throw InvalidProtocolBufferNanoException.truncatedMessage(); 195 } 196 197 final String result = new String(buffer, bufferPos, size, "UTF-8"); 198 bufferPos += size; 199 return result; 200 } 201 202 /** Read a {@code group} field value from the stream. */ 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 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. */ 230 public byte[] readBytes() throws IOException { 231 final int size = readRawVarint32(); 232 if (size < 0) { 233 throw InvalidProtocolBufferNanoException.negativeSize(); 234 } 235 if (size == 0) { 236 return WireFormatNano.EMPTY_BYTES; 237 } 238 if (size > (bufferSize - bufferPos)) { 239 throw InvalidProtocolBufferNanoException.truncatedMessage(); 240 } 241 242 final byte[] result = new byte[size]; 243 System.arraycopy(buffer, bufferPos, result, 0, size); 244 bufferPos += size; 245 return result; 246 } 247 248 /** Read a {@code uint32} field value from the stream. */ 249 public int readUInt32() throws IOException { 250 return readRawVarint32(); 251 } 252 253 /** 254 * Read an enum field value from the stream. Caller is responsible 255 * for converting the numeric value to an actual enum. 256 */ 257 public int readEnum() throws IOException { 258 return readRawVarint32(); 259 } 260 261 /** Read an {@code sfixed32} field value from the stream. */ 262 public int readSFixed32() throws IOException { 263 return readRawLittleEndian32(); 264 } 265 266 /** Read an {@code sfixed64} field value from the stream. */ 267 public long readSFixed64() throws IOException { 268 return readRawLittleEndian64(); 269 } 270 271 /** Read an {@code sint32} field value from the stream. */ 272 public int readSInt32() throws IOException { 273 return decodeZigZag32(readRawVarint32()); 274 } 275 276 /** Read an {@code sint64} field value from the stream. */ 277 public long readSInt64() throws IOException { 278 return decodeZigZag64(readRawVarint64()); 279 } 280 281 // ================================================================= 282 283 /** 284 * Read a raw Varint from the stream. If larger than 32 bits, discard the 285 * upper bits. 286 */ 287 public int readRawVarint32() throws IOException { 288 byte tmp = readRawByte(); 289 if (tmp >= 0) { 290 return tmp; 291 } 292 int result = tmp & 0x7f; 293 if ((tmp = readRawByte()) >= 0) { 294 result |= tmp << 7; 295 } else { 296 result |= (tmp & 0x7f) << 7; 297 if ((tmp = readRawByte()) >= 0) { 298 result |= tmp << 14; 299 } else { 300 result |= (tmp & 0x7f) << 14; 301 if ((tmp = readRawByte()) >= 0) { 302 result |= tmp << 21; 303 } else { 304 result |= (tmp & 0x7f) << 21; 305 result |= (tmp = readRawByte()) << 28; 306 if (tmp < 0) { 307 // Discard upper 32 bits. 308 for (int i = 0; i < 5; i++) { 309 if (readRawByte() >= 0) { 310 return result; 311 } 312 } 313 throw InvalidProtocolBufferNanoException.malformedVarint(); 314 } 315 } 316 } 317 } 318 return result; 319 } 320 321 /** Read a raw Varint from the stream. */ 322 public long readRawVarint64() throws IOException { 323 int shift = 0; 324 long result = 0; 325 while (shift < 64) { 326 final byte b = readRawByte(); 327 result |= (long)(b & 0x7F) << shift; 328 if ((b & 0x80) == 0) { 329 return result; 330 } 331 shift += 7; 332 } 333 throw InvalidProtocolBufferNanoException.malformedVarint(); 334 } 335 336 /** Read a 32-bit little-endian integer from the stream. */ 337 public int readRawLittleEndian32() throws IOException { 338 final byte b1 = readRawByte(); 339 final byte b2 = readRawByte(); 340 final byte b3 = readRawByte(); 341 final byte b4 = readRawByte(); 342 return ((b1 & 0xff) ) | 343 ((b2 & 0xff) << 8) | 344 ((b3 & 0xff) << 16) | 345 ((b4 & 0xff) << 24); 346 } 347 348 /** Read a 64-bit little-endian integer from the stream. */ 349 public long readRawLittleEndian64() throws IOException { 350 final byte b1 = readRawByte(); 351 final byte b2 = readRawByte(); 352 final byte b3 = readRawByte(); 353 final byte b4 = readRawByte(); 354 final byte b5 = readRawByte(); 355 final byte b6 = readRawByte(); 356 final byte b7 = readRawByte(); 357 final byte b8 = readRawByte(); 358 return (((long)b1 & 0xff) ) | 359 (((long)b2 & 0xff) << 8) | 360 (((long)b3 & 0xff) << 16) | 361 (((long)b4 & 0xff) << 24) | 362 (((long)b5 & 0xff) << 32) | 363 (((long)b6 & 0xff) << 40) | 364 (((long)b7 & 0xff) << 48) | 365 (((long)b8 & 0xff) << 56); 366 } 367 368 /** 369 * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers 370 * into values that can be efficiently encoded with varint. (Otherwise, 371 * negative values must be sign-extended to 64 bits to be varint encoded, 372 * thus always taking 10 bytes on the wire.) 373 * 374 * @param n An unsigned 32-bit integer, stored in a signed int because 375 * Java has no explicit unsigned support. 376 * @return A signed 32-bit integer. 377 */ 378 public static int decodeZigZag32(final int n) { 379 return (n >>> 1) ^ -(n & 1); 380 } 381 382 /** 383 * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers 384 * into values that can be efficiently encoded with varint. (Otherwise, 385 * negative values must be sign-extended to 64 bits to be varint encoded, 386 * thus always taking 10 bytes on the wire.) 387 * 388 * @param n An unsigned 64-bit integer, stored in a signed int because 389 * Java has no explicit unsigned support. 390 * @return A signed 64-bit integer. 391 */ 392 public static long decodeZigZag64(final long n) { 393 return (n >>> 1) ^ -(n & 1); 394 } 395 396 // ----------------------------------------------------------------- 397 398 private final byte[] buffer; 399 private int bufferStart; 400 private int bufferSize; 401 private int bufferSizeAfterLimit; 402 private int bufferPos; 403 private int lastTag; 404 405 /** The absolute position of the end of the current message. */ 406 private int currentLimit = Integer.MAX_VALUE; 407 408 /** See setRecursionLimit() */ 409 private int recursionDepth; 410 private int recursionLimit = DEFAULT_RECURSION_LIMIT; 411 412 /** See setSizeLimit() */ 413 private int sizeLimit = DEFAULT_SIZE_LIMIT; 414 415 private static final int DEFAULT_RECURSION_LIMIT = 64; 416 private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB 417 418 private CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) { 419 this.buffer = buffer; 420 bufferStart = off; 421 bufferSize = off + len; 422 bufferPos = off; 423 } 424 425 /** 426 * Set the maximum message recursion depth. In order to prevent malicious 427 * messages from causing stack overflows, {@code CodedInputStream} limits 428 * how deeply messages may be nested. The default limit is 64. 429 * 430 * @return the old limit. 431 */ 432 public int setRecursionLimit(final int limit) { 433 if (limit < 0) { 434 throw new IllegalArgumentException( 435 "Recursion limit cannot be negative: " + limit); 436 } 437 final int oldLimit = recursionLimit; 438 recursionLimit = limit; 439 return oldLimit; 440 } 441 442 /** 443 * Set the maximum message size. In order to prevent malicious 444 * messages from exhausting memory or causing integer overflows, 445 * {@code CodedInputStream} limits how large a message may be. 446 * The default limit is 64MB. You should set this limit as small 447 * as you can without harming your app's functionality. Note that 448 * size limits only apply when reading from an {@code InputStream}, not 449 * when constructed around a raw byte array. 450 * <p> 451 * If you want to read several messages from a single CodedInputStream, you 452 * could call {@link #resetSizeCounter()} after each one to avoid hitting the 453 * size limit. 454 * 455 * @return the old limit. 456 */ 457 public int setSizeLimit(final int limit) { 458 if (limit < 0) { 459 throw new IllegalArgumentException( 460 "Size limit cannot be negative: " + limit); 461 } 462 final int oldLimit = sizeLimit; 463 sizeLimit = limit; 464 return oldLimit; 465 } 466 467 /** 468 * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). 469 */ 470 public void resetSizeCounter() { 471 } 472 473 /** 474 * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This 475 * is called when descending into a length-delimited embedded message. 476 * 477 * @return the old limit. 478 */ 479 public int pushLimit(int byteLimit) throws InvalidProtocolBufferNanoException { 480 if (byteLimit < 0) { 481 throw InvalidProtocolBufferNanoException.negativeSize(); 482 } 483 byteLimit += bufferPos; 484 final int oldLimit = currentLimit; 485 if (byteLimit > oldLimit) { 486 throw InvalidProtocolBufferNanoException.truncatedMessage(); 487 } 488 currentLimit = byteLimit; 489 490 recomputeBufferSizeAfterLimit(); 491 492 return oldLimit; 493 } 494 495 private void recomputeBufferSizeAfterLimit() { 496 bufferSize += bufferSizeAfterLimit; 497 final int bufferEnd = bufferSize; 498 if (bufferEnd > currentLimit) { 499 // Limit is in current buffer. 500 bufferSizeAfterLimit = bufferEnd - currentLimit; 501 bufferSize -= bufferSizeAfterLimit; 502 } else { 503 bufferSizeAfterLimit = 0; 504 } 505 } 506 507 /** 508 * Discards the current limit, returning to the previous limit. 509 * 510 * @param oldLimit The old limit, as returned by {@code pushLimit}. 511 */ 512 public void popLimit(final int oldLimit) { 513 currentLimit = oldLimit; 514 recomputeBufferSizeAfterLimit(); 515 } 516 517 /** 518 * Returns the number of bytes to be read before the current limit. 519 * If no limit is set, returns -1. 520 */ 521 public int getBytesUntilLimit() { 522 if (currentLimit == Integer.MAX_VALUE) { 523 return -1; 524 } 525 526 final int currentAbsolutePosition = bufferPos; 527 return currentLimit - currentAbsolutePosition; 528 } 529 530 /** 531 * Returns true if the stream has reached the end of the input. This is the 532 * case if either the end of the underlying input source has been reached or 533 * if the stream has reached a limit created using {@link #pushLimit(int)}. 534 */ 535 public boolean isAtEnd() { 536 return bufferPos == bufferSize; 537 } 538 539 /** 540 * Get current position in buffer relative to beginning offset. 541 */ 542 public int getPosition() { 543 return bufferPos - bufferStart; 544 } 545 546 /** 547 * Get current (absolute) position in buffer. 548 */ 549 public int getAbsolutePosition() { 550 return bufferPos; 551 } 552 553 /** 554 * Return the raw underlying data in the buffer, directly. 555 */ 556 public byte[] getBuffer() { 557 return buffer; 558 } 559 560 /** 561 * Retrieves a subset of data in the buffer. The returned array is not backed by the original 562 * buffer array. 563 * 564 * @param offset the position (relative to the buffer start position) to start at. 565 * @param length the number of bytes to retrieve. 566 */ 567 public byte[] getData(int offset, int length) { 568 if (length == 0) { 569 return WireFormatNano.EMPTY_BYTES; 570 } 571 byte[] copy = new byte[length]; 572 int start = bufferStart + offset; 573 System.arraycopy(buffer, start, copy, 0, length); 574 return copy; 575 } 576 577 /** 578 * Rewind to previous position. Cannot go forward. 579 */ 580 public void rewindToPosition(int position) { 581 if (position > bufferPos - bufferStart) { 582 throw new IllegalArgumentException( 583 "Position " + position + " is beyond current " + (bufferPos - bufferStart)); 584 } 585 if (position < 0) { 586 throw new IllegalArgumentException("Bad position " + position); 587 } 588 bufferPos = bufferStart + position; 589 } 590 591 /** 592 * Read one byte from the input. 593 * 594 * @throws InvalidProtocolBufferNanoException The end of the stream or the current 595 * limit was reached. 596 */ 597 public byte readRawByte() throws IOException { 598 if (bufferPos == bufferSize) { 599 throw InvalidProtocolBufferNanoException.truncatedMessage(); 600 } 601 return buffer[bufferPos++]; 602 } 603 604 /** 605 * Read a fixed size of bytes from the input. 606 * 607 * @throws InvalidProtocolBufferNanoException The end of the stream or the current 608 * limit was reached. 609 */ 610 public byte[] readRawBytes(final int size) throws IOException { 611 if (size < 0) { 612 throw InvalidProtocolBufferNanoException.negativeSize(); 613 } 614 615 if (bufferPos + size > currentLimit) { 616 // Read to the end of the stream anyway. 617 skipRawBytes(currentLimit - bufferPos); 618 // Then fail. 619 throw InvalidProtocolBufferNanoException.truncatedMessage(); 620 } 621 622 if (size <= bufferSize - bufferPos) { 623 // We have all the bytes we need already. 624 final byte[] bytes = new byte[size]; 625 System.arraycopy(buffer, bufferPos, bytes, 0, size); 626 bufferPos += size; 627 return bytes; 628 } else { 629 throw InvalidProtocolBufferNanoException.truncatedMessage(); 630 } 631 } 632 633 /** 634 * Reads and discards {@code size} bytes. 635 * 636 * @throws InvalidProtocolBufferNanoException The end of the stream or the current 637 * limit was reached. 638 */ 639 public void skipRawBytes(final int size) throws IOException { 640 if (size < 0) { 641 throw InvalidProtocolBufferNanoException.negativeSize(); 642 } 643 644 if (bufferPos + size > currentLimit) { 645 // Read to the end of the stream anyway. 646 skipRawBytes(currentLimit - bufferPos); 647 // Then fail. 648 throw InvalidProtocolBufferNanoException.truncatedMessage(); 649 } 650 651 if (size <= bufferSize - bufferPos) { 652 // We have all the bytes we need already. 653 bufferPos += size; 654 } else { 655 throw InvalidProtocolBufferNanoException.truncatedMessage(); 656 } 657 } 658} 659