| Index: third_party/protobuf/java/src/main/java/com/google/protobuf/CodedInputStream.java
|
| diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/CodedInputStream.java b/third_party/protobuf/java/src/main/java/com/google/protobuf/CodedInputStream.java
|
| deleted file mode 100644
|
| index 33417a7ffe31c3d40d2171b7ba4efd4ea46038a8..0000000000000000000000000000000000000000
|
| --- a/third_party/protobuf/java/src/main/java/com/google/protobuf/CodedInputStream.java
|
| +++ /dev/null
|
| @@ -1,920 +0,0 @@
|
| -// Protocol Buffers - Google's data interchange format
|
| -// Copyright 2008 Google Inc. All rights reserved.
|
| -// http://code.google.com/p/protobuf/
|
| -//
|
| -// Redistribution and use in source and binary forms, with or without
|
| -// modification, are permitted provided that the following conditions are
|
| -// met:
|
| -//
|
| -// * Redistributions of source code must retain the above copyright
|
| -// notice, this list of conditions and the following disclaimer.
|
| -// * Redistributions in binary form must reproduce the above
|
| -// copyright notice, this list of conditions and the following disclaimer
|
| -// in the documentation and/or other materials provided with the
|
| -// distribution.
|
| -// * Neither the name of Google Inc. nor the names of its
|
| -// contributors may be used to endorse or promote products derived from
|
| -// this software without specific prior written permission.
|
| -//
|
| -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| -
|
| -package com.google.protobuf;
|
| -
|
| -import java.io.IOException;
|
| -import java.io.InputStream;
|
| -import java.util.ArrayList;
|
| -import java.util.List;
|
| -
|
| -/**
|
| - * Reads and decodes protocol message fields.
|
| - *
|
| - * This class contains two kinds of methods: methods that read specific
|
| - * protocol message constructs and field types (e.g. {@link #readTag()} and
|
| - * {@link #readInt32()}) and methods that read low-level values (e.g.
|
| - * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
|
| - * encoded protocol messages, you should use the former methods, but if you are
|
| - * reading some other format of your own design, use the latter.
|
| - *
|
| - * @author kenton@google.com Kenton Varda
|
| - */
|
| -public final class CodedInputStream {
|
| - /**
|
| - * Create a new CodedInputStream wrapping the given InputStream.
|
| - */
|
| - public static CodedInputStream newInstance(final InputStream input) {
|
| - return new CodedInputStream(input);
|
| - }
|
| -
|
| - /**
|
| - * Create a new CodedInputStream wrapping the given byte array.
|
| - */
|
| - public static CodedInputStream newInstance(final byte[] buf) {
|
| - return newInstance(buf, 0, buf.length);
|
| - }
|
| -
|
| - /**
|
| - * Create a new CodedInputStream wrapping the given byte array slice.
|
| - */
|
| - public static CodedInputStream newInstance(final byte[] buf, final int off,
|
| - final int len) {
|
| - CodedInputStream result = new CodedInputStream(buf, off, len);
|
| - try {
|
| - // Some uses of CodedInputStream can be more efficient if they know
|
| - // exactly how many bytes are available. By pushing the end point of the
|
| - // buffer as a limit, we allow them to get this information via
|
| - // getBytesUntilLimit(). Pushing a limit that we know is at the end of
|
| - // the stream can never hurt, since we can never past that point anyway.
|
| - result.pushLimit(len);
|
| - } catch (InvalidProtocolBufferException ex) {
|
| - // The only reason pushLimit() might throw an exception here is if len
|
| - // is negative. Normally pushLimit()'s parameter comes directly off the
|
| - // wire, so it's important to catch exceptions in case of corrupt or
|
| - // malicious data. However, in this case, we expect that len is not a
|
| - // user-supplied value, so we can assume that it being negative indicates
|
| - // a programming error. Therefore, throwing an unchecked exception is
|
| - // appropriate.
|
| - throw new IllegalArgumentException(ex);
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - // -----------------------------------------------------------------
|
| -
|
| - /**
|
| - * Attempt to read a field tag, returning zero if we have reached EOF.
|
| - * Protocol message parsers use this to read tags, since a protocol message
|
| - * may legally end wherever a tag occurs, and zero is not a valid tag number.
|
| - */
|
| - public int readTag() throws IOException {
|
| - if (isAtEnd()) {
|
| - lastTag = 0;
|
| - return 0;
|
| - }
|
| -
|
| - lastTag = readRawVarint32();
|
| - if (WireFormat.getTagFieldNumber(lastTag) == 0) {
|
| - // If we actually read zero (or any tag number corresponding to field
|
| - // number zero), that's not a valid tag.
|
| - throw InvalidProtocolBufferException.invalidTag();
|
| - }
|
| - return lastTag;
|
| - }
|
| -
|
| - /**
|
| - * Verifies that the last call to readTag() returned the given tag value.
|
| - * This is used to verify that a nested group ended with the correct
|
| - * end tag.
|
| - *
|
| - * @throws InvalidProtocolBufferException {@code value} does not match the
|
| - * last tag.
|
| - */
|
| - public void checkLastTagWas(final int value)
|
| - throws InvalidProtocolBufferException {
|
| - if (lastTag != value) {
|
| - throw InvalidProtocolBufferException.invalidEndTag();
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Reads and discards a single field, given its tag value.
|
| - *
|
| - * @return {@code false} if the tag is an endgroup tag, in which case
|
| - * nothing is skipped. Otherwise, returns {@code true}.
|
| - */
|
| - public boolean skipField(final int tag) throws IOException {
|
| - switch (WireFormat.getTagWireType(tag)) {
|
| - case WireFormat.WIRETYPE_VARINT:
|
| - readInt32();
|
| - return true;
|
| - case WireFormat.WIRETYPE_FIXED64:
|
| - readRawLittleEndian64();
|
| - return true;
|
| - case WireFormat.WIRETYPE_LENGTH_DELIMITED:
|
| - skipRawBytes(readRawVarint32());
|
| - return true;
|
| - case WireFormat.WIRETYPE_START_GROUP:
|
| - skipMessage();
|
| - checkLastTagWas(
|
| - WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
|
| - WireFormat.WIRETYPE_END_GROUP));
|
| - return true;
|
| - case WireFormat.WIRETYPE_END_GROUP:
|
| - return false;
|
| - case WireFormat.WIRETYPE_FIXED32:
|
| - readRawLittleEndian32();
|
| - return true;
|
| - default:
|
| - throw InvalidProtocolBufferException.invalidWireType();
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Reads and discards an entire message. This will read either until EOF
|
| - * or until an endgroup tag, whichever comes first.
|
| - */
|
| - public void skipMessage() throws IOException {
|
| - while (true) {
|
| - final int tag = readTag();
|
| - if (tag == 0 || !skipField(tag)) {
|
| - return;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // -----------------------------------------------------------------
|
| -
|
| - /** Read a {@code double} field value from the stream. */
|
| - public double readDouble() throws IOException {
|
| - return Double.longBitsToDouble(readRawLittleEndian64());
|
| - }
|
| -
|
| - /** Read a {@code float} field value from the stream. */
|
| - public float readFloat() throws IOException {
|
| - return Float.intBitsToFloat(readRawLittleEndian32());
|
| - }
|
| -
|
| - /** Read a {@code uint64} field value from the stream. */
|
| - public long readUInt64() throws IOException {
|
| - return readRawVarint64();
|
| - }
|
| -
|
| - /** Read an {@code int64} field value from the stream. */
|
| - public long readInt64() throws IOException {
|
| - return readRawVarint64();
|
| - }
|
| -
|
| - /** Read an {@code int32} field value from the stream. */
|
| - public int readInt32() throws IOException {
|
| - return readRawVarint32();
|
| - }
|
| -
|
| - /** Read a {@code fixed64} field value from the stream. */
|
| - public long readFixed64() throws IOException {
|
| - return readRawLittleEndian64();
|
| - }
|
| -
|
| - /** Read a {@code fixed32} field value from the stream. */
|
| - public int readFixed32() throws IOException {
|
| - return readRawLittleEndian32();
|
| - }
|
| -
|
| - /** Read a {@code bool} field value from the stream. */
|
| - public boolean readBool() throws IOException {
|
| - return readRawVarint32() != 0;
|
| - }
|
| -
|
| - /** Read a {@code string} field value from the stream. */
|
| - public String readString() throws IOException {
|
| - final int size = readRawVarint32();
|
| - if (size <= (bufferSize - bufferPos) && size > 0) {
|
| - // Fast path: We already have the bytes in a contiguous buffer, so
|
| - // just copy directly from it.
|
| - final String result = new String(buffer, bufferPos, size, "UTF-8");
|
| - bufferPos += size;
|
| - return result;
|
| - } else {
|
| - // Slow path: Build a byte array first then copy it.
|
| - return new String(readRawBytes(size), "UTF-8");
|
| - }
|
| - }
|
| -
|
| - /** Read a {@code group} field value from the stream. */
|
| - public void readGroup(final int fieldNumber,
|
| - final MessageLite.Builder builder,
|
| - final ExtensionRegistryLite extensionRegistry)
|
| - throws IOException {
|
| - if (recursionDepth >= recursionLimit) {
|
| - throw InvalidProtocolBufferException.recursionLimitExceeded();
|
| - }
|
| - ++recursionDepth;
|
| - builder.mergeFrom(this, extensionRegistry);
|
| - checkLastTagWas(
|
| - WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
|
| - --recursionDepth;
|
| - }
|
| -
|
| - /** Read a {@code group} field value from the stream. */
|
| - public <T extends MessageLite> T readGroup(
|
| - final int fieldNumber,
|
| - final Parser<T> parser,
|
| - final ExtensionRegistryLite extensionRegistry)
|
| - throws IOException {
|
| - if (recursionDepth >= recursionLimit) {
|
| - throw InvalidProtocolBufferException.recursionLimitExceeded();
|
| - }
|
| - ++recursionDepth;
|
| - T result = parser.parsePartialFrom(this, extensionRegistry);
|
| - checkLastTagWas(
|
| - WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
|
| - --recursionDepth;
|
| - return result;
|
| - }
|
| -
|
| - /**
|
| - * Reads a {@code group} field value from the stream and merges it into the
|
| - * given {@link UnknownFieldSet}.
|
| - *
|
| - * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
|
| - * you can just call {@link #readGroup}.
|
| - */
|
| - @Deprecated
|
| - public void readUnknownGroup(final int fieldNumber,
|
| - final MessageLite.Builder builder)
|
| - throws IOException {
|
| - // We know that UnknownFieldSet will ignore any ExtensionRegistry so it
|
| - // is safe to pass null here. (We can't call
|
| - // ExtensionRegistry.getEmptyRegistry() because that would make this
|
| - // class depend on ExtensionRegistry, which is not part of the lite
|
| - // library.)
|
| - readGroup(fieldNumber, builder, null);
|
| - }
|
| -
|
| - /** Read an embedded message field value from the stream. */
|
| - public void readMessage(final MessageLite.Builder builder,
|
| - final ExtensionRegistryLite extensionRegistry)
|
| - throws IOException {
|
| - final int length = readRawVarint32();
|
| - if (recursionDepth >= recursionLimit) {
|
| - throw InvalidProtocolBufferException.recursionLimitExceeded();
|
| - }
|
| - final int oldLimit = pushLimit(length);
|
| - ++recursionDepth;
|
| - builder.mergeFrom(this, extensionRegistry);
|
| - checkLastTagWas(0);
|
| - --recursionDepth;
|
| - popLimit(oldLimit);
|
| - }
|
| -
|
| - /** Read an embedded message field value from the stream. */
|
| - public <T extends MessageLite> T readMessage(
|
| - final Parser<T> parser,
|
| - final ExtensionRegistryLite extensionRegistry)
|
| - throws IOException {
|
| - int length = readRawVarint32();
|
| - if (recursionDepth >= recursionLimit) {
|
| - throw InvalidProtocolBufferException.recursionLimitExceeded();
|
| - }
|
| - final int oldLimit = pushLimit(length);
|
| - ++recursionDepth;
|
| - T result = parser.parsePartialFrom(this, extensionRegistry);
|
| - checkLastTagWas(0);
|
| - --recursionDepth;
|
| - popLimit(oldLimit);
|
| - return result;
|
| - }
|
| -
|
| - /** Read a {@code bytes} field value from the stream. */
|
| - public ByteString readBytes() throws IOException {
|
| - final int size = readRawVarint32();
|
| - if (size == 0) {
|
| - return ByteString.EMPTY;
|
| - } else if (size <= (bufferSize - bufferPos) && size > 0) {
|
| - // Fast path: We already have the bytes in a contiguous buffer, so
|
| - // just copy directly from it.
|
| - final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
|
| - bufferPos += size;
|
| - return result;
|
| - } else {
|
| - // Slow path: Build a byte array first then copy it.
|
| - return ByteString.copyFrom(readRawBytes(size));
|
| - }
|
| - }
|
| -
|
| - /** Read a {@code uint32} field value from the stream. */
|
| - public int readUInt32() throws IOException {
|
| - return readRawVarint32();
|
| - }
|
| -
|
| - /**
|
| - * Read an enum field value from the stream. Caller is responsible
|
| - * for converting the numeric value to an actual enum.
|
| - */
|
| - public int readEnum() throws IOException {
|
| - return readRawVarint32();
|
| - }
|
| -
|
| - /** Read an {@code sfixed32} field value from the stream. */
|
| - public int readSFixed32() throws IOException {
|
| - return readRawLittleEndian32();
|
| - }
|
| -
|
| - /** Read an {@code sfixed64} field value from the stream. */
|
| - public long readSFixed64() throws IOException {
|
| - return readRawLittleEndian64();
|
| - }
|
| -
|
| - /** Read an {@code sint32} field value from the stream. */
|
| - public int readSInt32() throws IOException {
|
| - return decodeZigZag32(readRawVarint32());
|
| - }
|
| -
|
| - /** Read an {@code sint64} field value from the stream. */
|
| - public long readSInt64() throws IOException {
|
| - return decodeZigZag64(readRawVarint64());
|
| - }
|
| -
|
| - // =================================================================
|
| -
|
| - /**
|
| - * Read a raw Varint from the stream. If larger than 32 bits, discard the
|
| - * upper bits.
|
| - */
|
| - public int readRawVarint32() throws IOException {
|
| - byte tmp = readRawByte();
|
| - if (tmp >= 0) {
|
| - return tmp;
|
| - }
|
| - int result = tmp & 0x7f;
|
| - if ((tmp = readRawByte()) >= 0) {
|
| - result |= tmp << 7;
|
| - } else {
|
| - result |= (tmp & 0x7f) << 7;
|
| - if ((tmp = readRawByte()) >= 0) {
|
| - result |= tmp << 14;
|
| - } else {
|
| - result |= (tmp & 0x7f) << 14;
|
| - if ((tmp = readRawByte()) >= 0) {
|
| - result |= tmp << 21;
|
| - } else {
|
| - result |= (tmp & 0x7f) << 21;
|
| - result |= (tmp = readRawByte()) << 28;
|
| - if (tmp < 0) {
|
| - // Discard upper 32 bits.
|
| - for (int i = 0; i < 5; i++) {
|
| - if (readRawByte() >= 0) {
|
| - return result;
|
| - }
|
| - }
|
| - throw InvalidProtocolBufferException.malformedVarint();
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - /**
|
| - * Reads a varint from the input one byte at a time, so that it does not
|
| - * read any bytes after the end of the varint. If you simply wrapped the
|
| - * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
|
| - * then you would probably end up reading past the end of the varint since
|
| - * CodedInputStream buffers its input.
|
| - */
|
| - static int readRawVarint32(final InputStream input) throws IOException {
|
| - final int firstByte = input.read();
|
| - if (firstByte == -1) {
|
| - throw InvalidProtocolBufferException.truncatedMessage();
|
| - }
|
| - return readRawVarint32(firstByte, input);
|
| - }
|
| -
|
| - /**
|
| - * Like {@link #readRawVarint32(InputStream)}, but expects that the caller
|
| - * has already read one byte. This allows the caller to determine if EOF
|
| - * has been reached before attempting to read.
|
| - */
|
| - public static int readRawVarint32(
|
| - final int firstByte, final InputStream input) throws IOException {
|
| - if ((firstByte & 0x80) == 0) {
|
| - return firstByte;
|
| - }
|
| -
|
| - int result = firstByte & 0x7f;
|
| - int offset = 7;
|
| - for (; offset < 32; offset += 7) {
|
| - final int b = input.read();
|
| - if (b == -1) {
|
| - throw InvalidProtocolBufferException.truncatedMessage();
|
| - }
|
| - result |= (b & 0x7f) << offset;
|
| - if ((b & 0x80) == 0) {
|
| - return result;
|
| - }
|
| - }
|
| - // Keep reading up to 64 bits.
|
| - for (; offset < 64; offset += 7) {
|
| - final int b = input.read();
|
| - if (b == -1) {
|
| - throw InvalidProtocolBufferException.truncatedMessage();
|
| - }
|
| - if ((b & 0x80) == 0) {
|
| - return result;
|
| - }
|
| - }
|
| - throw InvalidProtocolBufferException.malformedVarint();
|
| - }
|
| -
|
| - /** Read a raw Varint from the stream. */
|
| - public long readRawVarint64() throws IOException {
|
| - int shift = 0;
|
| - long result = 0;
|
| - while (shift < 64) {
|
| - final byte b = readRawByte();
|
| - result |= (long)(b & 0x7F) << shift;
|
| - if ((b & 0x80) == 0) {
|
| - return result;
|
| - }
|
| - shift += 7;
|
| - }
|
| - throw InvalidProtocolBufferException.malformedVarint();
|
| - }
|
| -
|
| - /** Read a 32-bit little-endian integer from the stream. */
|
| - public int readRawLittleEndian32() throws IOException {
|
| - final byte b1 = readRawByte();
|
| - final byte b2 = readRawByte();
|
| - final byte b3 = readRawByte();
|
| - final byte b4 = readRawByte();
|
| - return (((int)b1 & 0xff) ) |
|
| - (((int)b2 & 0xff) << 8) |
|
| - (((int)b3 & 0xff) << 16) |
|
| - (((int)b4 & 0xff) << 24);
|
| - }
|
| -
|
| - /** Read a 64-bit little-endian integer from the stream. */
|
| - public long readRawLittleEndian64() throws IOException {
|
| - final byte b1 = readRawByte();
|
| - final byte b2 = readRawByte();
|
| - final byte b3 = readRawByte();
|
| - final byte b4 = readRawByte();
|
| - final byte b5 = readRawByte();
|
| - final byte b6 = readRawByte();
|
| - final byte b7 = readRawByte();
|
| - final byte b8 = readRawByte();
|
| - return (((long)b1 & 0xff) ) |
|
| - (((long)b2 & 0xff) << 8) |
|
| - (((long)b3 & 0xff) << 16) |
|
| - (((long)b4 & 0xff) << 24) |
|
| - (((long)b5 & 0xff) << 32) |
|
| - (((long)b6 & 0xff) << 40) |
|
| - (((long)b7 & 0xff) << 48) |
|
| - (((long)b8 & 0xff) << 56);
|
| - }
|
| -
|
| - /**
|
| - * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
|
| - * into values that can be efficiently encoded with varint. (Otherwise,
|
| - * negative values must be sign-extended to 64 bits to be varint encoded,
|
| - * thus always taking 10 bytes on the wire.)
|
| - *
|
| - * @param n An unsigned 32-bit integer, stored in a signed int because
|
| - * Java has no explicit unsigned support.
|
| - * @return A signed 32-bit integer.
|
| - */
|
| - public static int decodeZigZag32(final int n) {
|
| - return (n >>> 1) ^ -(n & 1);
|
| - }
|
| -
|
| - /**
|
| - * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
|
| - * into values that can be efficiently encoded with varint. (Otherwise,
|
| - * negative values must be sign-extended to 64 bits to be varint encoded,
|
| - * thus always taking 10 bytes on the wire.)
|
| - *
|
| - * @param n An unsigned 64-bit integer, stored in a signed int because
|
| - * Java has no explicit unsigned support.
|
| - * @return A signed 64-bit integer.
|
| - */
|
| - public static long decodeZigZag64(final long n) {
|
| - return (n >>> 1) ^ -(n & 1);
|
| - }
|
| -
|
| - // -----------------------------------------------------------------
|
| -
|
| - private final byte[] buffer;
|
| - private int bufferSize;
|
| - private int bufferSizeAfterLimit;
|
| - private int bufferPos;
|
| - private final InputStream input;
|
| - private int lastTag;
|
| -
|
| - /**
|
| - * The total number of bytes read before the current buffer. The total
|
| - * bytes read up to the current position can be computed as
|
| - * {@code totalBytesRetired + bufferPos}. This value may be negative if
|
| - * reading started in the middle of the current buffer (e.g. if the
|
| - * constructor that takes a byte array and an offset was used).
|
| - */
|
| - private int totalBytesRetired;
|
| -
|
| - /** The absolute position of the end of the current message. */
|
| - private int currentLimit = Integer.MAX_VALUE;
|
| -
|
| - /** See setRecursionLimit() */
|
| - private int recursionDepth;
|
| - private int recursionLimit = DEFAULT_RECURSION_LIMIT;
|
| -
|
| - /** See setSizeLimit() */
|
| - private int sizeLimit = DEFAULT_SIZE_LIMIT;
|
| -
|
| - private static final int DEFAULT_RECURSION_LIMIT = 64;
|
| - private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
|
| - private static final int BUFFER_SIZE = 4096;
|
| -
|
| - private CodedInputStream(final byte[] buffer, final int off, final int len) {
|
| - this.buffer = buffer;
|
| - bufferSize = off + len;
|
| - bufferPos = off;
|
| - totalBytesRetired = -off;
|
| - input = null;
|
| - }
|
| -
|
| - private CodedInputStream(final InputStream input) {
|
| - buffer = new byte[BUFFER_SIZE];
|
| - bufferSize = 0;
|
| - bufferPos = 0;
|
| - totalBytesRetired = 0;
|
| - this.input = input;
|
| - }
|
| -
|
| - /**
|
| - * Set the maximum message recursion depth. In order to prevent malicious
|
| - * messages from causing stack overflows, {@code CodedInputStream} limits
|
| - * how deeply messages may be nested. The default limit is 64.
|
| - *
|
| - * @return the old limit.
|
| - */
|
| - public int setRecursionLimit(final int limit) {
|
| - if (limit < 0) {
|
| - throw new IllegalArgumentException(
|
| - "Recursion limit cannot be negative: " + limit);
|
| - }
|
| - final int oldLimit = recursionLimit;
|
| - recursionLimit = limit;
|
| - return oldLimit;
|
| - }
|
| -
|
| - /**
|
| - * Set the maximum message size. In order to prevent malicious
|
| - * messages from exhausting memory or causing integer overflows,
|
| - * {@code CodedInputStream} limits how large a message may be.
|
| - * The default limit is 64MB. You should set this limit as small
|
| - * as you can without harming your app's functionality. Note that
|
| - * size limits only apply when reading from an {@code InputStream}, not
|
| - * when constructed around a raw byte array (nor with
|
| - * {@link ByteString#newCodedInput}).
|
| - * <p>
|
| - * If you want to read several messages from a single CodedInputStream, you
|
| - * could call {@link #resetSizeCounter()} after each one to avoid hitting the
|
| - * size limit.
|
| - *
|
| - * @return the old limit.
|
| - */
|
| - public int setSizeLimit(final int limit) {
|
| - if (limit < 0) {
|
| - throw new IllegalArgumentException(
|
| - "Size limit cannot be negative: " + limit);
|
| - }
|
| - final int oldLimit = sizeLimit;
|
| - sizeLimit = limit;
|
| - return oldLimit;
|
| - }
|
| -
|
| - /**
|
| - * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
|
| - */
|
| - public void resetSizeCounter() {
|
| - totalBytesRetired = -bufferPos;
|
| - }
|
| -
|
| - /**
|
| - * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This
|
| - * is called when descending into a length-delimited embedded message.
|
| - *
|
| - * <p>Note that {@code pushLimit()} does NOT affect how many bytes the
|
| - * {@code CodedInputStream} reads from an underlying {@code InputStream} when
|
| - * refreshing its buffer. If you need to prevent reading past a certain
|
| - * point in the underlying {@code InputStream} (e.g. because you expect it to
|
| - * contain more data after the end of the message which you need to handle
|
| - * differently) then you must place a wrapper around your {@code InputStream}
|
| - * which limits the amount of data that can be read from it.
|
| - *
|
| - * @return the old limit.
|
| - */
|
| - public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
|
| - if (byteLimit < 0) {
|
| - throw InvalidProtocolBufferException.negativeSize();
|
| - }
|
| - byteLimit += totalBytesRetired + bufferPos;
|
| - final int oldLimit = currentLimit;
|
| - if (byteLimit > oldLimit) {
|
| - throw InvalidProtocolBufferException.truncatedMessage();
|
| - }
|
| - currentLimit = byteLimit;
|
| -
|
| - recomputeBufferSizeAfterLimit();
|
| -
|
| - return oldLimit;
|
| - }
|
| -
|
| - private void recomputeBufferSizeAfterLimit() {
|
| - bufferSize += bufferSizeAfterLimit;
|
| - final int bufferEnd = totalBytesRetired + bufferSize;
|
| - if (bufferEnd > currentLimit) {
|
| - // Limit is in current buffer.
|
| - bufferSizeAfterLimit = bufferEnd - currentLimit;
|
| - bufferSize -= bufferSizeAfterLimit;
|
| - } else {
|
| - bufferSizeAfterLimit = 0;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Discards the current limit, returning to the previous limit.
|
| - *
|
| - * @param oldLimit The old limit, as returned by {@code pushLimit}.
|
| - */
|
| - public void popLimit(final int oldLimit) {
|
| - currentLimit = oldLimit;
|
| - recomputeBufferSizeAfterLimit();
|
| - }
|
| -
|
| - /**
|
| - * Returns the number of bytes to be read before the current limit.
|
| - * If no limit is set, returns -1.
|
| - */
|
| - public int getBytesUntilLimit() {
|
| - if (currentLimit == Integer.MAX_VALUE) {
|
| - return -1;
|
| - }
|
| -
|
| - final int currentAbsolutePosition = totalBytesRetired + bufferPos;
|
| - return currentLimit - currentAbsolutePosition;
|
| - }
|
| -
|
| - /**
|
| - * Returns true if the stream has reached the end of the input. This is the
|
| - * case if either the end of the underlying input source has been reached or
|
| - * if the stream has reached a limit created using {@link #pushLimit(int)}.
|
| - */
|
| - public boolean isAtEnd() throws IOException {
|
| - return bufferPos == bufferSize && !refillBuffer(false);
|
| - }
|
| -
|
| - /**
|
| - * The total bytes read up to the current position. Calling
|
| - * {@link #resetSizeCounter()} resets this value to zero.
|
| - */
|
| - public int getTotalBytesRead() {
|
| - return totalBytesRetired + bufferPos;
|
| - }
|
| -
|
| - /**
|
| - * Called with {@code this.buffer} is empty to read more bytes from the
|
| - * input. If {@code mustSucceed} is true, refillBuffer() guarantees that
|
| - * either there will be at least one byte in the buffer when it returns
|
| - * or it will throw an exception. If {@code mustSucceed} is false,
|
| - * refillBuffer() returns false if no more bytes were available.
|
| - */
|
| - private boolean refillBuffer(final boolean mustSucceed) throws IOException {
|
| - if (bufferPos < bufferSize) {
|
| - throw new IllegalStateException(
|
| - "refillBuffer() called when buffer wasn't empty.");
|
| - }
|
| -
|
| - if (totalBytesRetired + bufferSize == currentLimit) {
|
| - // Oops, we hit a limit.
|
| - if (mustSucceed) {
|
| - throw InvalidProtocolBufferException.truncatedMessage();
|
| - } else {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - totalBytesRetired += bufferSize;
|
| -
|
| - bufferPos = 0;
|
| - bufferSize = (input == null) ? -1 : input.read(buffer);
|
| - if (bufferSize == 0 || bufferSize < -1) {
|
| - throw new IllegalStateException(
|
| - "InputStream#read(byte[]) returned invalid result: " + bufferSize +
|
| - "\nThe InputStream implementation is buggy.");
|
| - }
|
| - if (bufferSize == -1) {
|
| - bufferSize = 0;
|
| - if (mustSucceed) {
|
| - throw InvalidProtocolBufferException.truncatedMessage();
|
| - } else {
|
| - return false;
|
| - }
|
| - } else {
|
| - recomputeBufferSizeAfterLimit();
|
| - final int totalBytesRead =
|
| - totalBytesRetired + bufferSize + bufferSizeAfterLimit;
|
| - if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
|
| - throw InvalidProtocolBufferException.sizeLimitExceeded();
|
| - }
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Read one byte from the input.
|
| - *
|
| - * @throws InvalidProtocolBufferException The end of the stream or the current
|
| - * limit was reached.
|
| - */
|
| - public byte readRawByte() throws IOException {
|
| - if (bufferPos == bufferSize) {
|
| - refillBuffer(true);
|
| - }
|
| - return buffer[bufferPos++];
|
| - }
|
| -
|
| - /**
|
| - * Read a fixed size of bytes from the input.
|
| - *
|
| - * @throws InvalidProtocolBufferException The end of the stream or the current
|
| - * limit was reached.
|
| - */
|
| - public byte[] readRawBytes(final int size) throws IOException {
|
| - if (size < 0) {
|
| - throw InvalidProtocolBufferException.negativeSize();
|
| - }
|
| -
|
| - if (totalBytesRetired + bufferPos + size > currentLimit) {
|
| - // Read to the end of the stream anyway.
|
| - skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
|
| - // Then fail.
|
| - throw InvalidProtocolBufferException.truncatedMessage();
|
| - }
|
| -
|
| - if (size <= bufferSize - bufferPos) {
|
| - // We have all the bytes we need already.
|
| - final byte[] bytes = new byte[size];
|
| - System.arraycopy(buffer, bufferPos, bytes, 0, size);
|
| - bufferPos += size;
|
| - return bytes;
|
| - } else if (size < BUFFER_SIZE) {
|
| - // Reading more bytes than are in the buffer, but not an excessive number
|
| - // of bytes. We can safely allocate the resulting array ahead of time.
|
| -
|
| - // First copy what we have.
|
| - final byte[] bytes = new byte[size];
|
| - int pos = bufferSize - bufferPos;
|
| - System.arraycopy(buffer, bufferPos, bytes, 0, pos);
|
| - bufferPos = bufferSize;
|
| -
|
| - // We want to use refillBuffer() and then copy from the buffer into our
|
| - // byte array rather than reading directly into our byte array because
|
| - // the input may be unbuffered.
|
| - refillBuffer(true);
|
| -
|
| - while (size - pos > bufferSize) {
|
| - System.arraycopy(buffer, 0, bytes, pos, bufferSize);
|
| - pos += bufferSize;
|
| - bufferPos = bufferSize;
|
| - refillBuffer(true);
|
| - }
|
| -
|
| - System.arraycopy(buffer, 0, bytes, pos, size - pos);
|
| - bufferPos = size - pos;
|
| -
|
| - return bytes;
|
| - } else {
|
| - // The size is very large. For security reasons, we can't allocate the
|
| - // entire byte array yet. The size comes directly from the input, so a
|
| - // maliciously-crafted message could provide a bogus very large size in
|
| - // order to trick the app into allocating a lot of memory. We avoid this
|
| - // by allocating and reading only a small chunk at a time, so that the
|
| - // malicious message must actually *be* extremely large to cause
|
| - // problems. Meanwhile, we limit the allowed size of a message elsewhere.
|
| -
|
| - // Remember the buffer markers since we'll have to copy the bytes out of
|
| - // it later.
|
| - final int originalBufferPos = bufferPos;
|
| - final int originalBufferSize = bufferSize;
|
| -
|
| - // Mark the current buffer consumed.
|
| - totalBytesRetired += bufferSize;
|
| - bufferPos = 0;
|
| - bufferSize = 0;
|
| -
|
| - // Read all the rest of the bytes we need.
|
| - int sizeLeft = size - (originalBufferSize - originalBufferPos);
|
| - final List<byte[]> chunks = new ArrayList<byte[]>();
|
| -
|
| - while (sizeLeft > 0) {
|
| - final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
|
| - int pos = 0;
|
| - while (pos < chunk.length) {
|
| - final int n = (input == null) ? -1 :
|
| - input.read(chunk, pos, chunk.length - pos);
|
| - if (n == -1) {
|
| - throw InvalidProtocolBufferException.truncatedMessage();
|
| - }
|
| - totalBytesRetired += n;
|
| - pos += n;
|
| - }
|
| - sizeLeft -= chunk.length;
|
| - chunks.add(chunk);
|
| - }
|
| -
|
| - // OK, got everything. Now concatenate it all into one buffer.
|
| - final byte[] bytes = new byte[size];
|
| -
|
| - // Start by copying the leftover bytes from this.buffer.
|
| - int pos = originalBufferSize - originalBufferPos;
|
| - System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
|
| -
|
| - // And now all the chunks.
|
| - for (final byte[] chunk : chunks) {
|
| - System.arraycopy(chunk, 0, bytes, pos, chunk.length);
|
| - pos += chunk.length;
|
| - }
|
| -
|
| - // Done.
|
| - return bytes;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Reads and discards {@code size} bytes.
|
| - *
|
| - * @throws InvalidProtocolBufferException The end of the stream or the current
|
| - * limit was reached.
|
| - */
|
| - public void skipRawBytes(final int size) throws IOException {
|
| - if (size < 0) {
|
| - throw InvalidProtocolBufferException.negativeSize();
|
| - }
|
| -
|
| - if (totalBytesRetired + bufferPos + size > currentLimit) {
|
| - // Read to the end of the stream anyway.
|
| - skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
|
| - // Then fail.
|
| - throw InvalidProtocolBufferException.truncatedMessage();
|
| - }
|
| -
|
| - if (size <= bufferSize - bufferPos) {
|
| - // We have all the bytes we need already.
|
| - bufferPos += size;
|
| - } else {
|
| - // Skipping more bytes than are in the buffer. First skip what we have.
|
| - int pos = bufferSize - bufferPos;
|
| - bufferPos = bufferSize;
|
| -
|
| - // Keep refilling the buffer until we get to the point we wanted to skip
|
| - // to. This has the side effect of ensuring the limits are updated
|
| - // correctly.
|
| - refillBuffer(true);
|
| - while (size - pos > bufferSize) {
|
| - pos += bufferSize;
|
| - bufferPos = bufferSize;
|
| - refillBuffer(true);
|
| - }
|
| -
|
| - bufferPos = size - pos;
|
| - }
|
| - }
|
| -}
|
|
|