| // 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.AbstractMessageLite.Builder.LimitedInputStream; |
| 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.ListIterator; |
| 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 fields 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() { |
| fields = null; |
| fieldsDescending = null; |
| } |
| |
| /** 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; |
| } |
| |
| @Override |
| public UnknownFieldSet getDefaultInstanceForType() { |
| return defaultInstance; |
| } |
| |
| private static final UnknownFieldSet defaultInstance = |
| new UnknownFieldSet( |
| Collections.<Integer, Field>emptyMap(), Collections.<Integer, Field>emptyMap()); |
| |
| /** |
| * Construct an {@code UnknownFieldSet} around the given map. The map is expected to be immutable. |
| */ |
| UnknownFieldSet(final Map<Integer, Field> fields, final Map<Integer, Field> fieldsDescending) { |
| this.fields = fields; |
| this.fieldsDescending = fieldsDescending; |
| } |
| |
| private final Map<Integer, Field> fields; |
| |
| /** A copy of {@link #fields} who's iterator order is reversed. */ |
| private final Map<Integer, Field> fieldsDescending; |
| |
| |
| @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}. */ |
| @Override |
| public void writeTo(final CodedOutputStream output) throws IOException { |
| for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { |
| Field field = entry.getValue(); |
| field.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)}. |
| */ |
| @Override |
| public ByteString toByteString() { |
| 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)}. |
| */ |
| @Override |
| public byte[] toByteArray() { |
| 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)}. |
| */ |
| @Override |
| public void writeTo(final OutputStream output) throws IOException { |
| final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); |
| writeTo(codedOutput); |
| codedOutput.flush(); |
| } |
| |
| @Override |
| public void writeDelimitedTo(OutputStream output) throws IOException { |
| final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); |
| codedOutput.writeRawVarint32(getSerializedSize()); |
| writeTo(codedOutput); |
| codedOutput.flush(); |
| } |
| |
| /** Get the number of bytes required to encode this set. */ |
| @Override |
| public int getSerializedSize() { |
| 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); |
| } |
| } |
| |
| /** Serializes the set and writes it to {@code writer}. */ |
| void writeTo(Writer writer) throws IOException { |
| if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) { |
| // Write fields in descending order. |
| for (Map.Entry<Integer, Field> entry : fieldsDescending.entrySet()) { |
| entry.getValue().writeTo(entry.getKey(), writer); |
| } |
| } else { |
| // Write fields in ascending order. |
| for (Map.Entry<Integer, Field> entry : fields.entrySet()) { |
| entry.getValue().writeTo(entry.getKey(), writer); |
| } |
| } |
| } |
| |
| /** Serializes the set and writes it to {@code writer} using {@code MessageSet} wire format. */ |
| void writeAsMessageSetTo(final Writer writer) throws IOException { |
| if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) { |
| // Write fields in descending order. |
| for (final Map.Entry<Integer, Field> entry : fieldsDescending.entrySet()) { |
| entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), writer); |
| } |
| } else { |
| // Write fields in ascending order. |
| for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { |
| entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), writer); |
| } |
| } |
| } |
| |
| /** 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; |
| } |
| |
| @Override |
| public boolean isInitialized() { |
| // 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(); |
| } |
| |
| @Override |
| public Builder newBuilderForType() { |
| return newBuilder(); |
| } |
| |
| @Override |
| public Builder toBuilder() { |
| 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. |
| */ |
| @Override |
| public UnknownFieldSet build() { |
| getFieldBuilder(0); // Force lastField to be built. |
| final UnknownFieldSet result; |
| if (fields.isEmpty()) { |
| result = getDefaultInstance(); |
| } else { |
| Map<Integer, Field> descendingFields = null; |
| descendingFields = |
| Collections.unmodifiableMap(((TreeMap<Integer, Field>) fields).descendingMap()); |
| result = new UnknownFieldSet(Collections.unmodifiableMap(fields), descendingFields); |
| } |
| fields = null; |
| return result; |
| } |
| |
| @Override |
| public UnknownFieldSet buildPartial() { |
| // No required fields, so this is the same as build(). |
| return build(); |
| } |
| |
| @Override |
| public Builder clone() { |
| getFieldBuilder(0); // Force lastField to be built. |
| Map<Integer, Field> descendingFields = null; |
| descendingFields = |
| Collections.unmodifiableMap(((TreeMap<Integer, Field>) fields).descendingMap()); |
| return UnknownFieldSet.newBuilder().mergeFrom(new UnknownFieldSet(fields, descendingFields)); |
| } |
| |
| @Override |
| public UnknownFieldSet getDefaultInstanceForType() { |
| return UnknownFieldSet.getDefaultInstance(); |
| } |
| |
| private void reinitialize() { |
| fields = Collections.emptyMap(); |
| lastFieldNumber = 0; |
| lastField = null; |
| } |
| |
| /** Reset the builder to an empty set. */ |
| @Override |
| public Builder clear() { |
| reinitialize(); |
| return this; |
| } |
| |
| /** Clear fields from the set with a given field number. */ |
| public Builder clearField(final int number) { |
| 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.containsKey(number)) { |
| fields.remove(number); |
| } |
| 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; |
| } |
| |
| /** |
| * Convenience method for merging a length-delimited field. |
| * |
| * <p>For use by generated code only. |
| */ |
| public Builder mergeLengthDelimitedField(final int number, final ByteString value) { |
| if (number == 0) { |
| throw new IllegalArgumentException("Zero is not a valid field number."); |
| } |
| getFieldBuilder(number).addLengthDelimited(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. */ |
| @Override |
| public Builder mergeFrom(final CodedInputStream input) throws IOException { |
| 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 end group 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)}. |
| */ |
| @Override |
| public Builder mergeFrom(final ByteString data) 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)}. |
| */ |
| @Override |
| public Builder mergeFrom(final byte[] data) 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)}. |
| */ |
| @Override |
| public Builder mergeFrom(final InputStream input) throws IOException { |
| final CodedInputStream codedInput = CodedInputStream.newInstance(input); |
| mergeFrom(codedInput); |
| codedInput.checkLastTagWas(0); |
| return this; |
| } |
| |
| @Override |
| public boolean mergeDelimitedFrom(InputStream input) 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; |
| } |
| |
| @Override |
| public boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| // UnknownFieldSet has no extensions. |
| return mergeDelimitedFrom(input); |
| } |
| |
| @Override |
| public Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| // UnknownFieldSet has no extensions. |
| return mergeFrom(input); |
| } |
| |
| @Override |
| public Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry) |
| throws InvalidProtocolBufferException { |
| // UnknownFieldSet has no extensions. |
| return mergeFrom(data); |
| } |
| |
| @Override |
| public Builder mergeFrom(byte[] data, int off, int len) 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); |
| } |
| } |
| |
| @Override |
| public Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry) |
| throws InvalidProtocolBufferException { |
| // UnknownFieldSet has no extensions. |
| return mergeFrom(data); |
| } |
| |
| @Override |
| public Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry) |
| throws InvalidProtocolBufferException { |
| // UnknownFieldSet has no extensions. |
| return mergeFrom(data, off, len); |
| } |
| |
| @Override |
| public Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry) |
| throws IOException { |
| // UnknownFieldSet has no extensions. |
| return mergeFrom(input); |
| } |
| |
| @Override |
| public Builder mergeFrom(MessageLite m) { |
| if (m instanceof UnknownFieldSet) { |
| return mergeFrom((UnknownFieldSet) m); |
| } |
| throw new IllegalArgumentException( |
| "mergeFrom(MessageLite) can only merge messages of the same type."); |
| } |
| |
| @Override |
| public boolean isInitialized() { |
| // 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 message to a {@code ByteString} and returns it. This is just a trivial wrapper |
| * around {@link #writeTo(int, CodedOutputStream)}. |
| */ |
| public ByteString toByteString(int fieldNumber) { |
| try { |
| // TODO(lukes): consider caching serialized size in a volatile long |
| final ByteString.CodedBuilder out = |
| ByteString.newCodedBuilder(getSerializedSize(fieldNumber)); |
| writeTo(fieldNumber, out.getCodedOutput()); |
| return out.build(); |
| } catch (IOException e) { |
| throw new RuntimeException( |
| "Serializing to a ByteString should never fail with an IOException", e); |
| } |
| } |
| |
| /** 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); |
| } |
| } |
| |
| /** Serializes the field, including field number, and writes it to {@code writer}. */ |
| void writeTo(final int fieldNumber, final Writer writer) throws IOException { |
| writer.writeInt64List(fieldNumber, varint, false); |
| writer.writeFixed32List(fieldNumber, fixed32, false); |
| writer.writeFixed64List(fieldNumber, fixed64, false); |
| writer.writeBytesList(fieldNumber, lengthDelimited); |
| |
| if (writer.fieldOrder() == Writer.FieldOrder.ASCENDING) { |
| for (int i = 0; i < group.size(); i++) { |
| writer.writeStartGroup(fieldNumber); |
| group.get(i).writeTo(writer); |
| writer.writeEndGroup(fieldNumber); |
| } |
| } else { |
| for (int i = group.size() - 1; i >= 0; i--) { |
| writer.writeEndGroup(fieldNumber); |
| group.get(i).writeTo(writer); |
| writer.writeStartGroup(fieldNumber); |
| } |
| } |
| } |
| |
| /** |
| * Serializes the field, including field number, and writes it to {@code writer}, using {@code |
| * MessageSet} wire format. |
| */ |
| private void writeAsMessageSetExtensionTo(final int fieldNumber, final Writer writer) |
| throws IOException { |
| if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) { |
| // Write in descending field order. |
| ListIterator<ByteString> iter = lengthDelimited.listIterator(lengthDelimited.size()); |
| while (iter.hasPrevious()) { |
| writer.writeMessageSetItem(fieldNumber, iter.previous()); |
| } |
| } else { |
| // Write in ascending field order. |
| for (final ByteString value : lengthDelimited) { |
| writer.writeMessageSetItem(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; |
| } |
| } |
| } |
| |
| /** Parser to implement MessageLite interface. */ |
| public static final class Parser extends AbstractParser<UnknownFieldSet> { |
| @Override |
| public UnknownFieldSet parsePartialFrom( |
| CodedInputStream input, ExtensionRegistryLite extensionRegistry) |
| throws InvalidProtocolBufferException { |
| Builder builder = newBuilder(); |
| try { |
| builder.mergeFrom(input); |
| } catch (InvalidProtocolBufferException e) { |
| throw e.setUnfinishedMessage(builder.buildPartial()); |
| } catch (IOException e) { |
| throw new InvalidProtocolBufferException(e).setUnfinishedMessage(builder.buildPartial()); |
| } |
| return builder.buildPartial(); |
| } |
| } |
| |
| private static final Parser PARSER = new Parser(); |
| |
| @Override |
| public final Parser getParserForType() { |
| return PARSER; |
| } |
| } |