blob: 7658f629d3717775aa32404f542d2dd47f85ab79 [file] [log] [blame]
// 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.util.List;
import java.util.Map;
/** An adapter between the {@link Reader} interface and {@link CodedInputStream}. */
@ExperimentalApi
final class CodedInputStreamReader implements Reader {
private static final int FIXED32_MULTIPLE_MASK = FIXED32_SIZE - 1;
private static final int FIXED64_MULTIPLE_MASK = FIXED64_SIZE - 1;
private static final int NEXT_TAG_UNSET = 0;
private final CodedInputStream input;
private int tag;
private int endGroupTag;
private int nextTag = NEXT_TAG_UNSET;
public static CodedInputStreamReader forCodedInput(CodedInputStream input) {
if (input.wrapper != null) {
return input.wrapper;
}
return new CodedInputStreamReader(input);
}
private CodedInputStreamReader(CodedInputStream input) {
this.input = Internal.checkNotNull(input, "input");
this.input.wrapper = this;
}
@Override
public boolean shouldDiscardUnknownFields() {
return input.shouldDiscardUnknownFields();
}
@Override
public int getFieldNumber() throws IOException {
if (nextTag != NEXT_TAG_UNSET) {
tag = nextTag;
nextTag = NEXT_TAG_UNSET;
} else {
tag = input.readTag();
}
if (tag == 0 || tag == endGroupTag) {
return Reader.READ_DONE;
}
return WireFormat.getTagFieldNumber(tag);
}
@Override
public int getTag() {
return tag;
}
@Override
public boolean skipField() throws IOException {
if (input.isAtEnd() || tag == endGroupTag) {
return false;
}
return input.skipField(tag);
}
private void requireWireType(int requiredWireType) throws IOException {
if (WireFormat.getTagWireType(tag) != requiredWireType) {
throw InvalidProtocolBufferException.invalidWireType();
}
}
@Override
public double readDouble() throws IOException {
requireWireType(WIRETYPE_FIXED64);
return input.readDouble();
}
@Override
public float readFloat() throws IOException {
requireWireType(WIRETYPE_FIXED32);
return input.readFloat();
}
@Override
public long readUInt64() throws IOException {
requireWireType(WIRETYPE_VARINT);
return input.readUInt64();
}
@Override
public long readInt64() throws IOException {
requireWireType(WIRETYPE_VARINT);
return input.readInt64();
}
@Override
public int readInt32() throws IOException {
requireWireType(WIRETYPE_VARINT);
return input.readInt32();
}
@Override
public long readFixed64() throws IOException {
requireWireType(WIRETYPE_FIXED64);
return input.readFixed64();
}
@Override
public int readFixed32() throws IOException {
requireWireType(WIRETYPE_FIXED32);
return input.readFixed32();
}
@Override
public boolean readBool() throws IOException {
requireWireType(WIRETYPE_VARINT);
return input.readBool();
}
@Override
public String readString() throws IOException {
requireWireType(WIRETYPE_LENGTH_DELIMITED);
return input.readString();
}
@Override
public String readStringRequireUtf8() throws IOException {
requireWireType(WIRETYPE_LENGTH_DELIMITED);
return input.readStringRequireUtf8();
}
@SuppressWarnings("unchecked")
@Override
public <T> T readMessage(Class<T> clazz, ExtensionRegistryLite extensionRegistry)
throws IOException {
requireWireType(WIRETYPE_LENGTH_DELIMITED);
return readMessage(Protobuf.getInstance().schemaFor(clazz), extensionRegistry);
}
@SuppressWarnings("unchecked")
@Override
public <T> T readMessageBySchemaWithCheck(
Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException {
requireWireType(WIRETYPE_LENGTH_DELIMITED);
return readMessage(schema, extensionRegistry);
}
@SuppressWarnings("unchecked")
@Override
public <T> T readGroup(Class<T> clazz, ExtensionRegistryLite extensionRegistry)
throws IOException {
requireWireType(WIRETYPE_START_GROUP);
return readGroup(Protobuf.getInstance().schemaFor(clazz), extensionRegistry);
}
@SuppressWarnings("unchecked")
@Override
public <T> T readGroupBySchemaWithCheck(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
throws IOException {
requireWireType(WIRETYPE_START_GROUP);
return readGroup(schema, extensionRegistry);
}
// Should have the same semantics of CodedInputStream#readMessage()
private <T> T readMessage(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
throws IOException {
int size = input.readUInt32();
if (input.recursionDepth >= input.recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
}
// Push the new limit.
final int prevLimit = input.pushLimit(size);
// Allocate and read the message.
T message = schema.newInstance();
++input.recursionDepth;
schema.mergeFrom(message, this, extensionRegistry);
schema.makeImmutable(message);
input.checkLastTagWas(0);
--input.recursionDepth;
// Restore the previous limit.
input.popLimit(prevLimit);
return message;
}
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);
return input.readBytes();
}
@Override
public int readUInt32() throws IOException {
requireWireType(WIRETYPE_VARINT);
return input.readUInt32();
}
@Override
public int readEnum() throws IOException {
requireWireType(WIRETYPE_VARINT);
return input.readEnum();
}
@Override
public int readSFixed32() throws IOException {
requireWireType(WIRETYPE_FIXED32);
return input.readSFixed32();
}
@Override
public long readSFixed64() throws IOException {
requireWireType(WIRETYPE_FIXED64);
return input.readSFixed64();
}
@Override
public int readSInt32() throws IOException {
requireWireType(WIRETYPE_VARINT);
return input.readSInt32();
}
@Override
public long readSInt64() throws IOException {
requireWireType(WIRETYPE_VARINT);
return input.readSInt64();
}
@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 = input.readUInt32();
verifyPackedFixed64Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addDouble(input.readDouble());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED64:
while (true) {
plist.addDouble(input.readDouble());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
verifyPackedFixed64Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readDouble());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED64:
while (true) {
target.add(input.readDouble());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
verifyPackedFixed32Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addFloat(input.readFloat());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED32:
while (true) {
plist.addFloat(input.readFloat());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
verifyPackedFixed32Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readFloat());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED32:
while (true) {
target.add(input.readFloat());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addLong(input.readUInt64());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
plist.addLong(input.readUInt64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readUInt64());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
target.add(input.readUInt64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addLong(input.readInt64());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
plist.addLong(input.readInt64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readInt64());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
target.add(input.readInt64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addInt(input.readInt32());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
plist.addInt(input.readInt32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readInt32());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
target.add(input.readInt32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
verifyPackedFixed64Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addLong(input.readFixed64());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED64:
while (true) {
plist.addLong(input.readFixed64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
verifyPackedFixed64Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readFixed64());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED64:
while (true) {
target.add(input.readFixed64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
verifyPackedFixed32Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addInt(input.readFixed32());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED32:
while (true) {
plist.addInt(input.readFixed32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
verifyPackedFixed32Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readFixed32());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED32:
while (true) {
target.add(input.readFixed32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addBoolean(input.readBool());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
plist.addBoolean(input.readBool());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readBool());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
target.add(input.readBool());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
} else {
while (true) {
target.add(requireUtf8 ? readStringRequireUtf8() : readString());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 (input.isAtEnd() || nextTag != NEXT_TAG_UNSET) {
return;
}
int nextTag = input.readTag();
if (nextTag != listTag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 (input.isAtEnd() || nextTag != NEXT_TAG_UNSET) {
return;
}
int nextTag = input.readTag();
if (nextTag != listTag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addInt(input.readUInt32());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
plist.addInt(input.readUInt32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readUInt32());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
target.add(input.readUInt32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addInt(input.readEnum());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
plist.addInt(input.readEnum());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readEnum());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
target.add(input.readEnum());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
verifyPackedFixed32Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addInt(input.readSFixed32());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED32:
while (true) {
plist.addInt(input.readSFixed32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
verifyPackedFixed32Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readSFixed32());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED32:
while (true) {
target.add(input.readSFixed32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
verifyPackedFixed64Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addLong(input.readSFixed64());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED64:
while (true) {
plist.addLong(input.readSFixed64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
verifyPackedFixed64Length(bytes);
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readSFixed64());
} while (input.getTotalBytesRead() < endPos);
break;
case WIRETYPE_FIXED64:
while (true) {
target.add(input.readSFixed64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addInt(input.readSInt32());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
plist.addInt(input.readSInt32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readSInt32());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
target.add(input.readSInt32());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
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 = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
plist.addLong(input.readSInt64());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
plist.addLong(input.readSInt64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
} else {
switch (WireFormat.getTagWireType(tag)) {
case WIRETYPE_LENGTH_DELIMITED:
final int bytes = input.readUInt32();
int endPos = input.getTotalBytesRead() + bytes;
do {
target.add(input.readSInt64());
} while (input.getTotalBytesRead() < endPos);
requirePosition(endPos);
break;
case WIRETYPE_VARINT:
while (true) {
target.add(input.readSInt64());
if (input.isAtEnd()) {
return;
}
int nextTag = input.readTag();
if (nextTag != tag) {
// We've reached the end of the repeated field. Save the next tag value.
this.nextTag = nextTag;
return;
}
}
default:
throw InvalidProtocolBufferException.invalidWireType();
}
}
}
private void verifyPackedFixed64Length(int bytes) throws IOException {
if ((bytes & FIXED64_MULTIPLE_MASK) != 0) {
// Require that the number of bytes be a multiple of 8.
throw InvalidProtocolBufferException.parseFailure();
}
}
@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 = input.readUInt32();
final int prevLimit = input.pushLimit(size);
K key = metadata.defaultKey;
V value = metadata.defaultValue;
try {
while (true) {
int number = getFieldNumber();
if (number == READ_DONE || input.isAtEnd()) {
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 previous limit.
input.popLimit(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.");
}
}
private void verifyPackedFixed32Length(int bytes) throws IOException {
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 (input.getTotalBytesRead() != expectedPosition) {
throw InvalidProtocolBufferException.truncatedMessage();
}
}
}