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 <= (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, "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), "UTF-8"); 199 } 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 <= (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 { 240 // Slow path: Build a byte array first then copy it. 241 return readRawBytes(size); 242 } 243 } 244 245 /** Read a {@code uint32} field value from the stream. */ 246 public int readUInt32() throws IOException { 247 return readRawVarint32(); 248 } 249 250 /** 251 * Read an enum field value from the stream. Caller is responsible 252 * for converting the numeric value to an actual enum. 253 */ 254 public int readEnum() throws IOException { 255 return readRawVarint32(); 256 } 257 258 /** Read an {@code sfixed32} field value from the stream. */ 259 public int readSFixed32() throws IOException { 260 return readRawLittleEndian32(); 261 } 262 263 /** Read an {@code sfixed64} field value from the stream. */ 264 public long readSFixed64() throws IOException { 265 return readRawLittleEndian64(); 266 } 267 268 /** Read an {@code sint32} field value from the stream. */ 269 public int readSInt32() throws IOException { 270 return decodeZigZag32(readRawVarint32()); 271 } 272 273 /** Read an {@code sint64} field value from the stream. */ 274 public long readSInt64() throws IOException { 275 return decodeZigZag64(readRawVarint64()); 276 } 277 278 // ================================================================= 279 280 /** 281 * Read a raw Varint from the stream. If larger than 32 bits, discard the 282 * upper bits. 283 */ 284 public int readRawVarint32() throws IOException { 285 byte tmp = readRawByte(); 286 if (tmp >= 0) { 287 return tmp; 288 } 289 int result = tmp & 0x7f; 290 if ((tmp = readRawByte()) >= 0) { 291 result |= tmp << 7; 292 } else { 293 result |= (tmp & 0x7f) << 7; 294 if ((tmp = readRawByte()) >= 0) { 295 result |= tmp << 14; 296 } else { 297 result |= (tmp & 0x7f) << 14; 298 if ((tmp = readRawByte()) >= 0) { 299 result |= tmp << 21; 300 } else { 301 result |= (tmp & 0x7f) << 21; 302 result |= (tmp = readRawByte()) << 28; 303 if (tmp < 0) { 304 // Discard upper 32 bits. 305 for (int i = 0; i < 5; i++) { 306 if (readRawByte() >= 0) { 307 return result; 308 } 309 } 310 throw InvalidProtocolBufferNanoException.malformedVarint(); 311 } 312 } 313 } 314 } 315 return result; 316 } 317 318 /** Read a raw Varint from the stream. */ 319 public long readRawVarint64() throws IOException { 320 int shift = 0; 321 long result = 0; 322 while (shift < 64) { 323 final byte b = readRawByte(); 324 result |= (long)(b & 0x7F) << shift; 325 if ((b & 0x80) == 0) { 326 return result; 327 } 328 shift += 7; 329 } 330 throw InvalidProtocolBufferNanoException.malformedVarint(); 331 } 332 333 /** Read a 32-bit little-endian integer from the stream. */ 334 public int readRawLittleEndian32() throws IOException { 335 final byte b1 = readRawByte(); 336 final byte b2 = readRawByte(); 337 final byte b3 = readRawByte(); 338 final byte b4 = readRawByte(); 339 return ((b1 & 0xff) ) | 340 ((b2 & 0xff) << 8) | 341 ((b3 & 0xff) << 16) | 342 ((b4 & 0xff) << 24); 343 } 344 345 /** Read a 64-bit little-endian integer from the stream. */ 346 public long readRawLittleEndian64() throws IOException { 347 final byte b1 = readRawByte(); 348 final byte b2 = readRawByte(); 349 final byte b3 = readRawByte(); 350 final byte b4 = readRawByte(); 351 final byte b5 = readRawByte(); 352 final byte b6 = readRawByte(); 353 final byte b7 = readRawByte(); 354 final byte b8 = readRawByte(); 355 return (((long)b1 & 0xff) ) | 356 (((long)b2 & 0xff) << 8) | 357 (((long)b3 & 0xff) << 16) | 358 (((long)b4 & 0xff) << 24) | 359 (((long)b5 & 0xff) << 32) | 360 (((long)b6 & 0xff) << 40) | 361 (((long)b7 & 0xff) << 48) | 362 (((long)b8 & 0xff) << 56); 363 } 364 365 /** 366 * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers 367 * into values that can be efficiently encoded with varint. (Otherwise, 368 * negative values must be sign-extended to 64 bits to be varint encoded, 369 * thus always taking 10 bytes on the wire.) 370 * 371 * @param n An unsigned 32-bit integer, stored in a signed int because 372 * Java has no explicit unsigned support. 373 * @return A signed 32-bit integer. 374 */ 375 public static int decodeZigZag32(final int n) { 376 return (n >>> 1) ^ -(n & 1); 377 } 378 379 /** 380 * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers 381 * into values that can be efficiently encoded with varint. (Otherwise, 382 * negative values must be sign-extended to 64 bits to be varint encoded, 383 * thus always taking 10 bytes on the wire.) 384 * 385 * @param n An unsigned 64-bit integer, stored in a signed int because 386 * Java has no explicit unsigned support. 387 * @return A signed 64-bit integer. 388 */ 389 public static long decodeZigZag64(final long n) { 390 return (n >>> 1) ^ -(n & 1); 391 } 392 393 // ----------------------------------------------------------------- 394 395 private final byte[] buffer; 396 private int bufferStart; 397 private int bufferSize; 398 private int bufferSizeAfterLimit; 399 private int bufferPos; 400 private int lastTag; 401 402 /** The absolute position of the end of the current message. */ 403 private int currentLimit = Integer.MAX_VALUE; 404 405 /** See setRecursionLimit() */ 406 private int recursionDepth; 407 private int recursionLimit = DEFAULT_RECURSION_LIMIT; 408 409 /** See setSizeLimit() */ 410 private int sizeLimit = DEFAULT_SIZE_LIMIT; 411 412 private static final int DEFAULT_RECURSION_LIMIT = 64; 413 private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB 414 415 private CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) { 416 this.buffer = buffer; 417 bufferStart = off; 418 bufferSize = off + len; 419 bufferPos = off; 420 } 421 422 /** 423 * Set the maximum message recursion depth. In order to prevent malicious 424 * messages from causing stack overflows, {@code CodedInputStream} limits 425 * how deeply messages may be nested. The default limit is 64. 426 * 427 * @return the old limit. 428 */ 429 public int setRecursionLimit(final int limit) { 430 if (limit < 0) { 431 throw new IllegalArgumentException( 432 "Recursion limit cannot be negative: " + limit); 433 } 434 final int oldLimit = recursionLimit; 435 recursionLimit = limit; 436 return oldLimit; 437 } 438 439 /** 440 * Set the maximum message size. In order to prevent malicious 441 * messages from exhausting memory or causing integer overflows, 442 * {@code CodedInputStream} limits how large a message may be. 443 * The default limit is 64MB. You should set this limit as small 444 * as you can without harming your app's functionality. Note that 445 * size limits only apply when reading from an {@code InputStream}, not 446 * when constructed around a raw byte array. 447 * <p> 448 * If you want to read several messages from a single CodedInputStream, you 449 * could call {@link #resetSizeCounter()} after each one to avoid hitting the 450 * size limit. 451 * 452 * @return the old limit. 453 */ 454 public int setSizeLimit(final int limit) { 455 if (limit < 0) { 456 throw new IllegalArgumentException( 457 "Size limit cannot be negative: " + limit); 458 } 459 final int oldLimit = sizeLimit; 460 sizeLimit = limit; 461 return oldLimit; 462 } 463 464 /** 465 * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). 466 */ 467 public void resetSizeCounter() { 468 } 469 470 /** 471 * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This 472 * is called when descending into a length-delimited embedded message. 473 * 474 * @return the old limit. 475 */ 476 public int pushLimit(int byteLimit) throws InvalidProtocolBufferNanoException { 477 if (byteLimit < 0) { 478 throw InvalidProtocolBufferNanoException.negativeSize(); 479 } 480 byteLimit += bufferPos; 481 final int oldLimit = currentLimit; 482 if (byteLimit > oldLimit) { 483 throw InvalidProtocolBufferNanoException.truncatedMessage(); 484 } 485 currentLimit = byteLimit; 486 487 recomputeBufferSizeAfterLimit(); 488 489 return oldLimit; 490 } 491 492 private void recomputeBufferSizeAfterLimit() { 493 bufferSize += bufferSizeAfterLimit; 494 final int bufferEnd = bufferSize; 495 if (bufferEnd > currentLimit) { 496 // Limit is in current buffer. 497 bufferSizeAfterLimit = bufferEnd - currentLimit; 498 bufferSize -= bufferSizeAfterLimit; 499 } else { 500 bufferSizeAfterLimit = 0; 501 } 502 } 503 504 /** 505 * Discards the current limit, returning to the previous limit. 506 * 507 * @param oldLimit The old limit, as returned by {@code pushLimit}. 508 */ 509 public void popLimit(final int oldLimit) { 510 currentLimit = oldLimit; 511 recomputeBufferSizeAfterLimit(); 512 } 513 514 /** 515 * Returns the number of bytes to be read before the current limit. 516 * If no limit is set, returns -1. 517 */ 518 public int getBytesUntilLimit() { 519 if (currentLimit == Integer.MAX_VALUE) { 520 return -1; 521 } 522 523 final int currentAbsolutePosition = bufferPos; 524 return currentLimit - currentAbsolutePosition; 525 } 526 527 /** 528 * Returns true if the stream has reached the end of the input. This is the 529 * case if either the end of the underlying input source has been reached or 530 * if the stream has reached a limit created using {@link #pushLimit(int)}. 531 */ 532 public boolean isAtEnd() { 533 return bufferPos == bufferSize; 534 } 535 536 /** 537 * Get current position in buffer relative to beginning offset. 538 */ 539 public int getPosition() { 540 return bufferPos - bufferStart; 541 } 542 543 /** 544 * Retrieves a subset of data in the buffer. The returned array is not backed by the original 545 * buffer array. 546 * 547 * @param offset the position (relative to the buffer start position) to start at. 548 * @param length the number of bytes to retrieve. 549 */ 550 public byte[] getData(int offset, int length) { 551 if (length == 0) { 552 return WireFormatNano.EMPTY_BYTES; 553 } 554 byte[] copy = new byte[length]; 555 int start = bufferStart + offset; 556 System.arraycopy(buffer, start, copy, 0, length); 557 return copy; 558 } 559 560 /** 561 * Rewind to previous position. Cannot go forward. 562 */ 563 public void rewindToPosition(int position) { 564 if (position > bufferPos - bufferStart) { 565 throw new IllegalArgumentException( 566 "Position " + position + " is beyond current " + (bufferPos - bufferStart)); 567 } 568 if (position < 0) { 569 throw new IllegalArgumentException("Bad position " + position); 570 } 571 bufferPos = bufferStart + position; 572 } 573 574 /** 575 * Read one byte from the input. 576 * 577 * @throws InvalidProtocolBufferNanoException The end of the stream or the current 578 * limit was reached. 579 */ 580 public byte readRawByte() throws IOException { 581 if (bufferPos == bufferSize) { 582 throw InvalidProtocolBufferNanoException.truncatedMessage(); 583 } 584 return buffer[bufferPos++]; 585 } 586 587 /** 588 * Read a fixed size of bytes from the input. 589 * 590 * @throws InvalidProtocolBufferNanoException The end of the stream or the current 591 * limit was reached. 592 */ 593 public byte[] readRawBytes(final int size) throws IOException { 594 if (size < 0) { 595 throw InvalidProtocolBufferNanoException.negativeSize(); 596 } 597 598 if (bufferPos + size > currentLimit) { 599 // Read to the end of the stream anyway. 600 skipRawBytes(currentLimit - bufferPos); 601 // Then fail. 602 throw InvalidProtocolBufferNanoException.truncatedMessage(); 603 } 604 605 if (size <= bufferSize - bufferPos) { 606 // We have all the bytes we need already. 607 final byte[] bytes = new byte[size]; 608 System.arraycopy(buffer, bufferPos, bytes, 0, size); 609 bufferPos += size; 610 return bytes; 611 } else { 612 throw InvalidProtocolBufferNanoException.truncatedMessage(); 613 } 614 } 615 616 /** 617 * Reads and discards {@code size} bytes. 618 * 619 * @throws InvalidProtocolBufferNanoException The end of the stream or the current 620 * limit was reached. 621 */ 622 public void skipRawBytes(final int size) throws IOException { 623 if (size < 0) { 624 throw InvalidProtocolBufferNanoException.negativeSize(); 625 } 626 627 if (bufferPos + size > currentLimit) { 628 // Read to the end of the stream anyway. 629 skipRawBytes(currentLimit - bufferPos); 630 // Then fail. 631 throw InvalidProtocolBufferNanoException.truncatedMessage(); 632 } 633 634 if (size <= bufferSize - bufferPos) { 635 // We have all the bytes we need already. 636 bufferPos += size; 637 } else { 638 throw InvalidProtocolBufferNanoException.truncatedMessage(); 639 } 640 } 641} 642