| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. All rights reserved. |
| // https://developers.google.com/protocol-buffers/ |
| // |
| // 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 static com.google.protobuf.WireFormat.FIXED32_SIZE; |
| import static com.google.protobuf.WireFormat.FIXED64_SIZE; |
| import static com.google.protobuf.WireFormat.WIRETYPE_END_GROUP; |
| import static com.google.protobuf.WireFormat.WIRETYPE_FIXED32; |
| import static com.google.protobuf.WireFormat.WIRETYPE_FIXED64; |
| import static com.google.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED; |
| import static com.google.protobuf.WireFormat.WIRETYPE_START_GROUP; |
| import static com.google.protobuf.WireFormat.WIRETYPE_VARINT; |
| |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * A {@link Reader} that reads from a buffer containing a message serialized with the binary |
| * protocol. |
| */ |
| @ExperimentalApi |
| abstract class BinaryReader implements Reader { |
| private static final int FIXED32_MULTIPLE_MASK = FIXED32_SIZE - 1; |
| private static final int FIXED64_MULTIPLE_MASK = FIXED64_SIZE - 1; |
| |
| /** |
| * Creates a new reader using the given {@code buffer} as input. |
| * |
| * @param buffer the input buffer. The buffer (including position, limit, etc.) will not be |
| * modified. To increment the buffer position after the read completes, use the value returned |
| * by {@link #getTotalBytesRead()}. |
| * @param bufferIsImmutable if {@code true} the reader assumes that the content of {@code buffer} |
| * will never change and any allocated {@link ByteString} instances will by directly wrap |
| * slices of {@code buffer}. |
| * @return the reader |
| */ |
| public static BinaryReader newInstance(ByteBuffer buffer, boolean bufferIsImmutable) { |
| if (buffer.hasArray()) { |
| // TODO(nathanmittler): Add support for unsafe operations. |
| return new SafeHeapReader(buffer, bufferIsImmutable); |
| } |
| // TODO(nathanmittler): Add support for direct buffers |
| throw new IllegalArgumentException("Direct buffers not yet supported"); |
| } |
| |
| /** Only allow subclassing for inner classes. */ |
| private BinaryReader() {} |
| |
| /** Returns the total number of bytes read so far from the input buffer. */ |
| public abstract int getTotalBytesRead(); |
| |
| @Override |
| public boolean shouldDiscardUnknownFields() { |
| return false; |
| } |
| |
| /** |
| * A {@link BinaryReader} implementation that operates on a heap {@link ByteBuffer}. Uses only |
| * safe operations on the underlying array. |
| */ |
| private static final class SafeHeapReader extends BinaryReader { |
| private final boolean bufferIsImmutable; |
| private final byte[] buffer; |
| private int pos; |
| private final int initialPos; |
| private int limit; |
| private int tag; |
| private int endGroupTag; |
| |
| public SafeHeapReader(ByteBuffer bytebuf, boolean bufferIsImmutable) { |
| this.bufferIsImmutable = bufferIsImmutable; |
| buffer = bytebuf.array(); |
| initialPos = pos = bytebuf.arrayOffset() + bytebuf.position(); |
| limit = bytebuf.arrayOffset() + bytebuf.limit(); |
| } |
| |
| private boolean isAtEnd() { |
| return pos == limit; |
| } |
| |
| @Override |
| public int getTotalBytesRead() { |
| return pos - initialPos; |
| } |
| |
| @Override |
| public int getFieldNumber() throws IOException { |
| if (isAtEnd()) { |
| return Reader.READ_DONE; |
| } |
| tag = readVarint32(); |
| if (tag == endGroupTag) { |
| return Reader.READ_DONE; |
| } |
| return WireFormat.getTagFieldNumber(tag); |
| } |
| |
| @Override |
| public int getTag() { |
| return tag; |
| } |
| |
| @Override |
| public boolean skipField() throws IOException { |
| if (isAtEnd() || tag == endGroupTag) { |
| return false; |
| } |
| |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_VARINT: |
| skipVarint(); |
| return true; |
| case WIRETYPE_FIXED64: |
| skipBytes(FIXED64_SIZE); |
| return true; |
| case WIRETYPE_LENGTH_DELIMITED: |
| skipBytes(readVarint32()); |
| return true; |
| case WIRETYPE_FIXED32: |
| skipBytes(FIXED32_SIZE); |
| return true; |
| case WIRETYPE_START_GROUP: |
| skipGroup(); |
| return true; |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| |
| @Override |
| public double readDouble() throws IOException { |
| requireWireType(WIRETYPE_FIXED64); |
| return Double.longBitsToDouble(readLittleEndian64()); |
| } |
| |
| @Override |
| public float readFloat() throws IOException { |
| requireWireType(WIRETYPE_FIXED32); |
| return Float.intBitsToFloat(readLittleEndian32()); |
| } |
| |
| @Override |
| public long readUInt64() throws IOException { |
| requireWireType(WIRETYPE_VARINT); |
| return readVarint64(); |
| } |
| |
| @Override |
| public long readInt64() throws IOException { |
| requireWireType(WIRETYPE_VARINT); |
| return readVarint64(); |
| } |
| |
| @Override |
| public int readInt32() throws IOException { |
| requireWireType(WIRETYPE_VARINT); |
| return readVarint32(); |
| } |
| |
| @Override |
| public long readFixed64() throws IOException { |
| requireWireType(WIRETYPE_FIXED64); |
| return readLittleEndian64(); |
| } |
| |
| @Override |
| public int readFixed32() throws IOException { |
| requireWireType(WIRETYPE_FIXED32); |
| return readLittleEndian32(); |
| } |
| |
| @Override |
| public boolean readBool() throws IOException { |
| requireWireType(WIRETYPE_VARINT); |
| return readVarint32() != 0; |
| } |
| |
| @Override |
| public String readString() throws IOException { |
| return readStringInternal(false); |
| } |
| |
| @Override |
| public String readStringRequireUtf8() throws IOException { |
| return readStringInternal(true); |
| } |
| |
| public String readStringInternal(boolean requireUtf8) throws IOException { |
| requireWireType(WIRETYPE_LENGTH_DELIMITED); |
| final int size = readVarint32(); |
| if (size == 0) { |
| return ""; |
| } |
| |
| requireBytes(size); |
| if (requireUtf8 && !Utf8.isValidUtf8(buffer, pos, pos + size)) { |
| throw InvalidProtocolBufferException.invalidUtf8(); |
| } |
| String result = new String(buffer, pos, size, Internal.UTF_8); |
| pos += size; |
| return result; |
| } |
| |
| @Override |
| public <T> T readMessage(Class<T> clazz, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| requireWireType(WIRETYPE_LENGTH_DELIMITED); |
| return readMessage(Protobuf.getInstance().schemaFor(clazz), extensionRegistry); |
| } |
| |
| @Override |
| public <T> T readMessageBySchemaWithCheck( |
| Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException { |
| requireWireType(WIRETYPE_LENGTH_DELIMITED); |
| return readMessage(schema, extensionRegistry); |
| } |
| |
| private <T> T readMessage(Schema<T> schema, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| int size = readVarint32(); |
| requireBytes(size); |
| |
| // Update the limit. |
| int prevLimit = limit; |
| int newLimit = pos + size; |
| limit = newLimit; |
| |
| try { |
| // Allocate and read the message. |
| T message = schema.newInstance(); |
| schema.mergeFrom(message, this, extensionRegistry); |
| schema.makeImmutable(message); |
| |
| if (pos != newLimit) { |
| throw InvalidProtocolBufferException.parseFailure(); |
| } |
| return message; |
| } finally { |
| // Restore the limit. |
| limit = prevLimit; |
| } |
| } |
| |
| @Override |
| public <T> T readGroup(Class<T> clazz, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| requireWireType(WIRETYPE_START_GROUP); |
| return readGroup(Protobuf.getInstance().schemaFor(clazz), extensionRegistry); |
| } |
| |
| @Override |
| public <T> T readGroupBySchemaWithCheck( |
| Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException { |
| requireWireType(WIRETYPE_START_GROUP); |
| return readGroup(schema, extensionRegistry); |
| } |
| |
| private <T> T readGroup(Schema<T> schema, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| int prevEndGroupTag = endGroupTag; |
| endGroupTag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WIRETYPE_END_GROUP); |
| |
| try { |
| // Allocate and read the message. |
| T message = schema.newInstance(); |
| schema.mergeFrom(message, this, extensionRegistry); |
| schema.makeImmutable(message); |
| |
| if (tag != endGroupTag) { |
| throw InvalidProtocolBufferException.parseFailure(); |
| } |
| return message; |
| } finally { |
| // Restore the old end group tag. |
| endGroupTag = prevEndGroupTag; |
| } |
| } |
| |
| @Override |
| public ByteString readBytes() throws IOException { |
| requireWireType(WIRETYPE_LENGTH_DELIMITED); |
| int size = readVarint32(); |
| if (size == 0) { |
| return ByteString.EMPTY; |
| } |
| |
| requireBytes(size); |
| ByteString bytes = |
| bufferIsImmutable |
| ? ByteString.wrap(buffer, pos, size) |
| : ByteString.copyFrom(buffer, pos, size); |
| pos += size; |
| return bytes; |
| } |
| |
| @Override |
| public int readUInt32() throws IOException { |
| requireWireType(WIRETYPE_VARINT); |
| return readVarint32(); |
| } |
| |
| @Override |
| public int readEnum() throws IOException { |
| requireWireType(WIRETYPE_VARINT); |
| return readVarint32(); |
| } |
| |
| @Override |
| public int readSFixed32() throws IOException { |
| requireWireType(WIRETYPE_FIXED32); |
| return readLittleEndian32(); |
| } |
| |
| @Override |
| public long readSFixed64() throws IOException { |
| requireWireType(WIRETYPE_FIXED64); |
| return readLittleEndian64(); |
| } |
| |
| @Override |
| public int readSInt32() throws IOException { |
| requireWireType(WIRETYPE_VARINT); |
| return CodedInputStream.decodeZigZag32(readVarint32()); |
| } |
| |
| @Override |
| public long readSInt64() throws IOException { |
| requireWireType(WIRETYPE_VARINT); |
| return CodedInputStream.decodeZigZag64(readVarint64()); |
| } |
| |
| @Override |
| public void readDoubleList(List<Double> target) throws IOException { |
| if (target instanceof DoubleArrayList) { |
| DoubleArrayList plist = (DoubleArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed64Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addDouble(Double.longBitsToDouble(readLittleEndian64_NoCheck())); |
| } |
| break; |
| case WIRETYPE_FIXED64: |
| while (true) { |
| plist.addDouble(readDouble()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed64Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(Double.longBitsToDouble(readLittleEndian64_NoCheck())); |
| } |
| break; |
| case WIRETYPE_FIXED64: |
| while (true) { |
| target.add(readDouble()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readFloatList(List<Float> target) throws IOException { |
| if (target instanceof FloatArrayList) { |
| FloatArrayList plist = (FloatArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed32Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addFloat(Float.intBitsToFloat(readLittleEndian32_NoCheck())); |
| } |
| break; |
| case WIRETYPE_FIXED32: |
| while (true) { |
| plist.addFloat(readFloat()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed32Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(Float.intBitsToFloat(readLittleEndian32_NoCheck())); |
| } |
| break; |
| case WIRETYPE_FIXED32: |
| while (true) { |
| target.add(readFloat()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readUInt64List(List<Long> target) throws IOException { |
| if (target instanceof LongArrayList) { |
| LongArrayList plist = (LongArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addLong(readVarint64()); |
| } |
| requirePosition(fieldEndPos); |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| plist.addLong(readUInt64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readVarint64()); |
| } |
| requirePosition(fieldEndPos); |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| target.add(readUInt64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readInt64List(List<Long> target) throws IOException { |
| if (target instanceof LongArrayList) { |
| LongArrayList plist = (LongArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addLong(readVarint64()); |
| } |
| requirePosition(fieldEndPos); |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| plist.addLong(readInt64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readVarint64()); |
| } |
| requirePosition(fieldEndPos); |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| target.add(readInt64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readInt32List(List<Integer> target) throws IOException { |
| if (target instanceof IntArrayList) { |
| IntArrayList plist = (IntArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addInt(readVarint32()); |
| } |
| requirePosition(fieldEndPos); |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| plist.addInt(readInt32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readVarint32()); |
| } |
| requirePosition(fieldEndPos); |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| target.add(readInt32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readFixed64List(List<Long> target) throws IOException { |
| if (target instanceof LongArrayList) { |
| LongArrayList plist = (LongArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed64Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addLong(readLittleEndian64_NoCheck()); |
| } |
| break; |
| case WIRETYPE_FIXED64: |
| while (true) { |
| plist.addLong(readFixed64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed64Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readLittleEndian64_NoCheck()); |
| } |
| break; |
| case WIRETYPE_FIXED64: |
| while (true) { |
| target.add(readFixed64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readFixed32List(List<Integer> target) throws IOException { |
| if (target instanceof IntArrayList) { |
| IntArrayList plist = (IntArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed32Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addInt(readLittleEndian32_NoCheck()); |
| } |
| break; |
| case WIRETYPE_FIXED32: |
| while (true) { |
| plist.addInt(readFixed32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed32Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readLittleEndian32_NoCheck()); |
| } |
| break; |
| case WIRETYPE_FIXED32: |
| while (true) { |
| target.add(readFixed32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readBoolList(List<Boolean> target) throws IOException { |
| if (target instanceof BooleanArrayList) { |
| BooleanArrayList plist = (BooleanArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addBoolean(readVarint32() != 0); |
| } |
| requirePosition(fieldEndPos); |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| plist.addBoolean(readBool()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readVarint32() != 0); |
| } |
| requirePosition(fieldEndPos); |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| target.add(readBool()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readStringList(List<String> target) throws IOException { |
| readStringListInternal(target, false); |
| } |
| |
| @Override |
| public void readStringListRequireUtf8(List<String> target) throws IOException { |
| readStringListInternal(target, true); |
| } |
| |
| public void readStringListInternal(List<String> target, boolean requireUtf8) |
| throws IOException { |
| if (WireFormat.getTagWireType(tag) != WIRETYPE_LENGTH_DELIMITED) { |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| |
| if (target instanceof LazyStringList && !requireUtf8) { |
| LazyStringList lazyList = (LazyStringList) target; |
| while (true) { |
| lazyList.add(readBytes()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| } else { |
| while (true) { |
| target.add(readStringInternal(requireUtf8)); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| } |
| } |
| |
| @Override |
| public <T> void readMessageList( |
| List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| final Schema<T> schema = Protobuf.getInstance().schemaFor(targetType); |
| readMessageList(target, schema, extensionRegistry); |
| } |
| |
| @Override |
| public <T> void readMessageList( |
| List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| if (WireFormat.getTagWireType(tag) != WIRETYPE_LENGTH_DELIMITED) { |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| final int listTag = tag; |
| while (true) { |
| target.add(readMessage(schema, extensionRegistry)); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != listTag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| } |
| |
| @Override |
| public <T> void readGroupList( |
| List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| final Schema<T> schema = Protobuf.getInstance().schemaFor(targetType); |
| readGroupList(target, schema, extensionRegistry); |
| } |
| |
| @Override |
| public <T> void readGroupList( |
| List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| if (WireFormat.getTagWireType(tag) != WIRETYPE_START_GROUP) { |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| final int listTag = tag; |
| while (true) { |
| target.add(readGroup(schema, extensionRegistry)); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != listTag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| } |
| |
| @Override |
| public void readBytesList(List<ByteString> target) throws IOException { |
| if (WireFormat.getTagWireType(tag) != WIRETYPE_LENGTH_DELIMITED) { |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| |
| while (true) { |
| target.add(readBytes()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| } |
| |
| @Override |
| public void readUInt32List(List<Integer> target) throws IOException { |
| if (target instanceof IntArrayList) { |
| IntArrayList plist = (IntArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addInt(readVarint32()); |
| } |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| plist.addInt(readUInt32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readVarint32()); |
| } |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| target.add(readUInt32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readEnumList(List<Integer> target) throws IOException { |
| if (target instanceof IntArrayList) { |
| IntArrayList plist = (IntArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addInt(readVarint32()); |
| } |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| plist.addInt(readEnum()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readVarint32()); |
| } |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| target.add(readEnum()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readSFixed32List(List<Integer> target) throws IOException { |
| if (target instanceof IntArrayList) { |
| IntArrayList plist = (IntArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed32Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addInt(readLittleEndian32_NoCheck()); |
| } |
| break; |
| case WIRETYPE_FIXED32: |
| while (true) { |
| plist.addInt(readSFixed32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed32Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readLittleEndian32_NoCheck()); |
| } |
| break; |
| case WIRETYPE_FIXED32: |
| while (true) { |
| target.add(readSFixed32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readSFixed64List(List<Long> target) throws IOException { |
| if (target instanceof LongArrayList) { |
| LongArrayList plist = (LongArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed64Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addLong(readLittleEndian64_NoCheck()); |
| } |
| break; |
| case WIRETYPE_FIXED64: |
| while (true) { |
| plist.addLong(readSFixed64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| verifyPackedFixed64Length(bytes); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(readLittleEndian64_NoCheck()); |
| } |
| break; |
| case WIRETYPE_FIXED64: |
| while (true) { |
| target.add(readSFixed64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readSInt32List(List<Integer> target) throws IOException { |
| if (target instanceof IntArrayList) { |
| IntArrayList plist = (IntArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addInt(CodedInputStream.decodeZigZag32(readVarint32())); |
| } |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| plist.addInt(readSInt32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(CodedInputStream.decodeZigZag32(readVarint32())); |
| } |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| target.add(readSInt32()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @Override |
| public void readSInt64List(List<Long> target) throws IOException { |
| if (target instanceof LongArrayList) { |
| LongArrayList plist = (LongArrayList) target; |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| plist.addLong(CodedInputStream.decodeZigZag64(readVarint64())); |
| } |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| plist.addLong(readSInt64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } else { |
| switch (WireFormat.getTagWireType(tag)) { |
| case WIRETYPE_LENGTH_DELIMITED: |
| final int bytes = readVarint32(); |
| final int fieldEndPos = pos + bytes; |
| while (pos < fieldEndPos) { |
| target.add(CodedInputStream.decodeZigZag64(readVarint64())); |
| } |
| break; |
| case WIRETYPE_VARINT: |
| while (true) { |
| target.add(readSInt64()); |
| |
| if (isAtEnd()) { |
| return; |
| } |
| int prevPos = pos; |
| int nextTag = readVarint32(); |
| if (nextTag != tag) { |
| // We've reached the end of the repeated field. Rewind the buffer position to before |
| // the new tag. |
| pos = prevPos; |
| return; |
| } |
| } |
| default: |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public <K, V> void readMap( |
| Map<K, V> target, |
| MapEntryLite.Metadata<K, V> metadata, |
| ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| requireWireType(WIRETYPE_LENGTH_DELIMITED); |
| int size = readVarint32(); |
| requireBytes(size); |
| |
| // Update the limit. |
| int prevLimit = limit; |
| int newLimit = pos + size; |
| limit = newLimit; |
| |
| try { |
| K key = metadata.defaultKey; |
| V value = metadata.defaultValue; |
| while (true) { |
| int number = getFieldNumber(); |
| if (number == READ_DONE) { |
| break; |
| } |
| try { |
| switch (number) { |
| case 1: |
| key = (K) readField(metadata.keyType, null, null); |
| break; |
| case 2: |
| value = |
| (V) |
| readField( |
| metadata.valueType, |
| metadata.defaultValue.getClass(), |
| extensionRegistry); |
| break; |
| default: |
| if (!skipField()) { |
| throw new InvalidProtocolBufferException("Unable to parse map entry."); |
| } |
| break; |
| } |
| } catch (InvalidProtocolBufferException.InvalidWireTypeException ignore) { |
| // the type doesn't match, skip the field. |
| if (!skipField()) { |
| throw new InvalidProtocolBufferException("Unable to parse map entry."); |
| } |
| } |
| } |
| target.put(key, value); |
| } finally { |
| // Restore the limit. |
| limit = prevLimit; |
| } |
| } |
| |
| private Object readField( |
| WireFormat.FieldType fieldType, |
| Class<?> messageType, |
| ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| switch (fieldType) { |
| case BOOL: |
| return readBool(); |
| case BYTES: |
| return readBytes(); |
| case DOUBLE: |
| return readDouble(); |
| case ENUM: |
| return readEnum(); |
| case FIXED32: |
| return readFixed32(); |
| case FIXED64: |
| return readFixed64(); |
| case FLOAT: |
| return readFloat(); |
| case INT32: |
| return readInt32(); |
| case INT64: |
| return readInt64(); |
| case MESSAGE: |
| return readMessage(messageType, extensionRegistry); |
| case SFIXED32: |
| return readSFixed32(); |
| case SFIXED64: |
| return readSFixed64(); |
| case SINT32: |
| return readSInt32(); |
| case SINT64: |
| return readSInt64(); |
| case STRING: |
| return readStringRequireUtf8(); |
| case UINT32: |
| return readUInt32(); |
| case UINT64: |
| return readUInt64(); |
| default: |
| throw new RuntimeException("unsupported field type."); |
| } |
| } |
| |
| /** Read a raw Varint from the stream. If larger than 32 bits, discard the upper bits. */ |
| private int readVarint32() throws IOException { |
| // See implementation notes for readRawVarint64 |
| int i = pos; |
| |
| if (limit == pos) { |
| throw InvalidProtocolBufferException.truncatedMessage(); |
| } |
| |
| int x; |
| if ((x = buffer[i++]) >= 0) { |
| pos = i; |
| return x; |
| } else if (limit - i < 9) { |
| return (int) readVarint64SlowPath(); |
| } else if ((x ^= (buffer[i++] << 7)) < 0) { |
| x ^= (~0 << 7); |
| } else if ((x ^= (buffer[i++] << 14)) >= 0) { |
| x ^= (~0 << 7) ^ (~0 << 14); |
| } else if ((x ^= (buffer[i++] << 21)) < 0) { |
| x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); |
| } else { |
| int y = buffer[i++]; |
| x ^= y << 28; |
| x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); |
| if (y < 0 |
| && buffer[i++] < 0 |
| && buffer[i++] < 0 |
| && buffer[i++] < 0 |
| && buffer[i++] < 0 |
| && buffer[i++] < 0) { |
| throw InvalidProtocolBufferException.malformedVarint(); |
| } |
| } |
| pos = i; |
| return x; |
| } |
| |
| public long readVarint64() throws IOException { |
| // Implementation notes: |
| // |
| // Optimized for one-byte values, expected to be common. |
| // The particular code below was selected from various candidates |
| // empirically, by winning VarintBenchmark. |
| // |
| // Sign extension of (signed) Java bytes is usually a nuisance, but |
| // we exploit it here to more easily obtain the sign of bytes read. |
| // Instead of cleaning up the sign extension bits by masking eagerly, |
| // we delay until we find the final (positive) byte, when we clear all |
| // accumulated bits with one xor. We depend on javac to constant fold. |
| int i = pos; |
| |
| if (limit == i) { |
| throw InvalidProtocolBufferException.truncatedMessage(); |
| } |
| |
| final byte[] buffer = this.buffer; |
| long x; |
| int y; |
| if ((y = buffer[i++]) >= 0) { |
| pos = i; |
| return y; |
| } else if (limit - i < 9) { |
| return readVarint64SlowPath(); |
| } else if ((y ^= (buffer[i++] << 7)) < 0) { |
| x = y ^ (~0 << 7); |
| } else if ((y ^= (buffer[i++] << 14)) >= 0) { |
| x = y ^ ((~0 << 7) ^ (~0 << 14)); |
| } else if ((y ^= (buffer[i++] << 21)) < 0) { |
| x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); |
| } else if ((x = y ^ ((long) buffer[i++] << 28)) >= 0L) { |
| x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); |
| } else if ((x ^= ((long) buffer[i++] << 35)) < 0L) { |
| x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); |
| } else if ((x ^= ((long) buffer[i++] << 42)) >= 0L) { |
| x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42); |
| } else if ((x ^= ((long) buffer[i++] << 49)) < 0L) { |
| x ^= |
| (~0L << 7) |
| ^ (~0L << 14) |
| ^ (~0L << 21) |
| ^ (~0L << 28) |
| ^ (~0L << 35) |
| ^ (~0L << 42) |
| ^ (~0L << 49); |
| } else { |
| x ^= ((long) buffer[i++] << 56); |
| x ^= |
| (~0L << 7) |
| ^ (~0L << 14) |
| ^ (~0L << 21) |
| ^ (~0L << 28) |
| ^ (~0L << 35) |
| ^ (~0L << 42) |
| ^ (~0L << 49) |
| ^ (~0L << 56); |
| if (x < 0L) { |
| if (buffer[i++] < 0L) { |
| throw InvalidProtocolBufferException.malformedVarint(); |
| } |
| } |
| } |
| pos = i; |
| return x; |
| } |
| |
| private long readVarint64SlowPath() throws IOException { |
| long result = 0; |
| for (int shift = 0; shift < 64; shift += 7) { |
| final byte b = readByte(); |
| result |= (long) (b & 0x7F) << shift; |
| if ((b & 0x80) == 0) { |
| return result; |
| } |
| } |
| throw InvalidProtocolBufferException.malformedVarint(); |
| } |
| |
| private byte readByte() throws IOException { |
| if (pos == limit) { |
| throw InvalidProtocolBufferException.truncatedMessage(); |
| } |
| return buffer[pos++]; |
| } |
| |
| private int readLittleEndian32() throws IOException { |
| requireBytes(FIXED32_SIZE); |
| return readLittleEndian32_NoCheck(); |
| } |
| |
| private long readLittleEndian64() throws IOException { |
| requireBytes(FIXED64_SIZE); |
| return readLittleEndian64_NoCheck(); |
| } |
| |
| private int readLittleEndian32_NoCheck() { |
| int p = pos; |
| final byte[] buffer = this.buffer; |
| pos = p + FIXED32_SIZE; |
| return (((buffer[p] & 0xff)) |
| | ((buffer[p + 1] & 0xff) << 8) |
| | ((buffer[p + 2] & 0xff) << 16) |
| | ((buffer[p + 3] & 0xff) << 24)); |
| } |
| |
| private long readLittleEndian64_NoCheck() { |
| int p = pos; |
| final byte[] buffer = this.buffer; |
| pos = p + FIXED64_SIZE; |
| return (((buffer[p] & 0xffL)) |
| | ((buffer[p + 1] & 0xffL) << 8) |
| | ((buffer[p + 2] & 0xffL) << 16) |
| | ((buffer[p + 3] & 0xffL) << 24) |
| | ((buffer[p + 4] & 0xffL) << 32) |
| | ((buffer[p + 5] & 0xffL) << 40) |
| | ((buffer[p + 6] & 0xffL) << 48) |
| | ((buffer[p + 7] & 0xffL) << 56)); |
| } |
| |
| private void skipVarint() throws IOException { |
| if (limit - pos >= 10) { |
| final byte[] buffer = this.buffer; |
| int p = pos; |
| for (int i = 0; i < 10; i++) { |
| if (buffer[p++] >= 0) { |
| pos = p; |
| return; |
| } |
| } |
| } |
| skipVarintSlowPath(); |
| } |
| |
| private void skipVarintSlowPath() throws IOException { |
| for (int i = 0; i < 10; i++) { |
| if (readByte() >= 0) { |
| return; |
| } |
| } |
| throw InvalidProtocolBufferException.malformedVarint(); |
| } |
| |
| private void skipBytes(final int size) throws IOException { |
| requireBytes(size); |
| |
| pos += size; |
| } |
| |
| private void skipGroup() throws IOException { |
| int prevEndGroupTag = endGroupTag; |
| endGroupTag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WIRETYPE_END_GROUP); |
| while (true) { |
| if (getFieldNumber() == READ_DONE || !skipField()) { |
| break; |
| } |
| } |
| if (tag != endGroupTag) { |
| throw InvalidProtocolBufferException.parseFailure(); |
| } |
| endGroupTag = prevEndGroupTag; |
| } |
| |
| private void requireBytes(int size) throws IOException { |
| if (size < 0 || size > (limit - pos)) { |
| throw InvalidProtocolBufferException.truncatedMessage(); |
| } |
| } |
| |
| private void requireWireType(int requiredWireType) throws IOException { |
| if (WireFormat.getTagWireType(tag) != requiredWireType) { |
| throw InvalidProtocolBufferException.invalidWireType(); |
| } |
| } |
| |
| private void verifyPackedFixed64Length(int bytes) throws IOException { |
| requireBytes(bytes); |
| if ((bytes & FIXED64_MULTIPLE_MASK) != 0) { |
| // Require that the number of bytes be a multiple of 8. |
| throw InvalidProtocolBufferException.parseFailure(); |
| } |
| } |
| |
| private void verifyPackedFixed32Length(int bytes) throws IOException { |
| requireBytes(bytes); |
| if ((bytes & FIXED32_MULTIPLE_MASK) != 0) { |
| // Require that the number of bytes be a multiple of 4. |
| throw InvalidProtocolBufferException.parseFailure(); |
| } |
| } |
| |
| private void requirePosition(int expectedPosition) throws IOException { |
| if (pos != expectedPosition) { |
| throw InvalidProtocolBufferException.truncatedMessage(); |
| } |
| } |
| } |
| } |