com.google.protobuf.MessageReflection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of clarity-protobuf Show documentation
Show all versions of clarity-protobuf Show documentation
Clarity is an open source replay parser for Dota 2 and CSGO 1 and 2 written in Java. This JAR contains the protobuf classes for clarity.
// 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 com.google.protobuf.Descriptors.FieldDescriptor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* Reflection utility methods shared by both mutable and immutable messages.
*
* @author [email protected] (Pherl Liu)
*/
class MessageReflection {
static void writeMessageTo(Message message, CodedOutputStream output,
boolean alwaysWriteRequiredFields)
throws IOException {
final boolean isMessageSet =
message.getDescriptorForType().getOptions().getMessageSetWireFormat();
Map fields = message.getAllFields();
if (alwaysWriteRequiredFields) {
fields = new TreeMap(fields);
for (final FieldDescriptor field :
message.getDescriptorForType().getFields()) {
if (field.isRequired() && !fields.containsKey(field)) {
fields.put(field, message.getField(field));
}
}
}
for (final Map.Entry entry :
fields.entrySet()) {
final Descriptors.FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (isMessageSet && field.isExtension() &&
field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
!field.isRepeated()) {
output.writeMessageSetExtension(field.getNumber(), (Message) value);
} else {
FieldSet.writeField(field, value, output);
}
}
final UnknownFieldSet unknownFields = message.getUnknownFields();
if (isMessageSet) {
unknownFields.writeAsMessageSetTo(output);
} else {
unknownFields.writeTo(output);
}
}
static int getSerializedSize(Message message) {
int size = 0;
final boolean isMessageSet =
message.getDescriptorForType().getOptions().getMessageSetWireFormat();
for (final Map.Entry entry :
message.getAllFields().entrySet()) {
final Descriptors.FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (isMessageSet && field.isExtension() &&
field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
!field.isRepeated()) {
size += CodedOutputStream.computeMessageSetExtensionSize(
field.getNumber(), (Message) value);
} else {
size += FieldSet.computeFieldSize(field, value);
}
}
final UnknownFieldSet unknownFields = message.getUnknownFields();
if (isMessageSet) {
size += unknownFields.getSerializedSizeAsMessageSet();
} else {
size += unknownFields.getSerializedSize();
}
return size;
}
static String delimitWithCommas(List parts) {
StringBuilder result = new StringBuilder();
for (String part : parts) {
if (result.length() > 0) {
result.append(", ");
}
result.append(part);
}
return result.toString();
}
@SuppressWarnings("unchecked")
static boolean isInitialized(MessageOrBuilder message) {
// Check that all required fields are present.
for (final Descriptors.FieldDescriptor field : message
.getDescriptorForType()
.getFields()) {
if (field.isRequired()) {
if (!message.hasField(field)) {
return false;
}
}
}
// Check that embedded messages are initialized.
for (final Map.Entry entry :
message.getAllFields().entrySet()) {
final Descriptors.FieldDescriptor field = entry.getKey();
if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
for (final Message element
: (List) entry.getValue()) {
if (!element.isInitialized()) {
return false;
}
}
} else {
if (!((Message) entry.getValue()).isInitialized()) {
return false;
}
}
}
}
return true;
}
private static String subMessagePrefix(final String prefix,
final Descriptors.FieldDescriptor field,
final int index) {
final StringBuilder result = new StringBuilder(prefix);
if (field.isExtension()) {
result.append('(')
.append(field.getFullName())
.append(')');
} else {
result.append(field.getName());
}
if (index != -1) {
result.append('[')
.append(index)
.append(']');
}
result.append('.');
return result.toString();
}
private static void findMissingFields(final MessageOrBuilder message,
final String prefix,
final List results) {
for (final Descriptors.FieldDescriptor field :
message.getDescriptorForType().getFields()) {
if (field.isRequired() && !message.hasField(field)) {
results.add(prefix + field.getName());
}
}
for (final Map.Entry entry :
message.getAllFields().entrySet()) {
final Descriptors.FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
int i = 0;
for (final Object element : (List) value) {
findMissingFields((MessageOrBuilder) element,
subMessagePrefix(prefix, field, i++),
results);
}
} else {
if (message.hasField(field)) {
findMissingFields((MessageOrBuilder) value,
subMessagePrefix(prefix, field, -1),
results);
}
}
}
}
}
/**
* Populates {@code this.missingFields} with the full "path" of each missing
* required field in the given message.
*/
static List findMissingFields(
final MessageOrBuilder message) {
final List results = new ArrayList();
findMissingFields(message, "", results);
return results;
}
static interface MergeTarget {
enum ContainerType {
MESSAGE, EXTENSION_SET
}
/**
* Returns the descriptor for the target.
*/
public Descriptors.Descriptor getDescriptorForType();
public ContainerType getContainerType();
public ExtensionRegistry.ExtensionInfo findExtensionByName(
ExtensionRegistry registry, String name);
public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
ExtensionRegistry registry, Descriptors.Descriptor containingType,
int fieldNumber);
/**
* Obtains the value of the given field, or the default value if it is not
* set. For primitive fields, the boxed primitive value is returned. For
* enum fields, the EnumValueDescriptor for the value is returned. For
* embedded message fields, the sub-message is returned. For repeated
* fields, a java.util.List is returned.
*/
public Object getField(Descriptors.FieldDescriptor field);
/**
* Returns true if the given field is set. This is exactly equivalent to
* calling the generated "has" accessor method corresponding to the field.
*
* @throws IllegalArgumentException The field is a repeated field, or {@code
* field.getContainingType() != getDescriptorForType()}.
*/
boolean hasField(Descriptors.FieldDescriptor field);
/**
* Sets a field to the given value. The value must be of the correct type
* for this field, i.e. the same type that
* {@link Message#getField(Descriptors.FieldDescriptor)}
* would return.
*/
MergeTarget setField(Descriptors.FieldDescriptor field, Object value);
/**
* Clears the field. This is exactly equivalent to calling the generated
* "clear" accessor method corresponding to the field.
*/
MergeTarget clearField(Descriptors.FieldDescriptor field);
/**
* Sets an element of a repeated field to the given value. The value must
* be of the correct type for this field, i.e. the same type that {@link
* Message#getRepeatedField(Descriptors.FieldDescriptor, int)} would return.
*
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() !=
* getDescriptorForType()}.
*/
MergeTarget setRepeatedField(Descriptors.FieldDescriptor field,
int index, Object value);
/**
* Like {@code setRepeatedField}, but appends the value as a new element.
*
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() !=
* getDescriptorForType()}.
*/
MergeTarget addRepeatedField(Descriptors.FieldDescriptor field,
Object value);
/**
* Returns true if the given oneof is set.
*
* @throws IllegalArgumentException if
* {@code oneof.getContainingType() != getDescriptorForType()}.
*/
boolean hasOneof(Descriptors.OneofDescriptor oneof);
/**
* Clears the oneof. This is exactly equivalent to calling the generated
* "clear" accessor method corresponding to the oneof.
*/
MergeTarget clearOneof(Descriptors.OneofDescriptor oneof);
/**
* Obtains the FieldDescriptor if the given oneof is set. Returns null
* if no field is set.
*/
Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof);
/**
* Parse the input stream into a sub field group defined based on either
* FieldDescriptor or the default instance.
*/
Object parseGroup(CodedInputStream input, ExtensionRegistryLite registry,
Descriptors.FieldDescriptor descriptor, Message defaultInstance)
throws IOException;
/**
* Parse the input stream into a sub field message defined based on either
* FieldDescriptor or the default instance.
*/
Object parseMessage(CodedInputStream input, ExtensionRegistryLite registry,
Descriptors.FieldDescriptor descriptor, Message defaultInstance)
throws IOException;
/**
* Parse from a ByteString into a sub field message defined based on either
* FieldDescriptor or the default instance. There isn't a varint indicating
* the length of the message at the beginning of the input ByteString.
*/
Object parseMessageFromBytes(
ByteString bytes, ExtensionRegistryLite registry,
Descriptors.FieldDescriptor descriptor, Message defaultInstance)
throws IOException;
/**
* Read a primitive field from input. Note that builders and mutable
* messages may use different Java types to represent a primtive field.
*/
Object readPrimitiveField(
CodedInputStream input, WireFormat.FieldType type,
boolean checkUtf8) throws IOException;
/**
* Returns a new merge target for a sub-field. When defaultInstance is
* provided, it indicates the descriptor is for an extension type, and
* implementations should create a new instance from the defaultInstance
* prototype directly.
*/
MergeTarget newMergeTargetForField(
Descriptors.FieldDescriptor descriptor,
Message defaultInstance);
/**
* Finishes the merge and returns the underlying object.
*/
Object finish();
}
static class BuilderAdapter implements MergeTarget {
private final Message.Builder builder;
public Descriptors.Descriptor getDescriptorForType() {
return builder.getDescriptorForType();
}
public BuilderAdapter(Message.Builder builder) {
this.builder = builder;
}
public Object getField(Descriptors.FieldDescriptor field) {
return builder.getField(field);
}
@Override
public boolean hasField(Descriptors.FieldDescriptor field) {
return builder.hasField(field);
}
public MergeTarget setField(Descriptors.FieldDescriptor field,
Object value) {
builder.setField(field, value);
return this;
}
public MergeTarget clearField(Descriptors.FieldDescriptor field) {
builder.clearField(field);
return this;
}
public MergeTarget setRepeatedField(
Descriptors.FieldDescriptor field, int index, Object value) {
builder.setRepeatedField(field, index, value);
return this;
}
public MergeTarget addRepeatedField(
Descriptors.FieldDescriptor field, Object value) {
builder.addRepeatedField(field, value);
return this;
}
@Override
public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
return builder.hasOneof(oneof);
}
@Override
public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
builder.clearOneof(oneof);
return this;
}
@Override
public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
return builder.getOneofFieldDescriptor(oneof);
}
public ContainerType getContainerType() {
return ContainerType.MESSAGE;
}
public ExtensionRegistry.ExtensionInfo findExtensionByName(
ExtensionRegistry registry, String name) {
return registry.findImmutableExtensionByName(name);
}
public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
ExtensionRegistry registry, Descriptors.Descriptor containingType,
int fieldNumber) {
return registry.findImmutableExtensionByNumber(containingType,
fieldNumber);
}
public Object parseGroup(CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
Descriptors.FieldDescriptor field, Message defaultInstance)
throws IOException {
Message.Builder subBuilder;
// When default instance is not null. The field is an extension field.
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
Message originalMessage = (Message) getField(field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
}
input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
return subBuilder.buildPartial();
}
public Object parseMessage(CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
Descriptors.FieldDescriptor field, Message defaultInstance)
throws IOException {
Message.Builder subBuilder;
// When default instance is not null. The field is an extension field.
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
Message originalMessage = (Message) getField(field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
}
input.readMessage(subBuilder, extensionRegistry);
return subBuilder.buildPartial();
}
public Object parseMessageFromBytes(ByteString bytes,
ExtensionRegistryLite extensionRegistry,
Descriptors.FieldDescriptor field, Message defaultInstance)
throws IOException {
Message.Builder subBuilder;
// When default instance is not null. The field is an extension field.
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
Message originalMessage = (Message) getField(field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
}
subBuilder.mergeFrom(bytes, extensionRegistry);
return subBuilder.buildPartial();
}
public MergeTarget newMergeTargetForField(Descriptors.FieldDescriptor field,
Message defaultInstance) {
if (defaultInstance != null) {
return new BuilderAdapter(
defaultInstance.newBuilderForType());
} else {
return new BuilderAdapter(builder.newBuilderForField(field));
}
}
public Object readPrimitiveField(
CodedInputStream input, WireFormat.FieldType type,
boolean checkUtf8) throws IOException {
return FieldSet.readPrimitiveField(input, type, checkUtf8);
}
public Object finish() {
return builder.buildPartial();
}
}
static class ExtensionAdapter implements MergeTarget {
private final FieldSet extensions;
ExtensionAdapter(FieldSet extensions) {
this.extensions = extensions;
}
public Descriptors.Descriptor getDescriptorForType() {
throw new UnsupportedOperationException(
"getDescriptorForType() called on FieldSet object");
}
public Object getField(Descriptors.FieldDescriptor field) {
return extensions.getField(field);
}
public boolean hasField(Descriptors.FieldDescriptor field) {
return extensions.hasField(field);
}
public MergeTarget setField(Descriptors.FieldDescriptor field,
Object value) {
extensions.setField(field, value);
return this;
}
public MergeTarget clearField(Descriptors.FieldDescriptor field) {
extensions.clearField(field);
return this;
}
public MergeTarget setRepeatedField(
Descriptors.FieldDescriptor field, int index, Object value) {
extensions.setRepeatedField(field, index, value);
return this;
}
public MergeTarget addRepeatedField(
Descriptors.FieldDescriptor field, Object value) {
extensions.addRepeatedField(field, value);
return this;
}
@Override
public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
return false;
}
@Override
public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
// Nothing to clear.
return this;
}
@Override
public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
return null;
}
public ContainerType getContainerType() {
return ContainerType.EXTENSION_SET;
}
public ExtensionRegistry.ExtensionInfo findExtensionByName(
ExtensionRegistry registry, String name) {
return registry.findImmutableExtensionByName(name);
}
public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
ExtensionRegistry registry, Descriptors.Descriptor containingType,
int fieldNumber) {
return registry.findImmutableExtensionByNumber(containingType,
fieldNumber);
}
public Object parseGroup(CodedInputStream input,
ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
Message defaultInstance) throws IOException {
Message.Builder subBuilder =
defaultInstance.newBuilderForType();
if (!field.isRepeated()) {
Message originalMessage = (Message) getField(field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
}
input.readGroup(field.getNumber(), subBuilder, registry);
return subBuilder.buildPartial();
}
public Object parseMessage(CodedInputStream input,
ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
Message defaultInstance) throws IOException {
Message.Builder subBuilder =
defaultInstance.newBuilderForType();
if (!field.isRepeated()) {
Message originalMessage = (Message) getField(field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
}
input.readMessage(subBuilder, registry);
return subBuilder.buildPartial();
}
public Object parseMessageFromBytes(ByteString bytes,
ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
Message defaultInstance) throws IOException {
Message.Builder subBuilder = defaultInstance.newBuilderForType();
if (!field.isRepeated()) {
Message originalMessage = (Message) getField(field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
}
subBuilder.mergeFrom(bytes, registry);
return subBuilder.buildPartial();
}
public MergeTarget newMergeTargetForField(
Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
throw new UnsupportedOperationException(
"newMergeTargetForField() called on FieldSet object");
}
public Object readPrimitiveField(
CodedInputStream input, WireFormat.FieldType type,
boolean checkUtf8) throws IOException {
return FieldSet.readPrimitiveField(input, type, checkUtf8);
}
public Object finish() {
throw new UnsupportedOperationException(
"finish() called on FieldSet object");
}
}
/**
* Parses a single field into MergeTarget. The target can be Message.Builder,
* FieldSet or MutableMessage.
*
* Package-private because it is used by GeneratedMessage.ExtendableMessage.
*
* @param tag The tag, which should have already been read.
* @return {@code true} unless the tag is an end-group tag.
*/
static boolean mergeFieldFrom(
CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
Descriptors.Descriptor type,
MergeTarget target,
int tag) throws IOException {
if (type.getOptions().getMessageSetWireFormat() &&
tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
mergeMessageSetExtensionFromCodedStream(
input, unknownFields, extensionRegistry, type, target);
return true;
}
final int wireType = WireFormat.getTagWireType(tag);
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
final Descriptors.FieldDescriptor field;
Message defaultInstance = null;
if (type.isExtensionNumber(fieldNumber)) {
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (extensionRegistry instanceof ExtensionRegistry) {
final ExtensionRegistry.ExtensionInfo extension =
target.findExtensionByNumber((ExtensionRegistry) extensionRegistry,
type, fieldNumber);
if (extension == null) {
field = null;
} else {
field = extension.descriptor;
defaultInstance = extension.defaultInstance;
if (defaultInstance == null &&
field.getJavaType()
== Descriptors.FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalStateException(
"Message-typed extension lacked default instance: " +
field.getFullName());
}
}
} else {
field = null;
}
} else if (target.getContainerType() == MergeTarget.ContainerType.MESSAGE) {
field = type.findFieldByNumber(fieldNumber);
} else {
field = null;
}
boolean unknown = false;
boolean packed = false;
if (field == null) {
unknown = true; // Unknown field.
} else if (wireType == FieldSet.getWireFormatForFieldType(
field.getLiteType(),
false /* isPacked */)) {
packed = false;
} else if (field.isPackable() &&
wireType == FieldSet.getWireFormatForFieldType(
field.getLiteType(),
true /* isPacked */)) {
packed = true;
} else {
unknown = true; // Unknown wire type.
}
if (unknown) { // Unknown field or wrong wire type. Skip.
return unknownFields.mergeFieldFrom(tag, input);
}
if (packed) {
final int length = input.readRawVarint32();
final int limit = input.pushLimit(length);
if (field.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
final int rawValue = input.readEnum();
final Object value = field.getEnumType().findValueByNumber(rawValue);
if (value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
target.addRepeatedField(field, value);
}
} else {
while (input.getBytesUntilLimit() > 0) {
final Object value =
target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check());
target.addRepeatedField(field, value);
}
}
input.popLimit(limit);
} else {
final Object value;
switch (field.getType()) {
case GROUP: {
value = target
.parseGroup(input, extensionRegistry, field, defaultInstance);
break;
}
case MESSAGE: {
value = target
.parseMessage(input, extensionRegistry, field, defaultInstance);
break;
}
case ENUM:
final int rawValue = input.readEnum();
value = field.getEnumType().findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (value == null) {
unknownFields.mergeVarintField(fieldNumber, rawValue);
return true;
}
break;
default:
value = target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check());
break;
}
if (field.isRepeated()) {
target.addRepeatedField(field, value);
} else {
target.setField(field, value);
}
}
return true;
}
/**
* Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into
* MergeTarget.
*/
private static void mergeMessageSetExtensionFromCodedStream(
CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
Descriptors.Descriptor type,
MergeTarget target) throws IOException {
// The wire format for MessageSet is:
// message MessageSet {
// repeated group Item = 1 {
// required int32 typeId = 2;
// required bytes message = 3;
// }
// }
// "typeId" is the extension's field number. The extension can only be
// a message type, where "message" contains the encoded bytes of that
// message.
//
// In practice, we will probably never see a MessageSet item in which
// the message appears before the type ID, or where either field does not
// appear exactly once. However, in theory such cases are valid, so we
// should be prepared to accept them.
int typeId = 0;
ByteString rawBytes = null; // If we encounter "message" before "typeId"
ExtensionRegistry.ExtensionInfo extension = null;
// Read bytes from input, if we get it's type first then parse it eagerly,
// otherwise we store the raw bytes in a local variable.
while (true) {
final int tag = input.readTag();
if (tag == 0) {
break;
}
if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
typeId = input.readUInt32();
if (typeId != 0) {
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (extensionRegistry instanceof ExtensionRegistry) {
extension = target.findExtensionByNumber(
(ExtensionRegistry) extensionRegistry, type, typeId);
}
}
} else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
if (typeId != 0) {
if (extension != null &&
ExtensionRegistryLite.isEagerlyParseMessageSets()) {
// We already know the type, so we can parse directly from the
// input with no copying. Hooray!
eagerlyMergeMessageSetExtension(
input, extension, extensionRegistry, target);
rawBytes = null;
continue;
}
}
// We haven't seen a type ID yet or we want parse message lazily.
rawBytes = input.readBytes();
} else { // Unknown tag. Skip it.
if (!input.skipField(tag)) {
break; // End of group
}
}
}
input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
// Process the raw bytes.
if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
if (extension != null) { // We known the type
mergeMessageSetExtensionFromBytes(
rawBytes, extension, extensionRegistry, target);
} else { // We don't know how to parse this. Ignore it.
if (rawBytes != null) {
unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(rawBytes).build());
}
}
}
}
private static void mergeMessageSetExtensionFromBytes(
ByteString rawBytes,
ExtensionRegistry.ExtensionInfo extension,
ExtensionRegistryLite extensionRegistry,
MergeTarget target) throws IOException {
Descriptors.FieldDescriptor field = extension.descriptor;
boolean hasOriginalValue = target.hasField(field);
if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) {
// If the field already exists, we just parse the field.
Object value = target.parseMessageFromBytes(
rawBytes, extensionRegistry,field, extension.defaultInstance);
target.setField(field, value);
} else {
// Use LazyField to load MessageSet lazily.
LazyField lazyField = new LazyField(
extension.defaultInstance, extensionRegistry, rawBytes);
target.setField(field, lazyField);
}
}
private static void eagerlyMergeMessageSetExtension(
CodedInputStream input,
ExtensionRegistry.ExtensionInfo extension,
ExtensionRegistryLite extensionRegistry,
MergeTarget target) throws IOException {
Descriptors.FieldDescriptor field = extension.descriptor;
Object value = target.parseMessage(input, extensionRegistry, field,
extension.defaultInstance);
target.setField(field, value);
}
}