2013-04-18 23:35:02 +02:00
|
|
|
// Protocol Buffers - Google's data interchange format
|
|
|
|
// Copyright 2008 Google Inc. All rights reserved.
|
|
|
|
// http://code.google.com/p/protobuf/
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are
|
|
|
|
// met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above
|
|
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
|
|
// in the documentation and/or other materials provided with the
|
|
|
|
// distribution.
|
|
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
|
|
// contributors may be used to endorse or promote products derived from
|
|
|
|
// this software without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
package com.google.protobuf;
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
|
|
|
|
|
2013-04-18 23:35:02 +02:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.TreeMap;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@code UnknownFieldSet} is used to keep track of fields which were seen when
|
|
|
|
* parsing a protocol message but whose field numbers or types are unrecognized.
|
|
|
|
* This most frequently occurs when new fields are added to a message type
|
|
|
|
* and then messages containing those feilds are read by old software that was
|
|
|
|
* compiled before the new types were added.
|
|
|
|
*
|
|
|
|
* <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
|
|
|
|
* {@link Message.Builder} contains an {@link Builder}).
|
|
|
|
*
|
|
|
|
* <p>Most users will never need to use this class.
|
|
|
|
*
|
|
|
|
* @author kenton@google.com Kenton Varda
|
|
|
|
*/
|
|
|
|
public final class UnknownFieldSet implements MessageLite {
|
|
|
|
private UnknownFieldSet() {}
|
|
|
|
|
|
|
|
/** Create a new {@link Builder}. */
|
|
|
|
public static Builder newBuilder() {
|
|
|
|
return Builder.create();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new {@link Builder} and initialize it to be a copy
|
|
|
|
* of {@code copyFrom}.
|
|
|
|
*/
|
|
|
|
public static Builder newBuilder(final UnknownFieldSet copyFrom) {
|
|
|
|
return newBuilder().mergeFrom(copyFrom);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Get an empty {@code UnknownFieldSet}. */
|
|
|
|
public static UnknownFieldSet getDefaultInstance() {
|
|
|
|
return defaultInstance;
|
|
|
|
}
|
2013-11-11 00:26:50 +01:00
|
|
|
public UnknownFieldSet getDefaultInstanceForType() {
|
2013-04-18 23:35:02 +02:00
|
|
|
return defaultInstance;
|
|
|
|
}
|
|
|
|
private static final UnknownFieldSet defaultInstance =
|
|
|
|
new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct an {@code UnknownFieldSet} around the given map. The map is
|
|
|
|
* expected to be immutable.
|
|
|
|
*/
|
|
|
|
private UnknownFieldSet(final Map<Integer, Field> fields) {
|
|
|
|
this.fields = fields;
|
|
|
|
}
|
|
|
|
private Map<Integer, Field> fields;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(final Object other) {
|
|
|
|
if (this == other) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return (other instanceof UnknownFieldSet) &&
|
|
|
|
fields.equals(((UnknownFieldSet) other).fields);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
return fields.hashCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Get a map of fields in the set by number. */
|
|
|
|
public Map<Integer, Field> asMap() {
|
|
|
|
return fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Check if the given field number is present in the set. */
|
|
|
|
public boolean hasField(final int number) {
|
|
|
|
return fields.containsKey(number);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a field by number. Returns an empty field if not present. Never
|
|
|
|
* returns {@code null}.
|
|
|
|
*/
|
|
|
|
public Field getField(final int number) {
|
|
|
|
final Field result = fields.get(number);
|
|
|
|
return (result == null) ? Field.getDefaultInstance() : result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Serializes the set and writes it to {@code output}. */
|
2013-11-11 00:26:50 +01:00
|
|
|
public void writeTo(final CodedOutputStream output) throws IOException {
|
2013-04-18 23:35:02 +02:00
|
|
|
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
|
|
|
entry.getValue().writeTo(entry.getKey(), output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts the set to a string in protocol buffer text format. This is
|
|
|
|
* just a trivial wrapper around
|
|
|
|
* {@link TextFormat#printToString(UnknownFieldSet)}.
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return TextFormat.printToString(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Serializes the message to a {@code ByteString} and returns it. This is
|
|
|
|
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
|
|
|
|
*/
|
2013-11-11 00:26:50 +01:00
|
|
|
public ByteString toByteString() {
|
2013-04-18 23:35:02 +02:00
|
|
|
try {
|
|
|
|
final ByteString.CodedBuilder out =
|
|
|
|
ByteString.newCodedBuilder(getSerializedSize());
|
|
|
|
writeTo(out.getCodedOutput());
|
|
|
|
return out.build();
|
|
|
|
} catch (final IOException e) {
|
|
|
|
throw new RuntimeException(
|
|
|
|
"Serializing to a ByteString threw an IOException (should " +
|
|
|
|
"never happen).", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Serializes the message to a {@code byte} array and returns it. This is
|
|
|
|
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
|
|
|
|
*/
|
2013-11-11 00:26:50 +01:00
|
|
|
public byte[] toByteArray() {
|
2013-04-18 23:35:02 +02:00
|
|
|
try {
|
|
|
|
final byte[] result = new byte[getSerializedSize()];
|
|
|
|
final CodedOutputStream output = CodedOutputStream.newInstance(result);
|
|
|
|
writeTo(output);
|
|
|
|
output.checkNoSpaceLeft();
|
|
|
|
return result;
|
|
|
|
} catch (final IOException e) {
|
|
|
|
throw new RuntimeException(
|
|
|
|
"Serializing to a byte array threw an IOException " +
|
|
|
|
"(should never happen).", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Serializes the message and writes it to {@code output}. This is just a
|
|
|
|
* trivial wrapper around {@link #writeTo(CodedOutputStream)}.
|
|
|
|
*/
|
2013-11-11 00:26:50 +01:00
|
|
|
public void writeTo(final OutputStream output) throws IOException {
|
2013-04-18 23:35:02 +02:00
|
|
|
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
|
|
|
|
writeTo(codedOutput);
|
|
|
|
codedOutput.flush();
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public void writeDelimitedTo(OutputStream output) throws IOException {
|
2013-04-18 23:35:02 +02:00
|
|
|
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
|
|
|
|
codedOutput.writeRawVarint32(getSerializedSize());
|
|
|
|
writeTo(codedOutput);
|
|
|
|
codedOutput.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Get the number of bytes required to encode this set. */
|
2013-11-11 00:26:50 +01:00
|
|
|
public int getSerializedSize() {
|
2013-04-18 23:35:02 +02:00
|
|
|
int result = 0;
|
|
|
|
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
|
|
|
result += entry.getValue().getSerializedSize(entry.getKey());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Serializes the set and writes it to {@code output} using
|
|
|
|
* {@code MessageSet} wire format.
|
|
|
|
*/
|
|
|
|
public void writeAsMessageSetTo(final CodedOutputStream output)
|
|
|
|
throws IOException {
|
|
|
|
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
|
|
|
entry.getValue().writeAsMessageSetExtensionTo(
|
|
|
|
entry.getKey(), output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the number of bytes required to encode this set using
|
|
|
|
* {@code MessageSet} wire format.
|
|
|
|
*/
|
|
|
|
public int getSerializedSizeAsMessageSet() {
|
|
|
|
int result = 0;
|
|
|
|
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
|
|
|
result += entry.getValue().getSerializedSizeAsMessageSetExtension(
|
|
|
|
entry.getKey());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public boolean isInitialized() {
|
2013-04-18 23:35:02 +02:00
|
|
|
// UnknownFieldSets do not have required fields, so they are always
|
|
|
|
// initialized.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Parse an {@code UnknownFieldSet} from the given input stream. */
|
|
|
|
public static UnknownFieldSet parseFrom(final CodedInputStream input)
|
|
|
|
throws IOException {
|
|
|
|
return newBuilder().mergeFrom(input).build();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
|
|
|
|
public static UnknownFieldSet parseFrom(final ByteString data)
|
|
|
|
throws InvalidProtocolBufferException {
|
|
|
|
return newBuilder().mergeFrom(data).build();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
|
|
|
|
public static UnknownFieldSet parseFrom(final byte[] data)
|
|
|
|
throws InvalidProtocolBufferException {
|
|
|
|
return newBuilder().mergeFrom(data).build();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
|
|
|
|
public static UnknownFieldSet parseFrom(final InputStream input)
|
|
|
|
throws IOException {
|
|
|
|
return newBuilder().mergeFrom(input).build();
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder newBuilderForType() {
|
2013-04-18 23:35:02 +02:00
|
|
|
return newBuilder();
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder toBuilder() {
|
2013-04-18 23:35:02 +02:00
|
|
|
return newBuilder().mergeFrom(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builder for {@link UnknownFieldSet}s.
|
|
|
|
*
|
|
|
|
* <p>Note that this class maintains {@link Field.Builder}s for all fields
|
|
|
|
* in the set. Thus, adding one element to an existing {@link Field} does not
|
|
|
|
* require making a copy. This is important for efficient parsing of
|
|
|
|
* unknown repeated fields. However, it implies that {@link Field}s cannot
|
|
|
|
* be constructed independently, nor can two {@link UnknownFieldSet}s share
|
|
|
|
* the same {@code Field} object.
|
|
|
|
*
|
|
|
|
* <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
|
|
|
|
*/
|
|
|
|
public static final class Builder implements MessageLite.Builder {
|
|
|
|
// This constructor should never be called directly (except from 'create').
|
|
|
|
private Builder() {}
|
|
|
|
|
|
|
|
private Map<Integer, Field> fields;
|
|
|
|
|
|
|
|
// Optimization: We keep around a builder for the last field that was
|
|
|
|
// modified so that we can efficiently add to it multiple times in a
|
|
|
|
// row (important when parsing an unknown repeated field).
|
|
|
|
private int lastFieldNumber;
|
|
|
|
private Field.Builder lastField;
|
|
|
|
|
|
|
|
private static Builder create() {
|
|
|
|
Builder builder = new Builder();
|
|
|
|
builder.reinitialize();
|
|
|
|
return builder;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a field builder for the given field number which includes any
|
|
|
|
* values that already exist.
|
|
|
|
*/
|
|
|
|
private Field.Builder getFieldBuilder(final int number) {
|
|
|
|
if (lastField != null) {
|
|
|
|
if (number == lastFieldNumber) {
|
|
|
|
return lastField;
|
|
|
|
}
|
|
|
|
// Note: addField() will reset lastField and lastFieldNumber.
|
|
|
|
addField(lastFieldNumber, lastField.build());
|
|
|
|
}
|
|
|
|
if (number == 0) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
final Field existing = fields.get(number);
|
|
|
|
lastFieldNumber = number;
|
|
|
|
lastField = Field.newBuilder();
|
|
|
|
if (existing != null) {
|
|
|
|
lastField.mergeFrom(existing);
|
|
|
|
}
|
|
|
|
return lastField;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build the {@link UnknownFieldSet} and return it.
|
|
|
|
*
|
|
|
|
* <p>Once {@code build()} has been called, the {@code Builder} will no
|
|
|
|
* longer be usable. Calling any method after {@code build()} will result
|
|
|
|
* in undefined behavior and can cause a {@code NullPointerException} to be
|
|
|
|
* thrown.
|
|
|
|
*/
|
2013-11-11 00:26:50 +01:00
|
|
|
public UnknownFieldSet build() {
|
2013-04-18 23:35:02 +02:00
|
|
|
getFieldBuilder(0); // Force lastField to be built.
|
|
|
|
final UnknownFieldSet result;
|
|
|
|
if (fields.isEmpty()) {
|
|
|
|
result = getDefaultInstance();
|
|
|
|
} else {
|
|
|
|
result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
|
|
|
|
}
|
|
|
|
fields = null;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public UnknownFieldSet buildPartial() {
|
2013-04-18 23:35:02 +02:00
|
|
|
// No required fields, so this is the same as build().
|
|
|
|
return build();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Builder clone() {
|
|
|
|
getFieldBuilder(0); // Force lastField to be built.
|
|
|
|
return UnknownFieldSet.newBuilder().mergeFrom(
|
|
|
|
new UnknownFieldSet(fields));
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public UnknownFieldSet getDefaultInstanceForType() {
|
2013-04-18 23:35:02 +02:00
|
|
|
return UnknownFieldSet.getDefaultInstance();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void reinitialize() {
|
|
|
|
fields = Collections.emptyMap();
|
|
|
|
lastFieldNumber = 0;
|
|
|
|
lastField = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Reset the builder to an empty set. */
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder clear() {
|
2013-04-18 23:35:02 +02:00
|
|
|
reinitialize();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Merge the fields from {@code other} into this set. If a field number
|
|
|
|
* exists in both sets, {@code other}'s values for that field will be
|
|
|
|
* appended to the values in this set.
|
|
|
|
*/
|
|
|
|
public Builder mergeFrom(final UnknownFieldSet other) {
|
|
|
|
if (other != getDefaultInstance()) {
|
|
|
|
for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
|
|
|
|
mergeField(entry.getKey(), entry.getValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a field to the {@code UnknownFieldSet}. If a field with the same
|
|
|
|
* number already exists, the two are merged.
|
|
|
|
*/
|
|
|
|
public Builder mergeField(final int number, final Field field) {
|
|
|
|
if (number == 0) {
|
|
|
|
throw new IllegalArgumentException("Zero is not a valid field number.");
|
|
|
|
}
|
|
|
|
if (hasField(number)) {
|
|
|
|
getFieldBuilder(number).mergeFrom(field);
|
|
|
|
} else {
|
|
|
|
// Optimization: We could call getFieldBuilder(number).mergeFrom(field)
|
|
|
|
// in this case, but that would create a copy of the Field object.
|
|
|
|
// We'd rather reuse the one passed to us, so call addField() instead.
|
|
|
|
addField(number, field);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convenience method for merging a new field containing a single varint
|
|
|
|
* value. This is used in particular when an unknown enum value is
|
|
|
|
* encountered.
|
|
|
|
*/
|
|
|
|
public Builder mergeVarintField(final int number, final int value) {
|
|
|
|
if (number == 0) {
|
|
|
|
throw new IllegalArgumentException("Zero is not a valid field number.");
|
|
|
|
}
|
|
|
|
getFieldBuilder(number).addVarint(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Check if the given field number is present in the set. */
|
|
|
|
public boolean hasField(final int number) {
|
|
|
|
if (number == 0) {
|
|
|
|
throw new IllegalArgumentException("Zero is not a valid field number.");
|
|
|
|
}
|
|
|
|
return number == lastFieldNumber || fields.containsKey(number);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a field to the {@code UnknownFieldSet}. If a field with the same
|
|
|
|
* number already exists, it is removed.
|
|
|
|
*/
|
|
|
|
public Builder addField(final int number, final Field field) {
|
|
|
|
if (number == 0) {
|
|
|
|
throw new IllegalArgumentException("Zero is not a valid field number.");
|
|
|
|
}
|
|
|
|
if (lastField != null && lastFieldNumber == number) {
|
|
|
|
// Discard this.
|
|
|
|
lastField = null;
|
|
|
|
lastFieldNumber = 0;
|
|
|
|
}
|
|
|
|
if (fields.isEmpty()) {
|
|
|
|
fields = new TreeMap<Integer,Field>();
|
|
|
|
}
|
|
|
|
fields.put(number, field);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get all present {@code Field}s as an immutable {@code Map}. If more
|
|
|
|
* fields are added, the changes may or may not be reflected in this map.
|
|
|
|
*/
|
|
|
|
public Map<Integer, Field> asMap() {
|
|
|
|
getFieldBuilder(0); // Force lastField to be built.
|
|
|
|
return Collections.unmodifiableMap(fields);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse an entire message from {@code input} and merge its fields into
|
|
|
|
* this set.
|
|
|
|
*/
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(final CodedInputStream input) throws IOException {
|
2013-04-18 23:35:02 +02:00
|
|
|
while (true) {
|
|
|
|
final int tag = input.readTag();
|
|
|
|
if (tag == 0 || !mergeFieldFrom(tag, input)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a single field from {@code input} and merge it into this set.
|
|
|
|
* @param tag The field's tag number, which was already parsed.
|
|
|
|
* @return {@code false} if the tag is an engroup tag.
|
|
|
|
*/
|
|
|
|
public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
|
|
|
|
throws IOException {
|
|
|
|
final int number = WireFormat.getTagFieldNumber(tag);
|
|
|
|
switch (WireFormat.getTagWireType(tag)) {
|
|
|
|
case WireFormat.WIRETYPE_VARINT:
|
|
|
|
getFieldBuilder(number).addVarint(input.readInt64());
|
|
|
|
return true;
|
|
|
|
case WireFormat.WIRETYPE_FIXED64:
|
|
|
|
getFieldBuilder(number).addFixed64(input.readFixed64());
|
|
|
|
return true;
|
|
|
|
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
|
|
|
|
getFieldBuilder(number).addLengthDelimited(input.readBytes());
|
|
|
|
return true;
|
|
|
|
case WireFormat.WIRETYPE_START_GROUP:
|
|
|
|
final Builder subBuilder = newBuilder();
|
|
|
|
input.readGroup(number, subBuilder,
|
|
|
|
ExtensionRegistry.getEmptyRegistry());
|
|
|
|
getFieldBuilder(number).addGroup(subBuilder.build());
|
|
|
|
return true;
|
|
|
|
case WireFormat.WIRETYPE_END_GROUP:
|
|
|
|
return false;
|
|
|
|
case WireFormat.WIRETYPE_FIXED32:
|
|
|
|
getFieldBuilder(number).addFixed32(input.readFixed32());
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
throw InvalidProtocolBufferException.invalidWireType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
|
|
|
|
* set being built. This is just a small wrapper around
|
|
|
|
* {@link #mergeFrom(CodedInputStream)}.
|
|
|
|
*/
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(final ByteString data)
|
2013-04-18 23:35:02 +02:00
|
|
|
throws InvalidProtocolBufferException {
|
|
|
|
try {
|
|
|
|
final CodedInputStream input = data.newCodedInput();
|
|
|
|
mergeFrom(input);
|
|
|
|
input.checkLastTagWas(0);
|
|
|
|
return this;
|
|
|
|
} catch (final InvalidProtocolBufferException e) {
|
|
|
|
throw e;
|
|
|
|
} catch (final IOException e) {
|
|
|
|
throw new RuntimeException(
|
|
|
|
"Reading from a ByteString threw an IOException (should " +
|
|
|
|
"never happen).", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
|
|
|
|
* set being built. This is just a small wrapper around
|
|
|
|
* {@link #mergeFrom(CodedInputStream)}.
|
|
|
|
*/
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(final byte[] data)
|
2013-04-18 23:35:02 +02:00
|
|
|
throws InvalidProtocolBufferException {
|
|
|
|
try {
|
|
|
|
final CodedInputStream input = CodedInputStream.newInstance(data);
|
|
|
|
mergeFrom(input);
|
|
|
|
input.checkLastTagWas(0);
|
|
|
|
return this;
|
|
|
|
} catch (final InvalidProtocolBufferException e) {
|
|
|
|
throw e;
|
|
|
|
} catch (final IOException e) {
|
|
|
|
throw new RuntimeException(
|
|
|
|
"Reading from a byte array threw an IOException (should " +
|
|
|
|
"never happen).", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
|
|
|
|
* set being built. This is just a small wrapper around
|
|
|
|
* {@link #mergeFrom(CodedInputStream)}.
|
|
|
|
*/
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(final InputStream input) throws IOException {
|
2013-04-18 23:35:02 +02:00
|
|
|
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
|
|
|
|
mergeFrom(codedInput);
|
|
|
|
codedInput.checkLastTagWas(0);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public boolean mergeDelimitedFrom(InputStream input)
|
2013-04-18 23:35:02 +02:00
|
|
|
throws IOException {
|
|
|
|
final int firstByte = input.read();
|
|
|
|
if (firstByte == -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
final int size = CodedInputStream.readRawVarint32(firstByte, input);
|
|
|
|
final InputStream limitedInput = new LimitedInputStream(input, size);
|
|
|
|
mergeFrom(limitedInput);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public boolean mergeDelimitedFrom(
|
2013-04-18 23:35:02 +02:00
|
|
|
InputStream input,
|
|
|
|
ExtensionRegistryLite extensionRegistry) throws IOException {
|
|
|
|
// UnknownFieldSet has no extensions.
|
|
|
|
return mergeDelimitedFrom(input);
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(
|
2013-04-18 23:35:02 +02:00
|
|
|
CodedInputStream input,
|
|
|
|
ExtensionRegistryLite extensionRegistry) throws IOException {
|
|
|
|
// UnknownFieldSet has no extensions.
|
|
|
|
return mergeFrom(input);
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(
|
2013-04-18 23:35:02 +02:00
|
|
|
ByteString data,
|
|
|
|
ExtensionRegistryLite extensionRegistry)
|
|
|
|
throws InvalidProtocolBufferException {
|
|
|
|
// UnknownFieldSet has no extensions.
|
|
|
|
return mergeFrom(data);
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(byte[] data, int off, int len)
|
2013-04-18 23:35:02 +02:00
|
|
|
throws InvalidProtocolBufferException {
|
|
|
|
try {
|
|
|
|
final CodedInputStream input =
|
|
|
|
CodedInputStream.newInstance(data, off, len);
|
|
|
|
mergeFrom(input);
|
|
|
|
input.checkLastTagWas(0);
|
|
|
|
return this;
|
|
|
|
} catch (InvalidProtocolBufferException e) {
|
|
|
|
throw e;
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new RuntimeException(
|
|
|
|
"Reading from a byte array threw an IOException (should " +
|
|
|
|
"never happen).", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(
|
2013-04-18 23:35:02 +02:00
|
|
|
byte[] data,
|
|
|
|
ExtensionRegistryLite extensionRegistry)
|
|
|
|
throws InvalidProtocolBufferException {
|
|
|
|
// UnknownFieldSet has no extensions.
|
|
|
|
return mergeFrom(data);
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(
|
2013-04-18 23:35:02 +02:00
|
|
|
byte[] data, int off, int len,
|
|
|
|
ExtensionRegistryLite extensionRegistry)
|
|
|
|
throws InvalidProtocolBufferException {
|
|
|
|
// UnknownFieldSet has no extensions.
|
|
|
|
return mergeFrom(data, off, len);
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public Builder mergeFrom(
|
2013-04-18 23:35:02 +02:00
|
|
|
InputStream input,
|
|
|
|
ExtensionRegistryLite extensionRegistry) throws IOException {
|
|
|
|
// UnknownFieldSet has no extensions.
|
|
|
|
return mergeFrom(input);
|
|
|
|
}
|
|
|
|
|
2013-11-11 00:26:50 +01:00
|
|
|
public boolean isInitialized() {
|
2013-04-18 23:35:02 +02:00
|
|
|
// UnknownFieldSets do not have required fields, so they are always
|
|
|
|
// initialized.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents a single field in an {@code UnknownFieldSet}.
|
|
|
|
*
|
|
|
|
* <p>A {@code Field} consists of five lists of values. The lists correspond
|
|
|
|
* to the five "wire types" used in the protocol buffer binary format.
|
|
|
|
* The wire type of each field can be determined from the encoded form alone,
|
|
|
|
* without knowing the field's declared type. So, we are able to parse
|
|
|
|
* unknown values at least this far and separate them. Normally, only one
|
|
|
|
* of the five lists will contain any values, since it is impossible to
|
|
|
|
* define a valid message type that declares two different types for the
|
|
|
|
* same field number. However, the code is designed to allow for the case
|
|
|
|
* where the same unknown field number is encountered using multiple different
|
|
|
|
* wire types.
|
|
|
|
*
|
|
|
|
* <p>{@code Field} is an immutable class. To construct one, you must use a
|
|
|
|
* {@link Builder}.
|
|
|
|
*
|
|
|
|
* @see UnknownFieldSet
|
|
|
|
*/
|
|
|
|
public static final class Field {
|
|
|
|
private Field() {}
|
|
|
|
|
|
|
|
/** Construct a new {@link Builder}. */
|
|
|
|
public static Builder newBuilder() {
|
|
|
|
return Builder.create();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct a new {@link Builder} and initialize it to a copy of
|
|
|
|
* {@code copyFrom}.
|
|
|
|
*/
|
|
|
|
public static Builder newBuilder(final Field copyFrom) {
|
|
|
|
return newBuilder().mergeFrom(copyFrom);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Get an empty {@code Field}. */
|
|
|
|
public static Field getDefaultInstance() {
|
|
|
|
return fieldDefaultInstance;
|
|
|
|
}
|
|
|
|
private static final Field fieldDefaultInstance = newBuilder().build();
|
|
|
|
|
|
|
|
/** Get the list of varint values for this field. */
|
|
|
|
public List<Long> getVarintList() { return varint; }
|
|
|
|
|
|
|
|
/** Get the list of fixed32 values for this field. */
|
|
|
|
public List<Integer> getFixed32List() { return fixed32; }
|
|
|
|
|
|
|
|
/** Get the list of fixed64 values for this field. */
|
|
|
|
public List<Long> getFixed64List() { return fixed64; }
|
|
|
|
|
|
|
|
/** Get the list of length-delimited values for this field. */
|
|
|
|
public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the list of embedded group values for this field. These are
|
|
|
|
* represented using {@link UnknownFieldSet}s rather than {@link Message}s
|
|
|
|
* since the group's type is presumably unknown.
|
|
|
|
*/
|
|
|
|
public List<UnknownFieldSet> getGroupList() { return group; }
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(final Object other) {
|
|
|
|
if (this == other) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!(other instanceof Field)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return Arrays.equals(getIdentityArray(),
|
|
|
|
((Field) other).getIdentityArray());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
return Arrays.hashCode(getIdentityArray());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the array of objects to be used to uniquely identify this
|
|
|
|
* {@link Field} instance.
|
|
|
|
*/
|
|
|
|
private Object[] getIdentityArray() {
|
|
|
|
return new Object[] {
|
|
|
|
varint,
|
|
|
|
fixed32,
|
|
|
|
fixed64,
|
|
|
|
lengthDelimited,
|
|
|
|
group};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Serializes the field, including field number, and writes it to
|
|
|
|
* {@code output}.
|
|
|
|
*/
|
|
|
|
public void writeTo(final int fieldNumber, final CodedOutputStream output)
|
|
|
|
throws IOException {
|
|
|
|
for (final long value : varint) {
|
|
|
|
output.writeUInt64(fieldNumber, value);
|
|
|
|
}
|
|
|
|
for (final int value : fixed32) {
|
|
|
|
output.writeFixed32(fieldNumber, value);
|
|
|
|
}
|
|
|
|
for (final long value : fixed64) {
|
|
|
|
output.writeFixed64(fieldNumber, value);
|
|
|
|
}
|
|
|
|
for (final ByteString value : lengthDelimited) {
|
|
|
|
output.writeBytes(fieldNumber, value);
|
|
|
|
}
|
|
|
|
for (final UnknownFieldSet value : group) {
|
|
|
|
output.writeGroup(fieldNumber, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the number of bytes required to encode this field, including field
|
|
|
|
* number.
|
|
|
|
*/
|
|
|
|
public int getSerializedSize(final int fieldNumber) {
|
|
|
|
int result = 0;
|
|
|
|
for (final long value : varint) {
|
|
|
|
result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
|
|
|
|
}
|
|
|
|
for (final int value : fixed32) {
|
|
|
|
result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
|
|
|
|
}
|
|
|
|
for (final long value : fixed64) {
|
|
|
|
result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
|
|
|
|
}
|
|
|
|
for (final ByteString value : lengthDelimited) {
|
|
|
|
result += CodedOutputStream.computeBytesSize(fieldNumber, value);
|
|
|
|
}
|
|
|
|
for (final UnknownFieldSet value : group) {
|
|
|
|
result += CodedOutputStream.computeGroupSize(fieldNumber, value);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Serializes the field, including field number, and writes it to
|
|
|
|
* {@code output}, using {@code MessageSet} wire format.
|
|
|
|
*/
|
|
|
|
public void writeAsMessageSetExtensionTo(
|
|
|
|
final int fieldNumber,
|
|
|
|
final CodedOutputStream output)
|
|
|
|
throws IOException {
|
|
|
|
for (final ByteString value : lengthDelimited) {
|
|
|
|
output.writeRawMessageSetExtension(fieldNumber, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the number of bytes required to encode this field, including field
|
|
|
|
* number, using {@code MessageSet} wire format.
|
|
|
|
*/
|
|
|
|
public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
|
|
|
|
int result = 0;
|
|
|
|
for (final ByteString value : lengthDelimited) {
|
|
|
|
result += CodedOutputStream.computeRawMessageSetExtensionSize(
|
|
|
|
fieldNumber, value);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
private List<Long> varint;
|
|
|
|
private List<Integer> fixed32;
|
|
|
|
private List<Long> fixed64;
|
|
|
|
private List<ByteString> lengthDelimited;
|
|
|
|
private List<UnknownFieldSet> group;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to build a {@link Field} within an {@link UnknownFieldSet}.
|
|
|
|
*
|
|
|
|
* <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
|
|
|
|
*/
|
|
|
|
public static final class Builder {
|
|
|
|
// This constructor should never be called directly (except from 'create').
|
|
|
|
private Builder() {}
|
|
|
|
|
|
|
|
private static Builder create() {
|
|
|
|
Builder builder = new Builder();
|
|
|
|
builder.result = new Field();
|
|
|
|
return builder;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Field result;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build the field. After {@code build()} has been called, the
|
|
|
|
* {@code Builder} is no longer usable. Calling any other method will
|
|
|
|
* result in undefined behavior and can cause a
|
|
|
|
* {@code NullPointerException} to be thrown.
|
|
|
|
*/
|
|
|
|
public Field build() {
|
|
|
|
if (result.varint == null) {
|
|
|
|
result.varint = Collections.emptyList();
|
|
|
|
} else {
|
|
|
|
result.varint = Collections.unmodifiableList(result.varint);
|
|
|
|
}
|
|
|
|
if (result.fixed32 == null) {
|
|
|
|
result.fixed32 = Collections.emptyList();
|
|
|
|
} else {
|
|
|
|
result.fixed32 = Collections.unmodifiableList(result.fixed32);
|
|
|
|
}
|
|
|
|
if (result.fixed64 == null) {
|
|
|
|
result.fixed64 = Collections.emptyList();
|
|
|
|
} else {
|
|
|
|
result.fixed64 = Collections.unmodifiableList(result.fixed64);
|
|
|
|
}
|
|
|
|
if (result.lengthDelimited == null) {
|
|
|
|
result.lengthDelimited = Collections.emptyList();
|
|
|
|
} else {
|
|
|
|
result.lengthDelimited =
|
|
|
|
Collections.unmodifiableList(result.lengthDelimited);
|
|
|
|
}
|
|
|
|
if (result.group == null) {
|
|
|
|
result.group = Collections.emptyList();
|
|
|
|
} else {
|
|
|
|
result.group = Collections.unmodifiableList(result.group);
|
|
|
|
}
|
|
|
|
|
|
|
|
final Field returnMe = result;
|
|
|
|
result = null;
|
|
|
|
return returnMe;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Discard the field's contents. */
|
|
|
|
public Builder clear() {
|
|
|
|
result = new Field();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Merge the values in {@code other} into this field. For each list
|
|
|
|
* of values, {@code other}'s values are append to the ones in this
|
|
|
|
* field.
|
|
|
|
*/
|
|
|
|
public Builder mergeFrom(final Field other) {
|
|
|
|
if (!other.varint.isEmpty()) {
|
|
|
|
if (result.varint == null) {
|
|
|
|
result.varint = new ArrayList<Long>();
|
|
|
|
}
|
|
|
|
result.varint.addAll(other.varint);
|
|
|
|
}
|
|
|
|
if (!other.fixed32.isEmpty()) {
|
|
|
|
if (result.fixed32 == null) {
|
|
|
|
result.fixed32 = new ArrayList<Integer>();
|
|
|
|
}
|
|
|
|
result.fixed32.addAll(other.fixed32);
|
|
|
|
}
|
|
|
|
if (!other.fixed64.isEmpty()) {
|
|
|
|
if (result.fixed64 == null) {
|
|
|
|
result.fixed64 = new ArrayList<Long>();
|
|
|
|
}
|
|
|
|
result.fixed64.addAll(other.fixed64);
|
|
|
|
}
|
|
|
|
if (!other.lengthDelimited.isEmpty()) {
|
|
|
|
if (result.lengthDelimited == null) {
|
|
|
|
result.lengthDelimited = new ArrayList<ByteString>();
|
|
|
|
}
|
|
|
|
result.lengthDelimited.addAll(other.lengthDelimited);
|
|
|
|
}
|
|
|
|
if (!other.group.isEmpty()) {
|
|
|
|
if (result.group == null) {
|
|
|
|
result.group = new ArrayList<UnknownFieldSet>();
|
|
|
|
}
|
|
|
|
result.group.addAll(other.group);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Add a varint value. */
|
|
|
|
public Builder addVarint(final long value) {
|
|
|
|
if (result.varint == null) {
|
|
|
|
result.varint = new ArrayList<Long>();
|
|
|
|
}
|
|
|
|
result.varint.add(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Add a fixed32 value. */
|
|
|
|
public Builder addFixed32(final int value) {
|
|
|
|
if (result.fixed32 == null) {
|
|
|
|
result.fixed32 = new ArrayList<Integer>();
|
|
|
|
}
|
|
|
|
result.fixed32.add(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Add a fixed64 value. */
|
|
|
|
public Builder addFixed64(final long value) {
|
|
|
|
if (result.fixed64 == null) {
|
|
|
|
result.fixed64 = new ArrayList<Long>();
|
|
|
|
}
|
|
|
|
result.fixed64.add(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Add a length-delimited value. */
|
|
|
|
public Builder addLengthDelimited(final ByteString value) {
|
|
|
|
if (result.lengthDelimited == null) {
|
|
|
|
result.lengthDelimited = new ArrayList<ByteString>();
|
|
|
|
}
|
|
|
|
result.lengthDelimited.add(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Add an embedded group. */
|
|
|
|
public Builder addGroup(final UnknownFieldSet value) {
|
|
|
|
if (result.group == null) {
|
|
|
|
result.group = new ArrayList<UnknownFieldSet>();
|
|
|
|
}
|
|
|
|
result.group.add(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|