diff options
| author | Hao Nguyen <haon@google.com> | 2019-04-05 16:39:18 -0700 |
|---|---|---|
| committer | Hao Nguyen <haon@google.com> | 2019-04-05 16:39:18 -0700 |
| commit | a48a574f7e890436363ca8ac71d866252b216052 (patch) | |
| tree | 7829f1b60e31da551f22a3df4756bfef0b7f9096 /java | |
| parent | 3a3956e8a258784461270961c6577341356bce52 (diff) | |
| download | platform_external_protobuf-a48a574f7e890436363ca8ac71d866252b216052.tar.gz platform_external_protobuf-a48a574f7e890436363ca8ac71d866252b216052.tar.bz2 platform_external_protobuf-a48a574f7e890436363ca8ac71d866252b216052.zip | |
Down integrate to Github
Diffstat (limited to 'java')
112 files changed, 34654 insertions, 1584 deletions
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java index 172057509..ba0138af5 100644 --- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java +++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java @@ -106,6 +106,56 @@ public abstract class AbstractMessageLite< } + @ExperimentalApi + protected final boolean isInitializedInternal() { + return Protobuf.getInstance().schemaFor(this).isInitialized(this); + } + + @ExperimentalApi + protected final int getSerializedSizeInternal() { + return Protobuf.getInstance().schemaFor(this).getSerializedSize(this); + } + + int getSerializedSize(Schema schema) { + int memoizedSerializedSize = getMemoizedSerializedSize(); + if (memoizedSerializedSize == -1) { + memoizedSerializedSize = schema.getSerializedSize(this); + setMemoizedSerializedSize(memoizedSerializedSize); + } + return memoizedSerializedSize; + } + + @ExperimentalApi + protected final void writeToInternal(CodedOutputStream output) throws IOException { + Protobuf.getInstance() + .schemaFor(getClassInternal()) + .writeTo(this, CodedOutputStreamWriter.forCodedOutput(output)); + } + + @ExperimentalApi + protected void mergeFromInternal(CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + try { + Protobuf.getInstance() + .schemaFor(getClassInternal()) + .mergeFrom(this, CodedInputStreamReader.forCodedInput(input), extensionRegistry); + } catch (InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (IOException e) { + throw new InvalidProtocolBufferException(e).setUnfinishedMessage(this); + } + } + + @ExperimentalApi + protected void makeImmutableInternal() { + Protobuf.getInstance().schemaFor(getClassInternal()).makeImmutable(this); + } + + @SuppressWarnings("unchecked") + private Class<AbstractMessageLite<MessageType, BuilderType>> getClassInternal() { + return (Class<AbstractMessageLite<MessageType, BuilderType>>) getClass(); + } + /** Package private helper method for AbstractParser to create UninitializedMessageException. */ UninitializedMessageException newUninitializedMessageException() { return new UninitializedMessageException(this); diff --git a/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java b/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java new file mode 100755 index 000000000..a01a6c1a8 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java @@ -0,0 +1,263 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.Internal.checkNotNull; + +import java.nio.ByteBuffer; + +/** + * A buffer that was allocated by a {@link BufferAllocator}. For every buffer, it is guaranteed that + * at least one of {@link #hasArray()} or {@link #hasNioBuffer()} will be {@code true}. + */ +@ExperimentalApi +abstract class AllocatedBuffer { + /** + * Indicates whether this buffer contains a backing {@link ByteBuffer} (i.e. it is safe to call + * {@link #nioBuffer()}). + */ + public abstract boolean hasNioBuffer(); + + /** + * Indicates whether this buffer contains a backing array (i.e. it is safe to call {@link + * #array()}). + */ + public abstract boolean hasArray(); + + /** + * Returns the {@link ByteBuffer} that backs this buffer <i>(optional operation)</i>. + * + * <p>Call {@link #hasNioBuffer()} before invoking this method in order to ensure that this buffer + * has a backing {@link ByteBuffer}. + * + * @return The {@link ByteBuffer} that backs this buffer + * @throws UnsupportedOperationException If this buffer is not backed by a {@link ByteBuffer}. + */ + public abstract ByteBuffer nioBuffer(); + + /** + * Returns the byte array that backs this buffer <i>(optional operation)</i>. + * + * <p>Call {@link #hasArray()} before invoking this method in order to ensure that this buffer has + * an accessible backing array. + * + * @return The array that backs this buffer + * @throws java.nio.ReadOnlyBufferException If this buffer is backed by an array but is read-only + * @throws UnsupportedOperationException If this buffer is not backed by an accessible array + */ + public abstract byte[] array(); + + /** + * Returns the offset within this buffer's backing array of the first element of the buffer + * <i>(optional operation)</i>. + * + * <p>If this buffer is backed by an array then {@link #position()} corresponds to the array index + * {@link #position()} {@code +} {@link #arrayOffset()}. + * + * <p>Invoke the {@link #hasArray hasArray} method before invoking this method in order to ensure + * that this buffer has an accessible backing array. + * + * @return The offset within this buffer's array of the first element of the buffer + * @throws java.nio.ReadOnlyBufferException If this buffer is backed by an array but is read-only + * @throws UnsupportedOperationException If this buffer is not backed by an accessible array + */ + public abstract int arrayOffset(); + + /** + * Returns this buffer's position. + * + * @return The position of this buffer + */ + public abstract int position(); + + /** + * Sets this buffer's position. + * + * @param position The new position value; must be non-negative and no larger than the current + * limit + * @return This buffer + * @throws IllegalArgumentException If the preconditions on {@code position} do not hold + */ + public abstract AllocatedBuffer position(int position); + + /** + * Returns this buffer's limit. + * + * @return The limit of this buffer + */ + public abstract int limit(); + + /** + * Returns the number of elements between the current {@link #position()} and the {@link #limit()} + * . + * + * @return The number of elements remaining in this buffer + */ + public abstract int remaining(); + + /** + * Creates a new {@link AllocatedBuffer} that is backed by the given array. The returned buffer + * will have {@link #hasArray} == {@code true}, {@link #arrayOffset()} == {@code 0}, {@link + * #position()} == {@code 0} and {@link #limit()} equal to the length of {@code bytes}. + */ + public static AllocatedBuffer wrap(byte[] bytes) { + return wrapNoCheck(bytes, 0, bytes.length); + } + + /** + * Creates a new {@link AllocatedBuffer} that is backed by the given array. The returned buffer + * will have {@link #hasArray} == {@code true}, {@link #arrayOffset()} == {@code offset}, {@link + * #position()} == {@code 0} and {@link #limit()} == {@code length}. + */ + public static AllocatedBuffer wrap(final byte[] bytes, final int offset, final int length) { + if (offset < 0 || length < 0 || (offset + length) > bytes.length) { + throw new IndexOutOfBoundsException( + String.format("bytes.length=%d, offset=%d, length=%d", bytes.length, offset, length)); + } + + return wrapNoCheck(bytes, offset, length); + } + + /** + * Creates a new {@link AllocatedBuffer} that is backed by the given {@link ByteBuffer}. The + * returned buffer will have {@link #hasNioBuffer} == {@code true}. + */ + public static AllocatedBuffer wrap(final ByteBuffer buffer) { + checkNotNull(buffer, "buffer"); + + return new AllocatedBuffer() { + + @Override + public boolean hasNioBuffer() { + return true; + } + + @Override + public ByteBuffer nioBuffer() { + return buffer; + } + + @Override + public boolean hasArray() { + return buffer.hasArray(); + } + + @Override + public byte[] array() { + return buffer.array(); + } + + @Override + public int arrayOffset() { + return buffer.arrayOffset(); + } + + @Override + public int position() { + return buffer.position(); + } + + @Override + public AllocatedBuffer position(int position) { + buffer.position(position); + return this; + } + + @Override + public int limit() { + return buffer.limit(); + } + + @Override + public int remaining() { + return buffer.remaining(); + } + }; + } + + private static AllocatedBuffer wrapNoCheck( + final byte[] bytes, final int offset, final int length) { + return new AllocatedBuffer() { + // Relative to offset. + private int position; + + @Override + public boolean hasNioBuffer() { + return false; + } + + @Override + public ByteBuffer nioBuffer() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasArray() { + return true; + } + + @Override + public byte[] array() { + return bytes; + } + + @Override + public int arrayOffset() { + return offset; + } + + @Override + public int position() { + return position; + } + + @Override + public AllocatedBuffer position(int position) { + if (position < 0 || position > length) { + throw new IllegalArgumentException("Invalid position: " + position); + } + this.position = position; + return this; + } + + @Override + public int limit() { + // Relative to offset. + return length; + } + + @Override + public int remaining() { + return length - position; + } + }; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java new file mode 100755 index 000000000..a969c04c5 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java @@ -0,0 +1,1076 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.MessageSchema.getMutableUnknownFields; + +import com.google.protobuf.Internal.ProtobufList; +import java.io.IOException; + +/** + * Helper functions to decode protobuf wire format from a byte array. + * + * <p>Note that these functions don't do boundary check on the byte array but instead rely on Java + * VM to check it. That means parsing rountines utilizing these functions must catch + * IndexOutOfBoundsException and convert it to protobuf's InvalidProtocolBufferException when + * crossing protobuf public API boundaries. + */ +final class ArrayDecoders { + /** + * A helper used to return multiple values in a Java function. Java doesn't natively support + * returning multiple values in a function. Creating a new Object to hold the return values will + * be too expensive. Instead, we pass a Registers instance to functions that want to return + * multiple values and let the function set the return value in this Registers instance instead. + * + * <p>TODO(xiaofeng): This could be merged into CodedInputStream or CodedInputStreamReader which + * is already being passed through all the parsing rountines. + */ + static final class Registers { + public int int1; + public long long1; + public Object object1; + public final ExtensionRegistryLite extensionRegistry; + + Registers() { + this.extensionRegistry = ExtensionRegistryLite.getEmptyRegistry(); + } + + Registers(ExtensionRegistryLite extensionRegistry) { + if (extensionRegistry == null) { + throw new NullPointerException(); + } + this.extensionRegistry = extensionRegistry; + } + } + + /** + * Decodes a varint. Returns the position after the varint. The decoded varint is stored in + * registers.int1. + */ + static int decodeVarint32(byte[] data, int position, Registers registers) { + int value = data[position++]; + if (value >= 0) { + registers.int1 = value; + return position; + } + return decodeVarint32(value, data, position, registers); + } + + /** Like decodeVarint32 except that the first byte is already read. */ + static int decodeVarint32(int firstByte, byte[] data, int position, Registers registers) { + int value = firstByte & 0x7F; + final byte b2 = data[position++]; + if (b2 >= 0) { + registers.int1 = value | ((int) b2 << 7); + return position; + } + value |= (b2 & 0x7F) << 7; + + final byte b3 = data[position++]; + if (b3 >= 0) { + registers.int1 = value | ((int) b3 << 14); + return position; + } + value |= (b3 & 0x7F) << 14; + + final byte b4 = data[position++]; + if (b4 >= 0) { + registers.int1 = value | ((int) b4 << 21); + return position; + } + value |= (b4 & 0x7F) << 21; + + final byte b5 = data[position++]; + if (b5 >= 0) { + registers.int1 = value | ((int) b5 << 28); + return position; + } + value |= (b5 & 0x7F) << 28; + + while (data[position++] < 0) {} + + registers.int1 = value; + return position; + } + + /** + * Decodes a varint. Returns the position after the varint. The decoded varint is stored in + * registers.long1. + */ + static int decodeVarint64(byte[] data, int position, Registers registers) { + long value = data[position++]; + if (value >= 0) { + registers.long1 = value; + return position; + } else { + return decodeVarint64(value, data, position, registers); + } + } + + /** Like decodeVarint64 except that the first byte is already read. */ + static int decodeVarint64(long firstByte, byte[] data, int position, Registers registers) { + long value = firstByte & 0x7F; + byte next = data[position++]; + int shift = 7; + value |= (long) (next & 0x7F) << 7; + while (next < 0) { + next = data[position++]; + shift += 7; + value |= (long) (next & 0x7F) << shift; + } + registers.long1 = value; + return position; + } + + /** Decodes and returns a fixed32 value. */ + static int decodeFixed32(byte[] data, int position) { + return (data[position] & 0xff) + | ((data[position + 1] & 0xff) << 8) + | ((data[position + 2] & 0xff) << 16) + | ((data[position + 3] & 0xff) << 24); + } + + /** Decodes and returns a fixed64 value. */ + static long decodeFixed64(byte[] data, int position) { + return (data[position] & 0xffL) + | ((data[position + 1] & 0xffL) << 8) + | ((data[position + 2] & 0xffL) << 16) + | ((data[position + 3] & 0xffL) << 24) + | ((data[position + 4] & 0xffL) << 32) + | ((data[position + 5] & 0xffL) << 40) + | ((data[position + 6] & 0xffL) << 48) + | ((data[position + 7] & 0xffL) << 56); + } + + /** Decodes and returns a double value. */ + static double decodeDouble(byte[] data, int position) { + return Double.longBitsToDouble(decodeFixed64(data, position)); + } + + /** Decodes and returns a float value. */ + static float decodeFloat(byte[] data, int position) { + return Float.intBitsToFloat(decodeFixed32(data, position)); + } + + /** Decodes a string value. */ + static int decodeString(byte[] data, int position, Registers registers) + throws InvalidProtocolBufferException { + position = decodeVarint32(data, position, registers); + final int length = registers.int1; + if (length < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (length == 0) { + registers.object1 = ""; + return position; + } else { + registers.object1 = new String(data, position, length, Internal.UTF_8); + return position + length; + } + } + + /** Decodes a string value with utf8 check. */ + static int decodeStringRequireUtf8(byte[] data, int position, Registers registers) + throws InvalidProtocolBufferException { + position = decodeVarint32(data, position, registers); + final int length = registers.int1; + if (length < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (length == 0) { + registers.object1 = ""; + return position; + } else { + registers.object1 = Utf8.decodeUtf8(data, position, length); + return position + length; + } + } + + /** Decodes a bytes value. */ + static int decodeBytes(byte[] data, int position, Registers registers) + throws InvalidProtocolBufferException { + position = decodeVarint32(data, position, registers); + final int length = registers.int1; + if (length < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (length > data.length - position) { + throw InvalidProtocolBufferException.truncatedMessage(); + } else if (length == 0) { + registers.object1 = ByteString.EMPTY; + return position; + } else { + registers.object1 = ByteString.copyFrom(data, position, length); + return position + length; + } + } + + /** Decodes a message value. */ + @SuppressWarnings({"unchecked", "rawtypes"}) + static int decodeMessageField( + Schema schema, byte[] data, int position, int limit, Registers registers) throws IOException { + int length = data[position++]; + if (length < 0) { + position = decodeVarint32(length, data, position, registers); + length = registers.int1; + } + if (length < 0 || length > limit - position) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + Object result = schema.newInstance(); + schema.mergeFrom(result, data, position, position + length, registers); + schema.makeImmutable(result); + registers.object1 = result; + return position + length; + } + + /** Decodes a group value. */ + @SuppressWarnings({"unchecked", "rawtypes"}) + static int decodeGroupField( + Schema schema, byte[] data, int position, int limit, int endGroup, Registers registers) + throws IOException { + // A group field must has a MessageSchema (the only other subclass of Schema is MessageSetSchema + // and it can't be used in group fields). + final MessageSchema messageSchema = (MessageSchema) schema; + Object result = messageSchema.newInstance(); + // It's OK to directly use parseProto2Message since proto3 doesn't have group. + final int endPosition = + messageSchema.parseProto2Message(result, data, position, limit, endGroup, registers); + messageSchema.makeImmutable(result); + registers.object1 = result; + return endPosition; + } + + /** Decodes a repeated 32-bit varint field. Returns the position after all read values. */ + static int decodeVarint32List( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) { + final IntArrayList output = (IntArrayList) list; + position = decodeVarint32(data, position, registers); + output.addInt(registers.int1); + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeVarint32(data, nextPosition, registers); + output.addInt(registers.int1); + } + return position; + } + + /** Decodes a repeated 64-bit varint field. Returns the position after all read values. */ + static int decodeVarint64List( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) { + final LongArrayList output = (LongArrayList) list; + position = decodeVarint64(data, position, registers); + output.addLong(registers.long1); + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeVarint64(data, nextPosition, registers); + output.addLong(registers.long1); + } + return position; + } + + /** Decodes a repeated fixed32 field. Returns the position after all read values. */ + static int decodeFixed32List( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) { + final IntArrayList output = (IntArrayList) list; + output.addInt(decodeFixed32(data, position)); + position += 4; + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + output.addInt(decodeFixed32(data, nextPosition)); + position = nextPosition + 4; + } + return position; + } + + /** Decodes a repeated fixed64 field. Returns the position after all read values. */ + static int decodeFixed64List( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) { + final LongArrayList output = (LongArrayList) list; + output.addLong(decodeFixed64(data, position)); + position += 8; + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + output.addLong(decodeFixed64(data, nextPosition)); + position = nextPosition + 8; + } + return position; + } + + /** Decodes a repeated float field. Returns the position after all read values. */ + static int decodeFloatList( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) { + final FloatArrayList output = (FloatArrayList) list; + output.addFloat(decodeFloat(data, position)); + position += 4; + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + output.addFloat(decodeFloat(data, nextPosition)); + position = nextPosition + 4; + } + return position; + } + + /** Decodes a repeated double field. Returns the position after all read values. */ + static int decodeDoubleList( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) { + final DoubleArrayList output = (DoubleArrayList) list; + output.addDouble(decodeDouble(data, position)); + position += 8; + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + output.addDouble(decodeDouble(data, nextPosition)); + position = nextPosition + 8; + } + return position; + } + + /** Decodes a repeated boolean field. Returns the position after all read values. */ + static int decodeBoolList( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) { + final BooleanArrayList output = (BooleanArrayList) list; + position = decodeVarint64(data, position, registers); + output.addBoolean(registers.long1 != 0); + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeVarint64(data, nextPosition, registers); + output.addBoolean(registers.long1 != 0); + } + return position; + } + + /** Decodes a repeated sint32 field. Returns the position after all read values. */ + static int decodeSInt32List( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) { + final IntArrayList output = (IntArrayList) list; + position = decodeVarint32(data, position, registers); + output.addInt(CodedInputStream.decodeZigZag32(registers.int1)); + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeVarint32(data, nextPosition, registers); + output.addInt(CodedInputStream.decodeZigZag32(registers.int1)); + } + return position; + } + + /** Decodes a repeated sint64 field. Returns the position after all read values. */ + static int decodeSInt64List( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) { + final LongArrayList output = (LongArrayList) list; + position = decodeVarint64(data, position, registers); + output.addLong(CodedInputStream.decodeZigZag64(registers.long1)); + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeVarint64(data, nextPosition, registers); + output.addLong(CodedInputStream.decodeZigZag64(registers.long1)); + } + return position; + } + + /** Decodes a packed 32-bit varint field. Returns the position after all read values. */ + static int decodePackedVarint32List( + byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException { + final IntArrayList output = (IntArrayList) list; + position = decodeVarint32(data, position, registers); + final int fieldLimit = position + registers.int1; + while (position < fieldLimit) { + position = decodeVarint32(data, position, registers); + output.addInt(registers.int1); + } + if (position != fieldLimit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return position; + } + + /** Decodes a packed 64-bit varint field. Returns the position after all read values. */ + static int decodePackedVarint64List( + byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException { + final LongArrayList output = (LongArrayList) list; + position = decodeVarint32(data, position, registers); + final int fieldLimit = position + registers.int1; + while (position < fieldLimit) { + position = decodeVarint64(data, position, registers); + output.addLong(registers.long1); + } + if (position != fieldLimit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return position; + } + + /** Decodes a packed fixed32 field. Returns the position after all read values. */ + static int decodePackedFixed32List( + byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException { + final IntArrayList output = (IntArrayList) list; + position = decodeVarint32(data, position, registers); + final int fieldLimit = position + registers.int1; + while (position < fieldLimit) { + output.addInt(decodeFixed32(data, position)); + position += 4; + } + if (position != fieldLimit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return position; + } + + /** Decodes a packed fixed64 field. Returns the position after all read values. */ + static int decodePackedFixed64List( + byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException { + final LongArrayList output = (LongArrayList) list; + position = decodeVarint32(data, position, registers); + final int fieldLimit = position + registers.int1; + while (position < fieldLimit) { + output.addLong(decodeFixed64(data, position)); + position += 8; + } + if (position != fieldLimit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return position; + } + + /** Decodes a packed float field. Returns the position after all read values. */ + static int decodePackedFloatList( + byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException { + final FloatArrayList output = (FloatArrayList) list; + position = decodeVarint32(data, position, registers); + final int fieldLimit = position + registers.int1; + while (position < fieldLimit) { + output.addFloat(decodeFloat(data, position)); + position += 4; + } + if (position != fieldLimit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return position; + } + + /** Decodes a packed double field. Returns the position after all read values. */ + static int decodePackedDoubleList( + byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException { + final DoubleArrayList output = (DoubleArrayList) list; + position = decodeVarint32(data, position, registers); + final int fieldLimit = position + registers.int1; + while (position < fieldLimit) { + output.addDouble(decodeDouble(data, position)); + position += 8; + } + if (position != fieldLimit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return position; + } + + /** Decodes a packed boolean field. Returns the position after all read values. */ + static int decodePackedBoolList( + byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException { + final BooleanArrayList output = (BooleanArrayList) list; + position = decodeVarint32(data, position, registers); + final int fieldLimit = position + registers.int1; + while (position < fieldLimit) { + position = decodeVarint64(data, position, registers); + output.addBoolean(registers.long1 != 0); + } + if (position != fieldLimit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return position; + } + + /** Decodes a packed sint32 field. Returns the position after all read values. */ + static int decodePackedSInt32List( + byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException { + final IntArrayList output = (IntArrayList) list; + position = decodeVarint32(data, position, registers); + final int fieldLimit = position + registers.int1; + while (position < fieldLimit) { + position = decodeVarint32(data, position, registers); + output.addInt(CodedInputStream.decodeZigZag32(registers.int1)); + } + if (position != fieldLimit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return position; + } + + /** Decodes a packed sint64 field. Returns the position after all read values. */ + @SuppressWarnings("unchecked") + static int decodePackedSInt64List( + byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException { + final LongArrayList output = (LongArrayList) list; + position = decodeVarint32(data, position, registers); + final int fieldLimit = position + registers.int1; + while (position < fieldLimit) { + position = decodeVarint64(data, position, registers); + output.addLong(CodedInputStream.decodeZigZag64(registers.long1)); + } + if (position != fieldLimit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return position; + } + + /** Decodes a repeated string field. Returns the position after all read values. */ + @SuppressWarnings("unchecked") + static int decodeStringList( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) + throws InvalidProtocolBufferException { + final ProtobufList<String> output = (ProtobufList<String>) list; + position = decodeVarint32(data, position, registers); + final int length = registers.int1; + if (length < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (length == 0) { + output.add(""); + } else { + String value = new String(data, position, length, Internal.UTF_8); + output.add(value); + position += length; + } + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeVarint32(data, nextPosition, registers); + final int nextLength = registers.int1; + if (nextLength < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (nextLength == 0) { + output.add(""); + } else { + String value = new String(data, position, nextLength, Internal.UTF_8); + output.add(value); + position += nextLength; + } + } + return position; + } + + /** + * Decodes a repeated string field with utf8 check. Returns the position after all read values. + */ + @SuppressWarnings("unchecked") + static int decodeStringListRequireUtf8( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) + throws InvalidProtocolBufferException { + final ProtobufList<String> output = (ProtobufList<String>) list; + position = decodeVarint32(data, position, registers); + final int length = registers.int1; + if (length < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (length == 0) { + output.add(""); + } else { + if (!Utf8.isValidUtf8(data, position, position + length)) { + throw InvalidProtocolBufferException.invalidUtf8(); + } + String value = new String(data, position, length, Internal.UTF_8); + output.add(value); + position += length; + } + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeVarint32(data, nextPosition, registers); + final int nextLength = registers.int1; + if (nextLength < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (nextLength == 0) { + output.add(""); + } else { + if (!Utf8.isValidUtf8(data, position, position + nextLength)) { + throw InvalidProtocolBufferException.invalidUtf8(); + } + String value = new String(data, position, nextLength, Internal.UTF_8); + output.add(value); + position += nextLength; + } + } + return position; + } + + /** Decodes a repeated bytes field. Returns the position after all read values. */ + @SuppressWarnings("unchecked") + static int decodeBytesList( + int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) + throws InvalidProtocolBufferException { + final ProtobufList<ByteString> output = (ProtobufList<ByteString>) list; + position = decodeVarint32(data, position, registers); + final int length = registers.int1; + if (length < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (length > data.length - position) { + throw InvalidProtocolBufferException.truncatedMessage(); + } else if (length == 0) { + output.add(ByteString.EMPTY); + } else { + output.add(ByteString.copyFrom(data, position, length)); + position += length; + } + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeVarint32(data, nextPosition, registers); + final int nextLength = registers.int1; + if (nextLength < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (nextLength > data.length - position) { + throw InvalidProtocolBufferException.truncatedMessage(); + } else if (nextLength == 0) { + output.add(ByteString.EMPTY); + } else { + output.add(ByteString.copyFrom(data, position, nextLength)); + position += nextLength; + } + } + return position; + } + + /** + * Decodes a repeated message field + * + * @return The position of after read all messages + */ + @SuppressWarnings({"unchecked"}) + static int decodeMessageList( + Schema<?> schema, + int tag, + byte[] data, + int position, + int limit, + ProtobufList<?> list, + Registers registers) + throws IOException { + final ProtobufList<Object> output = (ProtobufList<Object>) list; + position = decodeMessageField(schema, data, position, limit, registers); + output.add(registers.object1); + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeMessageField(schema, data, nextPosition, limit, registers); + output.add(registers.object1); + } + return position; + } + + /** + * Decodes a repeated group field + * + * @return The position of after read all groups + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + static int decodeGroupList( + Schema schema, + int tag, + byte[] data, + int position, + int limit, + ProtobufList<?> list, + Registers registers) + throws IOException { + final ProtobufList<Object> output = (ProtobufList<Object>) list; + final int endgroup = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP; + position = decodeGroupField(schema, data, position, limit, endgroup, registers); + output.add(registers.object1); + while (position < limit) { + int nextPosition = decodeVarint32(data, position, registers); + if (tag != registers.int1) { + break; + } + position = decodeGroupField(schema, data, nextPosition, limit, endgroup, registers); + output.add(registers.object1); + } + return position; + } + + static int decodeExtensionOrUnknownField( + int tag, byte[] data, int position, int limit, + Object message, + MessageLite defaultInstance, + UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite> unknownFieldSchema, + Registers registers) + throws IOException { + final int number = tag >>> 3; + GeneratedMessageLite.GeneratedExtension extension = + registers.extensionRegistry.findLiteExtensionByNumber(defaultInstance, number); + if (extension == null) { + return decodeUnknownField( + tag, data, position, limit, getMutableUnknownFields(message), registers); + } else { + ((GeneratedMessageLite.ExtendableMessage<?, ?>) message).ensureExtensionsAreMutable(); + return decodeExtension( + tag, data, position, limit, (GeneratedMessageLite.ExtendableMessage) message, + extension, unknownFieldSchema, registers); + } + } + + static int decodeExtension( + int tag, + byte[] data, + int position, + int limit, + GeneratedMessageLite.ExtendableMessage<?, ?> message, + GeneratedMessageLite.GeneratedExtension<?, ?> extension, + UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite> unknownFieldSchema, + Registers registers) + throws IOException { + final FieldSet<GeneratedMessageLite.ExtensionDescriptor> extensions = message.extensions; + final int fieldNumber = tag >>> 3; + if (extension.descriptor.isRepeated() && extension.descriptor.isPacked()) { + switch (extension.getLiteType()) { + case DOUBLE: + { + DoubleArrayList list = new DoubleArrayList(); + position = decodePackedDoubleList(data, position, list, registers); + extensions.setField(extension.descriptor, list); + break; + } + case FLOAT: + { + FloatArrayList list = new FloatArrayList(); + position = decodePackedFloatList(data, position, list, registers); + extensions.setField(extension.descriptor, list); + break; + } + case INT64: + case UINT64: + { + LongArrayList list = new LongArrayList(); + position = decodePackedVarint64List(data, position, list, registers); + extensions.setField(extension.descriptor, list); + break; + } + case INT32: + case UINT32: + { + IntArrayList list = new IntArrayList(); + position = decodePackedVarint32List(data, position, list, registers); + extensions.setField(extension.descriptor, list); + break; + } + case FIXED64: + case SFIXED64: + { + LongArrayList list = new LongArrayList(); + position = decodePackedFixed64List(data, position, list, registers); + extensions.setField(extension.descriptor, list); + break; + } + case FIXED32: + case SFIXED32: + { + IntArrayList list = new IntArrayList(); + position = decodePackedFixed32List(data, position, list, registers); + extensions.setField(extension.descriptor, list); + break; + } + case BOOL: + { + BooleanArrayList list = new BooleanArrayList(); + position = decodePackedBoolList(data, position, list, registers); + extensions.setField(extension.descriptor, list); + break; + } + case SINT32: + { + IntArrayList list = new IntArrayList(); + position = decodePackedSInt32List(data, position, list, registers); + extensions.setField(extension.descriptor, list); + break; + } + case SINT64: + { + LongArrayList list = new LongArrayList(); + position = decodePackedSInt64List(data, position, list, registers); + extensions.setField(extension.descriptor, list); + break; + } + case ENUM: + { + IntArrayList list = new IntArrayList(); + position = decodePackedVarint32List(data, position, list, registers); + UnknownFieldSetLite unknownFields = message.unknownFields; + if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) { + unknownFields = null; + } + unknownFields = + SchemaUtil.filterUnknownEnumList( + fieldNumber, + list, + extension.descriptor.getEnumType(), + unknownFields, + unknownFieldSchema); + if (unknownFields != null) { + message.unknownFields = unknownFields; + } + extensions.setField(extension.descriptor, list); + break; + } + default: + throw new IllegalStateException( + "Type cannot be packed: " + extension.descriptor.getLiteType()); + } + } else { + Object value = null; + // Enum is a special case becasue unknown enum values will be put into UnknownFieldSetLite. + if (extension.getLiteType() == WireFormat.FieldType.ENUM) { + position = decodeVarint32(data, position, registers); + Object enumValue = extension.descriptor.getEnumType().findValueByNumber(registers.int1); + if (enumValue == null) { + UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields; + if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) { + unknownFields = UnknownFieldSetLite.newInstance(); + ((GeneratedMessageLite) message).unknownFields = unknownFields; + } + SchemaUtil.storeUnknownEnum( + fieldNumber, registers.int1, unknownFields, unknownFieldSchema); + return position; + } + // Note, we store the integer value instead of the actual enum object in FieldSet. + // This is also different from full-runtime where we store EnumValueDescriptor. + value = registers.int1; + } else { + switch (extension.getLiteType()) { + case DOUBLE: + value = decodeDouble(data, position); + position += 8; + break; + case FLOAT: + value = decodeFloat(data, position); + position += 4; + break; + case INT64: + case UINT64: + position = decodeVarint64(data, position, registers); + value = registers.long1; + break; + case INT32: + case UINT32: + position = decodeVarint32(data, position, registers); + value = registers.int1; + break; + case FIXED64: + case SFIXED64: + value = decodeFixed64(data, position); + position += 8; + break; + case FIXED32: + case SFIXED32: + value = decodeFixed32(data, position); + position += 4; + break; + case BOOL: + position = decodeVarint64(data, position, registers); + value = (registers.long1 != 0); + break; + case BYTES: + position = decodeBytes(data, position, registers); + value = registers.object1; + break; + case SINT32: + position = decodeVarint32(data, position, registers); + value = CodedInputStream.decodeZigZag32(registers.int1); + break; + case SINT64: + position = decodeVarint64(data, position, registers); + value = CodedInputStream.decodeZigZag64(registers.long1); + break; + case STRING: + position = decodeString(data, position, registers); + value = registers.object1; + break; + case GROUP: + final int endTag = (fieldNumber << 3) | WireFormat.WIRETYPE_END_GROUP; + position = decodeGroupField( + Protobuf.getInstance().schemaFor(extension.getMessageDefaultInstance().getClass()), + data, position, limit, endTag, registers); + value = registers.object1; + break; + + case MESSAGE: + position = decodeMessageField( + Protobuf.getInstance().schemaFor(extension.getMessageDefaultInstance().getClass()), + data, position, limit, registers); + value = registers.object1; + break; + + case ENUM: + throw new IllegalStateException("Shouldn't reach here."); + } + } + if (extension.isRepeated()) { + extensions.addRepeatedField(extension.descriptor, value); + } else { + switch (extension.getLiteType()) { + case MESSAGE: + case GROUP: + Object oldValue = extensions.getField(extension.descriptor); + if (oldValue != null) { + value = Internal.mergeMessage(oldValue, value); + } + break; + default: + break; + } + extensions.setField(extension.descriptor, value); + } + } + return position; + } + + /** Decodes an unknown field. */ + static int decodeUnknownField( + int tag, + byte[] data, + int position, + int limit, + UnknownFieldSetLite unknownFields, + Registers registers) + throws InvalidProtocolBufferException { + if (WireFormat.getTagFieldNumber(tag) == 0) { + throw InvalidProtocolBufferException.invalidTag(); + } + switch (WireFormat.getTagWireType(tag)) { + case WireFormat.WIRETYPE_VARINT: + position = decodeVarint64(data, position, registers); + unknownFields.storeField(tag, registers.long1); + return position; + case WireFormat.WIRETYPE_FIXED32: + unknownFields.storeField(tag, decodeFixed32(data, position)); + return position + 4; + case WireFormat.WIRETYPE_FIXED64: + unknownFields.storeField(tag, decodeFixed64(data, position)); + return position + 8; + case WireFormat.WIRETYPE_LENGTH_DELIMITED: + position = decodeVarint32(data, position, registers); + final int length = registers.int1; + if (length < 0) { + throw InvalidProtocolBufferException.negativeSize(); + } else if (length > data.length - position) { + throw InvalidProtocolBufferException.truncatedMessage(); + } else if (length == 0) { + unknownFields.storeField(tag, ByteString.EMPTY); + } else { + unknownFields.storeField(tag, ByteString.copyFrom(data, position, length)); + } + return position + length; + case WireFormat.WIRETYPE_START_GROUP: + final UnknownFieldSetLite child = UnknownFieldSetLite.newInstance(); + final int endGroup = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP; + int lastTag = 0; + while (position < limit) { + position = decodeVarint32(data, position, registers); + lastTag = registers.int1; + if (lastTag == endGroup) { + break; + } + position = decodeUnknownField(lastTag, data, position, limit, child, registers); + } + if (position > limit || lastTag != endGroup) { + throw InvalidProtocolBufferException.parseFailure(); + } + unknownFields.storeField(tag, child); + return position; + default: + throw InvalidProtocolBufferException.invalidTag(); + } + } + + /** Skips an unknown field. */ + static int skipField(int tag, byte[] data, int position, int limit, Registers registers) + throws InvalidProtocolBufferException { + if (WireFormat.getTagFieldNumber(tag) == 0) { + throw InvalidProtocolBufferException.invalidTag(); + } + switch (WireFormat.getTagWireType(tag)) { + case WireFormat.WIRETYPE_VARINT: + position = decodeVarint64(data, position, registers); + return position; + case WireFormat.WIRETYPE_FIXED32: + return position + 4; + case WireFormat.WIRETYPE_FIXED64: + return position + 8; + case WireFormat.WIRETYPE_LENGTH_DELIMITED: + position = decodeVarint32(data, position, registers); + return position + registers.int1; + case WireFormat.WIRETYPE_START_GROUP: + final int endGroup = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP; + int lastTag = 0; + while (position < limit) { + position = decodeVarint32(data, position, registers); + lastTag = registers.int1; + if (lastTag == endGroup) { + break; + } + position = skipField(lastTag, data, position, limit, registers); + } + if (position > limit || lastTag != endGroup) { + throw InvalidProtocolBufferException.parseFailure(); + } + return position; + default: + throw InvalidProtocolBufferException.invalidTag(); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/BinaryReader.java b/java/core/src/main/java/com/google/protobuf/BinaryReader.java new file mode 100755 index 000000000..d64574c2a --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/BinaryReader.java @@ -0,0 +1,1729 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.WireFormat.FIXED32_SIZE; +import static com.google.protobuf.WireFormat.FIXED64_SIZE; +import static com.google.protobuf.WireFormat.WIRETYPE_END_GROUP; +import static com.google.protobuf.WireFormat.WIRETYPE_FIXED32; +import static com.google.protobuf.WireFormat.WIRETYPE_FIXED64; +import static com.google.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED; +import static com.google.protobuf.WireFormat.WIRETYPE_START_GROUP; +import static com.google.protobuf.WireFormat.WIRETYPE_VARINT; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; + +/** + * A {@link Reader} that reads from a buffer containing a message serialized with the binary + * protocol. + */ +@ExperimentalApi +abstract class BinaryReader implements Reader { + private static final int FIXED32_MULTIPLE_MASK = FIXED32_SIZE - 1; + private static final int FIXED64_MULTIPLE_MASK = FIXED64_SIZE - 1; + + /** + * Creates a new reader using the given {@code buffer} as input. + * + * @param buffer the input buffer. The buffer (including position, limit, etc.) will not be + * modified. To increment the buffer position after the read completes, use the value returned + * by {@link #getTotalBytesRead()}. + * @param bufferIsImmutable if {@code true} the reader assumes that the content of {@code buffer} + * will never change and any allocated {@link ByteString} instances will by directly wrap + * slices of {@code buffer}. + * @return the reader + */ + public static BinaryReader newInstance(ByteBuffer buffer, boolean bufferIsImmutable) { + if (buffer.hasArray()) { + // TODO(nathanmittler): Add support for unsafe operations. + return new SafeHeapReader(buffer, bufferIsImmutable); + } + // TODO(nathanmittler): Add support for direct buffers + throw new IllegalArgumentException("Direct buffers not yet supported"); + } + + /** Only allow subclassing for inner classes. */ + private BinaryReader() {} + + /** Returns the total number of bytes read so far from the input buffer. */ + public abstract int getTotalBytesRead(); + + @Override + public boolean shouldDiscardUnknownFields() { + return false; + } + + /** + * A {@link BinaryReader} implementation that operates on a heap {@link ByteBuffer}. Uses only + * safe operations on the underlying array. + */ + private static final class SafeHeapReader extends BinaryReader { + private final boolean bufferIsImmutable; + private final byte[] buffer; + private int pos; + private final int initialPos; + private int limit; + private int tag; + private int endGroupTag; + + public SafeHeapReader(ByteBuffer bytebuf, boolean bufferIsImmutable) { + this.bufferIsImmutable = bufferIsImmutable; + buffer = bytebuf.array(); + initialPos = pos = bytebuf.arrayOffset() + bytebuf.position(); + limit = bytebuf.arrayOffset() + bytebuf.limit(); + } + + private boolean isAtEnd() { + return pos == limit; + } + + @Override + public int getTotalBytesRead() { + return pos - initialPos; + } + + @Override + public int getFieldNumber() throws IOException { + if (isAtEnd()) { + return Reader.READ_DONE; + } + tag = readVarint32(); + if (tag == endGroupTag) { + return Reader.READ_DONE; + } + return WireFormat.getTagFieldNumber(tag); + } + + @Override + public int getTag() { + return tag; + } + + @Override + public boolean skipField() throws IOException { + if (isAtEnd() || tag == endGroupTag) { + return false; + } + + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_VARINT: + skipVarint(); + return true; + case WIRETYPE_FIXED64: + skipBytes(FIXED64_SIZE); + return true; + case WIRETYPE_LENGTH_DELIMITED: + skipBytes(readVarint32()); + return true; + case WIRETYPE_FIXED32: + skipBytes(FIXED32_SIZE); + return true; + case WIRETYPE_START_GROUP: + skipGroup(); + return true; + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + + @Override + public double readDouble() throws IOException { + requireWireType(WIRETYPE_FIXED64); + return Double.longBitsToDouble(readLittleEndian64()); + } + + @Override + public float readFloat() throws IOException { + requireWireType(WIRETYPE_FIXED32); + return Float.intBitsToFloat(readLittleEndian32()); + } + + @Override + public long readUInt64() throws IOException { + requireWireType(WIRETYPE_VARINT); + return readVarint64(); + } + + @Override + public long readInt64() throws IOException { + requireWireType(WIRETYPE_VARINT); + return readVarint64(); + } + + @Override + public int readInt32() throws IOException { + requireWireType(WIRETYPE_VARINT); + return readVarint32(); + } + + @Override + public long readFixed64() throws IOException { + requireWireType(WIRETYPE_FIXED64); + return readLittleEndian64(); + } + + @Override + public int readFixed32() throws IOException { + requireWireType(WIRETYPE_FIXED32); + return readLittleEndian32(); + } + + @Override + public boolean readBool() throws IOException { + requireWireType(WIRETYPE_VARINT); + return readVarint32() != 0; + } + + @Override + public String readString() throws IOException { + return readStringInternal(false); + } + + @Override + public String readStringRequireUtf8() throws IOException { + return readStringInternal(true); + } + + public String readStringInternal(boolean requireUtf8) throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + final int size = readVarint32(); + if (size == 0) { + return ""; + } + + requireBytes(size); + if (requireUtf8 && !Utf8.isValidUtf8(buffer, pos, pos + size)) { + throw InvalidProtocolBufferException.invalidUtf8(); + } + String result = new String(buffer, pos, size, Internal.UTF_8); + pos += size; + return result; + } + + @Override + public <T> T readMessage(Class<T> clazz, ExtensionRegistryLite extensionRegistry) + throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + return readMessage(Protobuf.getInstance().schemaFor(clazz), extensionRegistry); + } + + @Override + public <T> T readMessageBySchemaWithCheck( + Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + return readMessage(schema, extensionRegistry); + } + + private <T> T readMessage(Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException { + int size = readVarint32(); + requireBytes(size); + + // Update the limit. + int prevLimit = limit; + int newLimit = pos + size; + limit = newLimit; + + try { + // Allocate and read the message. + T message = schema.newInstance(); + schema.mergeFrom(message, this, extensionRegistry); + schema.makeImmutable(message); + + if (pos != newLimit) { + throw InvalidProtocolBufferException.parseFailure(); + } + return message; + } finally { + // Restore the limit. + limit = prevLimit; + } + } + + @Override + public <T> T readGroup(Class<T> clazz, ExtensionRegistryLite extensionRegistry) + throws IOException { + requireWireType(WIRETYPE_START_GROUP); + return readGroup(Protobuf.getInstance().schemaFor(clazz), extensionRegistry); + } + + @Override + public <T> T readGroupBySchemaWithCheck( + Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException { + requireWireType(WIRETYPE_START_GROUP); + return readGroup(schema, extensionRegistry); + } + + private <T> T readGroup(Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException { + int prevEndGroupTag = endGroupTag; + endGroupTag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WIRETYPE_END_GROUP); + + try { + // Allocate and read the message. + T message = schema.newInstance(); + schema.mergeFrom(message, this, extensionRegistry); + schema.makeImmutable(message); + + if (tag != endGroupTag) { + throw InvalidProtocolBufferException.parseFailure(); + } + return message; + } finally { + // Restore the old end group tag. + endGroupTag = prevEndGroupTag; + } + } + + @Override + public ByteString readBytes() throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + int size = readVarint32(); + if (size == 0) { + return ByteString.EMPTY; + } + + requireBytes(size); + ByteString bytes = + bufferIsImmutable + ? ByteString.wrap(buffer, pos, size) + : ByteString.copyFrom(buffer, pos, size); + pos += size; + return bytes; + } + + @Override + public int readUInt32() throws IOException { + requireWireType(WIRETYPE_VARINT); + return readVarint32(); + } + + @Override + public int readEnum() throws IOException { + requireWireType(WIRETYPE_VARINT); + return readVarint32(); + } + + @Override + public int readSFixed32() throws IOException { + requireWireType(WIRETYPE_FIXED32); + return readLittleEndian32(); + } + + @Override + public long readSFixed64() throws IOException { + requireWireType(WIRETYPE_FIXED64); + return readLittleEndian64(); + } + + @Override + public int readSInt32() throws IOException { + requireWireType(WIRETYPE_VARINT); + return CodedInputStream.decodeZigZag32(readVarint32()); + } + + @Override + public long readSInt64() throws IOException { + requireWireType(WIRETYPE_VARINT); + return CodedInputStream.decodeZigZag64(readVarint64()); + } + + @Override + public void readDoubleList(List<Double> target) throws IOException { + if (target instanceof DoubleArrayList) { + DoubleArrayList plist = (DoubleArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed64Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addDouble(Double.longBitsToDouble(readLittleEndian64_NoCheck())); + } + break; + case WIRETYPE_FIXED64: + while (true) { + plist.addDouble(readDouble()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed64Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(Double.longBitsToDouble(readLittleEndian64_NoCheck())); + } + break; + case WIRETYPE_FIXED64: + while (true) { + target.add(readDouble()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readFloatList(List<Float> target) throws IOException { + if (target instanceof FloatArrayList) { + FloatArrayList plist = (FloatArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed32Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addFloat(Float.intBitsToFloat(readLittleEndian32_NoCheck())); + } + break; + case WIRETYPE_FIXED32: + while (true) { + plist.addFloat(readFloat()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed32Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(Float.intBitsToFloat(readLittleEndian32_NoCheck())); + } + break; + case WIRETYPE_FIXED32: + while (true) { + target.add(readFloat()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readUInt64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addLong(readVarint64()); + } + requirePosition(fieldEndPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addLong(readUInt64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readVarint64()); + } + requirePosition(fieldEndPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(readUInt64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readInt64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addLong(readVarint64()); + } + requirePosition(fieldEndPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addLong(readInt64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readVarint64()); + } + requirePosition(fieldEndPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(readInt64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readInt32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addInt(readVarint32()); + } + requirePosition(fieldEndPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addInt(readInt32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readVarint32()); + } + requirePosition(fieldEndPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(readInt32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readFixed64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed64Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addLong(readLittleEndian64_NoCheck()); + } + break; + case WIRETYPE_FIXED64: + while (true) { + plist.addLong(readFixed64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed64Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readLittleEndian64_NoCheck()); + } + break; + case WIRETYPE_FIXED64: + while (true) { + target.add(readFixed64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readFixed32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed32Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addInt(readLittleEndian32_NoCheck()); + } + break; + case WIRETYPE_FIXED32: + while (true) { + plist.addInt(readFixed32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed32Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readLittleEndian32_NoCheck()); + } + break; + case WIRETYPE_FIXED32: + while (true) { + target.add(readFixed32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readBoolList(List<Boolean> target) throws IOException { + if (target instanceof BooleanArrayList) { + BooleanArrayList plist = (BooleanArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addBoolean(readVarint32() != 0); + } + requirePosition(fieldEndPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addBoolean(readBool()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readVarint32() != 0); + } + requirePosition(fieldEndPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(readBool()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readStringList(List<String> target) throws IOException { + readStringListInternal(target, false); + } + + @Override + public void readStringListRequireUtf8(List<String> target) throws IOException { + readStringListInternal(target, true); + } + + public void readStringListInternal(List<String> target, boolean requireUtf8) + throws IOException { + if (WireFormat.getTagWireType(tag) != WIRETYPE_LENGTH_DELIMITED) { + throw InvalidProtocolBufferException.invalidWireType(); + } + + if (target instanceof LazyStringList && !requireUtf8) { + LazyStringList lazyList = (LazyStringList) target; + while (true) { + lazyList.add(readBytes()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + } else { + while (true) { + target.add(readStringInternal(requireUtf8)); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + } + } + + @Override + public <T> void readMessageList( + List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry) + throws IOException { + final Schema<T> schema = Protobuf.getInstance().schemaFor(targetType); + readMessageList(target, schema, extensionRegistry); + } + + @Override + public <T> void readMessageList( + List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException { + if (WireFormat.getTagWireType(tag) != WIRETYPE_LENGTH_DELIMITED) { + throw InvalidProtocolBufferException.invalidWireType(); + } + final int listTag = tag; + while (true) { + target.add(readMessage(schema, extensionRegistry)); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != listTag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + } + + @Override + public <T> void readGroupList( + List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry) + throws IOException { + final Schema<T> schema = Protobuf.getInstance().schemaFor(targetType); + readGroupList(target, schema, extensionRegistry); + } + + @Override + public <T> void readGroupList( + List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException { + if (WireFormat.getTagWireType(tag) != WIRETYPE_START_GROUP) { + throw InvalidProtocolBufferException.invalidWireType(); + } + final int listTag = tag; + while (true) { + target.add(readGroup(schema, extensionRegistry)); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != listTag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + } + + @Override + public void readBytesList(List<ByteString> target) throws IOException { + if (WireFormat.getTagWireType(tag) != WIRETYPE_LENGTH_DELIMITED) { + throw InvalidProtocolBufferException.invalidWireType(); + } + + while (true) { + target.add(readBytes()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + } + + @Override + public void readUInt32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addInt(readVarint32()); + } + break; + case WIRETYPE_VARINT: + while (true) { + plist.addInt(readUInt32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readVarint32()); + } + break; + case WIRETYPE_VARINT: + while (true) { + target.add(readUInt32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readEnumList(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addInt(readVarint32()); + } + break; + case WIRETYPE_VARINT: + while (true) { + plist.addInt(readEnum()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readVarint32()); + } + break; + case WIRETYPE_VARINT: + while (true) { + target.add(readEnum()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readSFixed32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed32Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addInt(readLittleEndian32_NoCheck()); + } + break; + case WIRETYPE_FIXED32: + while (true) { + plist.addInt(readSFixed32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed32Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readLittleEndian32_NoCheck()); + } + break; + case WIRETYPE_FIXED32: + while (true) { + target.add(readSFixed32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readSFixed64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed64Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addLong(readLittleEndian64_NoCheck()); + } + break; + case WIRETYPE_FIXED64: + while (true) { + plist.addLong(readSFixed64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + verifyPackedFixed64Length(bytes); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(readLittleEndian64_NoCheck()); + } + break; + case WIRETYPE_FIXED64: + while (true) { + target.add(readSFixed64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readSInt32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addInt(CodedInputStream.decodeZigZag32(readVarint32())); + } + break; + case WIRETYPE_VARINT: + while (true) { + plist.addInt(readSInt32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(CodedInputStream.decodeZigZag32(readVarint32())); + } + break; + case WIRETYPE_VARINT: + while (true) { + target.add(readSInt32()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readSInt64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + plist.addLong(CodedInputStream.decodeZigZag64(readVarint64())); + } + break; + case WIRETYPE_VARINT: + while (true) { + plist.addLong(readSInt64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = readVarint32(); + final int fieldEndPos = pos + bytes; + while (pos < fieldEndPos) { + target.add(CodedInputStream.decodeZigZag64(readVarint64())); + } + break; + case WIRETYPE_VARINT: + while (true) { + target.add(readSInt64()); + + if (isAtEnd()) { + return; + } + int prevPos = pos; + int nextTag = readVarint32(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Rewind the buffer position to before + // the new tag. + pos = prevPos; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @SuppressWarnings("unchecked") + @Override + public <K, V> void readMap( + Map<K, V> target, + MapEntryLite.Metadata<K, V> metadata, + ExtensionRegistryLite extensionRegistry) + throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + int size = readVarint32(); + requireBytes(size); + + // Update the limit. + int prevLimit = limit; + int newLimit = pos + size; + limit = newLimit; + + try { + K key = metadata.defaultKey; + V value = metadata.defaultValue; + while (true) { + int number = getFieldNumber(); + if (number == READ_DONE) { + break; + } + try { + switch (number) { + case 1: + key = (K) readField(metadata.keyType, null, null); + break; + case 2: + value = + (V) + readField( + metadata.valueType, + metadata.defaultValue.getClass(), + extensionRegistry); + break; + default: + if (!skipField()) { + throw new InvalidProtocolBufferException("Unable to parse map entry."); + } + break; + } + } catch (InvalidProtocolBufferException.InvalidWireTypeException ignore) { + // the type doesn't match, skip the field. + if (!skipField()) { + throw new InvalidProtocolBufferException("Unable to parse map entry."); + } + } + } + target.put(key, value); + } finally { + // Restore the limit. + limit = prevLimit; + } + } + + private Object readField( + WireFormat.FieldType fieldType, + Class<?> messageType, + ExtensionRegistryLite extensionRegistry) + throws IOException { + switch (fieldType) { + case BOOL: + return readBool(); + case BYTES: + return readBytes(); + case DOUBLE: + return readDouble(); + case ENUM: + return readEnum(); + case FIXED32: + return readFixed32(); + case FIXED64: + return readFixed64(); + case FLOAT: + return readFloat(); + case INT32: + return readInt32(); + case INT64: + return readInt64(); + case MESSAGE: + return readMessage(messageType, extensionRegistry); + case SFIXED32: + return readSFixed32(); + case SFIXED64: + return readSFixed64(); + case SINT32: + return readSInt32(); + case SINT64: + return readSInt64(); + case STRING: + return readStringRequireUtf8(); + case UINT32: + return readUInt32(); + case UINT64: + return readUInt64(); + default: + throw new RuntimeException("unsupported field type."); + } + } + + /** Read a raw Varint from the stream. If larger than 32 bits, discard the upper bits. */ + private int readVarint32() throws IOException { + // See implementation notes for readRawVarint64 + int i = pos; + + if (limit == pos) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + + int x; + if ((x = buffer[i++]) >= 0) { + pos = i; + return x; + } else if (limit - i < 9) { + return (int) readVarint64SlowPath(); + } else if ((x ^= (buffer[i++] << 7)) < 0) { + x ^= (~0 << 7); + } else if ((x ^= (buffer[i++] << 14)) >= 0) { + x ^= (~0 << 7) ^ (~0 << 14); + } else if ((x ^= (buffer[i++] << 21)) < 0) { + x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); + } else { + int y = buffer[i++]; + x ^= y << 28; + x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); + if (y < 0 + && buffer[i++] < 0 + && buffer[i++] < 0 + && buffer[i++] < 0 + && buffer[i++] < 0 + && buffer[i++] < 0) { + throw InvalidProtocolBufferException.malformedVarint(); + } + } + pos = i; + return x; + } + + public long readVarint64() throws IOException { + // Implementation notes: + // + // Optimized for one-byte values, expected to be common. + // The particular code below was selected from various candidates + // empirically, by winning VarintBenchmark. + // + // Sign extension of (signed) Java bytes is usually a nuisance, but + // we exploit it here to more easily obtain the sign of bytes read. + // Instead of cleaning up the sign extension bits by masking eagerly, + // we delay until we find the final (positive) byte, when we clear all + // accumulated bits with one xor. We depend on javac to constant fold. + int i = pos; + + if (limit == i) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + + final byte[] buffer = this.buffer; + long x; + int y; + if ((y = buffer[i++]) >= 0) { + pos = i; + return y; + } else if (limit - i < 9) { + return readVarint64SlowPath(); + } else if ((y ^= (buffer[i++] << 7)) < 0) { + x = y ^ (~0 << 7); + } else if ((y ^= (buffer[i++] << 14)) >= 0) { + x = y ^ ((~0 << 7) ^ (~0 << 14)); + } else if ((y ^= (buffer[i++] << 21)) < 0) { + x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); + } else if ((x = y ^ ((long) buffer[i++] << 28)) >= 0L) { + x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); + } else if ((x ^= ((long) buffer[i++] << 35)) < 0L) { + x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); + } else if ((x ^= ((long) buffer[i++] << 42)) >= 0L) { + x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42); + } else if ((x ^= ((long) buffer[i++] << 49)) < 0L) { + x ^= + (~0L << 7) + ^ (~0L << 14) + ^ (~0L << 21) + ^ (~0L << 28) + ^ (~0L << 35) + ^ (~0L << 42) + ^ (~0L << 49); + } else { + x ^= ((long) buffer[i++] << 56); + x ^= + (~0L << 7) + ^ (~0L << 14) + ^ (~0L << 21) + ^ (~0L << 28) + ^ (~0L << 35) + ^ (~0L << 42) + ^ (~0L << 49) + ^ (~0L << 56); + if (x < 0L) { + if (buffer[i++] < 0L) { + throw InvalidProtocolBufferException.malformedVarint(); + } + } + } + pos = i; + return x; + } + + private long readVarint64SlowPath() throws IOException { + long result = 0; + for (int shift = 0; shift < 64; shift += 7) { + final byte b = readByte(); + result |= (long) (b & 0x7F) << shift; + if ((b & 0x80) == 0) { + return result; + } + } + throw InvalidProtocolBufferException.malformedVarint(); + } + + private byte readByte() throws IOException { + if (pos == limit) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + return buffer[pos++]; + } + + private int readLittleEndian32() throws IOException { + requireBytes(FIXED32_SIZE); + return readLittleEndian32_NoCheck(); + } + + private long readLittleEndian64() throws IOException { + requireBytes(FIXED64_SIZE); + return readLittleEndian64_NoCheck(); + } + + private int readLittleEndian32_NoCheck() { + int p = pos; + final byte[] buffer = this.buffer; + pos = p + FIXED32_SIZE; + return (((buffer[p] & 0xff)) + | ((buffer[p + 1] & 0xff) << 8) + | ((buffer[p + 2] & 0xff) << 16) + | ((buffer[p + 3] & 0xff) << 24)); + } + + private long readLittleEndian64_NoCheck() { + int p = pos; + final byte[] buffer = this.buffer; + pos = p + FIXED64_SIZE; + return (((buffer[p] & 0xffL)) + | ((buffer[p + 1] & 0xffL) << 8) + | ((buffer[p + 2] & 0xffL) << 16) + | ((buffer[p + 3] & 0xffL) << 24) + | ((buffer[p + 4] & 0xffL) << 32) + | ((buffer[p + 5] & 0xffL) << 40) + | ((buffer[p + 6] & 0xffL) << 48) + | ((buffer[p + 7] & 0xffL) << 56)); + } + + private void skipVarint() throws IOException { + if (limit - pos >= 10) { + final byte[] buffer = this.buffer; + int p = pos; + for (int i = 0; i < 10; i++) { + if (buffer[p++] >= 0) { + pos = p; + return; + } + } + } + skipVarintSlowPath(); + } + + private void skipVarintSlowPath() throws IOException { + for (int i = 0; i < 10; i++) { + if (readByte() >= 0) { + return; + } + } + throw InvalidProtocolBufferException.malformedVarint(); + } + + private void skipBytes(final int size) throws IOException { + requireBytes(size); + + pos += size; + } + + private void skipGroup() throws IOException { + int prevEndGroupTag = endGroupTag; + endGroupTag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WIRETYPE_END_GROUP); + while (true) { + if (getFieldNumber() == READ_DONE || !skipField()) { + break; + } + } + if (tag != endGroupTag) { + throw InvalidProtocolBufferException.parseFailure(); + } + endGroupTag = prevEndGroupTag; + } + + private void requireBytes(int size) throws IOException { + if (size < 0 || size > (limit - pos)) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + } + + private void requireWireType(int requiredWireType) throws IOException { + if (WireFormat.getTagWireType(tag) != requiredWireType) { + throw InvalidProtocolBufferException.invalidWireType(); + } + } + + private void verifyPackedFixed64Length(int bytes) throws IOException { + requireBytes(bytes); + if ((bytes & FIXED64_MULTIPLE_MASK) != 0) { + // Require that the number of bytes be a multiple of 8. + throw InvalidProtocolBufferException.parseFailure(); + } + } + + private void verifyPackedFixed32Length(int bytes) throws IOException { + requireBytes(bytes); + if ((bytes & FIXED32_MULTIPLE_MASK) != 0) { + // Require that the number of bytes be a multiple of 4. + throw InvalidProtocolBufferException.parseFailure(); + } + } + + private void requirePosition(int expectedPosition) throws IOException { + if (pos != expectedPosition) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/BinaryWriter.java b/java/core/src/main/java/com/google/protobuf/BinaryWriter.java new file mode 100755 index 000000000..b1dbb8bf4 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/BinaryWriter.java @@ -0,0 +1,3071 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.Internal.checkNotNull; +import static com.google.protobuf.WireFormat.FIXED32_SIZE; +import static com.google.protobuf.WireFormat.FIXED64_SIZE; +import static com.google.protobuf.WireFormat.MAX_VARINT32_SIZE; +import static com.google.protobuf.WireFormat.MAX_VARINT64_SIZE; +import static com.google.protobuf.WireFormat.MESSAGE_SET_ITEM; +import static com.google.protobuf.WireFormat.MESSAGE_SET_MESSAGE; +import static com.google.protobuf.WireFormat.MESSAGE_SET_TYPE_ID; +import static com.google.protobuf.WireFormat.WIRETYPE_END_GROUP; +import static com.google.protobuf.WireFormat.WIRETYPE_FIXED32; +import static com.google.protobuf.WireFormat.WIRETYPE_FIXED64; +import static com.google.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED; +import static com.google.protobuf.WireFormat.WIRETYPE_START_GROUP; +import static com.google.protobuf.WireFormat.WIRETYPE_VARINT; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayDeque; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +/** + * A protobuf writer that serializes messages in their binary form. Messages are serialized in + * reverse in order to avoid calculating the serialized size of each nested message. Since the + * message size is not known in advance, the writer employs a strategy of chunking and buffer + * chaining. Buffers are allocated as-needed by a provided {@link BufferAllocator}. Once writing is + * finished, the application can access the buffers in forward-writing order by calling {@link + * #complete()}. + * + * <p>Once {@link #complete()} has been called, the writer can not be reused for additional writes. + * The {@link #getTotalBytesWritten()} will continue to reflect the total of the write and will not + * be reset. + */ +@ExperimentalApi +abstract class BinaryWriter extends ByteOutput implements Writer { + public static final int DEFAULT_CHUNK_SIZE = 4096; + + private final BufferAllocator alloc; + private final int chunkSize; + + final ArrayDeque<AllocatedBuffer> buffers = new ArrayDeque<AllocatedBuffer>(4); + int totalDoneBytes; + + /** + * Creates a new {@link BinaryWriter} that will allocate heap buffers of {@link + * #DEFAULT_CHUNK_SIZE} as necessary. + */ + public static BinaryWriter newHeapInstance(BufferAllocator alloc) { + return newHeapInstance(alloc, DEFAULT_CHUNK_SIZE); + } + + /** + * Creates a new {@link BinaryWriter} that will allocate heap buffers of {@code chunkSize} as + * necessary. + */ + public static BinaryWriter newHeapInstance(BufferAllocator alloc, int chunkSize) { + return isUnsafeHeapSupported() + ? newUnsafeHeapInstance(alloc, chunkSize) + : newSafeHeapInstance(alloc, chunkSize); + } + + /** + * Creates a new {@link BinaryWriter} that will allocate direct (i.e. non-heap) buffers of {@link + * #DEFAULT_CHUNK_SIZE} as necessary. + */ + public static BinaryWriter newDirectInstance(BufferAllocator alloc) { + return newDirectInstance(alloc, DEFAULT_CHUNK_SIZE); + } + + /** + * Creates a new {@link BinaryWriter} that will allocate direct (i.e. non-heap) buffers of {@code + * chunkSize} as necessary. + */ + public static BinaryWriter newDirectInstance(BufferAllocator alloc, int chunkSize) { + return isUnsafeDirectSupported() + ? newUnsafeDirectInstance(alloc, chunkSize) + : newSafeDirectInstance(alloc, chunkSize); + } + + static boolean isUnsafeHeapSupported() { + return UnsafeHeapWriter.isSupported(); + } + + static boolean isUnsafeDirectSupported() { + return UnsafeDirectWriter.isSupported(); + } + + static BinaryWriter newSafeHeapInstance(BufferAllocator alloc, int chunkSize) { + return new SafeHeapWriter(alloc, chunkSize); + } + + static BinaryWriter newUnsafeHeapInstance(BufferAllocator alloc, int chunkSize) { + if (!isUnsafeHeapSupported()) { + throw new UnsupportedOperationException("Unsafe operations not supported"); + } + return new UnsafeHeapWriter(alloc, chunkSize); + } + + static BinaryWriter newSafeDirectInstance(BufferAllocator alloc, int chunkSize) { + return new SafeDirectWriter(alloc, chunkSize); + } + + static BinaryWriter newUnsafeDirectInstance(BufferAllocator alloc, int chunkSize) { + if (!isUnsafeDirectSupported()) { + throw new UnsupportedOperationException("Unsafe operations not supported"); + } + return new UnsafeDirectWriter(alloc, chunkSize); + } + + /** Only allow subclassing for inner classes. */ + private BinaryWriter(BufferAllocator alloc, int chunkSize) { + if (chunkSize <= 0) { + throw new IllegalArgumentException("chunkSize must be > 0"); + } + this.alloc = checkNotNull(alloc, "alloc"); + this.chunkSize = chunkSize; + } + + @Override + public final FieldOrder fieldOrder() { + return FieldOrder.DESCENDING; + } + + /** + * Completes the write operation and returns a queue of {@link AllocatedBuffer} objects in + * forward-writing order. This method should only be called once. + * + * <p>After calling this method, the writer can not be reused. Create a new writer for future + * writes. + */ + public final Queue<AllocatedBuffer> complete() { + finishCurrentBuffer(); + return buffers; + } + + @Override + public final void writeSFixed32(int fieldNumber, int value) throws IOException { + writeFixed32(fieldNumber, value); + } + + @Override + public final void writeInt64(int fieldNumber, long value) throws IOException { + writeUInt64(fieldNumber, value); + } + + @Override + public final void writeSFixed64(int fieldNumber, long value) throws IOException { + writeFixed64(fieldNumber, value); + } + + @Override + public final void writeFloat(int fieldNumber, float value) throws IOException { + writeFixed32(fieldNumber, Float.floatToRawIntBits(value)); + } + + @Override + public final void writeDouble(int fieldNumber, double value) throws IOException { + writeFixed64(fieldNumber, Double.doubleToRawLongBits(value)); + } + + @Override + public final void writeEnum(int fieldNumber, int value) throws IOException { + writeInt32(fieldNumber, value); + } + + @Override + public final void writeInt32List(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + if (list instanceof IntArrayList) { + writeInt32List_Internal(fieldNumber, (IntArrayList) list, packed); + } else { + writeInt32List_Internal(fieldNumber, list, packed); + } + } + + private final void writeInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeInt32(list.get(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeInt32(fieldNumber, list.get(i)); + } + } + } + + private final void writeInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeInt32(list.getInt(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeInt32(fieldNumber, list.getInt(i)); + } + } + } + + @Override + public final void writeFixed32List(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + if (list instanceof IntArrayList) { + writeFixed32List_Internal(fieldNumber, (IntArrayList) list, packed); + } else { + writeFixed32List_Internal(fieldNumber, list, packed); + } + } + + private final void writeFixed32List_Internal(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed32(list.get(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed32(fieldNumber, list.get(i)); + } + } + } + + private final void writeFixed32List_Internal(int fieldNumber, IntArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed32(list.getInt(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed32(fieldNumber, list.getInt(i)); + } + } + } + + @Override + public final void writeInt64List(int fieldNumber, List<Long> list, boolean packed) + throws IOException { + writeUInt64List(fieldNumber, list, packed); + } + + @Override + public final void writeUInt64List(int fieldNumber, List<Long> list, boolean packed) + throws IOException { + if (list instanceof LongArrayList) { + writeUInt64List_Internal(fieldNumber, (LongArrayList) list, packed); + } else { + writeUInt64List_Internal(fieldNumber, list, packed); + } + } + + private final void writeUInt64List_Internal(int fieldNumber, List<Long> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeVarint64(list.get(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeUInt64(fieldNumber, list.get(i)); + } + } + } + + private final void writeUInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeVarint64(list.getLong(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeUInt64(fieldNumber, list.getLong(i)); + } + } + } + + @Override + public final void writeFixed64List(int fieldNumber, List<Long> list, boolean packed) + throws IOException { + if (list instanceof LongArrayList) { + writeFixed64List_Internal(fieldNumber, (LongArrayList) list, packed); + } else { + writeFixed64List_Internal(fieldNumber, list, packed); + } + } + + private final void writeFixed64List_Internal(int fieldNumber, List<Long> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed64(list.get(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed64(fieldNumber, list.get(i)); + } + } + } + + private final void writeFixed64List_Internal(int fieldNumber, LongArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed64(list.getLong(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed64(fieldNumber, list.getLong(i)); + } + } + } + + @Override + public final void writeFloatList(int fieldNumber, List<Float> list, boolean packed) + throws IOException { + if (list instanceof FloatArrayList) { + writeFloatList_Internal(fieldNumber, (FloatArrayList) list, packed); + } else { + writeFloatList_Internal(fieldNumber, list, packed); + } + } + + private final void writeFloatList_Internal(int fieldNumber, List<Float> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed32(Float.floatToRawIntBits(list.get(i))); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeFloat(fieldNumber, list.get(i)); + } + } + } + + private final void writeFloatList_Internal(int fieldNumber, FloatArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed32(Float.floatToRawIntBits(list.getFloat(i))); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeFloat(fieldNumber, list.getFloat(i)); + } + } + } + + @Override + public final void writeDoubleList(int fieldNumber, List<Double> list, boolean packed) + throws IOException { + if (list instanceof DoubleArrayList) { + writeDoubleList_Internal(fieldNumber, (DoubleArrayList) list, packed); + } else { + writeDoubleList_Internal(fieldNumber, list, packed); + } + } + + private final void writeDoubleList_Internal(int fieldNumber, List<Double> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed64(Double.doubleToRawLongBits(list.get(i))); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeDouble(fieldNumber, list.get(i)); + } + } + } + + private final void writeDoubleList_Internal(int fieldNumber, DoubleArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeFixed64(Double.doubleToRawLongBits(list.getDouble(i))); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeDouble(fieldNumber, list.getDouble(i)); + } + } + } + + @Override + public final void writeEnumList(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + writeInt32List(fieldNumber, list, packed); + } + + @Override + public final void writeBoolList(int fieldNumber, List<Boolean> list, boolean packed) + throws IOException { + if (list instanceof BooleanArrayList) { + writeBoolList_Internal(fieldNumber, (BooleanArrayList) list, packed); + } else { + writeBoolList_Internal(fieldNumber, list, packed); + } + } + + private final void writeBoolList_Internal(int fieldNumber, List<Boolean> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + list.size()); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeBool(list.get(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeBool(fieldNumber, list.get(i)); + } + } + } + + private final void writeBoolList_Internal(int fieldNumber, BooleanArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + list.size()); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeBool(list.getBoolean(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeBool(fieldNumber, list.getBoolean(i)); + } + } + } + + @Override + public final void writeStringList(int fieldNumber, List<String> list) throws IOException { + if (list instanceof LazyStringList) { + final LazyStringList lazyList = (LazyStringList) list; + for (int i = list.size() - 1; i >= 0; i--) { + writeLazyString(fieldNumber, lazyList.getRaw(i)); + } + } else { + for (int i = list.size() - 1; i >= 0; i--) { + writeString(fieldNumber, list.get(i)); + } + } + } + + private void writeLazyString(int fieldNumber, Object value) throws IOException { + if (value instanceof String) { + writeString(fieldNumber, (String) value); + } else { + writeBytes(fieldNumber, (ByteString) value); + } + } + + @Override + public final void writeBytesList(int fieldNumber, List<ByteString> list) throws IOException { + for (int i = list.size() - 1; i >= 0; i--) { + writeBytes(fieldNumber, list.get(i)); + } + } + + @Override + public final void writeUInt32List(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + if (list instanceof IntArrayList) { + writeUInt32List_Internal(fieldNumber, (IntArrayList) list, packed); + } else { + writeUInt32List_Internal(fieldNumber, list, packed); + } + } + + private final void writeUInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeVarint32(list.get(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeUInt32(fieldNumber, list.get(i)); + } + } + } + + private final void writeUInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeVarint32(list.getInt(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeUInt32(fieldNumber, list.getInt(i)); + } + } + } + + @Override + public final void writeSFixed32List(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + writeFixed32List(fieldNumber, list, packed); + } + + @Override + public final void writeSFixed64List(int fieldNumber, List<Long> list, boolean packed) + throws IOException { + writeFixed64List(fieldNumber, list, packed); + } + + @Override + public final void writeSInt32List(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + if (list instanceof IntArrayList) { + writeSInt32List_Internal(fieldNumber, (IntArrayList) list, packed); + } else { + writeSInt32List_Internal(fieldNumber, list, packed); + } + } + + private final void writeSInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeSInt32(list.get(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeSInt32(fieldNumber, list.get(i)); + } + } + } + + private final void writeSInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeSInt32(list.getInt(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeSInt32(fieldNumber, list.getInt(i)); + } + } + } + + @Override + public final void writeSInt64List(int fieldNumber, List<Long> list, boolean packed) + throws IOException { + if (list instanceof LongArrayList) { + writeSInt64List_Internal(fieldNumber, (LongArrayList) list, packed); + } else { + writeSInt64List_Internal(fieldNumber, list, packed); + } + } + + private static final int MAP_KEY_NUMBER = 1; + private static final int MAP_VALUE_NUMBER = 2; + + @Override + public <K, V> void writeMap(int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map) + throws IOException { + // TODO(liujisi): Reverse write those entries. + for (Map.Entry<K, V> entry : map.entrySet()) { + int prevBytes = getTotalBytesWritten(); + writeMapEntryField(this, MAP_VALUE_NUMBER, metadata.valueType, entry.getValue()); + writeMapEntryField(this, MAP_KEY_NUMBER, metadata.keyType, entry.getKey()); + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + } + + static final void writeMapEntryField( + Writer writer, int fieldNumber, WireFormat.FieldType fieldType, Object object) + throws IOException { + switch (fieldType) { + case BOOL: + writer.writeBool(fieldNumber, (Boolean) object); + break; + case FIXED32: + writer.writeFixed32(fieldNumber, (Integer) object); + break; + case FIXED64: + writer.writeFixed64(fieldNumber, (Long) object); + break; + case INT32: + writer.writeInt32(fieldNumber, (Integer) object); + break; + case INT64: + writer.writeInt64(fieldNumber, (Long) object); + break; + case SFIXED32: + writer.writeSFixed32(fieldNumber, (Integer) object); + break; + case SFIXED64: + writer.writeSFixed64(fieldNumber, (Long) object); + break; + case SINT32: + writer.writeSInt32(fieldNumber, (Integer) object); + break; + case SINT64: + writer.writeSInt64(fieldNumber, (Long) object); + break; + case STRING: + writer.writeString(fieldNumber, (String) object); + break; + case UINT32: + writer.writeUInt32(fieldNumber, (Integer) object); + break; + case UINT64: + writer.writeUInt64(fieldNumber, (Long) object); + break; + case FLOAT: + writer.writeFloat(fieldNumber, (Float) object); + break; + case DOUBLE: + writer.writeDouble(fieldNumber, (Double) object); + break; + case MESSAGE: + writer.writeMessage(fieldNumber, object); + break; + case BYTES: + writer.writeBytes(fieldNumber, (ByteString) object); + break; + case ENUM: + if (object instanceof Internal.EnumLite) { + writer.writeEnum(fieldNumber, ((Internal.EnumLite) object).getNumber()); + } else if (object instanceof Integer) { + writer.writeEnum(fieldNumber, (Integer) object); + } else { + throw new IllegalArgumentException("Unexpected type for enum in map."); + } + break; + default: + throw new IllegalArgumentException("Unsupported map value type for: " + fieldType); + } + } + + private final void writeSInt64List_Internal(int fieldNumber, List<Long> list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeSInt64(list.get(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeSInt64(fieldNumber, list.get(i)); + } + } + } + + private final void writeSInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed) + throws IOException { + if (packed) { + requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE)); + int prevBytes = getTotalBytesWritten(); + for (int i = list.size() - 1; i >= 0; --i) { + writeSInt64(list.getLong(i)); + } + int length = getTotalBytesWritten() - prevBytes; + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } else { + for (int i = list.size() - 1; i >= 0; --i) { + writeSInt64(fieldNumber, list.getLong(i)); + } + } + } + + @Override + public final void writeMessageList(int fieldNumber, List<?> list) throws IOException { + for (int i = list.size() - 1; i >= 0; i--) { + writeMessage(fieldNumber, list.get(i)); + } + } + + @Override + public final void writeMessageList(int fieldNumber, List<?> list, Schema schema) + throws IOException { + for (int i = list.size() - 1; i >= 0; i--) { + writeMessage(fieldNumber, list.get(i), schema); + } + } + + @Override + public final void writeGroupList(int fieldNumber, List<?> list) throws IOException { + for (int i = list.size() - 1; i >= 0; i--) { + writeGroup(fieldNumber, list.get(i)); + } + } + + @Override + public final void writeGroupList(int fieldNumber, List<?> list, Schema schema) + throws IOException { + for (int i = list.size() - 1; i >= 0; i--) { + writeGroup(fieldNumber, list.get(i), schema); + } + } + + @Override + public final void writeMessageSetItem(int fieldNumber, Object value) throws IOException { + writeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP); + if (value instanceof ByteString) { + writeBytes(MESSAGE_SET_MESSAGE, (ByteString) value); + } else { + writeMessage(MESSAGE_SET_MESSAGE, value); + } + writeUInt32(MESSAGE_SET_TYPE_ID, fieldNumber); + writeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP); + } + + final AllocatedBuffer newHeapBuffer() { + return alloc.allocateHeapBuffer(chunkSize); + } + + final AllocatedBuffer newHeapBuffer(int capacity) { + return alloc.allocateHeapBuffer(Math.max(capacity, chunkSize)); + } + + final AllocatedBuffer newDirectBuffer() { + return alloc.allocateDirectBuffer(chunkSize); + } + + final AllocatedBuffer newDirectBuffer(int capacity) { + return alloc.allocateDirectBuffer(Math.max(capacity, chunkSize)); + } + + /** + * Gets the total number of bytes that have been written. This will not be reset by a call to + * {@link #complete()}. + */ + public abstract int getTotalBytesWritten(); + + abstract void requireSpace(int size); + + abstract void finishCurrentBuffer(); + + abstract void writeTag(int fieldNumber, int wireType); + + abstract void writeVarint32(int value); + + abstract void writeInt32(int value); + + abstract void writeSInt32(int value); + + abstract void writeFixed32(int value); + + abstract void writeVarint64(long value); + + abstract void writeSInt64(long value); + + abstract void writeFixed64(long value); + + abstract void writeBool(boolean value); + + abstract void writeString(String in); + + /** + * Not using the version in CodedOutputStream due to the fact that benchmarks have shown a + * performance improvement when returning a byte (rather than an int). + */ + private static byte computeUInt64SizeNoTag(long value) { + // handle two popular special cases up front ... + if ((value & (~0L << 7)) == 0L) { + // Byte 1 + return 1; + } + if (value < 0L) { + // Byte 10 + return 10; + } + // ... leaving us with 8 remaining, which we can divide and conquer + byte n = 2; + if ((value & (~0L << 35)) != 0L) { + // Byte 6-9 + n += 4; // + (value >>> 63); + value >>>= 28; + } + if ((value & (~0L << 21)) != 0L) { + // Byte 4-5 or 8-9 + n += 2; + value >>>= 14; + } + if ((value & (~0L << 14)) != 0L) { + // Byte 3 or 7 + n += 1; + } + return n; + } + + /** Writer that uses safe operations on target array. */ + private static final class SafeHeapWriter extends BinaryWriter { + private AllocatedBuffer allocatedBuffer; + private byte[] buffer; + private int offset; + private int limit; + private int offsetMinusOne; + private int limitMinusOne; + private int pos; + + SafeHeapWriter(BufferAllocator alloc, int chunkSize) { + super(alloc, chunkSize); + nextBuffer(); + } + + @Override + void finishCurrentBuffer() { + if (allocatedBuffer != null) { + totalDoneBytes += bytesWrittenToCurrentBuffer(); + allocatedBuffer.position((pos - allocatedBuffer.arrayOffset()) + 1); + allocatedBuffer = null; + pos = 0; + limitMinusOne = 0; + } + } + + private void nextBuffer() { + nextBuffer(newHeapBuffer()); + } + + private void nextBuffer(int capacity) { + nextBuffer(newHeapBuffer(capacity)); + } + + private void nextBuffer(AllocatedBuffer allocatedBuffer) { + if (!allocatedBuffer.hasArray()) { + throw new RuntimeException("Allocator returned non-heap buffer"); + } + + finishCurrentBuffer(); + + buffers.addFirst(allocatedBuffer); + + this.allocatedBuffer = allocatedBuffer; + this.buffer = allocatedBuffer.array(); + int arrayOffset = allocatedBuffer.arrayOffset(); + this.limit = arrayOffset + allocatedBuffer.limit(); + this.offset = arrayOffset + allocatedBuffer.position(); + this.offsetMinusOne = offset - 1; + this.limitMinusOne = limit - 1; + this.pos = limitMinusOne; + } + + @Override + public int getTotalBytesWritten() { + return totalDoneBytes + bytesWrittenToCurrentBuffer(); + } + + int bytesWrittenToCurrentBuffer() { + return limitMinusOne - pos; + } + + int spaceLeft() { + return pos - offsetMinusOne; + } + + @Override + public void writeUInt32(int fieldNumber, int value) throws IOException { + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeInt32(int fieldNumber, int value) throws IOException { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeInt32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeSInt32(int fieldNumber, int value) throws IOException { + requireSpace(MAX_VARINT32_SIZE * 2); + writeSInt32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeFixed32(int fieldNumber, int value) throws IOException { + requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE); + writeFixed32(value); + writeTag(fieldNumber, WIRETYPE_FIXED32); + } + + @Override + public void writeUInt64(int fieldNumber, long value) throws IOException { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeVarint64(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeSInt64(int fieldNumber, long value) throws IOException { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeSInt64(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeFixed64(int fieldNumber, long value) throws IOException { + requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE); + writeFixed64(value); + writeTag(fieldNumber, WIRETYPE_FIXED64); + } + + @Override + public void writeBool(int fieldNumber, boolean value) throws IOException { + requireSpace(MAX_VARINT32_SIZE + 1); + write((byte) (value ? 1 : 0)); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeString(int fieldNumber, String value) throws IOException { + int prevBytes = getTotalBytesWritten(); + writeString(value); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(2 * MAX_VARINT32_SIZE); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeBytes(int fieldNumber, ByteString value) throws IOException { + try { + value.writeToReverse(this); + } catch (IOException e) { + // Should never happen since the writer does not throw. + throw new RuntimeException(e); + } + + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(value.size()); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeMessage(int fieldNumber, Object value) throws IOException { + int prevBytes = getTotalBytesWritten(); + Protobuf.getInstance().writeTo(value, this); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException { + int prevBytes = getTotalBytesWritten(); + schema.writeTo(value, this); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeGroup(int fieldNumber, Object value) throws IOException { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + Protobuf.getInstance().writeTo(value, this); + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + schema.writeTo(value, this); + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeStartGroup(int fieldNumber) { + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeEndGroup(int fieldNumber) { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + } + + @Override + void writeInt32(int value) { + if (value >= 0) { + writeVarint32(value); + } else { + writeVarint64(value); + } + } + + @Override + void writeSInt32(int value) { + writeVarint32(CodedOutputStream.encodeZigZag32(value)); + } + + @Override + void writeSInt64(long value) { + writeVarint64(CodedOutputStream.encodeZigZag64(value)); + } + + @Override + void writeBool(boolean value) { + write((byte) (value ? 1 : 0)); + } + + @Override + void writeTag(int fieldNumber, int wireType) { + writeVarint32(WireFormat.makeTag(fieldNumber, wireType)); + } + + @Override + void writeVarint32(int value) { + if ((value & (~0 << 7)) == 0) { + writeVarint32OneByte(value); + } else if ((value & (~0 << 14)) == 0) { + writeVarint32TwoBytes(value); + } else if ((value & (~0 << 21)) == 0) { + writeVarint32ThreeBytes(value); + } else if ((value & (~0 << 28)) == 0) { + writeVarint32FourBytes(value); + } else { + writeVarint32FiveBytes(value); + } + } + + private void writeVarint32OneByte(int value) { + buffer[pos--] = (byte) value; + } + + private void writeVarint32TwoBytes(int value) { + buffer[pos--] = (byte) (value >>> 7); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint32ThreeBytes(int value) { + buffer[pos--] = (byte) (value >>> 14); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint32FourBytes(int value) { + buffer[pos--] = (byte) (value >>> 21); + buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint32FiveBytes(int value) { + buffer[pos--] = (byte) (value >>> 28); + buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + @Override + void writeVarint64(long value) { + switch (computeUInt64SizeNoTag(value)) { + case 1: + writeVarint64OneByte(value); + break; + case 2: + writeVarint64TwoBytes(value); + break; + case 3: + writeVarint64ThreeBytes(value); + break; + case 4: + writeVarint64FourBytes(value); + break; + case 5: + writeVarint64FiveBytes(value); + break; + case 6: + writeVarint64SixBytes(value); + break; + case 7: + writeVarint64SevenBytes(value); + break; + case 8: + writeVarint64EightBytes(value); + break; + case 9: + writeVarint64NineBytes(value); + break; + case 10: + writeVarint64TenBytes(value); + break; + } + } + + private void writeVarint64OneByte(long value) { + buffer[pos--] = (byte) value; + } + + private void writeVarint64TwoBytes(long value) { + buffer[pos--] = (byte) (value >>> 7); + buffer[pos--] = (byte) (((int) value & 0x7F) | 0x80); + } + + private void writeVarint64ThreeBytes(long value) { + buffer[pos--] = (byte) (((int) value) >>> 14); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint64FourBytes(long value) { + buffer[pos--] = (byte) (value >>> 21); + buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint64FiveBytes(long value) { + buffer[pos--] = (byte) (value >>> 28); + buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint64SixBytes(long value) { + buffer[pos--] = (byte) (value >>> 35); + buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint64SevenBytes(long value) { + buffer[pos--] = (byte) (value >>> 42); + buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint64EightBytes(long value) { + buffer[pos--] = (byte) (value >>> 49); + buffer[pos--] = (byte) (((value >>> 42) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint64NineBytes(long value) { + buffer[pos--] = (byte) (value >>> 56); + buffer[pos--] = (byte) (((value >>> 49) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 42) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + private void writeVarint64TenBytes(long value) { + buffer[pos--] = (byte) (value >>> 63); + buffer[pos--] = (byte) (((value >>> 56) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 49) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 42) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80); + buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80); + buffer[pos--] = (byte) ((value & 0x7F) | 0x80); + } + + @Override + void writeFixed32(int value) { + buffer[pos--] = (byte) ((value >> 24) & 0xFF); + buffer[pos--] = (byte) ((value >> 16) & 0xFF); + buffer[pos--] = (byte) ((value >> 8) & 0xFF); + buffer[pos--] = (byte) (value & 0xFF); + } + + @Override + void writeFixed64(long value) { + buffer[pos--] = (byte) ((int) (value >> 56) & 0xFF); + buffer[pos--] = (byte) ((int) (value >> 48) & 0xFF); + buffer[pos--] = (byte) ((int) (value >> 40) & 0xFF); + buffer[pos--] = (byte) ((int) (value >> 32) & 0xFF); + buffer[pos--] = (byte) ((int) (value >> 24) & 0xFF); + buffer[pos--] = (byte) ((int) (value >> 16) & 0xFF); + buffer[pos--] = (byte) ((int) (value >> 8) & 0xFF); + buffer[pos--] = (byte) ((int) (value) & 0xFF); + } + + @Override + void writeString(String in) { + // Request enough space to write the ASCII string. + requireSpace(in.length()); + + // We know the buffer is big enough... + int i = in.length() - 1; + // Set pos to the start of the ASCII string. + pos -= i; + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) { + buffer[pos + i] = (byte) c; + } + if (i == -1) { + // Move pos past the String. + pos -= 1; + return; + } + pos += i; + for (char c; i >= 0; i--) { + c = in.charAt(i); + if (c < 0x80 && pos > offsetMinusOne) { + buffer[pos--] = (byte) c; + } else if (c < 0x800 && pos > offset) { // 11 bits, two UTF-8 bytes + buffer[pos--] = (byte) (0x80 | (0x3F & c)); + buffer[pos--] = (byte) ((0xF << 6) | (c >>> 6)); + } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) + && pos > (offset + 1)) { + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + buffer[pos--] = (byte) (0x80 | (0x3F & c)); + buffer[pos--] = (byte) (0x80 | (0x3F & (c >>> 6))); + buffer[pos--] = (byte) ((0xF << 5) | (c >>> 12)); + } else if (pos > (offset + 2)) { + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, + // four UTF-8 bytes + char high = 0; + if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) { + throw new Utf8.UnpairedSurrogateException(i - 1, i); + } + i--; + int codePoint = Character.toCodePoint(high, c); + buffer[pos--] = (byte) (0x80 | (0x3F & codePoint)); + buffer[pos--] = (byte) (0x80 | (0x3F & (codePoint >>> 6))); + buffer[pos--] = (byte) (0x80 | (0x3F & (codePoint >>> 12))); + buffer[pos--] = (byte) ((0xF << 4) | (codePoint >>> 18)); + } else { + // Buffer is full - allocate a new one and revisit the current character. + requireSpace(i); + i++; + } + } + } + + @Override + public void write(byte value) { + buffer[pos--] = value; + } + + @Override + public void write(byte[] value, int offset, int length) { + if (spaceLeft() < length) { + nextBuffer(length); + } + + pos -= length; + System.arraycopy(value, offset, buffer, pos + 1, length); + } + + @Override + public void writeLazy(byte[] value, int offset, int length) { + if (spaceLeft() < length) { + // We consider the value to be immutable (likely the internals of a ByteString). Just + // wrap it in a Netty buffer and add it to the output buffer. + totalDoneBytes += length; + buffers.addFirst(AllocatedBuffer.wrap(value, offset, length)); + + // Advance the writer to the next buffer. + // TODO(nathanmittler): Consider slicing if space available above some threshold. + nextBuffer(); + return; + } + + pos -= length; + System.arraycopy(value, offset, buffer, pos + 1, length); + } + + @Override + public void write(ByteBuffer value) { + int length = value.remaining(); + if (spaceLeft() < length) { + nextBuffer(length); + } + + pos -= length; + value.get(buffer, pos + 1, length); + } + + @Override + public void writeLazy(ByteBuffer value) { + int length = value.remaining(); + if (spaceLeft() < length) { + // We consider the value to be immutable (likely the internals of a ByteString). Just + // wrap it in a Netty buffer and add it to the output buffer. + totalDoneBytes += length; + buffers.addFirst(AllocatedBuffer.wrap(value)); + + // Advance the writer to the next buffer. + // TODO(nathanmittler): Consider slicing if space available above some threshold. + nextBuffer(); + } + + pos -= length; + value.get(buffer, pos + 1, length); + } + + @Override + void requireSpace(int size) { + if (spaceLeft() < size) { + nextBuffer(size); + } + } + } + + /** Writer that uses unsafe operations on a target array. */ + private static final class UnsafeHeapWriter extends BinaryWriter { + private AllocatedBuffer allocatedBuffer; + private byte[] buffer; + private long offset; + private long limit; + private long offsetMinusOne; + private long limitMinusOne; + private long pos; + + UnsafeHeapWriter(BufferAllocator alloc, int chunkSize) { + super(alloc, chunkSize); + nextBuffer(); + } + + /** Indicates whether the required unsafe operations are supported on this platform. */ + static boolean isSupported() { + return UnsafeUtil.hasUnsafeArrayOperations(); + } + + @Override + void finishCurrentBuffer() { + if (allocatedBuffer != null) { + totalDoneBytes += bytesWrittenToCurrentBuffer(); + allocatedBuffer.position((arrayPos() - allocatedBuffer.arrayOffset()) + 1); + allocatedBuffer = null; + pos = 0; + limitMinusOne = 0; + } + } + + private int arrayPos() { + return (int) pos; + } + + private void nextBuffer() { + nextBuffer(newHeapBuffer()); + } + + private void nextBuffer(int capacity) { + nextBuffer(newHeapBuffer(capacity)); + } + + private void nextBuffer(AllocatedBuffer allocatedBuffer) { + if (!allocatedBuffer.hasArray()) { + throw new RuntimeException("Allocator returned non-heap buffer"); + } + + finishCurrentBuffer(); + buffers.addFirst(allocatedBuffer); + + this.allocatedBuffer = allocatedBuffer; + this.buffer = allocatedBuffer.array(); + int arrayOffset = allocatedBuffer.arrayOffset(); + this.limit = arrayOffset + allocatedBuffer.limit(); + this.offset = arrayOffset + allocatedBuffer.position(); + this.offsetMinusOne = offset - 1; + this.limitMinusOne = limit - 1; + this.pos = limitMinusOne; + } + + @Override + public int getTotalBytesWritten() { + return totalDoneBytes + bytesWrittenToCurrentBuffer(); + } + + int bytesWrittenToCurrentBuffer() { + return (int) (limitMinusOne - pos); + } + + int spaceLeft() { + return (int) (pos - offsetMinusOne); + } + + @Override + public void writeUInt32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeInt32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeInt32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeSInt32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE * 2); + writeSInt32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeFixed32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE); + writeFixed32(value); + writeTag(fieldNumber, WIRETYPE_FIXED32); + } + + @Override + public void writeUInt64(int fieldNumber, long value) { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeVarint64(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeSInt64(int fieldNumber, long value) { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeSInt64(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeFixed64(int fieldNumber, long value) { + requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE); + writeFixed64(value); + writeTag(fieldNumber, WIRETYPE_FIXED64); + } + + @Override + public void writeBool(int fieldNumber, boolean value) { + requireSpace(MAX_VARINT32_SIZE + 1); + write((byte) (value ? 1 : 0)); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeString(int fieldNumber, String value) { + int prevBytes = getTotalBytesWritten(); + writeString(value); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(2 * MAX_VARINT32_SIZE); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeBytes(int fieldNumber, ByteString value) { + try { + value.writeToReverse(this); + } catch (IOException e) { + // Should never happen since the writer does not throw. + throw new RuntimeException(e); + } + + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(value.size()); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeMessage(int fieldNumber, Object value) throws IOException { + int prevBytes = getTotalBytesWritten(); + Protobuf.getInstance().writeTo(value, this); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException { + int prevBytes = getTotalBytesWritten(); + schema.writeTo(value, this); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeGroup(int fieldNumber, Object value) throws IOException { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + Protobuf.getInstance().writeTo(value, this); + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + schema.writeTo(value, this); + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeStartGroup(int fieldNumber) { + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeEndGroup(int fieldNumber) { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + } + + @Override + void writeInt32(int value) { + if (value >= 0) { + writeVarint32(value); + } else { + writeVarint64(value); + } + } + + @Override + void writeSInt32(int value) { + writeVarint32(CodedOutputStream.encodeZigZag32(value)); + } + + @Override + void writeSInt64(long value) { + writeVarint64(CodedOutputStream.encodeZigZag64(value)); + } + + @Override + void writeBool(boolean value) { + write((byte) (value ? 1 : 0)); + } + + @Override + void writeTag(int fieldNumber, int wireType) { + writeVarint32(WireFormat.makeTag(fieldNumber, wireType)); + } + + @Override + void writeVarint32(int value) { + if ((value & (~0 << 7)) == 0) { + writeVarint32OneByte(value); + } else if ((value & (~0 << 14)) == 0) { + writeVarint32TwoBytes(value); + } else if ((value & (~0 << 21)) == 0) { + writeVarint32ThreeBytes(value); + } else if ((value & (~0 << 28)) == 0) { + writeVarint32FourBytes(value); + } else { + writeVarint32FiveBytes(value); + } + } + + private void writeVarint32OneByte(int value) { + UnsafeUtil.putByte(buffer, pos--, (byte) value); + } + + private void writeVarint32TwoBytes(int value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 7)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint32ThreeBytes(int value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 14)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint32FourBytes(int value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 21)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint32FiveBytes(int value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 28)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + @Override + void writeVarint64(long value) { + switch (computeUInt64SizeNoTag(value)) { + case 1: + writeVarint64OneByte(value); + break; + case 2: + writeVarint64TwoBytes(value); + break; + case 3: + writeVarint64ThreeBytes(value); + break; + case 4: + writeVarint64FourBytes(value); + break; + case 5: + writeVarint64FiveBytes(value); + break; + case 6: + writeVarint64SixBytes(value); + break; + case 7: + writeVarint64SevenBytes(value); + break; + case 8: + writeVarint64EightBytes(value); + break; + case 9: + writeVarint64NineBytes(value); + break; + case 10: + writeVarint64TenBytes(value); + break; + } + } + + private void writeVarint64OneByte(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) value); + } + + private void writeVarint64TwoBytes(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 7)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((int) value & 0x7F) | 0x80)); + } + + private void writeVarint64ThreeBytes(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (((int) value) >>> 14)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64FourBytes(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 21)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64FiveBytes(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 28)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64SixBytes(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 35)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64SevenBytes(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 42)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64EightBytes(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 49)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 42) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64NineBytes(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 56)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 49) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 42) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64TenBytes(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 63)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 56) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 49) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 42) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80)); + } + + @Override + void writeFixed32(int value) { + UnsafeUtil.putByte(buffer, pos--, (byte) ((value >> 24) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value >> 16) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((value >> 8) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) (value & 0xFF)); + } + + @Override + void writeFixed64(long value) { + UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 56) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 48) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 40) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 32) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 24) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 16) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 8) & 0xFF)); + UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value) & 0xFF)); + } + + @Override + void writeString(String in) { + // Request enough space to write the ASCII string. + requireSpace(in.length()); + + // We know the buffer is big enough... + int i = in.length() - 1; + // Set pos to the start of the ASCII string. + // pos -= i; + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) { + UnsafeUtil.putByte(buffer, pos--, (byte) c); + } + if (i == -1) { + // Move pos past the String. + return; + } + for (char c; i >= 0; i--) { + c = in.charAt(i); + if (c < 0x80 && pos > offsetMinusOne) { + UnsafeUtil.putByte(buffer, pos--, (byte) c); + } else if (c < 0x800 && pos > offset) { // 11 bits, two UTF-8 bytes + UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & c))); + UnsafeUtil.putByte(buffer, pos--, (byte) ((0xF << 6) | (c >>> 6))); + } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) + && pos > offset + 1) { + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & c))); + UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & (c >>> 6)))); + UnsafeUtil.putByte(buffer, pos--, (byte) ((0xF << 5) | (c >>> 12))); + } else if (pos > offset + 2) { + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, + // four UTF-8 bytes + final char high; + if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) { + throw new Utf8.UnpairedSurrogateException(i - 1, i); + } + i--; + int codePoint = Character.toCodePoint(high, c); + UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & codePoint))); + UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & (codePoint >>> 6)))); + UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & (codePoint >>> 12)))); + UnsafeUtil.putByte(buffer, pos--, (byte) ((0xF << 4) | (codePoint >>> 18))); + } else { + // Buffer is full - allocate a new one and revisit the current character. + requireSpace(i); + i++; + } + } + } + + @Override + public void write(byte value) { + UnsafeUtil.putByte(buffer, pos--, value); + } + + @Override + public void write(byte[] value, int offset, int length) { + if (offset < 0 || offset + length > value.length) { + throw new ArrayIndexOutOfBoundsException( + String.format("value.length=%d, offset=%d, length=%d", value.length, offset, length)); + } + requireSpace(length); + + pos -= length; + System.arraycopy(value, offset, buffer, arrayPos() + 1, length); + } + + @Override + public void writeLazy(byte[] value, int offset, int length) { + if (offset < 0 || offset + length > value.length) { + throw new ArrayIndexOutOfBoundsException( + String.format("value.length=%d, offset=%d, length=%d", value.length, offset, length)); + } + if (spaceLeft() < length) { + // We consider the value to be immutable (likely the internals of a ByteString). Just + // wrap it in a Netty buffer and add it to the output buffer. + totalDoneBytes += length; + buffers.addFirst(AllocatedBuffer.wrap(value, offset, length)); + + // Advance the writer to the next buffer. + // TODO(nathanmittler): Consider slicing if space available above some threshold. + nextBuffer(); + return; + } + + pos -= length; + System.arraycopy(value, offset, buffer, arrayPos() + 1, length); + } + + @Override + public void write(ByteBuffer value) { + int length = value.remaining(); + requireSpace(length); + + pos -= length; + value.get(buffer, arrayPos() + 1, length); + } + + @Override + public void writeLazy(ByteBuffer value) { + int length = value.remaining(); + if (spaceLeft() < length) { + // We consider the value to be immutable (likely the internals of a ByteString). Just + // wrap it in a Netty buffer and add it to the output buffer. + totalDoneBytes += length; + buffers.addFirst(AllocatedBuffer.wrap(value)); + + // Advance the writer to the next buffer. + // TODO(nathanmittler): Consider slicing if space available above some threshold. + nextBuffer(); + } + + pos -= length; + value.get(buffer, arrayPos() + 1, length); + } + + @Override + void requireSpace(int size) { + if (spaceLeft() < size) { + nextBuffer(size); + } + } + } + + /** Writer that uses safe operations on a target {@link ByteBuffer}. */ + private static final class SafeDirectWriter extends BinaryWriter { + private ByteBuffer buffer; + private int limitMinusOne; + private int pos; + + SafeDirectWriter(BufferAllocator alloc, int chunkSize) { + super(alloc, chunkSize); + nextBuffer(); + } + + private void nextBuffer() { + nextBuffer(newDirectBuffer()); + } + + private void nextBuffer(int capacity) { + nextBuffer(newDirectBuffer(capacity)); + } + + private void nextBuffer(AllocatedBuffer allocatedBuffer) { + if (!allocatedBuffer.hasNioBuffer()) { + throw new RuntimeException("Allocated buffer does not have NIO buffer"); + } + ByteBuffer nioBuffer = allocatedBuffer.nioBuffer(); + if (!nioBuffer.isDirect()) { + throw new RuntimeException("Allocator returned non-direct buffer"); + } + + finishCurrentBuffer(); + buffers.addFirst(allocatedBuffer); + + buffer = nioBuffer; + buffer.limit(buffer.capacity()); + buffer.position(0); + // Set byte order to little endian for fast writing of fixed 32/64. + buffer.order(ByteOrder.LITTLE_ENDIAN); + + limitMinusOne = buffer.limit() - 1; + pos = limitMinusOne; + } + + @Override + public int getTotalBytesWritten() { + return totalDoneBytes + bytesWrittenToCurrentBuffer(); + } + + private int bytesWrittenToCurrentBuffer() { + return limitMinusOne - pos; + } + + private int spaceLeft() { + return pos + 1; + } + + @Override + void finishCurrentBuffer() { + if (buffer != null) { + totalDoneBytes += bytesWrittenToCurrentBuffer(); + // Update the indices on the netty buffer. + buffer.position(pos + 1); + buffer = null; + pos = 0; + limitMinusOne = 0; + } + } + + @Override + public void writeUInt32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeInt32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeInt32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeSInt32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE * 2); + writeSInt32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeFixed32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE); + writeFixed32(value); + writeTag(fieldNumber, WIRETYPE_FIXED32); + } + + @Override + public void writeUInt64(int fieldNumber, long value) { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeVarint64(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeSInt64(int fieldNumber, long value) { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeSInt64(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeFixed64(int fieldNumber, long value) { + requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE); + writeFixed64(value); + writeTag(fieldNumber, WIRETYPE_FIXED64); + } + + @Override + public void writeBool(int fieldNumber, boolean value) { + requireSpace(MAX_VARINT32_SIZE + 1); + write((byte) (value ? 1 : 0)); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeString(int fieldNumber, String value) { + int prevBytes = getTotalBytesWritten(); + writeString(value); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(2 * MAX_VARINT32_SIZE); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeBytes(int fieldNumber, ByteString value) { + try { + value.writeToReverse(this); + } catch (IOException e) { + // Should never happen since the writer does not throw. + throw new RuntimeException(e); + } + + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(value.size()); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeMessage(int fieldNumber, Object value) throws IOException { + int prevBytes = getTotalBytesWritten(); + Protobuf.getInstance().writeTo(value, this); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException { + int prevBytes = getTotalBytesWritten(); + schema.writeTo(value, this); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeGroup(int fieldNumber, Object value) throws IOException { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + Protobuf.getInstance().writeTo(value, this); + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + schema.writeTo(value, this); + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeStartGroup(int fieldNumber) { + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeEndGroup(int fieldNumber) { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + } + + @Override + void writeInt32(int value) { + if (value >= 0) { + writeVarint32(value); + } else { + writeVarint64(value); + } + } + + @Override + void writeSInt32(int value) { + writeVarint32(CodedOutputStream.encodeZigZag32(value)); + } + + @Override + void writeSInt64(long value) { + writeVarint64(CodedOutputStream.encodeZigZag64(value)); + } + + @Override + void writeBool(boolean value) { + write((byte) (value ? 1 : 0)); + } + + @Override + void writeTag(int fieldNumber, int wireType) { + writeVarint32(WireFormat.makeTag(fieldNumber, wireType)); + } + + @Override + void writeVarint32(int value) { + if ((value & (~0 << 7)) == 0) { + writeVarint32OneByte(value); + } else if ((value & (~0 << 14)) == 0) { + writeVarint32TwoBytes(value); + } else if ((value & (~0 << 21)) == 0) { + writeVarint32ThreeBytes(value); + } else if ((value & (~0 << 28)) == 0) { + writeVarint32FourBytes(value); + } else { + writeVarint32FiveBytes(value); + } + } + + private void writeVarint32OneByte(int value) { + buffer.put(pos--, (byte) value); + } + + private void writeVarint32TwoBytes(int value) { + // Byte order is little-endian. + pos -= 2; + buffer.putShort(pos + 1, (short) (((value & (0x7F << 7)) << 1) | ((value & 0x7F) | 0x80))); + } + + private void writeVarint32ThreeBytes(int value) { + // Byte order is little-endian. + pos -= 3; + buffer.putInt( + pos, + ((value & (0x7F << 14)) << 10) + | (((value & (0x7F << 7)) | (0x80 << 7)) << 9) + | ((value & 0x7F) | 0x80) << 8); + } + + private void writeVarint32FourBytes(int value) { + // Byte order is little-endian. + pos -= 4; + buffer.putInt( + pos + 1, + ((value & (0x7F << 21)) << 3) + | (((value & (0x7F << 14)) | (0x80 << 14)) << 2) + | (((value & (0x7F << 7)) | (0x80 << 7)) << 1) + | ((value & 0x7F) | 0x80)); + } + + private void writeVarint32FiveBytes(int value) { + // Byte order is little-endian. + buffer.put(pos--, (byte) (value >>> 28)); + pos -= 4; + buffer.putInt( + pos + 1, + ((((value >>> 21) & 0x7F) | 0x80) << 24) + | ((((value >>> 14) & 0x7F) | 0x80) << 16) + | ((((value >>> 7) & 0x7F) | 0x80) << 8) + | ((value & 0x7F) | 0x80)); + } + + @Override + void writeVarint64(long value) { + switch (computeUInt64SizeNoTag(value)) { + case 1: + writeVarint64OneByte(value); + break; + case 2: + writeVarint64TwoBytes(value); + break; + case 3: + writeVarint64ThreeBytes(value); + break; + case 4: + writeVarint64FourBytes(value); + break; + case 5: + writeVarint64FiveBytes(value); + break; + case 6: + writeVarint64SixBytes(value); + break; + case 7: + writeVarint64SevenBytes(value); + break; + case 8: + writeVarint64EightBytes(value); + break; + case 9: + writeVarint64NineBytes(value); + break; + case 10: + writeVarint64TenBytes(value); + break; + } + } + + private void writeVarint64OneByte(long value) { + writeVarint32OneByte((int) value); + } + + private void writeVarint64TwoBytes(long value) { + writeVarint32TwoBytes((int) value); + } + + private void writeVarint64ThreeBytes(long value) { + writeVarint32ThreeBytes((int) value); + } + + private void writeVarint64FourBytes(long value) { + writeVarint32FourBytes((int) value); + } + + private void writeVarint64FiveBytes(long value) { + // Byte order is little-endian. + pos -= 5; + buffer.putLong( + pos - 2, + ((value & (0x7FL << 28)) << 28) + | (((value & (0x7F << 21)) | (0x80 << 21)) << 27) + | (((value & (0x7F << 14)) | (0x80 << 14)) << 26) + | (((value & (0x7F << 7)) | (0x80 << 7)) << 25) + | (((value & 0x7F) | 0x80)) << 24); + } + + private void writeVarint64SixBytes(long value) { + // Byte order is little-endian. + pos -= 6; + buffer.putLong( + pos - 1, + ((value & (0x7FL << 35)) << 21) + | (((value & (0x7FL << 28)) | (0x80L << 28)) << 20) + | (((value & (0x7F << 21)) | (0x80 << 21)) << 19) + | (((value & (0x7F << 14)) | (0x80 << 14)) << 18) + | (((value & (0x7F << 7)) | (0x80 << 7)) << 17) + | (((value & 0x7F) | 0x80)) << 16); + } + + private void writeVarint64SevenBytes(long value) { + // Byte order is little-endian. + pos -= 7; + buffer.putLong( + pos, + ((value & (0x7FL << 42)) << 14) + | (((value & (0x7FL << 35)) | (0x80L << 35)) << 13) + | (((value & (0x7FL << 28)) | (0x80L << 28)) << 12) + | (((value & (0x7F << 21)) | (0x80 << 21)) << 11) + | (((value & (0x7F << 14)) | (0x80 << 14)) << 10) + | (((value & (0x7F << 7)) | (0x80 << 7)) << 9) + | (((value & 0x7F) | 0x80)) << 8); + } + + private void writeVarint64EightBytes(long value) { + // Byte order is little-endian. + pos -= 8; + buffer.putLong( + pos + 1, + ((value & (0x7FL << 49)) << 7) + | (((value & (0x7FL << 42)) | (0x80L << 42)) << 6) + | (((value & (0x7FL << 35)) | (0x80L << 35)) << 5) + | (((value & (0x7FL << 28)) | (0x80L << 28)) << 4) + | (((value & (0x7F << 21)) | (0x80 << 21)) << 3) + | (((value & (0x7F << 14)) | (0x80 << 14)) << 2) + | (((value & (0x7F << 7)) | (0x80 << 7)) << 1) + | ((value & 0x7F) | 0x80)); + } + + private void writeVarint64EightBytesWithSign(long value) { + // Byte order is little-endian. + pos -= 8; + buffer.putLong( + pos + 1, + (((value & (0x7FL << 49)) | (0x80L << 49)) << 7) + | (((value & (0x7FL << 42)) | (0x80L << 42)) << 6) + | (((value & (0x7FL << 35)) | (0x80L << 35)) << 5) + | (((value & (0x7FL << 28)) | (0x80L << 28)) << 4) + | (((value & (0x7F << 21)) | (0x80 << 21)) << 3) + | (((value & (0x7F << 14)) | (0x80 << 14)) << 2) + | (((value & (0x7F << 7)) | (0x80 << 7)) << 1) + | ((value & 0x7F) | 0x80)); + } + + private void writeVarint64NineBytes(long value) { + buffer.put(pos--, (byte) (value >>> 56)); + writeVarint64EightBytesWithSign(value & 0xFFFFFFFFFFFFFFL); + } + + private void writeVarint64TenBytes(long value) { + buffer.put(pos--, (byte) (value >>> 63)); + buffer.put(pos--, (byte) (((value >>> 56) & 0x7F) | 0x80)); + writeVarint64EightBytesWithSign(value & 0xFFFFFFFFFFFFFFL); + } + + @Override + void writeFixed32(int value) { + pos -= 4; + buffer.putInt(pos + 1, value); + } + + @Override + void writeFixed64(long value) { + pos -= 8; + buffer.putLong(pos + 1, value); + } + + @Override + void writeString(String in) { + // Request enough space to write the ASCII string. + requireSpace(in.length()); + + // We know the buffer is big enough... + int i = in.length() - 1; + pos -= i; + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) { + buffer.put(pos + i, (byte) c); + } + if (i == -1) { + // Move the position past the ASCII string. + pos -= 1; + return; + } + pos += i; + for (char c; i >= 0; i--) { + c = in.charAt(i); + if (c < 0x80 && pos >= 0) { + buffer.put(pos--, (byte) c); + } else if (c < 0x800 && pos > 0) { // 11 bits, two UTF-8 bytes + buffer.put(pos--, (byte) (0x80 | (0x3F & c))); + buffer.put(pos--, (byte) ((0xF << 6) | (c >>> 6))); + } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && pos > 1) { + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + buffer.put(pos--, (byte) (0x80 | (0x3F & c))); + buffer.put(pos--, (byte) (0x80 | (0x3F & (c >>> 6)))); + buffer.put(pos--, (byte) ((0xF << 5) | (c >>> 12))); + } else if (pos > 2) { + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, + // four UTF-8 bytes + char high = 0; + if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) { + throw new Utf8.UnpairedSurrogateException(i - 1, i); + } + i--; + int codePoint = Character.toCodePoint(high, c); + buffer.put(pos--, (byte) (0x80 | (0x3F & codePoint))); + buffer.put(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 6)))); + buffer.put(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 12)))); + buffer.put(pos--, (byte) ((0xF << 4) | (codePoint >>> 18))); + } else { + // Buffer is full - allocate a new one and revisit the current character. + requireSpace(i); + i++; + } + } + } + + @Override + public void write(byte value) { + buffer.put(pos--, value); + } + + @Override + public void write(byte[] value, int offset, int length) { + if (spaceLeft() < length) { + nextBuffer(length); + } + + pos -= length; + buffer.position(pos + 1); + buffer.put(value, offset, length); + } + + @Override + public void writeLazy(byte[] value, int offset, int length) { + if (spaceLeft() < length) { + // We consider the value to be immutable (likely the internals of a ByteString). Just + // wrap it in a Netty buffer and add it to the output buffer. + totalDoneBytes += length; + buffers.addFirst(AllocatedBuffer.wrap(value, offset, length)); + + // Advance the writer to the next buffer. + // TODO(nathanmittler): Consider slicing if space available above some threshold. + nextBuffer(); + return; + } + + pos -= length; + buffer.position(pos + 1); + buffer.put(value, offset, length); + } + + @Override + public void write(ByteBuffer value) { + int length = value.remaining(); + if (spaceLeft() < length) { + nextBuffer(length); + } + + pos -= length; + buffer.position(pos + 1); + buffer.put(value); + } + + @Override + public void writeLazy(ByteBuffer value) { + int length = value.remaining(); + if (spaceLeft() < length) { + // We consider the value to be immutable (likely the internals of a ByteString). Just + // wrap it in a Netty buffer and add it to the output buffer. + totalDoneBytes += length; + buffers.addFirst(AllocatedBuffer.wrap(value)); + + // Advance the writer to the next buffer. + // TODO(nathanmittler): Consider slicing if space available above some threshold. + nextBuffer(); + return; + } + + pos -= length; + buffer.position(pos + 1); + buffer.put(value); + } + + @Override + void requireSpace(int size) { + if (spaceLeft() < size) { + nextBuffer(size); + } + } + } + + /** Writer that uses unsafe operations on a target {@link ByteBuffer}. */ + private static final class UnsafeDirectWriter extends BinaryWriter { + private ByteBuffer buffer; + private long bufferOffset; + private long limitMinusOne; + private long pos; + + UnsafeDirectWriter(BufferAllocator alloc, int chunkSize) { + super(alloc, chunkSize); + nextBuffer(); + } + + /** Indicates whether the required unsafe operations are supported on this platform. */ + private static boolean isSupported() { + return UnsafeUtil.hasUnsafeByteBufferOperations(); + } + + private void nextBuffer() { + nextBuffer(newDirectBuffer()); + } + + private void nextBuffer(int capacity) { + nextBuffer(newDirectBuffer(capacity)); + } + + private void nextBuffer(AllocatedBuffer allocatedBuffer) { + if (!allocatedBuffer.hasNioBuffer()) { + throw new RuntimeException("Allocated buffer does not have NIO buffer"); + } + ByteBuffer nioBuffer = allocatedBuffer.nioBuffer(); + if (!nioBuffer.isDirect()) { + throw new RuntimeException("Allocator returned non-direct buffer"); + } + + finishCurrentBuffer(); + buffers.addFirst(allocatedBuffer); + + buffer = nioBuffer; + buffer.limit(buffer.capacity()); + buffer.position(0); + + bufferOffset = UnsafeUtil.addressOffset(buffer); + limitMinusOne = bufferOffset + (buffer.limit() - 1); + pos = limitMinusOne; + } + + @Override + public int getTotalBytesWritten() { + return totalDoneBytes + bytesWrittenToCurrentBuffer(); + } + + private int bytesWrittenToCurrentBuffer() { + return (int) (limitMinusOne - pos); + } + + private int spaceLeft() { + return bufferPos() + 1; + } + + @Override + void finishCurrentBuffer() { + if (buffer != null) { + totalDoneBytes += bytesWrittenToCurrentBuffer(); + // Update the indices on the netty buffer. + buffer.position(bufferPos() + 1); + buffer = null; + pos = 0; + limitMinusOne = 0; + } + } + + private int bufferPos() { + return (int) (pos - bufferOffset); + } + + @Override + public void writeUInt32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeInt32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeInt32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeSInt32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE * 2); + writeSInt32(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeFixed32(int fieldNumber, int value) { + requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE); + writeFixed32(value); + writeTag(fieldNumber, WIRETYPE_FIXED32); + } + + @Override + public void writeUInt64(int fieldNumber, long value) { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeVarint64(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeSInt64(int fieldNumber, long value) { + requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE); + writeSInt64(value); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeFixed64(int fieldNumber, long value) { + requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE); + writeFixed64(value); + writeTag(fieldNumber, WIRETYPE_FIXED64); + } + + @Override + public void writeBool(int fieldNumber, boolean value) { + requireSpace(MAX_VARINT32_SIZE + 1); + write((byte) (value ? 1 : 0)); + writeTag(fieldNumber, WIRETYPE_VARINT); + } + + @Override + public void writeString(int fieldNumber, String value) { + int prevBytes = getTotalBytesWritten(); + writeString(value); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(2 * MAX_VARINT32_SIZE); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeBytes(int fieldNumber, ByteString value) { + try { + value.writeToReverse(this); + } catch (IOException e) { + // Should never happen since the writer does not throw. + throw new RuntimeException(e); + } + + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(value.size()); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeMessage(int fieldNumber, Object value) throws IOException { + int prevBytes = getTotalBytesWritten(); + Protobuf.getInstance().writeTo(value, this); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException { + int prevBytes = getTotalBytesWritten(); + schema.writeTo(value, this); + int length = getTotalBytesWritten() - prevBytes; + requireSpace(MAX_VARINT32_SIZE * 2); + writeVarint32(length); + writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + } + + @Override + public void writeGroup(int fieldNumber, Object value) throws IOException { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + Protobuf.getInstance().writeTo(value, this); + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + schema.writeTo(value, this); + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeStartGroup(int fieldNumber) { + writeTag(fieldNumber, WIRETYPE_START_GROUP); + } + + @Override + public void writeEndGroup(int fieldNumber) { + writeTag(fieldNumber, WIRETYPE_END_GROUP); + } + + @Override + void writeInt32(int value) { + if (value >= 0) { + writeVarint32(value); + } else { + writeVarint64(value); + } + } + + @Override + void writeSInt32(int value) { + writeVarint32(CodedOutputStream.encodeZigZag32(value)); + } + + @Override + void writeSInt64(long value) { + writeVarint64(CodedOutputStream.encodeZigZag64(value)); + } + + @Override + void writeBool(boolean value) { + write((byte) (value ? 1 : 0)); + } + + @Override + void writeTag(int fieldNumber, int wireType) { + writeVarint32(WireFormat.makeTag(fieldNumber, wireType)); + } + + @Override + void writeVarint32(int value) { + if ((value & (~0 << 7)) == 0) { + writeVarint32OneByte(value); + } else if ((value & (~0 << 14)) == 0) { + writeVarint32TwoBytes(value); + } else if ((value & (~0 << 21)) == 0) { + writeVarint32ThreeBytes(value); + } else if ((value & (~0 << 28)) == 0) { + writeVarint32FourBytes(value); + } else { + writeVarint32FiveBytes(value); + } + } + + private void writeVarint32OneByte(int value) { + UnsafeUtil.putByte(pos--, (byte) value); + } + + private void writeVarint32TwoBytes(int value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 7)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint32ThreeBytes(int value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 14)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint32FourBytes(int value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 21)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint32FiveBytes(int value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 28)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + @Override + void writeVarint64(long value) { + switch (computeUInt64SizeNoTag(value)) { + case 1: + writeVarint64OneByte(value); + break; + case 2: + writeVarint64TwoBytes(value); + break; + case 3: + writeVarint64ThreeBytes(value); + break; + case 4: + writeVarint64FourBytes(value); + break; + case 5: + writeVarint64FiveBytes(value); + break; + case 6: + writeVarint64SixBytes(value); + break; + case 7: + writeVarint64SevenBytes(value); + break; + case 8: + writeVarint64EightBytes(value); + break; + case 9: + writeVarint64NineBytes(value); + break; + case 10: + writeVarint64TenBytes(value); + break; + } + } + + private void writeVarint64OneByte(long value) { + UnsafeUtil.putByte(pos--, (byte) value); + } + + private void writeVarint64TwoBytes(long value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 7)); + UnsafeUtil.putByte(pos--, (byte) (((int) value & 0x7F) | 0x80)); + } + + private void writeVarint64ThreeBytes(long value) { + UnsafeUtil.putByte(pos--, (byte) (((int) value) >>> 14)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64FourBytes(long value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 21)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64FiveBytes(long value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 28)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64SixBytes(long value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 35)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64SevenBytes(long value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 42)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64EightBytes(long value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 49)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 42) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64NineBytes(long value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 56)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 49) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 42) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + private void writeVarint64TenBytes(long value) { + UnsafeUtil.putByte(pos--, (byte) (value >>> 63)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 56) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 49) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 42) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80)); + UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80)); + } + + @Override + void writeFixed32(int value) { + UnsafeUtil.putByte(pos--, (byte) ((value >> 24) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) ((value >> 16) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) ((value >> 8) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) (value & 0xFF)); + } + + @Override + void writeFixed64(long value) { + UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 56) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 48) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 40) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 32) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 24) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 16) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 8) & 0xFF)); + UnsafeUtil.putByte(pos--, (byte) ((int) (value) & 0xFF)); + } + + @Override + void writeString(String in) { + // Request enough space to write the ASCII string. + requireSpace(in.length()); + + // We know the buffer is big enough... + int i = in.length() - 1; + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) { + UnsafeUtil.putByte(pos--, (byte) c); + } + if (i == -1) { + // ASCII. + return; + } + for (char c; i >= 0; i--) { + c = in.charAt(i); + if (c < 0x80 && pos >= bufferOffset) { + UnsafeUtil.putByte(pos--, (byte) c); + } else if (c < 0x800 && pos > bufferOffset) { // 11 bits, two UTF-8 bytes + UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & c))); + UnsafeUtil.putByte(pos--, (byte) ((0xF << 6) | (c >>> 6))); + } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) + && pos > bufferOffset + 1) { + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & c))); + UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & (c >>> 6)))); + UnsafeUtil.putByte(pos--, (byte) ((0xF << 5) | (c >>> 12))); + } else if (pos > bufferOffset + 2) { + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, + // four UTF-8 bytes + final char high; + if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) { + throw new Utf8.UnpairedSurrogateException(i - 1, i); + } + i--; + int codePoint = Character.toCodePoint(high, c); + UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & codePoint))); + UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 6)))); + UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 12)))); + UnsafeUtil.putByte(pos--, (byte) ((0xF << 4) | (codePoint >>> 18))); + } else { + // Buffer is full - allocate a new one and revisit the current character. + requireSpace(i); + i++; + } + } + } + + @Override + public void write(byte value) { + UnsafeUtil.putByte(pos--, value); + } + + @Override + public void write(byte[] value, int offset, int length) { + if (spaceLeft() < length) { + nextBuffer(length); + } + + pos -= length; + buffer.position(bufferPos() + 1); + buffer.put(value, offset, length); + } + + @Override + public void writeLazy(byte[] value, int offset, int length) { + if (spaceLeft() < length) { + // We consider the value to be immutable (likely the internals of a ByteString). Just + // wrap it in a Netty buffer and add it to the output buffer. + totalDoneBytes += length; + buffers.addFirst(AllocatedBuffer.wrap(value, offset, length)); + + // Advance the writer to the next buffer. + // TODO(nathanmittler): Consider slicing if space available above some threshold. + nextBuffer(); + return; + } + + pos -= length; + buffer.position(bufferPos() + 1); + buffer.put(value, offset, length); + } + + @Override + public void write(ByteBuffer value) { + int length = value.remaining(); + if (spaceLeft() < length) { + nextBuffer(length); + } + + pos -= length; + buffer.position(bufferPos() + 1); + buffer.put(value); + } + + @Override + public void writeLazy(ByteBuffer value) { + int length = value.remaining(); + if (spaceLeft() < length) { + // We consider the value to be immutable (likely the internals of a ByteString). Just + // wrap it in a Netty buffer and add it to the output buffer. + totalDoneBytes += length; + buffers.addFirst(AllocatedBuffer.wrap(value)); + + // Advance the writer to the next buffer. + // TODO(nathanmittler): Consider slicing if space available above some threshold. + nextBuffer(); + return; + } + + pos -= length; + buffer.position(bufferPos() + 1); + buffer.put(value); + } + + @Override + void requireSpace(int size) { + if (spaceLeft() < size) { + nextBuffer(size); + } + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/BufferAllocator.java b/java/core/src/main/java/com/google/protobuf/BufferAllocator.java new file mode 100755 index 000000000..bfd9c7237 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/BufferAllocator.java @@ -0,0 +1,64 @@ +// 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 java.nio.ByteBuffer; + +/** + * An object responsible for allocation of buffers. This is an extension point to enable buffer + * pooling within an application. + */ +@ExperimentalApi +abstract class BufferAllocator { + private static final BufferAllocator UNPOOLED = + new BufferAllocator() { + @Override + public AllocatedBuffer allocateHeapBuffer(int capacity) { + return AllocatedBuffer.wrap(new byte[capacity]); + } + + @Override + public AllocatedBuffer allocateDirectBuffer(int capacity) { + return AllocatedBuffer.wrap(ByteBuffer.allocateDirect(capacity)); + } + }; + + /** Returns an unpooled buffer allocator, which will create a new buffer for each request. */ + public static BufferAllocator unpooled() { + return UNPOOLED; + } + + /** Allocates a buffer with the given capacity that is backed by an array on the heap. */ + public abstract AllocatedBuffer allocateHeapBuffer(int capacity); + + /** Allocates a direct (i.e. non-heap) buffer with the given capacity. */ + public abstract AllocatedBuffer allocateDirectBuffer(int capacity); +} diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java index 648991dc2..e5454a63d 100644 --- a/java/core/src/main/java/com/google/protobuf/ByteString.java +++ b/java/core/src/main/java/com/google/protobuf/ByteString.java @@ -732,6 +732,16 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { */ abstract void writeTo(ByteOutput byteOutput) throws IOException; + /** + * This method behaves exactly the same as {@link #writeTo(ByteOutput)} unless the {@link + * ByteString} is a rope. For ropes, the leaf nodes are written in reverse order to the {@code + * byteOutput}. + * + * @param byteOutput the output target to receive the bytes + * @throws IOException if an I/O error occurs + * @see UnsafeByteOperations#unsafeWriteToReverse(ByteString, ByteOutput) + */ + abstract void writeToReverse(ByteOutput byteOutput) throws IOException; /** * Constructs a read-only {@code java.nio.ByteBuffer} whose content is equal to the contents of @@ -862,6 +872,10 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { return true; } + @Override + void writeToReverse(ByteOutput byteOutput) throws IOException { + writeTo(byteOutput); + } /** * Check equality of the substring of given length of this object starting at zero with another @@ -1438,14 +1452,16 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { LiteralByteString lbsOther = (LiteralByteString) other; byte[] thisBytes = bytes; byte[] otherBytes = lbsOther.bytes; - - return UnsafeUtil.mismatch( - thisBytes, - getOffsetIntoBytes(), - otherBytes, - lbsOther.getOffsetIntoBytes() + offset, - length) - == -1; + int thisLimit = getOffsetIntoBytes() + length; + for (int thisIndex = getOffsetIntoBytes(), + otherIndex = lbsOther.getOffsetIntoBytes() + offset; + (thisIndex < thisLimit); + ++thisIndex, ++otherIndex) { + if (thisBytes[thisIndex] != otherBytes[otherIndex]) { + return false; + } + } + return true; } return other.substring(offset, offset + length).equals(substring(0, length)); diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java index 6cece058e..87c683725 100644 --- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java +++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java @@ -72,6 +72,9 @@ public abstract class CodedInputStream { /** Visible for subclasses. See setSizeLimit() */ int sizeLimit = DEFAULT_SIZE_LIMIT; + /** Used to adapt to the experimental {@link Reader} interface. */ + CodedInputStreamReader wrapper; + /** Create a new CodedInputStream wrapping the given InputStream. */ public static CodedInputStream newInstance(final InputStream input) { return newInstance(input, DEFAULT_BUFFER_SIZE); @@ -2263,7 +2266,7 @@ public abstract class CodedInputStream { return result; } // Slow path: Build a byte array first then copy it. - return new String(readRawBytesSlowPath(size), UTF_8); + return new String(readRawBytesSlowPath(size, /* ensureNoLeakedReferences= */ false), UTF_8); } @Override @@ -2287,7 +2290,7 @@ public abstract class CodedInputStream { pos = tempPos + size; } else { // Slow path: Build a byte array first then copy it. - bytes = readRawBytesSlowPath(size); + bytes = readRawBytesSlowPath(size, /* ensureNoLeakedReferences= */ false); tempPos = 0; } return Utf8.decodeUtf8(bytes, tempPos, size); @@ -2392,7 +2395,8 @@ public abstract class CodedInputStream { return result; } else { // Slow path: Build a byte array first then copy it. - return readRawBytesSlowPath(size); + // TODO(dweis): Do we want to protect from malicious input streams here? + return readRawBytesSlowPath(size, /* ensureNoLeakedReferences= */ false); } } @@ -2409,7 +2413,10 @@ public abstract class CodedInputStream { return Internal.EMPTY_BYTE_BUFFER; } // Slow path: Build a byte array first then copy it. - return ByteBuffer.wrap(readRawBytesSlowPath(size)); + + // We must copy as the byte array was handed off to the InputStream and a malicious + // implementation could retain a reference. + return ByteBuffer.wrap(readRawBytesSlowPath(size, /* ensureNoLeakedReferences= */ true)); } @Override @@ -2812,19 +2819,24 @@ public abstract class CodedInputStream { pos = tempPos + size; return Arrays.copyOfRange(buffer, tempPos, tempPos + size); } else { - return readRawBytesSlowPath(size); + // TODO(dweis): Do we want to protect from malicious input streams here? + return readRawBytesSlowPath(size, /* ensureNoLeakedReferences= */ false); } } /** * Exactly like readRawBytes, but caller must have already checked the fast path: (size <= * (bufferSize - pos) && size > 0) + * + * If ensureNoLeakedReferences is true, the value is guaranteed to have not escaped to + * untrusted code. */ - private byte[] readRawBytesSlowPath(final int size) throws IOException { + private byte[] readRawBytesSlowPath( + final int size, boolean ensureNoLeakedReferences) throws IOException { // Attempt to read the data in one byte array when it's safe to do. byte[] result = readRawBytesSlowPathOneChunk(size); if (result != null) { - return result; + return ensureNoLeakedReferences ? result.clone() : result; } final int originalBufferPos = pos; @@ -2862,6 +2874,8 @@ public abstract class CodedInputStream { /** * Attempts to read the data in one byte array when it's safe to do. Returns null if the size to * read is too large and needs to be allocated in smaller chunks for security reasons. + * + * Returns a byte[] that may have escaped to user code via InputStream APIs. */ private byte[] readRawBytesSlowPathOneChunk(final int size) throws IOException { if (size == 0) { @@ -2916,7 +2930,11 @@ public abstract class CodedInputStream { return null; } - /** Reads the remaining data in small chunks from the input stream. */ + /** + * Reads the remaining data in small chunks from the input stream. + * + * Returns a byte[] that may have escaped to user code via InputStream APIs. + */ private List<byte[]> readRawBytesSlowPathRemainingChunks(int sizeLeft) throws IOException { // The size is very large. For security reasons, we can't allocate the // entire byte array yet. The size comes directly from the input, so a @@ -2953,7 +2971,9 @@ public abstract class CodedInputStream { private ByteString readBytesSlowPath(final int size) throws IOException { final byte[] result = readRawBytesSlowPathOneChunk(size); if (result != null) { - return ByteString.wrap(result); + // We must copy as the byte array was handed off to the InputStream and a malicious + // implementation could retain a reference. + return ByteString.copyFrom(result); } final int originalBufferPos = pos; @@ -2971,13 +2991,20 @@ public abstract class CodedInputStream { // chunks. List<byte[]> chunks = readRawBytesSlowPathRemainingChunks(sizeLeft); - // Wrap the byte arrays into a single ByteString. - List<ByteString> byteStrings = new ArrayList<ByteString>(1 + chunks.size()); - byteStrings.add(ByteString.copyFrom(buffer, originalBufferPos, bufferedBytes)); - for (byte[] chunk : chunks) { - byteStrings.add(ByteString.wrap(chunk)); + // OK, got everything. Now concatenate it all into one buffer. + final byte[] bytes = new byte[size]; + + // Start by copying the leftover bytes from this.buffer. + System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); + + // And now all the chunks. + int tempPos = bufferedBytes; + for (final byte[] chunk : chunks) { + System.arraycopy(chunk, 0, bytes, tempPos, chunk.length); + tempPos += chunk.length; } - return ByteString.copyFrom(byteStrings); + + return ByteString.wrap(bytes); } @Override diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java b/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java new file mode 100755 index 000000000..7658f629d --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java @@ -0,0 +1,1333 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.WireFormat.FIXED32_SIZE; +import static com.google.protobuf.WireFormat.FIXED64_SIZE; +import static com.google.protobuf.WireFormat.WIRETYPE_END_GROUP; +import static com.google.protobuf.WireFormat.WIRETYPE_FIXED32; +import static com.google.protobuf.WireFormat.WIRETYPE_FIXED64; +import static com.google.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED; +import static com.google.protobuf.WireFormat.WIRETYPE_START_GROUP; +import static com.google.protobuf.WireFormat.WIRETYPE_VARINT; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** An adapter between the {@link Reader} interface and {@link CodedInputStream}. */ +@ExperimentalApi +final class CodedInputStreamReader implements Reader { + private static final int FIXED32_MULTIPLE_MASK = FIXED32_SIZE - 1; + private static final int FIXED64_MULTIPLE_MASK = FIXED64_SIZE - 1; + private static final int NEXT_TAG_UNSET = 0; + + private final CodedInputStream input; + private int tag; + private int endGroupTag; + private int nextTag = NEXT_TAG_UNSET; + + public static CodedInputStreamReader forCodedInput(CodedInputStream input) { + if (input.wrapper != null) { + return input.wrapper; + } + return new CodedInputStreamReader(input); + } + + private CodedInputStreamReader(CodedInputStream input) { + this.input = Internal.checkNotNull(input, "input"); + this.input.wrapper = this; + } + + @Override + public boolean shouldDiscardUnknownFields() { + return input.shouldDiscardUnknownFields(); + } + + @Override + public int getFieldNumber() throws IOException { + if (nextTag != NEXT_TAG_UNSET) { + tag = nextTag; + nextTag = NEXT_TAG_UNSET; + } else { + tag = input.readTag(); + } + if (tag == 0 || tag == endGroupTag) { + return Reader.READ_DONE; + } + return WireFormat.getTagFieldNumber(tag); + } + + @Override + public int getTag() { + return tag; + } + + @Override + public boolean skipField() throws IOException { + if (input.isAtEnd() || tag == endGroupTag) { + return false; + } + return input.skipField(tag); + } + + private void requireWireType(int requiredWireType) throws IOException { + if (WireFormat.getTagWireType(tag) != requiredWireType) { + throw InvalidProtocolBufferException.invalidWireType(); + } + } + + @Override + public double readDouble() throws IOException { + requireWireType(WIRETYPE_FIXED64); + return input.readDouble(); + } + + @Override + public float readFloat() throws IOException { + requireWireType(WIRETYPE_FIXED32); + return input.readFloat(); + } + + @Override + public long readUInt64() throws IOException { + requireWireType(WIRETYPE_VARINT); + return input.readUInt64(); + } + + @Override + public long readInt64() throws IOException { + requireWireType(WIRETYPE_VARINT); + return input.readInt64(); + } + + @Override + public int readInt32() throws IOException { + requireWireType(WIRETYPE_VARINT); + return input.readInt32(); + } + + @Override + public long readFixed64() throws IOException { + requireWireType(WIRETYPE_FIXED64); + return input.readFixed64(); + } + + @Override + public int readFixed32() throws IOException { + requireWireType(WIRETYPE_FIXED32); + return input.readFixed32(); + } + + @Override + public boolean readBool() throws IOException { + requireWireType(WIRETYPE_VARINT); + return input.readBool(); + } + + @Override + public String readString() throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + return input.readString(); + } + + @Override + public String readStringRequireUtf8() throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + return input.readStringRequireUtf8(); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T readMessage(Class<T> clazz, ExtensionRegistryLite extensionRegistry) + throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + return readMessage(Protobuf.getInstance().schemaFor(clazz), extensionRegistry); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T readMessageBySchemaWithCheck( + Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + return readMessage(schema, extensionRegistry); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T readGroup(Class<T> clazz, ExtensionRegistryLite extensionRegistry) + throws IOException { + requireWireType(WIRETYPE_START_GROUP); + return readGroup(Protobuf.getInstance().schemaFor(clazz), extensionRegistry); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T readGroupBySchemaWithCheck(Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException { + requireWireType(WIRETYPE_START_GROUP); + return readGroup(schema, extensionRegistry); + } + + // Should have the same semantics of CodedInputStream#readMessage() + private <T> T readMessage(Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException { + int size = input.readUInt32(); + if (input.recursionDepth >= input.recursionLimit) { + throw InvalidProtocolBufferException.recursionLimitExceeded(); + } + + // Push the new limit. + final int prevLimit = input.pushLimit(size); + // Allocate and read the message. + T message = schema.newInstance(); + ++input.recursionDepth; + schema.mergeFrom(message, this, extensionRegistry); + schema.makeImmutable(message); + input.checkLastTagWas(0); + --input.recursionDepth; + // Restore the previous limit. + input.popLimit(prevLimit); + return message; + } + + private <T> T readGroup(Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException { + int prevEndGroupTag = endGroupTag; + endGroupTag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WIRETYPE_END_GROUP); + + try { + // Allocate and read the message. + T message = schema.newInstance(); + schema.mergeFrom(message, this, extensionRegistry); + schema.makeImmutable(message); + + if (tag != endGroupTag) { + throw InvalidProtocolBufferException.parseFailure(); + } + return message; + } finally { + // Restore the old end group tag. + endGroupTag = prevEndGroupTag; + } + } + + @Override + public ByteString readBytes() throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + return input.readBytes(); + } + + @Override + public int readUInt32() throws IOException { + requireWireType(WIRETYPE_VARINT); + return input.readUInt32(); + } + + @Override + public int readEnum() throws IOException { + requireWireType(WIRETYPE_VARINT); + return input.readEnum(); + } + + @Override + public int readSFixed32() throws IOException { + requireWireType(WIRETYPE_FIXED32); + return input.readSFixed32(); + } + + @Override + public long readSFixed64() throws IOException { + requireWireType(WIRETYPE_FIXED64); + return input.readSFixed64(); + } + + @Override + public int readSInt32() throws IOException { + requireWireType(WIRETYPE_VARINT); + return input.readSInt32(); + } + + @Override + public long readSInt64() throws IOException { + requireWireType(WIRETYPE_VARINT); + return input.readSInt64(); + } + + @Override + public void readDoubleList(List<Double> target) throws IOException { + if (target instanceof DoubleArrayList) { + DoubleArrayList plist = (DoubleArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed64Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addDouble(input.readDouble()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED64: + while (true) { + plist.addDouble(input.readDouble()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed64Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readDouble()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED64: + while (true) { + target.add(input.readDouble()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readFloatList(List<Float> target) throws IOException { + if (target instanceof FloatArrayList) { + FloatArrayList plist = (FloatArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed32Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addFloat(input.readFloat()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED32: + while (true) { + plist.addFloat(input.readFloat()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed32Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readFloat()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED32: + while (true) { + target.add(input.readFloat()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readUInt64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addLong(input.readUInt64()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addLong(input.readUInt64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readUInt64()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(input.readUInt64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readInt64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addLong(input.readInt64()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addLong(input.readInt64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readInt64()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(input.readInt64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readInt32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addInt(input.readInt32()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addInt(input.readInt32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readInt32()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(input.readInt32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readFixed64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed64Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addLong(input.readFixed64()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED64: + while (true) { + plist.addLong(input.readFixed64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed64Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readFixed64()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED64: + while (true) { + target.add(input.readFixed64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readFixed32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed32Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addInt(input.readFixed32()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED32: + while (true) { + plist.addInt(input.readFixed32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed32Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readFixed32()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED32: + while (true) { + target.add(input.readFixed32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readBoolList(List<Boolean> target) throws IOException { + if (target instanceof BooleanArrayList) { + BooleanArrayList plist = (BooleanArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addBoolean(input.readBool()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addBoolean(input.readBool()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readBool()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(input.readBool()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readStringList(List<String> target) throws IOException { + readStringListInternal(target, false); + } + + @Override + public void readStringListRequireUtf8(List<String> target) throws IOException { + readStringListInternal(target, true); + } + + public void readStringListInternal(List<String> target, boolean requireUtf8) throws IOException { + if (WireFormat.getTagWireType(tag) != WIRETYPE_LENGTH_DELIMITED) { + throw InvalidProtocolBufferException.invalidWireType(); + } + + if (target instanceof LazyStringList && !requireUtf8) { + LazyStringList lazyList = (LazyStringList) target; + while (true) { + lazyList.add(readBytes()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + } else { + while (true) { + target.add(requireUtf8 ? readStringRequireUtf8() : readString()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + } + } + + @Override + public <T> void readMessageList( + List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry) + throws IOException { + final Schema<T> schema = Protobuf.getInstance().schemaFor(targetType); + readMessageList(target, schema, extensionRegistry); + } + + @Override + public <T> void readMessageList( + List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException { + if (WireFormat.getTagWireType(tag) != WIRETYPE_LENGTH_DELIMITED) { + throw InvalidProtocolBufferException.invalidWireType(); + } + final int listTag = tag; + while (true) { + target.add(readMessage(schema, extensionRegistry)); + if (input.isAtEnd() || nextTag != NEXT_TAG_UNSET) { + return; + } + int nextTag = input.readTag(); + if (nextTag != listTag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + } + + @Override + public <T> void readGroupList( + List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry) + throws IOException { + final Schema<T> schema = Protobuf.getInstance().schemaFor(targetType); + readGroupList(target, schema, extensionRegistry); + } + + @Override + public <T> void readGroupList( + List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException { + if (WireFormat.getTagWireType(tag) != WIRETYPE_START_GROUP) { + throw InvalidProtocolBufferException.invalidWireType(); + } + final int listTag = tag; + while (true) { + target.add(readGroup(schema, extensionRegistry)); + if (input.isAtEnd() || nextTag != NEXT_TAG_UNSET) { + return; + } + int nextTag = input.readTag(); + if (nextTag != listTag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + } + + @Override + public void readBytesList(List<ByteString> target) throws IOException { + if (WireFormat.getTagWireType(tag) != WIRETYPE_LENGTH_DELIMITED) { + throw InvalidProtocolBufferException.invalidWireType(); + } + + while (true) { + target.add(readBytes()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + } + + @Override + public void readUInt32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addInt(input.readUInt32()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addInt(input.readUInt32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readUInt32()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(input.readUInt32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readEnumList(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addInt(input.readEnum()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addInt(input.readEnum()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readEnum()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(input.readEnum()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readSFixed32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed32Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addInt(input.readSFixed32()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED32: + while (true) { + plist.addInt(input.readSFixed32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed32Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readSFixed32()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED32: + while (true) { + target.add(input.readSFixed32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readSFixed64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed64Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addLong(input.readSFixed64()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED64: + while (true) { + plist.addLong(input.readSFixed64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + verifyPackedFixed64Length(bytes); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readSFixed64()); + } while (input.getTotalBytesRead() < endPos); + break; + case WIRETYPE_FIXED64: + while (true) { + target.add(input.readSFixed64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readSInt32List(List<Integer> target) throws IOException { + if (target instanceof IntArrayList) { + IntArrayList plist = (IntArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addInt(input.readSInt32()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addInt(input.readSInt32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readSInt32()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(input.readSInt32()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + @Override + public void readSInt64List(List<Long> target) throws IOException { + if (target instanceof LongArrayList) { + LongArrayList plist = (LongArrayList) target; + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + plist.addLong(input.readSInt64()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + plist.addLong(input.readSInt64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } else { + switch (WireFormat.getTagWireType(tag)) { + case WIRETYPE_LENGTH_DELIMITED: + final int bytes = input.readUInt32(); + int endPos = input.getTotalBytesRead() + bytes; + do { + target.add(input.readSInt64()); + } while (input.getTotalBytesRead() < endPos); + requirePosition(endPos); + break; + case WIRETYPE_VARINT: + while (true) { + target.add(input.readSInt64()); + if (input.isAtEnd()) { + return; + } + int nextTag = input.readTag(); + if (nextTag != tag) { + // We've reached the end of the repeated field. Save the next tag value. + this.nextTag = nextTag; + return; + } + } + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + } + + private void verifyPackedFixed64Length(int bytes) throws IOException { + if ((bytes & FIXED64_MULTIPLE_MASK) != 0) { + // Require that the number of bytes be a multiple of 8. + throw InvalidProtocolBufferException.parseFailure(); + } + } + + @SuppressWarnings("unchecked") + @Override + public <K, V> void readMap( + Map<K, V> target, + MapEntryLite.Metadata<K, V> metadata, + ExtensionRegistryLite extensionRegistry) + throws IOException { + requireWireType(WIRETYPE_LENGTH_DELIMITED); + int size = input.readUInt32(); + final int prevLimit = input.pushLimit(size); + K key = metadata.defaultKey; + V value = metadata.defaultValue; + try { + while (true) { + int number = getFieldNumber(); + if (number == READ_DONE || input.isAtEnd()) { + break; + } + try { + switch (number) { + case 1: + key = (K) readField(metadata.keyType, null, null); + break; + case 2: + value = + (V) + readField( + metadata.valueType, metadata.defaultValue.getClass(), extensionRegistry); + break; + default: + if (!skipField()) { + throw new InvalidProtocolBufferException("Unable to parse map entry."); + } + break; + } + } catch (InvalidProtocolBufferException.InvalidWireTypeException ignore) { + // the type doesn't match, skip the field. + if (!skipField()) { + throw new InvalidProtocolBufferException("Unable to parse map entry."); + } + } + } + target.put(key, value); + } finally { + // Restore the previous limit. + input.popLimit(prevLimit); + } + } + + private Object readField( + WireFormat.FieldType fieldType, Class<?> messageType, ExtensionRegistryLite extensionRegistry) + throws IOException { + switch (fieldType) { + case BOOL: + return readBool(); + case BYTES: + return readBytes(); + case DOUBLE: + return readDouble(); + case ENUM: + return readEnum(); + case FIXED32: + return readFixed32(); + case FIXED64: + return readFixed64(); + case FLOAT: + return readFloat(); + case INT32: + return readInt32(); + case INT64: + return readInt64(); + case MESSAGE: + return readMessage(messageType, extensionRegistry); + case SFIXED32: + return readSFixed32(); + case SFIXED64: + return readSFixed64(); + case SINT32: + return readSInt32(); + case SINT64: + return readSInt64(); + case STRING: + return readStringRequireUtf8(); + case UINT32: + return readUInt32(); + case UINT64: + return readUInt64(); + default: + throw new RuntimeException("unsupported field type."); + } + } + + private void verifyPackedFixed32Length(int bytes) throws IOException { + if ((bytes & FIXED32_MULTIPLE_MASK) != 0) { + // Require that the number of bytes be a multiple of 4. + throw InvalidProtocolBufferException.parseFailure(); + } + } + + private void requirePosition(int expectedPosition) throws IOException { + if (input.getTotalBytesRead() != expectedPosition) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java index 3823f81fc..a9192d33e 100644 --- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java +++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java @@ -60,6 +60,9 @@ public abstract class CodedOutputStream extends ByteOutput { private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName()); private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations(); + /** Used to adapt to the experimental {@link Writer} interface. */ + CodedOutputStreamWriter wrapper; + /** @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. */ @Deprecated public static final int LITTLE_ENDIAN_32_SIZE = FIXED32_SIZE; @@ -361,6 +364,10 @@ public abstract class CodedOutputStream extends ByteOutput { public abstract void writeMessage(final int fieldNumber, final MessageLite value) throws IOException; + /** Write an embedded message field, including tag, to the stream. */ + // Abstract to avoid overhead of additional virtual method calls. + abstract void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) + throws IOException; /** * Write a MessageSet extension field to the stream. For historical reasons, the wire format @@ -466,6 +473,9 @@ public abstract class CodedOutputStream extends ByteOutput { // Abstract to avoid overhead of additional virtual method calls. public abstract void writeMessageNoTag(final MessageLite value) throws IOException; + /** Write an embedded message field to the stream. */ + // Abstract to avoid overhead of additional virtual method calls. + abstract void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException; // ================================================================= @@ -651,6 +661,14 @@ public abstract class CodedOutputStream extends ByteOutput { return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value); } + /** + * Compute the number of bytes that would be needed to encode an embedded message field, including + * tag. + */ + static int computeMessageSize( + final int fieldNumber, final MessageLite value, final Schema schema) { + return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value, schema); + } /** * Compute the number of bytes that would be needed to encode a MessageSet extension to the @@ -859,6 +877,10 @@ public abstract class CodedOutputStream extends ByteOutput { return computeLengthDelimitedFieldSize(value.getSerializedSize()); } + /** Compute the number of bytes that would be needed to encode an embedded message field. */ + static int computeMessageSizeNoTag(final MessageLite value, final Schema schema) { + return computeLengthDelimitedFieldSize(((AbstractMessageLite) value).getSerializedSize(schema)); + } static int computeLengthDelimitedFieldSize(int fieldLength) { return computeUInt32SizeNoTag(fieldLength) + fieldLength; @@ -993,6 +1015,18 @@ public abstract class CodedOutputStream extends ByteOutput { writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); } + /** + * Write a {@code group} field, including tag, to the stream. + * + * @deprecated groups are deprecated. + */ + @Deprecated + final void writeGroup(final int fieldNumber, final MessageLite value, Schema schema) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); + writeGroupNoTag(value, schema); + writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); + } /** * Write a {@code group} field to the stream. @@ -1004,6 +1038,15 @@ public abstract class CodedOutputStream extends ByteOutput { value.writeTo(this); } + /** + * Write a {@code group} field to the stream. + * + * @deprecated groups are deprecated. + */ + @Deprecated + final void writeGroupNoTag(final MessageLite value, Schema schema) throws IOException { + schema.writeTo(value, wrapper); + } /** * Compute the number of bytes that would be needed to encode a {@code group} field, including @@ -1016,6 +1059,16 @@ public abstract class CodedOutputStream extends ByteOutput { return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value); } + /** + * Compute the number of bytes that would be needed to encode a {@code group} field, including + * tag. + * + * @deprecated groups are deprecated. + */ + @Deprecated + static int computeGroupSize(final int fieldNumber, final MessageLite value, Schema schema) { + return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value, schema); + } /** Compute the number of bytes that would be needed to encode a {@code group} field. */ @Deprecated @@ -1023,6 +1076,11 @@ public abstract class CodedOutputStream extends ByteOutput { return value.getSerializedSize(); } + /** Compute the number of bytes that would be needed to encode a {@code group} field. */ + @Deprecated + static int computeGroupSizeNoTag(final MessageLite value, Schema schema) { + return ((AbstractMessageLite) value).getSerializedSize(schema); + } /** * Encode and write a varint. {@code value} is treated as unsigned, so it won't be sign-extended @@ -1216,6 +1274,13 @@ public abstract class CodedOutputStream extends ByteOutput { writeMessageNoTag(value); } + @Override + final void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); + schema.writeTo(value, wrapper); + } @Override public final void writeMessageSetExtension(final int fieldNumber, final MessageLite value) @@ -1241,6 +1306,11 @@ public abstract class CodedOutputStream extends ByteOutput { value.writeTo(this); } + @Override + final void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException { + writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); + schema.writeTo(value, wrapper); + } @Override public final void write(byte value) throws IOException { @@ -1571,6 +1641,12 @@ public abstract class CodedOutputStream extends ByteOutput { writeMessageNoTag(value); } + @Override + void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value, schema); + } @Override public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) @@ -1596,6 +1672,11 @@ public abstract class CodedOutputStream extends ByteOutput { value.writeTo(this); } + @Override + void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException { + writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); + schema.writeTo(value, wrapper); + } @Override public void write(byte value) throws IOException { @@ -1893,6 +1974,11 @@ public abstract class CodedOutputStream extends ByteOutput { writeMessageNoTag(value); } + @Override + void writeMessage(int fieldNumber, MessageLite value, Schema schema) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value, schema); + } @Override public void writeMessageSetExtension(int fieldNumber, MessageLite value) throws IOException { @@ -1916,6 +2002,11 @@ public abstract class CodedOutputStream extends ByteOutput { value.writeTo(this); } + @Override + void writeMessageNoTag(MessageLite value, Schema schema) throws IOException { + writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); + schema.writeTo(value, wrapper); + } @Override public void write(byte value) throws IOException { @@ -2419,6 +2510,12 @@ public abstract class CodedOutputStream extends ByteOutput { writeMessageNoTag(value); } + @Override + void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value, schema); + } @Override public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) @@ -2444,6 +2541,11 @@ public abstract class CodedOutputStream extends ByteOutput { value.writeTo(this); } + @Override + void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException { + writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); + schema.writeTo(value, wrapper); + } @Override public void write(byte value) throws IOException { @@ -2722,6 +2824,12 @@ public abstract class CodedOutputStream extends ByteOutput { writeMessageNoTag(value); } + @Override + void writeMessage(final int fieldNumber, final MessageLite value, Schema schema) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value, schema); + } @Override public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) @@ -2747,6 +2855,11 @@ public abstract class CodedOutputStream extends ByteOutput { value.writeTo(this); } + @Override + void writeMessageNoTag(final MessageLite value, Schema schema) throws IOException { + writeUInt32NoTag(((AbstractMessageLite) value).getSerializedSize(schema)); + schema.writeTo(value, wrapper); + } @Override public void write(byte value) throws IOException { diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStreamWriter.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStreamWriter.java new file mode 100755 index 000000000..0d1983cb0 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStreamWriter.java @@ -0,0 +1,691 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.Internal.checkNotNull; +import static com.google.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** An adapter between the {@link Writer} interface and {@link CodedOutputStream}. */ +@ExperimentalApi +final class CodedOutputStreamWriter implements Writer { + private final CodedOutputStream output; + + public static CodedOutputStreamWriter forCodedOutput(CodedOutputStream output) { + if (output.wrapper != null) { + return output.wrapper; + } + return new CodedOutputStreamWriter(output); + } + + private CodedOutputStreamWriter(CodedOutputStream output) { + this.output = checkNotNull(output, "output"); + this.output.wrapper = this; + } + + @Override + public FieldOrder fieldOrder() { + return FieldOrder.ASCENDING; + } + + public int getTotalBytesWritten() { + return output.getTotalBytesWritten(); + } + + @Override + public void writeSFixed32(int fieldNumber, int value) throws IOException { + output.writeSFixed32(fieldNumber, value); + } + + @Override + public void writeInt64(int fieldNumber, long value) throws IOException { + output.writeInt64(fieldNumber, value); + } + + @Override + public void writeSFixed64(int fieldNumber, long value) throws IOException { + output.writeSFixed64(fieldNumber, value); + } + + @Override + public void writeFloat(int fieldNumber, float value) throws IOException { + output.writeFloat(fieldNumber, value); + } + + @Override + public void writeDouble(int fieldNumber, double value) throws IOException { + output.writeDouble(fieldNumber, value); + } + + @Override + public void writeEnum(int fieldNumber, int value) throws IOException { + output.writeEnum(fieldNumber, value); + } + + @Override + public void writeUInt64(int fieldNumber, long value) throws IOException { + output.writeUInt64(fieldNumber, value); + } + + @Override + public void writeInt32(int fieldNumber, int value) throws IOException { + output.writeInt32(fieldNumber, value); + } + + @Override + public void writeFixed64(int fieldNumber, long value) throws IOException { + output.writeFixed64(fieldNumber, value); + } + + @Override + public void writeFixed32(int fieldNumber, int value) throws IOException { + output.writeFixed32(fieldNumber, value); + } + + @Override + public void writeBool(int fieldNumber, boolean value) throws IOException { + output.writeBool(fieldNumber, value); + } + + @Override + public void writeString(int fieldNumber, String value) throws IOException { + output.writeString(fieldNumber, value); + } + + @Override + public void writeBytes(int fieldNumber, ByteString value) throws IOException { + output.writeBytes(fieldNumber, value); + } + + @Override + public void writeUInt32(int fieldNumber, int value) throws IOException { + output.writeUInt32(fieldNumber, value); + } + + @Override + public void writeSInt32(int fieldNumber, int value) throws IOException { + output.writeSInt32(fieldNumber, value); + } + + @Override + public void writeSInt64(int fieldNumber, long value) throws IOException { + output.writeSInt64(fieldNumber, value); + } + + @Override + public void writeMessage(int fieldNumber, Object value) throws IOException { + output.writeMessage(fieldNumber, (MessageLite) value); + } + + @Override + public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException { + output.writeMessage(fieldNumber, (MessageLite) value, schema); + } + + @Override + public void writeGroup(int fieldNumber, Object value) throws IOException { + output.writeGroup(fieldNumber, (MessageLite) value); + } + + @Override + public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException { + output.writeGroup(fieldNumber, (MessageLite) value, schema); + } + + @Override + public void writeStartGroup(int fieldNumber) throws IOException { + output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); + } + + @Override + public void writeEndGroup(int fieldNumber) throws IOException { + output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); + } + + @Override + public final void writeMessageSetItem(int fieldNumber, Object value) throws IOException { + if (value instanceof ByteString) { + output.writeRawMessageSetExtension(fieldNumber, (ByteString) value); + } else { + output.writeMessageSetExtension(fieldNumber, (MessageLite) value); + } + } + + @Override + public void writeInt32List(int fieldNumber, List<Integer> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeInt32SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeInt32NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeInt32(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeFixed32List(int fieldNumber, List<Integer> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeFixed32SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeFixed32NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeFixed32(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeInt64List(int fieldNumber, List<Long> value, boolean packed) throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeInt64SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeInt64NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeInt64(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeUInt64List(int fieldNumber, List<Long> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeUInt64SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeUInt64NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeUInt64(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeFixed64List(int fieldNumber, List<Long> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeFixed64SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeFixed64NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeFixed64(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeFloatList(int fieldNumber, List<Float> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeFloatSizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeFloatNoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeFloat(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeDoubleList(int fieldNumber, List<Double> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeDoubleSizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeDoubleNoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeDouble(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeEnumList(int fieldNumber, List<Integer> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeEnumSizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeEnumNoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeEnum(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeBoolList(int fieldNumber, List<Boolean> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeBoolSizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeBoolNoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeBool(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeStringList(int fieldNumber, List<String> value) throws IOException { + if (value instanceof LazyStringList) { + final LazyStringList lazyList = (LazyStringList) value; + for (int i = 0; i < value.size(); ++i) { + writeLazyString(fieldNumber, lazyList.getRaw(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeString(fieldNumber, value.get(i)); + } + } + } + + private void writeLazyString(int fieldNumber, Object value) throws IOException { + if (value instanceof String) { + output.writeString(fieldNumber, (String) value); + } else { + output.writeBytes(fieldNumber, (ByteString) value); + } + } + + @Override + public void writeBytesList(int fieldNumber, List<ByteString> value) throws IOException { + for (int i = 0; i < value.size(); ++i) { + output.writeBytes(fieldNumber, value.get(i)); + } + } + + @Override + public void writeUInt32List(int fieldNumber, List<Integer> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeUInt32SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeUInt32NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeUInt32(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeSFixed32List(int fieldNumber, List<Integer> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeSFixed32SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeSFixed32NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeSFixed32(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeSFixed64List(int fieldNumber, List<Long> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeSFixed64SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeSFixed64NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeSFixed64(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeSInt32List(int fieldNumber, List<Integer> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeSInt32SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeSInt32NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeSInt32(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeSInt64List(int fieldNumber, List<Long> value, boolean packed) + throws IOException { + if (packed) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + + // Compute and write the length of the data. + int dataSize = 0; + for (int i = 0; i < value.size(); ++i) { + dataSize += CodedOutputStream.computeSInt64SizeNoTag(value.get(i)); + } + output.writeUInt32NoTag(dataSize); + + // Write the data itself, without any tags. + for (int i = 0; i < value.size(); ++i) { + output.writeSInt64NoTag(value.get(i)); + } + } else { + for (int i = 0; i < value.size(); ++i) { + output.writeSInt64(fieldNumber, value.get(i)); + } + } + } + + @Override + public void writeMessageList(int fieldNumber, List<?> value) throws IOException { + for (int i = 0; i < value.size(); ++i) { + writeMessage(fieldNumber, value.get(i)); + } + } + + @Override + public void writeMessageList(int fieldNumber, List<?> value, Schema schema) throws IOException { + for (int i = 0; i < value.size(); ++i) { + writeMessage(fieldNumber, value.get(i), schema); + } + } + + @Override + public void writeGroupList(int fieldNumber, List<?> value) throws IOException { + for (int i = 0; i < value.size(); ++i) { + writeGroup(fieldNumber, value.get(i)); + } + } + + @Override + public void writeGroupList(int fieldNumber, List<?> value, Schema schema) throws IOException { + for (int i = 0; i < value.size(); ++i) { + writeGroup(fieldNumber, value.get(i), schema); + } + } + + @Override + public <K, V> void writeMap(int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map) + throws IOException { + if (output.isSerializationDeterministic()) { + writeDeterministicMap(fieldNumber, metadata, map); + return; + } + for (Map.Entry<K, V> entry : map.entrySet()) { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + output.writeUInt32NoTag( + MapEntryLite.computeSerializedSize(metadata, entry.getKey(), entry.getValue())); + MapEntryLite.writeTo(output, metadata, entry.getKey(), entry.getValue()); + } + } + + @SuppressWarnings("unchecked") + private <K, V> void writeDeterministicMap( + int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map) throws IOException { + switch (metadata.keyType) { + case BOOL: + V value; + if ((value = map.get(Boolean.FALSE)) != null) { + writeDeterministicBooleanMapEntry( + fieldNumber, /* key= */ false, value, (MapEntryLite.Metadata<Boolean, V>) metadata); + } + if ((value = map.get(Boolean.TRUE)) != null) { + writeDeterministicBooleanMapEntry( + fieldNumber, /* key= */ true, value, (MapEntryLite.Metadata<Boolean, V>) metadata); + } + break; + case FIXED32: + case INT32: + case SFIXED32: + case SINT32: + case UINT32: + writeDeterministicIntegerMap( + fieldNumber, (MapEntryLite.Metadata<Integer, V>) metadata, (Map<Integer, V>) map); + break; + case FIXED64: + case INT64: + case SFIXED64: + case SINT64: + case UINT64: + writeDeterministicLongMap( + fieldNumber, (MapEntryLite.Metadata<Long, V>) metadata, (Map<Long, V>) map); + break; + case STRING: + writeDeterministicStringMap( + fieldNumber, (MapEntryLite.Metadata<String, V>) metadata, (Map<String, V>) map); + break; + default: + throw new IllegalArgumentException("does not support key type: " + metadata.keyType); + } + } + + private <V> void writeDeterministicBooleanMapEntry( + int fieldNumber, boolean key, V value, MapEntryLite.Metadata<Boolean, V> metadata) + throws IOException { + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value)); + MapEntryLite.writeTo(output, metadata, key, value); + } + + private <V> void writeDeterministicIntegerMap( + int fieldNumber, MapEntryLite.Metadata<Integer, V> metadata, Map<Integer, V> map) + throws IOException { + int[] keys = new int[map.size()]; + int index = 0; + for (int k : map.keySet()) { + keys[index++] = k; + } + Arrays.sort(keys); + for (int key : keys) { + V value = map.get(key); + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value)); + MapEntryLite.writeTo(output, metadata, key, value); + } + } + + private <V> void writeDeterministicLongMap( + int fieldNumber, MapEntryLite.Metadata<Long, V> metadata, Map<Long, V> map) + throws IOException { + long[] keys = new long[map.size()]; + int index = 0; + for (long k : map.keySet()) { + keys[index++] = k; + } + Arrays.sort(keys); + for (long key : keys) { + V value = map.get(key); + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value)); + MapEntryLite.writeTo(output, metadata, key, value); + } + } + + private <V> void writeDeterministicStringMap( + int fieldNumber, MapEntryLite.Metadata<String, V> metadata, Map<String, V> map) + throws IOException { + String[] keys = new String[map.size()]; + int index = 0; + for (String k : map.keySet()) { + keys[index++] = k; + } + Arrays.sort(keys); + for (String key : keys) { + V value = map.get(key); + output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED); + output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value)); + MapEntryLite.writeTo(output, metadata, key, value); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java new file mode 100755 index 000000000..cd29b7beb --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java @@ -0,0 +1,693 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.FieldInfo.forField; +import static com.google.protobuf.FieldInfo.forFieldWithEnumVerifier; +import static com.google.protobuf.FieldInfo.forMapField; +import static com.google.protobuf.FieldInfo.forOneofMemberField; +import static com.google.protobuf.FieldInfo.forPackedField; +import static com.google.protobuf.FieldInfo.forPackedFieldWithEnumVerifier; +import static com.google.protobuf.FieldInfo.forProto2OptionalField; +import static com.google.protobuf.FieldInfo.forProto2RequiredField; +import static com.google.protobuf.FieldInfo.forRepeatedMessageField; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor.Type; +import com.google.protobuf.Descriptors.OneofDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.concurrent.ConcurrentHashMap; + +/** A factory for message info based on protobuf descriptors for a {@link GeneratedMessageV3}. */ +@ExperimentalApi +final class DescriptorMessageInfoFactory implements MessageInfoFactory { + private static final String GET_DEFAULT_INSTANCE_METHOD_NAME = "getDefaultInstance"; + private static final DescriptorMessageInfoFactory instance = new DescriptorMessageInfoFactory(); + private static final Set<String> specialFieldNames = + new HashSet<>(Arrays.asList("cached_size", "serialized_size", "class")); + + // Disallow construction - it's a singleton. + private DescriptorMessageInfoFactory() {} + + public static DescriptorMessageInfoFactory getInstance() { + return instance; + } + + @Override + public boolean isSupported(Class<?> messageType) { + return GeneratedMessageV3.class.isAssignableFrom(messageType); + } + + @Override + public MessageInfo messageInfoFor(Class<?> messageType) { + if (!GeneratedMessageV3.class.isAssignableFrom(messageType)) { + throw new IllegalArgumentException("Unsupported message type: " + messageType.getName()); + } + + return convert(messageType, descriptorForType(messageType)); + } + + private static Message getDefaultInstance(Class<?> messageType) { + try { + Method method = messageType.getDeclaredMethod(GET_DEFAULT_INSTANCE_METHOD_NAME); + return (Message) method.invoke(null); + } catch (Exception e) { + throw new IllegalArgumentException( + "Unable to get default instance for message class " + messageType.getName(), e); + } + } + + private static Descriptor descriptorForType(Class<?> messageType) { + return getDefaultInstance(messageType).getDescriptorForType(); + } + + private static MessageInfo convert(Class<?> messageType, Descriptor messageDescriptor) { + switch (messageDescriptor.getFile().getSyntax()) { + case PROTO2: + return convertProto2(messageType, messageDescriptor); + case PROTO3: + return convertProto3(messageType, messageDescriptor); + default: + throw new IllegalArgumentException( + "Unsupported syntax: " + messageDescriptor.getFile().getSyntax()); + } + } + + /** + * A helper class to determine whether a message type needs to implement {@code isInitialized()}. + * + * <p>If a message type doesn't have any required fields or extensions (directly and + * transitively), it doesn't need to implement isInitialized() and can always return true there. + * It's a bit tricky to determine whether a type has transitive required fields because protobuf + * allows cycle references within the same .proto file (e.g., message Foo has a Bar field, and + * message Bar has a Foo field). For that we use Tarjan's strongly connected components algorithm + * to classify messages into strongly connected groups. Messages in the same group are + * transitively including each other, so they should either all have transitive required fields + * (or extensions), or none have. + * + * <p>The code is adapted from the C++ implementation: + * https://cs.corp.google.com/piper///depot/google3/net/proto2/compiler/cpp/internal/helpers.h?type=cs&rcl=161303268&l=346 + * + * <p>This class is thread-safe. + */ + static class IsInitializedCheckAnalyzer { + + private final Map<Descriptor, Boolean> resultCache = + new ConcurrentHashMap<Descriptor, Boolean>(); + + // The following data members are part of Tarjan's SCC algorithm. See: + // https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + private int index = 0; + private final Stack<Node> stack = new Stack<Node>(); + private final Map<Descriptor, Node> nodeCache = new HashMap<Descriptor, Node>(); + + public boolean needsIsInitializedCheck(Descriptor descriptor) { + Boolean cachedValue = resultCache.get(descriptor); + if (cachedValue != null) { + return cachedValue; + } + synchronized (this) { + // Double-check the cache because some other thread may have updated it while we + // were acquiring the lock. + cachedValue = resultCache.get(descriptor); + if (cachedValue != null) { + return cachedValue; + } + return dfs(descriptor).component.needsIsInitializedCheck; + } + } + + private static class Node { + final Descriptor descriptor; + final int index; + int lowLink; + StronglyConnectedComponent component; // null if the node is still on stack. + + Node(Descriptor descriptor, int index) { + this.descriptor = descriptor; + this.index = index; + this.lowLink = index; + this.component = null; + } + } + + private static class StronglyConnectedComponent { + final List<Descriptor> messages = new ArrayList<Descriptor>(); + boolean needsIsInitializedCheck = false; + } + + private Node dfs(Descriptor descriptor) { + Node result = new Node(descriptor, index++); + stack.push(result); + nodeCache.put(descriptor, result); + + // Recurse the fields / nodes in graph + for (FieldDescriptor field : descriptor.getFields()) { + if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { + Node child = nodeCache.get(field.getMessageType()); + if (child == null) { + // Unexplored node + child = dfs(field.getMessageType()); + result.lowLink = Math.min(result.lowLink, child.lowLink); + } else { + if (child.component == null) { + // Still in the stack so we found a back edge. + result.lowLink = Math.min(result.lowLink, child.lowLink); + } + } + } + } + + if (result.index == result.lowLink) { + // This is the root of a strongly connected component. + StronglyConnectedComponent component = new StronglyConnectedComponent(); + while (true) { + Node node = stack.pop(); + node.component = component; + component.messages.add(node.descriptor); + if (node == result) { + break; + } + } + + analyze(component); + } + + return result; + } + + // Determine whether messages in this SCC needs isInitialized check. + private void analyze(StronglyConnectedComponent component) { + boolean needsIsInitializedCheck = false; + loop: + for (Descriptor descriptor : component.messages) { + if (descriptor.isExtendable()) { + needsIsInitializedCheck = true; + break; + } + + for (FieldDescriptor field : descriptor.getFields()) { + if (field.isRequired()) { + needsIsInitializedCheck = true; + break loop; + } + + if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { + // Since we are analyzing the graph bottom-up, all referenced fields should either be + // in this same component or in a different already-analyzed component. + Node node = nodeCache.get(field.getMessageType()); + if (node.component != component) { + if (node.component.needsIsInitializedCheck) { + needsIsInitializedCheck = true; + break loop; + } + } + } + } + } + + component.needsIsInitializedCheck = needsIsInitializedCheck; + + for (Descriptor descriptor : component.messages) { + resultCache.put(descriptor, component.needsIsInitializedCheck); + } + } + } + + private static IsInitializedCheckAnalyzer isInitializedCheckAnalyzer = + new IsInitializedCheckAnalyzer(); + + private static boolean needsIsInitializedCheck(Descriptor descriptor) { + return isInitializedCheckAnalyzer.needsIsInitializedCheck(descriptor); + } + + private static StructuralMessageInfo convertProto2( + Class<?> messageType, Descriptor messageDescriptor) { + List<FieldDescriptor> fieldDescriptors = messageDescriptor.getFields(); + StructuralMessageInfo.Builder builder = + StructuralMessageInfo.newBuilder(fieldDescriptors.size()); + builder.withDefaultInstance(getDefaultInstance(messageType)); + builder.withSyntax(ProtoSyntax.PROTO2); + builder.withMessageSetWireFormat(messageDescriptor.getOptions().getMessageSetWireFormat()); + + OneofState oneofState = new OneofState(); + int bitFieldIndex = 0; + int presenceMask = 1; + Field bitField = null; + + // Fields in the descriptor are ordered by the index position in which they appear in the + // proto file. This is the same order used to determine the presence mask used in the + // bitFields. So to determine the appropriate presence mask to be used for a field, we simply + // need to shift the presence mask whenever a presence-checked field is encountered. + for (int i = 0; i < fieldDescriptors.size(); ++i) { + final FieldDescriptor fd = fieldDescriptors.get(i); + boolean enforceUtf8 = fd.getFile().getOptions().getJavaStringCheckUtf8(); + Internal.EnumVerifier enumVerifier = null; + if (fd.getJavaType() == Descriptors.FieldDescriptor.JavaType.ENUM) { + enumVerifier = + new Internal.EnumVerifier() { + @Override + public boolean isInRange(int number) { + return fd.getEnumType().findValueByNumber(number) != null; + } + }; + } + if (fd.getContainingOneof() != null) { + // Build a oneof member field. + builder.withField(buildOneofMember(messageType, fd, oneofState, enforceUtf8, enumVerifier)); + } else { + Field field = field(messageType, fd); + int number = fd.getNumber(); + FieldType type = getFieldType(fd); + + if (fd.isMapField()) { + // Map field points to an auto-generated message entry type with the definition: + // message MapEntry { + // K key = 1; + // V value = 2; + // } + final FieldDescriptor valueField = fd.getMessageType().findFieldByNumber(2); + if (valueField.getJavaType() == Descriptors.FieldDescriptor.JavaType.ENUM) { + enumVerifier = + new Internal.EnumVerifier() { + @Override + public boolean isInRange(int number) { + return valueField.getEnumType().findValueByNumber(number) != null; + } + }; + } + builder.withField( + forMapField( + field, + number, + SchemaUtil.getMapDefaultEntry(messageType, fd.getName()), + enumVerifier)); + continue; + } + + if (fd.isRepeated()) { + // Repeated fields are not presence-checked. + if (enumVerifier != null) { + if (fd.isPacked()) { + builder.withField( + forPackedFieldWithEnumVerifier( + field, number, type, enumVerifier, cachedSizeField(messageType, fd))); + } else { + builder.withField(forFieldWithEnumVerifier(field, number, type, enumVerifier)); + } + } else if (fd.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { + builder.withField( + forRepeatedMessageField( + field, number, type, getTypeForRepeatedMessageField(messageType, fd))); + } else { + if (fd.isPacked()) { + builder.withField( + forPackedField(field, number, type, cachedSizeField(messageType, fd))); + } else { + builder.withField(forField(field, number, type, enforceUtf8)); + } + } + continue; + } + + if (bitField == null) { + // Lazy-create the next bitfield since we know it must exist. + bitField = bitField(messageType, bitFieldIndex); + } + + // It's a presence-checked field. + if (fd.isRequired()) { + builder.withField( + forProto2RequiredField( + field, number, type, bitField, presenceMask, enforceUtf8, enumVerifier)); + } else { + builder.withField( + forProto2OptionalField( + field, number, type, bitField, presenceMask, enforceUtf8, enumVerifier)); + } + } + + // Update the presence mask for the next iteration. If the shift clears out the mask, we will + // go to the next bitField. + presenceMask <<= 1; + if (presenceMask == 0) { + bitField = null; + presenceMask = 1; + bitFieldIndex++; + } + } + + List<Integer> fieldsToCheckIsInitialized = new ArrayList<Integer>(); + for (int i = 0; i < fieldDescriptors.size(); ++i) { + FieldDescriptor fd = fieldDescriptors.get(i); + if (fd.isRequired() + || (fd.getJavaType() == FieldDescriptor.JavaType.MESSAGE + && needsIsInitializedCheck(fd.getMessageType()))) { + fieldsToCheckIsInitialized.add(fd.getNumber()); + } + } + int[] numbers = new int[fieldsToCheckIsInitialized.size()]; + for (int i = 0; i < fieldsToCheckIsInitialized.size(); i++) { + numbers[i] = fieldsToCheckIsInitialized.get(i); + } + builder.withCheckInitialized(numbers); + + return builder.build(); + } + + private static StructuralMessageInfo convertProto3( + Class<?> messageType, Descriptor messageDescriptor) { + List<FieldDescriptor> fieldDescriptors = messageDescriptor.getFields(); + StructuralMessageInfo.Builder builder = + StructuralMessageInfo.newBuilder(fieldDescriptors.size()); + builder.withDefaultInstance(getDefaultInstance(messageType)); + builder.withSyntax(ProtoSyntax.PROTO3); + + OneofState oneofState = new OneofState(); + boolean enforceUtf8 = true; + for (int i = 0; i < fieldDescriptors.size(); ++i) { + FieldDescriptor fd = fieldDescriptors.get(i); + if (fd.getContainingOneof() != null) { + // Build a oneof member field. + builder.withField(buildOneofMember(messageType, fd, oneofState, enforceUtf8, null)); + continue; + } + if (fd.isMapField()) { + builder.withField( + forMapField( + field(messageType, fd), + fd.getNumber(), + SchemaUtil.getMapDefaultEntry(messageType, fd.getName()), + null)); + continue; + } + if (fd.isRepeated() && fd.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { + builder.withField( + forRepeatedMessageField( + field(messageType, fd), + fd.getNumber(), + getFieldType(fd), + getTypeForRepeatedMessageField(messageType, fd))); + continue; + } + if (fd.isPacked()) { + builder.withField( + forPackedField( + field(messageType, fd), + fd.getNumber(), + getFieldType(fd), + cachedSizeField(messageType, fd))); + } else { + builder.withField( + forField(field(messageType, fd), fd.getNumber(), getFieldType(fd), enforceUtf8)); + } + } + + return builder.build(); + } + + /** Builds info for a oneof member field. */ + private static FieldInfo buildOneofMember( + Class<?> messageType, + FieldDescriptor fd, + OneofState oneofState, + boolean enforceUtf8, + Internal.EnumVerifier enumVerifier) { + OneofInfo oneof = oneofState.getOneof(messageType, fd.getContainingOneof()); + FieldType type = getFieldType(fd); + Class<?> oneofStoredType = getOneofStoredType(messageType, fd, type); + return forOneofMemberField( + fd.getNumber(), type, oneof, oneofStoredType, enforceUtf8, enumVerifier); + } + + private static Class<?> getOneofStoredType( + Class<?> messageType, FieldDescriptor fd, FieldType type) { + switch (type.getJavaType()) { + case BOOLEAN: + return Boolean.class; + case BYTE_STRING: + return ByteString.class; + case DOUBLE: + return Double.class; + case FLOAT: + return Float.class; + case ENUM: + case INT: + return Integer.class; + case LONG: + return Long.class; + case STRING: + return String.class; + case MESSAGE: + return getOneofStoredTypeForMessage(messageType, fd); + default: + throw new IllegalArgumentException("Invalid type for oneof: " + type); + } + } + + private static FieldType getFieldType(FieldDescriptor fd) { + switch (fd.getType()) { + case BOOL: + if (!fd.isRepeated()) { + return FieldType.BOOL; + } + return fd.isPacked() ? FieldType.BOOL_LIST_PACKED : FieldType.BOOL_LIST; + case BYTES: + return fd.isRepeated() ? FieldType.BYTES_LIST : FieldType.BYTES; + case DOUBLE: + if (!fd.isRepeated()) { + return FieldType.DOUBLE; + } + return fd.isPacked() ? FieldType.DOUBLE_LIST_PACKED : FieldType.DOUBLE_LIST; + case ENUM: + if (!fd.isRepeated()) { + return FieldType.ENUM; + } + return fd.isPacked() ? FieldType.ENUM_LIST_PACKED : FieldType.ENUM_LIST; + case FIXED32: + if (!fd.isRepeated()) { + return FieldType.FIXED32; + } + return fd.isPacked() ? FieldType.FIXED32_LIST_PACKED : FieldType.FIXED32_LIST; + case FIXED64: + if (!fd.isRepeated()) { + return FieldType.FIXED64; + } + return fd.isPacked() ? FieldType.FIXED64_LIST_PACKED : FieldType.FIXED64_LIST; + case FLOAT: + if (!fd.isRepeated()) { + return FieldType.FLOAT; + } + return fd.isPacked() ? FieldType.FLOAT_LIST_PACKED : FieldType.FLOAT_LIST; + case GROUP: + return fd.isRepeated() ? FieldType.GROUP_LIST : FieldType.GROUP; + case INT32: + if (!fd.isRepeated()) { + return FieldType.INT32; + } + return fd.isPacked() ? FieldType.INT32_LIST_PACKED : FieldType.INT32_LIST; + case INT64: + if (!fd.isRepeated()) { + return FieldType.INT64; + } + return fd.isPacked() ? FieldType.INT64_LIST_PACKED : FieldType.INT64_LIST; + case MESSAGE: + if (fd.isMapField()) { + return FieldType.MAP; + } + return fd.isRepeated() ? FieldType.MESSAGE_LIST : FieldType.MESSAGE; + case SFIXED32: + if (!fd.isRepeated()) { + return FieldType.SFIXED32; + } + return fd.isPacked() ? FieldType.SFIXED32_LIST_PACKED : FieldType.SFIXED32_LIST; + case SFIXED64: + if (!fd.isRepeated()) { + return FieldType.SFIXED64; + } + return fd.isPacked() ? FieldType.SFIXED64_LIST_PACKED : FieldType.SFIXED64_LIST; + case SINT32: + if (!fd.isRepeated()) { + return FieldType.SINT32; + } + return fd.isPacked() ? FieldType.SINT32_LIST_PACKED : FieldType.SINT32_LIST; + case SINT64: + if (!fd.isRepeated()) { + return FieldType.SINT64; + } + return fd.isPacked() ? FieldType.SINT64_LIST_PACKED : FieldType.SINT64_LIST; + case STRING: + return fd.isRepeated() ? FieldType.STRING_LIST : FieldType.STRING; + case UINT32: + if (!fd.isRepeated()) { + return FieldType.UINT32; + } + return fd.isPacked() ? FieldType.UINT32_LIST_PACKED : FieldType.UINT32_LIST; + case UINT64: + if (!fd.isRepeated()) { + return FieldType.UINT64; + } + return fd.isPacked() ? FieldType.UINT64_LIST_PACKED : FieldType.UINT64_LIST; + default: + throw new IllegalArgumentException("Unsupported field type: " + fd.getType()); + } + } + + private static Field bitField(Class<?> messageType, int index) { + return field(messageType, "bitField" + index + "_"); + } + + private static Field field(Class<?> messageType, FieldDescriptor fd) { + return field(messageType, getFieldName(fd)); + } + + private static Field cachedSizeField(Class<?> messageType, FieldDescriptor fd) { + return field(messageType, getCachedSizeFieldName(fd)); + } + + private static Field field(Class<?> messageType, String fieldName) { + try { + return messageType.getDeclaredField(fieldName); + } catch (Exception e) { + throw new IllegalArgumentException( + "Unable to find field " + fieldName + " in message class " + messageType.getName()); + } + } + + static String getFieldName(FieldDescriptor fd) { + String name = (fd.getType() == FieldDescriptor.Type.GROUP) + ? fd.getMessageType().getName() + : fd.getName(); + String suffix = specialFieldNames.contains(name) ? "__" : "_"; + return snakeCaseToCamelCase(name) + suffix; + } + + private static String getCachedSizeFieldName(FieldDescriptor fd) { + return snakeCaseToCamelCase(fd.getName()) + "MemoizedSerializedSize"; + } + + /** + * This method must match exactly with the corresponding function in protocol compiler. See: + * https://github.com/google/protobuf/blob/v3.0.0/src/google/protobuf/compiler/java/java_helpers.cc#L153 + */ + private static String snakeCaseToCamelCase(String snakeCase) { + StringBuilder sb = new StringBuilder(snakeCase.length() + 1); + boolean capNext = false; + for (int ctr = 0; ctr < snakeCase.length(); ctr++) { + char next = snakeCase.charAt(ctr); + if (next == '_') { + capNext = true; + } else if (Character.isDigit(next)) { + sb.append(next); + capNext = true; + } else if (capNext) { + sb.append(Character.toUpperCase(next)); + capNext = false; + } else if (ctr == 0) { + sb.append(Character.toLowerCase(next)); + } else { + sb.append(next); + } + } + return sb.toString(); + } + + /** + * Inspects the message to identify the stored type for a message field that is part of a oneof. + */ + private static Class<?> getOneofStoredTypeForMessage(Class<?> messageType, FieldDescriptor fd) { + try { + String name = fd.getType() == Type.GROUP ? fd.getMessageType().getName() : fd.getName(); + Method getter = messageType.getDeclaredMethod(getterForField(name)); + return getter.getReturnType(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** Inspects the message to identify the message type of a repeated message field. */ + private static Class<?> getTypeForRepeatedMessageField(Class<?> messageType, FieldDescriptor fd) { + try { + String name = fd.getType() == Type.GROUP ? fd.getMessageType().getName() : fd.getName(); + Method getter = messageType.getDeclaredMethod(getterForField(name), int.class); + return getter.getReturnType(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** Constructs the name of the get method for the given field in the proto. */ + private static String getterForField(String snakeCase) { + String camelCase = snakeCaseToCamelCase(snakeCase); + StringBuilder builder = new StringBuilder("get"); + // Capitalize the first character in the field name. + builder.append(Character.toUpperCase(camelCase.charAt(0))); + builder.append(camelCase.substring(1, camelCase.length())); + return builder.toString(); + } + + private static final class OneofState { + private OneofInfo[] oneofs = new OneofInfo[2]; + + OneofInfo getOneof(Class<?> messageType, OneofDescriptor desc) { + int index = desc.getIndex(); + if (index >= oneofs.length) { + // Grow the array. + oneofs = Arrays.copyOf(oneofs, index * 2); + } + OneofInfo info = oneofs[index]; + if (info == null) { + info = newInfo(messageType, desc); + oneofs[index] = info; + } + return info; + } + + private static OneofInfo newInfo(Class<?> messageType, OneofDescriptor desc) { + String camelCase = snakeCaseToCamelCase(desc.getName()); + String valueFieldName = camelCase + "_"; + String caseFieldName = camelCase + "Case_"; + + return new OneofInfo( + desc.getIndex(), field(messageType, caseFieldName), field(messageType, valueFieldName)); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java index 0ce5f5493..11843b6c3 100644 --- a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java +++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java @@ -110,12 +110,23 @@ public class ExtensionRegistryLite { return ExtensionRegistryFactory.create(); } + private static volatile ExtensionRegistryLite emptyRegistry; + /** * Get the unmodifiable singleton empty instance of either ExtensionRegistryLite or {@code * ExtensionRegistry} (if the full (non-Lite) proto libraries are available). */ public static ExtensionRegistryLite getEmptyRegistry() { - return ExtensionRegistryFactory.createEmpty(); + ExtensionRegistryLite result = emptyRegistry; + if (result == null) { + synchronized (ExtensionRegistryLite.class) { + result = emptyRegistry; + if (result == null) { + result = emptyRegistry = ExtensionRegistryFactory.createEmpty(); + } + } + } + return result; } diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java new file mode 100755 index 000000000..2eae22d26 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java @@ -0,0 +1,98 @@ +// 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 java.io.IOException; +import java.util.Map; + +abstract class ExtensionSchema<T extends FieldSet.FieldDescriptorLite<T>> { + + /** Returns true for messages that support extensions. */ + abstract boolean hasExtensions(MessageLite prototype); + + /** Returns the extension {@link FieldSet} for the message instance. */ + abstract FieldSet<T> getExtensions(Object message); + + /** Replaces the extension {@link FieldSet} for the message instance. */ + abstract void setExtensions(Object message, FieldSet<T> extensions); + + /** Returns the extension {@link FieldSet} and ensures it's mutable. */ + abstract FieldSet<T> getMutableExtensions(Object message); + + /** Marks the extension {@link FieldSet} as immutable. */ + abstract void makeImmutable(Object message); + + /** + * Parses an extension. Returns the passed-in unknownFields parameter if no unknown enum value is + * found or a modified unknownFields (a new instance if the passed-in unknownFields is null) + * containing unknown enum values found while parsing. + * + * @param <UT> The type used to store unknown fields. It's either UnknownFieldSet in full runtime + * or UnknownFieldSetLite in lite runtime. + */ + abstract <UT, UB> UB parseExtension( + Reader reader, + Object extension, + ExtensionRegistryLite extensionRegistry, + FieldSet<T> extensions, + UB unknownFields, + UnknownFieldSchema<UT, UB> unknownFieldSchema) + throws IOException; + + /** Gets the field number of an extension entry. */ + abstract int extensionNumber(Map.Entry<?, ?> extension); + + /** Serializes one extension entry. */ + abstract void serializeExtension(Writer writer, Map.Entry<?, ?> extension) throws IOException; + + /** Finds an extension by field number. */ + abstract Object findExtensionByNumber( + ExtensionRegistryLite extensionRegistry, MessageLite defaultInstance, int number); + + /** Parses a length-prefixed MessageSet item from the reader. */ + abstract void parseLengthPrefixedMessageSetItem( + Reader reader, + Object extension, + ExtensionRegistryLite extensionRegistry, + FieldSet<T> extensions) + throws IOException; + + /** + * Parses the entire content of a {@link ByteString} as one MessageSet item. Unlike {@link + * #parseLengthPrefixedMessageSetItem}, there isn't a length-prefix. + */ + abstract void parseMessageSetItem( + ByteString data, + Object extension, + ExtensionRegistryLite extensionRegistry, + FieldSet<T> extensions) + throws IOException; +} diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java new file mode 100755 index 000000000..90558518b --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java @@ -0,0 +1,547 @@ +// 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.EnumValueDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("unchecked") +final class ExtensionSchemaFull extends ExtensionSchema<FieldDescriptor> { + + private static final long EXTENSION_FIELD_OFFSET = getExtensionsFieldOffset(); + + private static <T> long getExtensionsFieldOffset() { + try { + Field field = GeneratedMessageV3.ExtendableMessage.class.getDeclaredField("extensions"); + return UnsafeUtil.objectFieldOffset(field); + } catch (Throwable e) { + throw new IllegalStateException("Unable to lookup extension field offset"); + } + } + + @Override + boolean hasExtensions(MessageLite prototype) { + return prototype instanceof GeneratedMessageV3.ExtendableMessage; + } + + @Override + public FieldSet<FieldDescriptor> getExtensions(Object message) { + return (FieldSet<FieldDescriptor>) UnsafeUtil.getObject(message, EXTENSION_FIELD_OFFSET); + } + + @Override + void setExtensions(Object message, FieldSet<FieldDescriptor> extensions) { + UnsafeUtil.putObject(message, EXTENSION_FIELD_OFFSET, extensions); + } + + @Override + FieldSet<FieldDescriptor> getMutableExtensions(Object message) { + FieldSet<FieldDescriptor> extensions = getExtensions(message); + if (extensions.isImmutable()) { + extensions = extensions.clone(); + setExtensions(message, extensions); + } + return extensions; + } + + @Override + void makeImmutable(Object message) { + getExtensions(message).makeImmutable(); + } + + @Override + <UT, UB> UB parseExtension( + Reader reader, + Object extensionObject, + ExtensionRegistryLite extensionRegistry, + FieldSet<FieldDescriptor> extensions, + UB unknownFields, + UnknownFieldSchema<UT, UB> unknownFieldSchema) + throws IOException { + ExtensionRegistry.ExtensionInfo extension = (ExtensionRegistry.ExtensionInfo) extensionObject; + int fieldNumber = extension.descriptor.getNumber(); + + if (extension.descriptor.isRepeated() && extension.descriptor.isPacked()) { + Object value = null; + switch (extension.descriptor.getLiteType()) { + case DOUBLE: + { + List<Double> list = new ArrayList<Double>(); + reader.readDoubleList(list); + value = list; + break; + } + case FLOAT: + { + List<Float> list = new ArrayList<Float>(); + reader.readFloatList(list); + value = list; + break; + } + case INT64: + { + List<Long> list = new ArrayList<Long>(); + reader.readInt64List(list); + value = list; + break; + } + case UINT64: + { + List<Long> list = new ArrayList<Long>(); + reader.readUInt64List(list); + value = list; + break; + } + case INT32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readInt32List(list); + value = list; + break; + } + case FIXED64: + { + List<Long> list = new ArrayList<Long>(); + reader.readFixed64List(list); + value = list; + break; + } + case FIXED32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readFixed32List(list); + value = list; + break; + } + case BOOL: + { + List<Boolean> list = new ArrayList<Boolean>(); + reader.readBoolList(list); + value = list; + break; + } + case UINT32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readUInt32List(list); + value = list; + break; + } + case SFIXED32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readSFixed32List(list); + value = list; + break; + } + case SFIXED64: + { + List<Long> list = new ArrayList<Long>(); + reader.readSFixed64List(list); + value = list; + break; + } + case SINT32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readSInt32List(list); + value = list; + break; + } + case SINT64: + { + List<Long> list = new ArrayList<Long>(); + reader.readSInt64List(list); + value = list; + break; + } + case ENUM: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readEnumList(list); + List<EnumValueDescriptor> enumList = new ArrayList<EnumValueDescriptor>(); + for (int number : list) { + EnumValueDescriptor enumDescriptor = + extension.descriptor.getEnumType().findValueByNumber(number); + if (enumDescriptor != null) { + enumList.add(enumDescriptor); + } else { + unknownFields = + SchemaUtil.storeUnknownEnum( + fieldNumber, number, unknownFields, unknownFieldSchema); + } + } + value = enumList; + break; + } + default: + throw new IllegalStateException( + "Type cannot be packed: " + extension.descriptor.getLiteType()); + } + extensions.setField(extension.descriptor, value); + } else { + Object value = null; + // Enum is a special case because unknown enum values will be put into UnknownFieldSetLite. + if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) { + int number = reader.readInt32(); + Object enumValue = extension.descriptor.getEnumType().findValueByNumber(number); + if (enumValue == null) { + return SchemaUtil.storeUnknownEnum( + fieldNumber, number, unknownFields, unknownFieldSchema); + } + value = enumValue; + } else { + switch (extension.descriptor.getLiteType()) { + case DOUBLE: + value = reader.readDouble(); + break; + case FLOAT: + value = reader.readFloat(); + break; + case INT64: + value = reader.readInt64(); + break; + case UINT64: + value = reader.readUInt64(); + break; + case INT32: + value = reader.readInt32(); + break; + case FIXED64: + value = reader.readFixed64(); + break; + case FIXED32: + value = reader.readFixed32(); + break; + case BOOL: + value = reader.readBool(); + break; + case BYTES: + value = reader.readBytes(); + break; + case UINT32: + value = reader.readUInt32(); + break; + case SFIXED32: + value = reader.readSFixed32(); + break; + case SFIXED64: + value = reader.readSFixed64(); + break; + case SINT32: + value = reader.readSInt32(); + break; + case SINT64: + value = reader.readSInt64(); + break; + + case STRING: + value = reader.readString(); + break; + case GROUP: + value = reader.readGroup(extension.defaultInstance.getClass(), extensionRegistry); + break; + + case MESSAGE: + value = reader.readMessage(extension.defaultInstance.getClass(), extensionRegistry); + break; + + case ENUM: + throw new IllegalStateException("Shouldn't reach here."); + } + } + if (extension.descriptor.isRepeated()) { + extensions.addRepeatedField(extension.descriptor, value); + } else { + switch (extension.descriptor.getLiteType()) { + case MESSAGE: + case GROUP: + Object oldValue = extensions.getField(extension.descriptor); + if (oldValue != null) { + value = Internal.mergeMessage(oldValue, value); + } + break; + default: + break; + } + extensions.setField(extension.descriptor, value); + } + } + return unknownFields; + } + + @Override + int extensionNumber(Map.Entry<?, ?> extension) { + FieldDescriptor descriptor = (FieldDescriptor) extension.getKey(); + return descriptor.getNumber(); + } + + @Override + void serializeExtension(Writer writer, Map.Entry<?, ?> extension) throws IOException { + FieldDescriptor descriptor = (FieldDescriptor) extension.getKey(); + if (descriptor.isRepeated()) { + switch (descriptor.getLiteType()) { + case DOUBLE: + SchemaUtil.writeDoubleList( + descriptor.getNumber(), + (List<Double>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case FLOAT: + SchemaUtil.writeFloatList( + descriptor.getNumber(), + (List<Float>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case INT64: + SchemaUtil.writeInt64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case UINT64: + SchemaUtil.writeUInt64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case INT32: + SchemaUtil.writeInt32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case FIXED64: + SchemaUtil.writeFixed64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case FIXED32: + SchemaUtil.writeFixed32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case BOOL: + SchemaUtil.writeBoolList( + descriptor.getNumber(), + (List<Boolean>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case BYTES: + SchemaUtil.writeBytesList( + descriptor.getNumber(), (List<ByteString>) extension.getValue(), writer); + break; + case UINT32: + SchemaUtil.writeUInt32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case SFIXED32: + SchemaUtil.writeSFixed32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case SFIXED64: + SchemaUtil.writeSFixed64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case SINT32: + SchemaUtil.writeSInt32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case SINT64: + SchemaUtil.writeSInt64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case ENUM: + { + List<EnumValueDescriptor> enumList = (List<EnumValueDescriptor>) extension.getValue(); + List<Integer> list = new ArrayList<Integer>(); + for (EnumValueDescriptor d : enumList) { + list.add(d.getNumber()); + } + SchemaUtil.writeInt32List(descriptor.getNumber(), list, writer, descriptor.isPacked()); + break; + } + case STRING: + SchemaUtil.writeStringList( + descriptor.getNumber(), (List<String>) extension.getValue(), writer); + break; + case GROUP: + SchemaUtil.writeGroupList(descriptor.getNumber(), (List<?>) extension.getValue(), writer); + break; + case MESSAGE: + SchemaUtil.writeMessageList( + descriptor.getNumber(), (List<?>) extension.getValue(), writer); + break; + } + } else { + switch (descriptor.getLiteType()) { + case DOUBLE: + writer.writeDouble(descriptor.getNumber(), (Double) extension.getValue()); + break; + case FLOAT: + writer.writeFloat(descriptor.getNumber(), (Float) extension.getValue()); + break; + case INT64: + writer.writeInt64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case UINT64: + writer.writeUInt64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case INT32: + writer.writeInt32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case FIXED64: + writer.writeFixed64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case FIXED32: + writer.writeFixed32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case BOOL: + writer.writeBool(descriptor.getNumber(), (Boolean) extension.getValue()); + break; + case BYTES: + writer.writeBytes(descriptor.getNumber(), (ByteString) extension.getValue()); + break; + case UINT32: + writer.writeUInt32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case SFIXED32: + writer.writeSFixed32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case SFIXED64: + writer.writeSFixed64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case SINT32: + writer.writeSInt32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case SINT64: + writer.writeSInt64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case ENUM: + writer.writeInt32( + descriptor.getNumber(), ((EnumValueDescriptor) extension.getValue()).getNumber()); + break; + case STRING: + writer.writeString(descriptor.getNumber(), (String) extension.getValue()); + break; + case GROUP: + writer.writeGroup(descriptor.getNumber(), extension.getValue()); + break; + case MESSAGE: + writer.writeMessage(descriptor.getNumber(), extension.getValue()); + break; + } + } + } + + @Override + Object findExtensionByNumber( + ExtensionRegistryLite extensionRegistry, MessageLite defaultInstance, int number) { + return ((ExtensionRegistry) extensionRegistry) + .findExtensionByNumber(((Message) defaultInstance).getDescriptorForType(), number); + } + + @Override + void parseLengthPrefixedMessageSetItem( + Reader reader, + Object extension, + ExtensionRegistryLite extensionRegistry, + FieldSet<FieldDescriptor> extensions) + throws IOException { + ExtensionRegistry.ExtensionInfo extensionInfo = (ExtensionRegistry.ExtensionInfo) extension; + + if (ExtensionRegistryLite.isEagerlyParseMessageSets()) { + Object value = + reader.readMessage(extensionInfo.defaultInstance.getClass(), extensionRegistry); + extensions.setField(extensionInfo.descriptor, value); + } else { + extensions.setField( + extensionInfo.descriptor, + new LazyField(extensionInfo.defaultInstance, extensionRegistry, reader.readBytes())); + } + } + + @Override + void parseMessageSetItem( + ByteString data, + Object extension, + ExtensionRegistryLite extensionRegistry, + FieldSet<FieldDescriptor> extensions) + throws IOException { + ExtensionRegistry.ExtensionInfo extensionInfo = (ExtensionRegistry.ExtensionInfo) extension; + Object value = extensionInfo.defaultInstance.newBuilderForType().buildPartial(); + + if (ExtensionRegistryLite.isEagerlyParseMessageSets()) { + Reader reader = BinaryReader.newInstance(ByteBuffer.wrap(data.toByteArray()), true); + Protobuf.getInstance().mergeFrom(value, reader, extensionRegistry); + extensions.setField(extensionInfo.descriptor, value); + + if (reader.getFieldNumber() != Reader.READ_DONE) { + throw InvalidProtocolBufferException.invalidEndTag(); + } + } else { + extensions.setField( + extensionInfo.descriptor, + new LazyField(extensionInfo.defaultInstance, extensionRegistry, data)); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java new file mode 100755 index 000000000..7f6846eb0 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java @@ -0,0 +1,541 @@ +// 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.GeneratedMessageLite.ExtensionDescriptor; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("unchecked") +final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> { + + @Override + boolean hasExtensions(MessageLite prototype) { + return prototype instanceof GeneratedMessageLite.ExtendableMessage; + } + + @Override + FieldSet<ExtensionDescriptor> getExtensions(Object message) { + return ((GeneratedMessageLite.ExtendableMessage<?, ?>) message).extensions; + } + + @Override + void setExtensions(Object message, FieldSet<ExtensionDescriptor> extensions) { + ((GeneratedMessageLite.ExtendableMessage<?, ?>) message).extensions = extensions; + } + + @Override + FieldSet<ExtensionDescriptor> getMutableExtensions(Object message) { + return ((GeneratedMessageLite.ExtendableMessage<?, ?>) message).ensureExtensionsAreMutable(); + } + + @Override + void makeImmutable(Object message) { + getExtensions(message).makeImmutable(); + } + + @Override + <UT, UB> UB parseExtension( + Reader reader, + Object extensionObject, + ExtensionRegistryLite extensionRegistry, + FieldSet<ExtensionDescriptor> extensions, + UB unknownFields, + UnknownFieldSchema<UT, UB> unknownFieldSchema) + throws IOException { + GeneratedMessageLite.GeneratedExtension<?, ?> extension = + (GeneratedMessageLite.GeneratedExtension<?, ?>) extensionObject; + int fieldNumber = extension.getNumber(); + + if (extension.descriptor.isRepeated() && extension.descriptor.isPacked()) { + Object value = null; + switch (extension.getLiteType()) { + case DOUBLE: + { + List<Double> list = new ArrayList<Double>(); + reader.readDoubleList(list); + value = list; + break; + } + case FLOAT: + { + List<Float> list = new ArrayList<Float>(); + reader.readFloatList(list); + value = list; + break; + } + case INT64: + { + List<Long> list = new ArrayList<Long>(); + reader.readInt64List(list); + value = list; + break; + } + case UINT64: + { + List<Long> list = new ArrayList<Long>(); + reader.readUInt64List(list); + value = list; + break; + } + case INT32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readInt32List(list); + value = list; + break; + } + case FIXED64: + { + List<Long> list = new ArrayList<Long>(); + reader.readFixed64List(list); + value = list; + break; + } + case FIXED32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readFixed32List(list); + value = list; + break; + } + case BOOL: + { + List<Boolean> list = new ArrayList<Boolean>(); + reader.readBoolList(list); + value = list; + break; + } + case UINT32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readUInt32List(list); + value = list; + break; + } + case SFIXED32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readSFixed32List(list); + value = list; + break; + } + case SFIXED64: + { + List<Long> list = new ArrayList<Long>(); + reader.readSFixed64List(list); + value = list; + break; + } + case SINT32: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readSInt32List(list); + value = list; + break; + } + case SINT64: + { + List<Long> list = new ArrayList<Long>(); + reader.readSInt64List(list); + value = list; + break; + } + case ENUM: + { + List<Integer> list = new ArrayList<Integer>(); + reader.readEnumList(list); + unknownFields = + SchemaUtil.filterUnknownEnumList( + fieldNumber, + list, + extension.descriptor.getEnumType(), + unknownFields, + unknownFieldSchema); + value = list; + break; + } + default: + throw new IllegalStateException( + "Type cannot be packed: " + extension.descriptor.getLiteType()); + } + extensions.setField(extension.descriptor, value); + } else { + Object value = null; + // Enum is a special case becasue unknown enum values will be put into UnknownFieldSetLite. + if (extension.getLiteType() == WireFormat.FieldType.ENUM) { + int number = reader.readInt32(); + Object enumValue = extension.descriptor.getEnumType().findValueByNumber(number); + if (enumValue == null) { + return SchemaUtil.storeUnknownEnum( + fieldNumber, number, unknownFields, unknownFieldSchema); + } + // Note, we store the integer value instead of the actual enum object in FieldSet. + // This is also different from full-runtime where we store EnumValueDescriptor. + value = number; + } else { + switch (extension.getLiteType()) { + case DOUBLE: + value = reader.readDouble(); + break; + case FLOAT: + value = reader.readFloat(); + break; + case INT64: + value = reader.readInt64(); + break; + case UINT64: + value = reader.readUInt64(); + break; + case INT32: + value = reader.readInt32(); + break; + case FIXED64: + value = reader.readFixed64(); + break; + case FIXED32: + value = reader.readFixed32(); + break; + case BOOL: + value = reader.readBool(); + break; + case BYTES: + value = reader.readBytes(); + break; + case UINT32: + value = reader.readUInt32(); + break; + case SFIXED32: + value = reader.readSFixed32(); + break; + case SFIXED64: + value = reader.readSFixed64(); + break; + case SINT32: + value = reader.readSInt32(); + break; + case SINT64: + value = reader.readSInt64(); + break; + + case STRING: + value = reader.readString(); + break; + case GROUP: + value = + reader.readGroup( + extension.getMessageDefaultInstance().getClass(), extensionRegistry); + break; + + case MESSAGE: + value = + reader.readMessage( + extension.getMessageDefaultInstance().getClass(), extensionRegistry); + break; + + case ENUM: + throw new IllegalStateException("Shouldn't reach here."); + } + } + if (extension.isRepeated()) { + extensions.addRepeatedField(extension.descriptor, value); + } else { + switch (extension.getLiteType()) { + case MESSAGE: + case GROUP: + Object oldValue = extensions.getField(extension.descriptor); + if (oldValue != null) { + value = Internal.mergeMessage(oldValue, value); + } + break; + default: + break; + } + extensions.setField(extension.descriptor, value); + } + } + return unknownFields; + } + + @Override + int extensionNumber(Map.Entry<?, ?> extension) { + GeneratedMessageLite.ExtensionDescriptor descriptor = + (GeneratedMessageLite.ExtensionDescriptor) extension.getKey(); + return descriptor.getNumber(); + } + + @Override + void serializeExtension(Writer writer, Map.Entry<?, ?> extension) throws IOException { + GeneratedMessageLite.ExtensionDescriptor descriptor = + (GeneratedMessageLite.ExtensionDescriptor) extension.getKey(); + if (descriptor.isRepeated()) { + switch (descriptor.getLiteType()) { + case DOUBLE: + SchemaUtil.writeDoubleList( + descriptor.getNumber(), + (List<Double>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case FLOAT: + SchemaUtil.writeFloatList( + descriptor.getNumber(), + (List<Float>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case INT64: + SchemaUtil.writeInt64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case UINT64: + SchemaUtil.writeUInt64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case INT32: + SchemaUtil.writeInt32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case FIXED64: + SchemaUtil.writeFixed64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case FIXED32: + SchemaUtil.writeFixed32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case BOOL: + SchemaUtil.writeBoolList( + descriptor.getNumber(), + (List<Boolean>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case BYTES: + SchemaUtil.writeBytesList( + descriptor.getNumber(), (List<ByteString>) extension.getValue(), writer); + break; + case UINT32: + SchemaUtil.writeUInt32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case SFIXED32: + SchemaUtil.writeSFixed32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case SFIXED64: + SchemaUtil.writeSFixed64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case SINT32: + SchemaUtil.writeSInt32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case SINT64: + SchemaUtil.writeSInt64List( + descriptor.getNumber(), + (List<Long>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case ENUM: + SchemaUtil.writeInt32List( + descriptor.getNumber(), + (List<Integer>) extension.getValue(), + writer, + descriptor.isPacked()); + break; + case STRING: + SchemaUtil.writeStringList( + descriptor.getNumber(), (List<String>) extension.getValue(), writer); + break; + case GROUP: + { + List<?> data = (List<?>) extension.getValue(); + if (data != null && !data.isEmpty()) { + SchemaUtil.writeGroupList( + descriptor.getNumber(), + (List<?>) extension.getValue(), + writer, + Protobuf.getInstance().schemaFor(data.get(0).getClass())); + } + } + break; + case MESSAGE: + { + List<?> data = (List<?>) extension.getValue(); + if (data != null && !data.isEmpty()) { + SchemaUtil.writeMessageList( + descriptor.getNumber(), + (List<?>) extension.getValue(), + writer, + Protobuf.getInstance().schemaFor(data.get(0).getClass())); + } + } + break; + } + } else { + switch (descriptor.getLiteType()) { + case DOUBLE: + writer.writeDouble(descriptor.getNumber(), (Double) extension.getValue()); + break; + case FLOAT: + writer.writeFloat(descriptor.getNumber(), (Float) extension.getValue()); + break; + case INT64: + writer.writeInt64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case UINT64: + writer.writeUInt64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case INT32: + writer.writeInt32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case FIXED64: + writer.writeFixed64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case FIXED32: + writer.writeFixed32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case BOOL: + writer.writeBool(descriptor.getNumber(), (Boolean) extension.getValue()); + break; + case BYTES: + writer.writeBytes(descriptor.getNumber(), (ByteString) extension.getValue()); + break; + case UINT32: + writer.writeUInt32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case SFIXED32: + writer.writeSFixed32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case SFIXED64: + writer.writeSFixed64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case SINT32: + writer.writeSInt32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case SINT64: + writer.writeSInt64(descriptor.getNumber(), (Long) extension.getValue()); + break; + case ENUM: + writer.writeInt32(descriptor.getNumber(), (Integer) extension.getValue()); + break; + case STRING: + writer.writeString(descriptor.getNumber(), (String) extension.getValue()); + break; + case GROUP: + writer.writeGroup( + descriptor.getNumber(), + extension.getValue(), + Protobuf.getInstance().schemaFor(extension.getValue().getClass())); + break; + case MESSAGE: + writer.writeMessage( + descriptor.getNumber(), + extension.getValue(), + Protobuf.getInstance().schemaFor(extension.getValue().getClass())); + break; + } + } + } + + @Override + Object findExtensionByNumber( + ExtensionRegistryLite extensionRegistry, MessageLite defaultInstance, int number) { + return extensionRegistry.findLiteExtensionByNumber(defaultInstance, number); + } + + @Override + void parseLengthPrefixedMessageSetItem( + Reader reader, + Object extensionObject, + ExtensionRegistryLite extensionRegistry, + FieldSet<ExtensionDescriptor> extensions) + throws IOException { + GeneratedMessageLite.GeneratedExtension<?, ?> extension = + (GeneratedMessageLite.GeneratedExtension<?, ?>) extensionObject; + Object value = + reader.readMessage(extension.getMessageDefaultInstance().getClass(), extensionRegistry); + extensions.setField(extension.descriptor, value); + } + + @Override + void parseMessageSetItem( + ByteString data, + Object extensionObject, + ExtensionRegistryLite extensionRegistry, + FieldSet<ExtensionDescriptor> extensions) + throws IOException { + GeneratedMessageLite.GeneratedExtension<?, ?> extension = + (GeneratedMessageLite.GeneratedExtension<?, ?>) extensionObject; + Object value = extension.getMessageDefaultInstance().newBuilderForType().buildPartial(); + + Reader reader = BinaryReader.newInstance(ByteBuffer.wrap(data.toByteArray()), true); + + Protobuf.getInstance().mergeFrom(value, reader, extensionRegistry); + extensions.setField(extension.descriptor, value); + + if (reader.getFieldNumber() != Reader.READ_DONE) { + throw InvalidProtocolBufferException.invalidEndTag(); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchemas.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchemas.java new file mode 100755 index 000000000..46ce327d1 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchemas.java @@ -0,0 +1,56 @@ +// 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; + +final class ExtensionSchemas { + private static final ExtensionSchema<?> LITE_SCHEMA = new ExtensionSchemaLite(); + private static final ExtensionSchema<?> FULL_SCHEMA = loadSchemaForFullRuntime(); + + private static ExtensionSchema<?> loadSchemaForFullRuntime() { + try { + Class<?> clazz = Class.forName("com.google.protobuf.ExtensionSchemaFull"); + return (ExtensionSchema) clazz.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + return null; + } + } + + static ExtensionSchema<?> lite() { + return LITE_SCHEMA; + } + + static ExtensionSchema<?> full() { + if (FULL_SCHEMA == null) { + throw new IllegalStateException("Protobuf runtime is not correctly loaded."); + } + return FULL_SCHEMA; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/FieldInfo.java b/java/core/src/main/java/com/google/protobuf/FieldInfo.java new file mode 100755 index 000000000..71a307a89 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/FieldInfo.java @@ -0,0 +1,577 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.Internal.checkNotNull; + +import com.google.protobuf.Internal.EnumVerifier; +import java.lang.reflect.Field; + +/** Information for a single field in a protobuf message class. */ +@ExperimentalApi +final class FieldInfo implements Comparable<FieldInfo> { + private final Field field; + private final FieldType type; + private final Class<?> messageClass; // The message type for repeated message fields. + private final int fieldNumber; + private final Field presenceField; + private final int presenceMask; + private final boolean required; + private final boolean enforceUtf8; + private final OneofInfo oneof; + private final Field cachedSizeField; + /** + * The actual type stored in the oneof value for this field. Since the oneof value is an {@link + * Object}, primitives will store their boxed type. Only valid in conjunction with {@link #oneof} + * (both must be either null or non-null. + */ + private final Class<?> oneofStoredType; + + // TODO(liujisi): make map default entry lazy? + private final Object mapDefaultEntry; + + private final EnumVerifier enumVerifier; + + /** Constructs a new descriptor for a field. */ + public static FieldInfo forField( + Field field, int fieldNumber, FieldType fieldType, boolean enforceUtf8) { + checkFieldNumber(fieldNumber); + checkNotNull(field, "field"); + checkNotNull(fieldType, "fieldType"); + if (fieldType == FieldType.MESSAGE_LIST || fieldType == FieldType.GROUP_LIST) { + throw new IllegalStateException("Shouldn't be called for repeated message fields."); + } + return new FieldInfo( + field, + fieldNumber, + fieldType, + /* messageClass= */ null, + /* presenceField= */ null, + /* presenceMask= */ 0, + /* required= */ false, + enforceUtf8, + /* oneof= */ null, + /* oneofStoredType= */ null, + /* mapDefaultEntry= */ null, + /* enumVerifier= */ null, + /* cachedSizeField= */ null); + } + + /** Constructs a new descriptor for a packed field. */ + public static FieldInfo forPackedField( + Field field, int fieldNumber, FieldType fieldType, Field cachedSizeField) { + checkFieldNumber(fieldNumber); + checkNotNull(field, "field"); + checkNotNull(fieldType, "fieldType"); + if (fieldType == FieldType.MESSAGE_LIST || fieldType == FieldType.GROUP_LIST) { + throw new IllegalStateException("Shouldn't be called for repeated message fields."); + } + return new FieldInfo( + field, + fieldNumber, + fieldType, + /* messageClass= */ null, + /* presenceField= */ null, + /* presenceMask= */ 0, + /* required= */ false, + /* enforceUtf8= */ false, + /* oneof= */ null, + /* oneofStoredType= */ null, + /* mapDefaultEntry= */ null, + /* enumVerifier= */ null, + cachedSizeField); + } + + /** Constructs a new descriptor for a repeated message field. */ + public static FieldInfo forRepeatedMessageField( + Field field, int fieldNumber, FieldType fieldType, Class<?> messageClass) { + checkFieldNumber(fieldNumber); + checkNotNull(field, "field"); + checkNotNull(fieldType, "fieldType"); + checkNotNull(messageClass, "messageClass"); + return new FieldInfo( + field, + fieldNumber, + fieldType, + messageClass, + /* presenceField= */ null, + /* presenceMask= */ 0, + /* required= */ false, + /* enforceUtf8= */ false, + /* oneof= */ null, + /* oneofStoredType= */ null, + /* mapDefaultEntry= */ null, + /* enumVerifier= */ null, + /* cachedSizeField= */ null); + } + + public static FieldInfo forFieldWithEnumVerifier( + Field field, int fieldNumber, FieldType fieldType, EnumVerifier enumVerifier) { + checkFieldNumber(fieldNumber); + checkNotNull(field, "field"); + return new FieldInfo( + field, + fieldNumber, + fieldType, + /* messageClass= */ null, + /* presenceField= */ null, + /* presenceMask= */ 0, + /* required= */ false, + /* enforceUtf8= */ false, + /* oneof= */ null, + /* oneofStoredType= */ null, + /* mapDefaultEntry= */ null, + enumVerifier, + /* cachedSizeField= */ null); + } + + public static FieldInfo forPackedFieldWithEnumVerifier( + Field field, + int fieldNumber, + FieldType fieldType, + EnumVerifier enumVerifier, + Field cachedSizeField) { + checkFieldNumber(fieldNumber); + checkNotNull(field, "field"); + return new FieldInfo( + field, + fieldNumber, + fieldType, + /* messageClass= */ null, + /* presenceField= */ null, + /* presenceMask= */ 0, + /* required= */ false, + /* enforceUtf8= */ false, + /* oneof= */ null, + /* oneofStoredType= */ null, + /* mapDefaultEntry= */ null, + enumVerifier, + cachedSizeField); + } + + /** Constructor for a proto2 optional field. */ + public static FieldInfo forProto2OptionalField( + Field field, + int fieldNumber, + FieldType fieldType, + Field presenceField, + int presenceMask, + boolean enforceUtf8, + EnumVerifier enumVerifier) { + checkFieldNumber(fieldNumber); + checkNotNull(field, "field"); + checkNotNull(fieldType, "fieldType"); + checkNotNull(presenceField, "presenceField"); + if (presenceField != null && !isExactlyOneBitSet(presenceMask)) { + throw new IllegalArgumentException( + "presenceMask must have exactly one bit set: " + presenceMask); + } + return new FieldInfo( + field, + fieldNumber, + fieldType, + /* messageClass= */ null, + presenceField, + presenceMask, + /* required= */ false, + enforceUtf8, + /* oneof= */ null, + /* oneofStoredType= */ null, + /* mapDefaultEntry= */ null, + enumVerifier, + /* cachedSizeField= */ null); + } + + /** + * Constructor for a field that is part of a oneof. + * + * @param fieldNumber the unique field number for this field within the message. + * @param fieldType the type of the field (must be non-null). + * @param oneof the oneof for which this field is associated (must be non-null). + * @param oneofStoredType the actual type stored in the oneof value for this field. Since the + * oneof value is an {@link Object}, primitives will store their boxed type. Must be non-null. + * @param enforceUtf8 Only used for string fields. If {@code true}, will enforce UTF-8 on a string + * field. + * @return the {@link FieldInfo} describing this field. + */ + public static FieldInfo forOneofMemberField( + int fieldNumber, + FieldType fieldType, + OneofInfo oneof, + Class<?> oneofStoredType, + boolean enforceUtf8, + EnumVerifier enumVerifier) { + checkFieldNumber(fieldNumber); + checkNotNull(fieldType, "fieldType"); + checkNotNull(oneof, "oneof"); + checkNotNull(oneofStoredType, "oneofStoredType"); + if (!fieldType.isScalar()) { + throw new IllegalArgumentException( + "Oneof is only supported for scalar fields. Field " + + fieldNumber + + " is of type " + + fieldType); + } + return new FieldInfo( + /* field= */ null, + fieldNumber, + fieldType, + /* messageClass= */ null, + /* presenceField= */ null, + /* presenceMask= */ 0, + /* required= */ false, + enforceUtf8, + oneof, + oneofStoredType, + /* mapDefaultEntry= */ null, + enumVerifier, + /* cachedSizeField= */ null); + } + + private static void checkFieldNumber(int fieldNumber) { + if (fieldNumber <= 0) { + throw new IllegalArgumentException("fieldNumber must be positive: " + fieldNumber); + } + } + + /** Constructor for a proto2 required field. */ + public static FieldInfo forProto2RequiredField( + Field field, + int fieldNumber, + FieldType fieldType, + Field presenceField, + int presenceMask, + boolean enforceUtf8, + EnumVerifier enumVerifier) { + checkFieldNumber(fieldNumber); + checkNotNull(field, "field"); + checkNotNull(fieldType, "fieldType"); + checkNotNull(presenceField, "presenceField"); + if (presenceField != null && !isExactlyOneBitSet(presenceMask)) { + throw new IllegalArgumentException( + "presenceMask must have exactly one bit set: " + presenceMask); + } + return new FieldInfo( + field, + fieldNumber, + fieldType, + /* messageClass= */ null, + presenceField, + presenceMask, + /* required= */ true, + enforceUtf8, + /* oneof= */ null, + /* oneofStoredType= */ null, + /* mapDefaultEntry= */ null, + /* enumVerifier= */ enumVerifier, + /* cachedSizeField= */ null); + } + + public static FieldInfo forMapField( + Field field, int fieldNumber, Object mapDefaultEntry, EnumVerifier enumVerifier) { + checkNotNull(mapDefaultEntry, "mapDefaultEntry"); + checkFieldNumber(fieldNumber); + checkNotNull(field, "field"); + return new FieldInfo( + field, + fieldNumber, + FieldType.MAP, + /* messageClass= */ null, + /* presenceField= */ null, + /* presenceMask= */ 0, + /* required= */ false, + /* enforceUtf8= */ true, + /* oneof= */ null, + /* oneofStoredType= */ null, + mapDefaultEntry, + enumVerifier, + /* cachedSizeField= */ null); + } + + private FieldInfo( + Field field, + int fieldNumber, + FieldType type, + Class<?> messageClass, + Field presenceField, + int presenceMask, + boolean required, + boolean enforceUtf8, + OneofInfo oneof, + Class<?> oneofStoredType, + Object mapDefaultEntry, + EnumVerifier enumVerifier, + Field cachedSizeField) { + this.field = field; + this.type = type; + this.messageClass = messageClass; + this.fieldNumber = fieldNumber; + this.presenceField = presenceField; + this.presenceMask = presenceMask; + this.required = required; + this.enforceUtf8 = enforceUtf8; + this.oneof = oneof; + this.oneofStoredType = oneofStoredType; + this.mapDefaultEntry = mapDefaultEntry; + this.enumVerifier = enumVerifier; + this.cachedSizeField = cachedSizeField; + } + + /** Gets the field number for the field. */ + public int getFieldNumber() { + return fieldNumber; + } + + /** Gets the subject {@link Field} of this descriptor. */ + public Field getField() { + return field; + } + + /** Gets the type information for the field. */ + public FieldType getType() { + return type; + } + + /** Gets the oneof for which this field is a member, or {@code null} if not part of a oneof. */ + public OneofInfo getOneof() { + return oneof; + } + + /** + * Gets the actual type stored in the oneof value by this field. Since the oneof value is an + * {@link Object}, primitives will store their boxed type. For non-oneof fields, this will always + * be {@code null}. + */ + public Class<?> getOneofStoredType() { + return oneofStoredType; + } + + /** Gets the {@code EnumVerifier} if the field is an enum field. */ + public EnumVerifier getEnumVerifier() { + return enumVerifier; + } + + @Override + public int compareTo(FieldInfo o) { + return fieldNumber - o.fieldNumber; + } + + /** + * For repeated message fields, returns the message type of the field. For other fields, returns + * {@code null}. + */ + public Class<?> getListElementType() { + return messageClass; + } + + /** Gets the presence bit field. Only valid for unary fields. For lists, returns {@code null}. */ + public Field getPresenceField() { + return presenceField; + } + + public Object getMapDefaultEntry() { + return mapDefaultEntry; + } + + /** + * If {@link #getPresenceField()} is non-{@code null}, returns the mask used to identify the + * presence bit for this field in the message. + */ + public int getPresenceMask() { + return presenceMask; + } + + /** Whether this is a required field. */ + public boolean isRequired() { + return required; + } + + /** + * Whether a UTF-8 should be enforced on string fields. Only applies to strings and string lists. + */ + public boolean isEnforceUtf8() { + return enforceUtf8; + } + + public Field getCachedSizeField() { + return cachedSizeField; + } + + /** + * For singular or repeated message fields, returns the message type. For other fields, returns + * {@code null}. + */ + public Class<?> getMessageFieldClass() { + switch (type) { + case MESSAGE: + case GROUP: + return field != null ? field.getType() : oneofStoredType; + case MESSAGE_LIST: + case GROUP_LIST: + return messageClass; + default: + return null; + } + } + + public static Builder newBuilder() { + return new Builder(); + } + + /** A builder for {@link FieldInfo} instances. */ + public static final class Builder { + private Field field; + private FieldType type; + private int fieldNumber; + private Field presenceField; + private int presenceMask; + private boolean required; + private boolean enforceUtf8; + private OneofInfo oneof; + private Class<?> oneofStoredType; + private Object mapDefaultEntry; + private EnumVerifier enumVerifier; + private Field cachedSizeField; + + private Builder() {} + + /** + * Specifies the actual field on the message represented by this field. This should not be + * called for oneof member fields. + */ + public Builder withField(Field field) { + if (oneof != null) { + throw new IllegalStateException("Cannot set field when building a oneof."); + } + this.field = field; + return this; + } + + /** Specifies the type of this field. */ + public Builder withType(FieldType type) { + this.type = type; + return this; + } + + /** Specifies the unique field number for this field within the message. */ + public Builder withFieldNumber(int fieldNumber) { + this.fieldNumber = fieldNumber; + return this; + } + + /** Specifies proto2 presence information. This should not be called for oneof fields. */ + public Builder withPresence(Field presenceField, int presenceMask) { + this.presenceField = checkNotNull(presenceField, "presenceField"); + this.presenceMask = presenceMask; + return this; + } + + /** + * Sets the information for building a oneof member field. This is incompatible with {@link + * #withField(Field)} and {@link #withPresence(Field, int)}. + * + * @param oneof the oneof for which this field is associated. + * @param oneofStoredType the actual type stored in the oneof value for this field. Since the + * oneof value is an {@link Object}, primitives will store their boxed type. + */ + public Builder withOneof(OneofInfo oneof, Class<?> oneofStoredType) { + if (field != null || presenceField != null) { + throw new IllegalStateException( + "Cannot set oneof when field or presenceField have been provided"); + } + this.oneof = oneof; + this.oneofStoredType = oneofStoredType; + return this; + } + + public Builder withRequired(boolean required) { + this.required = required; + return this; + } + + public Builder withMapDefaultEntry(Object mapDefaultEntry) { + this.mapDefaultEntry = mapDefaultEntry; + return this; + } + + public Builder withEnforceUtf8(boolean enforceUtf8) { + this.enforceUtf8 = enforceUtf8; + return this; + } + + public Builder withEnumVerifier(EnumVerifier enumVerifier) { + this.enumVerifier = enumVerifier; + return this; + } + + public Builder withCachedSizeField(Field cachedSizeField) { + this.cachedSizeField = cachedSizeField; + return this; + } + + public FieldInfo build() { + if (oneof != null) { + return forOneofMemberField( + fieldNumber, type, oneof, oneofStoredType, enforceUtf8, enumVerifier); + } + if (mapDefaultEntry != null) { + return forMapField(field, fieldNumber, mapDefaultEntry, enumVerifier); + } + if (presenceField != null) { + if (required) { + return forProto2RequiredField( + field, fieldNumber, type, presenceField, presenceMask, enforceUtf8, enumVerifier); + } else { + return forProto2OptionalField( + field, fieldNumber, type, presenceField, presenceMask, enforceUtf8, enumVerifier); + } + } + if (enumVerifier != null) { + if (cachedSizeField == null) { + return forFieldWithEnumVerifier(field, fieldNumber, type, enumVerifier); + } else { + return forPackedFieldWithEnumVerifier( + field, fieldNumber, type, enumVerifier, cachedSizeField); + } + } else { + if (cachedSizeField == null) { + return forField(field, fieldNumber, type, enforceUtf8); + } else { + return forPackedField(field, fieldNumber, type, cachedSizeField); + } + } + } + } + + private static boolean isExactlyOneBitSet(int value) { + return value != 0 && (value & (value - 1)) == 0; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java index 40a37625a..ddfd0e560 100644 --- a/java/core/src/main/java/com/google/protobuf/FieldSet.java +++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java @@ -218,6 +218,17 @@ final class FieldSet< return fields.entrySet().iterator(); } + /** + * Get an iterator over the fields in the map in descending (i.e. reverse) order. This iterator + * should not be leaked out of the protobuf library as it is not protected from mutation when + * fields is not immutable. + */ + Iterator<Map.Entry<FieldDescriptorType, Object>> descendingIterator() { + if (hasLazyField) { + return new LazyIterator<FieldDescriptorType>(fields.descendingEntrySet().iterator()); + } + return fields.descendingEntrySet().iterator(); + } /** Useful for implementing {@link Message#hasField(Descriptors.FieldDescriptor)}. */ public boolean hasField(final FieldDescriptorType descriptor) { diff --git a/java/core/src/main/java/com/google/protobuf/FieldType.java b/java/core/src/main/java/com/google/protobuf/FieldType.java new file mode 100755 index 000000000..1b8f9e5da --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/FieldType.java @@ -0,0 +1,346 @@ +// 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 java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.List; + +/** Enumeration identifying all relevant type information for a protobuf field. */ +@ExperimentalApi +public enum FieldType { + DOUBLE(0, Collection.SCALAR, JavaType.DOUBLE), + FLOAT(1, Collection.SCALAR, JavaType.FLOAT), + INT64(2, Collection.SCALAR, JavaType.LONG), + UINT64(3, Collection.SCALAR, JavaType.LONG), + INT32(4, Collection.SCALAR, JavaType.INT), + FIXED64(5, Collection.SCALAR, JavaType.LONG), + FIXED32(6, Collection.SCALAR, JavaType.INT), + BOOL(7, Collection.SCALAR, JavaType.BOOLEAN), + STRING(8, Collection.SCALAR, JavaType.STRING), + MESSAGE(9, Collection.SCALAR, JavaType.MESSAGE), + BYTES(10, Collection.SCALAR, JavaType.BYTE_STRING), + UINT32(11, Collection.SCALAR, JavaType.INT), + ENUM(12, Collection.SCALAR, JavaType.ENUM), + SFIXED32(13, Collection.SCALAR, JavaType.INT), + SFIXED64(14, Collection.SCALAR, JavaType.LONG), + SINT32(15, Collection.SCALAR, JavaType.INT), + SINT64(16, Collection.SCALAR, JavaType.LONG), + GROUP(17, Collection.SCALAR, JavaType.MESSAGE), + DOUBLE_LIST(18, Collection.VECTOR, JavaType.DOUBLE), + FLOAT_LIST(19, Collection.VECTOR, JavaType.FLOAT), + INT64_LIST(20, Collection.VECTOR, JavaType.LONG), + UINT64_LIST(21, Collection.VECTOR, JavaType.LONG), + INT32_LIST(22, Collection.VECTOR, JavaType.INT), + FIXED64_LIST(23, Collection.VECTOR, JavaType.LONG), + FIXED32_LIST(24, Collection.VECTOR, JavaType.INT), + BOOL_LIST(25, Collection.VECTOR, JavaType.BOOLEAN), + STRING_LIST(26, Collection.VECTOR, JavaType.STRING), + MESSAGE_LIST(27, Collection.VECTOR, JavaType.MESSAGE), + BYTES_LIST(28, Collection.VECTOR, JavaType.BYTE_STRING), + UINT32_LIST(29, Collection.VECTOR, JavaType.INT), + ENUM_LIST(30, Collection.VECTOR, JavaType.ENUM), + SFIXED32_LIST(31, Collection.VECTOR, JavaType.INT), + SFIXED64_LIST(32, Collection.VECTOR, JavaType.LONG), + SINT32_LIST(33, Collection.VECTOR, JavaType.INT), + SINT64_LIST(34, Collection.VECTOR, JavaType.LONG), + DOUBLE_LIST_PACKED(35, Collection.PACKED_VECTOR, JavaType.DOUBLE), + FLOAT_LIST_PACKED(36, Collection.PACKED_VECTOR, JavaType.FLOAT), + INT64_LIST_PACKED(37, Collection.PACKED_VECTOR, JavaType.LONG), + UINT64_LIST_PACKED(38, Collection.PACKED_VECTOR, JavaType.LONG), + INT32_LIST_PACKED(39, Collection.PACKED_VECTOR, JavaType.INT), + FIXED64_LIST_PACKED(40, Collection.PACKED_VECTOR, JavaType.LONG), + FIXED32_LIST_PACKED(41, Collection.PACKED_VECTOR, JavaType.INT), + BOOL_LIST_PACKED(42, Collection.PACKED_VECTOR, JavaType.BOOLEAN), + UINT32_LIST_PACKED(43, Collection.PACKED_VECTOR, JavaType.INT), + ENUM_LIST_PACKED(44, Collection.PACKED_VECTOR, JavaType.ENUM), + SFIXED32_LIST_PACKED(45, Collection.PACKED_VECTOR, JavaType.INT), + SFIXED64_LIST_PACKED(46, Collection.PACKED_VECTOR, JavaType.LONG), + SINT32_LIST_PACKED(47, Collection.PACKED_VECTOR, JavaType.INT), + SINT64_LIST_PACKED(48, Collection.PACKED_VECTOR, JavaType.LONG), + GROUP_LIST(49, Collection.VECTOR, JavaType.MESSAGE), + MAP(50, Collection.MAP, JavaType.VOID); + + private final JavaType javaType; + private final int id; + private final Collection collection; + private final Class<?> elementType; + private final boolean primitiveScalar; + + FieldType(int id, Collection collection, JavaType javaType) { + this.id = id; + this.collection = collection; + this.javaType = javaType; + + switch (collection) { + case MAP: + elementType = javaType.getBoxedType(); + break; + case VECTOR: + elementType = javaType.getBoxedType(); + break; + case SCALAR: + default: + elementType = null; + break; + } + + boolean primitiveScalar = false; + if (collection == Collection.SCALAR) { + switch (javaType) { + case BYTE_STRING: + case MESSAGE: + case STRING: + break; + default: + primitiveScalar = true; + break; + } + } + this.primitiveScalar = primitiveScalar; + } + + /** A reliable unique identifier for this type. */ + public int id() { + return id; + } + + /** + * Gets the {@link JavaType} for this field. For lists, this identifies the type of the elements + * contained within the list. + */ + public JavaType getJavaType() { + return javaType; + } + + /** Indicates whether a list field should be represented on the wire in packed form. */ + public boolean isPacked() { + return Collection.PACKED_VECTOR.equals(collection); + } + + /** + * Indicates whether this field type represents a primitive scalar value. If this is {@code true}, + * then {@link #isScalar()} will also be {@code true}. + */ + public boolean isPrimitiveScalar() { + return primitiveScalar; + } + + /** Indicates whether this field type represents a scalar value. */ + public boolean isScalar() { + return collection == Collection.SCALAR; + } + + /** Indicates whether this field represents a list of values. */ + public boolean isList() { + return collection.isList(); + } + + /** Indicates whether this field represents a map. */ + public boolean isMap() { + return collection == Collection.MAP; + } + + /** Indicates whether or not this {@link FieldType} can be applied to the given {@link Field}. */ + public boolean isValidForField(Field field) { + if (Collection.VECTOR.equals(collection)) { + return isValidForList(field); + } else { + return javaType.getType().isAssignableFrom(field.getType()); + } + } + + private boolean isValidForList(Field field) { + Class<?> clazz = field.getType(); + if (!javaType.getType().isAssignableFrom(clazz)) { + // The field isn't a List type. + return false; + } + Type[] types = EMPTY_TYPES; + Type genericType = field.getGenericType(); + if (genericType instanceof ParameterizedType) { + types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments(); + } + Type listParameter = getListParameter(clazz, types); + if (!(listParameter instanceof Class)) { + // It's a wildcard, we should allow anything in the list. + return true; + } + return elementType.isAssignableFrom((Class<?>) listParameter); + } + + /** + * Looks up the appropriate {@link FieldType} by it's identifier. + * + * @return the {@link FieldType} or {@code null} if not found. + */ + /* @Nullable */ + public static FieldType forId(int id) { + if (id < 0 || id >= VALUES.length) { + return null; + } + return VALUES[id]; + } + + private static final FieldType[] VALUES; + private static final Type[] EMPTY_TYPES = new Type[0]; + + static { + FieldType[] values = values(); + VALUES = new FieldType[values.length]; + for (FieldType type : values) { + VALUES[type.id] = type; + } + } + + /** + * Given a class, finds a generic super class or interface that extends {@link List}. + * + * @return the generic super class/interface, or {@code null} if not found. + */ + /* @Nullable */ + private static Type getGenericSuperList(Class<?> clazz) { + // First look at interfaces. + Type[] genericInterfaces = clazz.getGenericInterfaces(); + for (Type genericInterface : genericInterfaces) { + if (genericInterface instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) genericInterface; + Class<?> rawType = (Class<?>) parameterizedType.getRawType(); + if (List.class.isAssignableFrom(rawType)) { + return genericInterface; + } + } + } + + // Try the subclass + Type type = clazz.getGenericSuperclass(); + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + Class<?> rawType = (Class<?>) parameterizedType.getRawType(); + if (List.class.isAssignableFrom(rawType)) { + return type; + } + } + + // No super class/interface extends List. + return null; + } + + /** + * Inspects the inheritance hierarchy for the given class and finds the generic type parameter for + * {@link List}. + * + * @param clazz the class to begin the search. + * @param realTypes the array of actual type parameters for {@code clazz}. These will be used to + * substitute generic parameters up the inheritance hierarchy. If {@code clazz} does not have + * any generic parameters, this list should be empty. + * @return the {@link List} parameter. + */ + private static Type getListParameter(Class<?> clazz, Type[] realTypes) { + top: + while (clazz != List.class) { + // First look at generic subclass and interfaces. + Type genericType = getGenericSuperList(clazz); + if (genericType instanceof ParameterizedType) { + // Replace any generic parameters with the real values. + ParameterizedType parameterizedType = (ParameterizedType) genericType; + Type[] superArgs = parameterizedType.getActualTypeArguments(); + for (int i = 0; i < superArgs.length; ++i) { + Type superArg = superArgs[i]; + if (superArg instanceof TypeVariable) { + // Get the type variables for this class so that we can match them to the variables + // used on the super class. + TypeVariable<?>[] clazzParams = clazz.getTypeParameters(); + if (realTypes.length != clazzParams.length) { + throw new RuntimeException("Type array mismatch"); + } + + // Replace the variable parameter with the real type. + boolean foundReplacement = false; + for (int j = 0; j < clazzParams.length; ++j) { + if (superArg == clazzParams[j]) { + Type realType = realTypes[j]; + superArgs[i] = realType; + foundReplacement = true; + break; + } + } + if (!foundReplacement) { + throw new RuntimeException("Unable to find replacement for " + superArg); + } + } + } + + Class<?> parent = (Class<?>) parameterizedType.getRawType(); + + realTypes = superArgs; + clazz = parent; + continue; + } + + // None of the parameterized types inherit List. Just continue up the inheritance hierarchy + // toward the List interface until we can identify the parameters. + realTypes = EMPTY_TYPES; + for (Class<?> iface : clazz.getInterfaces()) { + if (List.class.isAssignableFrom(iface)) { + clazz = iface; + continue top; + } + } + clazz = clazz.getSuperclass(); + } + + if (realTypes.length != 1) { + throw new RuntimeException("Unable to identify parameter type for List<T>"); + } + return realTypes[0]; + } + + enum Collection { + SCALAR(false), + VECTOR(true), + PACKED_VECTOR(true), + MAP(false); + + private final boolean isList; + + Collection(boolean isList) { + this.isList = isList; + } + + /** @return the isList */ + public boolean isList() { + return isList; + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageInfoFactory.java new file mode 100755 index 000000000..3e3efb929 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageInfoFactory.java @@ -0,0 +1,65 @@ +// 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; + +/** A factory for message info that is generated into the message itself. */ +@ExperimentalApi +class GeneratedMessageInfoFactory implements MessageInfoFactory { + + private static final GeneratedMessageInfoFactory instance = new GeneratedMessageInfoFactory(); + + // Disallow construction - it's a singleton. + private GeneratedMessageInfoFactory() {} + + public static GeneratedMessageInfoFactory getInstance() { + return instance; + } + + @Override + public boolean isSupported(Class<?> messageType) { + return GeneratedMessageLite.class.isAssignableFrom(messageType); + } + + @Override + public MessageInfo messageInfoFor(Class<?> messageType) { + if (!GeneratedMessageLite.class.isAssignableFrom(messageType)) { + throw new IllegalArgumentException("Unsupported message type: " + messageType.getName()); + } + + try { + return (MessageInfo) GeneratedMessageLite.getDefaultInstance( + messageType.asSubclass(GeneratedMessageLite.class)) + .buildMessageInfo(); + } catch (Exception e) { + throw new RuntimeException("Unable to get message info for " + messageType.getName(), e); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java index 619ef0999..61cbed60a 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -61,12 +61,6 @@ public abstract class GeneratedMessageLite< MessageType extends GeneratedMessageLite<MessageType, BuilderType>, BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>> extends AbstractMessageLite<MessageType, BuilderType> { - // BEGIN REGULAR - static final boolean ENABLE_EXPERIMENTAL_RUNTIME_AT_BUILD_TIME = false; - // END REGULAR - // BEGIN EXPERIMENTAL - // static final boolean ENABLE_EXPERIMENTAL_RUNTIME_AT_BUILD_TIME = true; - // END EXPERIMENTAL /** For use by generated code only. Lazily initialized to reduce allocations. */ protected UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance(); @@ -115,32 +109,10 @@ public abstract class GeneratedMessageLite< if (memoizedHashCode != 0) { return memoizedHashCode; } - // BEGIN EXPERIMENTAL - // memoizedHashCode = Protobuf.getInstance().schemaFor(this).hashCode(this); - // return memoizedHashCode; - // END EXPERIMENTAL - // BEGIN REGULAR - HashCodeVisitor visitor = new HashCodeVisitor(); - visit(visitor, (MessageType) this); - memoizedHashCode = visitor.hashCode; + memoizedHashCode = Protobuf.getInstance().schemaFor(this).hashCode(this); return memoizedHashCode; - // END REGULAR } - // BEGIN REGULAR - @SuppressWarnings("unchecked") // Guaranteed by runtime - int hashCode(HashCodeVisitor visitor) { - if (memoizedHashCode == 0) { - int inProgressHashCode = visitor.hashCode; - visitor.hashCode = 0; - visit(visitor, (MessageType) this); - memoizedHashCode = visitor.hashCode; - visitor.hashCode = inProgressHashCode; - } - return memoizedHashCode; - } - // END REGULAR - @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime @Override public boolean equals(Object other) { @@ -152,36 +124,8 @@ public abstract class GeneratedMessageLite< return false; } - // BEGIN EXPERIMENTAL - // return Protobuf.getInstance().schemaFor(this).equals(this, (MessageType) other); - // END EXPERIMENTAL - // BEGIN REGULAR - - try { - visit(EqualsVisitor.INSTANCE, (MessageType) other); - } catch (EqualsVisitor.NotEqualsException e) { - return false; - } - return true; - // END REGULAR - } - - // BEGIN REGULAR - /** Same as {@link #equals(Object)} but throws {@code NotEqualsException}. */ - @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime - boolean equals(EqualsVisitor visitor, MessageLite other) { - if (this == other) { - return true; - } - - if (!getDefaultInstanceForType().getClass().isInstance(other)) { - return false; - } - - visit(visitor, (MessageType) other); - return true; + return Protobuf.getInstance().schemaFor(this).equals(this, (MessageType) other); } - // END REGULAR // The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as // mutable during the parsing constructor and immutable after. This allows us to avoid @@ -223,13 +167,7 @@ public abstract class GeneratedMessageLite< /** Called by subclasses to complete parsing. For use by generated code only. */ protected void makeImmutable() { - // BEGIN REGULAR - dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE); - unknownFields.makeImmutable(); - // END REGULAR - // BEGIN EXPERIMENTAL - // Protobuf.getInstance().schemaFor(this).makeImmutable(this); - // END EXPERIMENTAL + Protobuf.getInstance().schemaFor(this).makeImmutable(this); } protected final < @@ -266,17 +204,12 @@ public abstract class GeneratedMessageLite< * <p>For use by generated code only. */ public static enum MethodToInvoke { - // BEGIN REGULAR - IS_INITIALIZED, - VISIT, - MERGE_FROM_STREAM, - MAKE_IMMUTABLE, - // END REGULAR // Rely on/modify instance state GET_MEMOIZED_IS_INITIALIZED, SET_MEMOIZED_IS_INITIALIZED, // Rely on static state + BUILD_MESSAGE_INFO, NEW_MUTABLE_INSTANCE, NEW_BUILDER, GET_DEFAULT_INSTANCE, @@ -290,10 +223,6 @@ public abstract class GeneratedMessageLite< * count. * * <ul> - * <li>{@code MERGE_FROM_STREAM} is parameterized with an {@link CodedInputStream} and {@link - * ExtensionRegistryLite}. It consumes the input stream, parsing the contents into the - * returned protocol buffer. If parsing throws an {@link InvalidProtocolBufferException}, - * the implementation wraps it in a RuntimeException. * <li>{@code NEW_INSTANCE} returns a new instance of the protocol buffer that has not yet been * made immutable. See {@code MAKE_IMMUTABLE}. * <li>{@code IS_INITIALIZED} returns {@code null} for false and the default instance for true. @@ -303,9 +232,6 @@ public abstract class GeneratedMessageLite< * <li>{@code SET_MEMOIZED_IS_INITIALIZED} sets the memoized {@code isInitilaized} byte value to * 1 if the first parameter is not null, or to 0 if the first parameter is null. * <li>{@code NEW_BUILDER} returns a {@code BuilderType} instance. - * <li>{@code VISIT} is parameterized with a {@code Visitor} and a {@code MessageType} and - * recursively iterates through the fields side by side between this and the instance. - * <li>{@code MAKE_IMMUTABLE} sets all internal fields to an immutable state. * </ul> * * This method, plus the implementation of the Builder, enables the Builder class to be proguarded @@ -325,13 +251,6 @@ public abstract class GeneratedMessageLite< return dynamicMethod(method, null, null); } - // BEGIN REGULAR - void visit(Visitor visitor, MessageType other) { - dynamicMethod(MethodToInvoke.VISIT, visitor, other); - unknownFields = visitor.visitUnknownFields(unknownFields, other.unknownFields); - } - // END REGULAR - @Override int getMemoizedSerializedSize() { return memoizedSerializedSize; @@ -342,7 +261,60 @@ public abstract class GeneratedMessageLite< memoizedSerializedSize = size; } + public void writeTo(CodedOutputStream output) throws IOException { + writeToInternal(output); + } + + public int getSerializedSize() { + if (memoizedSerializedSize == -1) { + memoizedSerializedSize = getSerializedSizeInternal(); + } + return memoizedSerializedSize; + } + + /** Constructs a {@link MessageInfo} for this message type. */ + Object buildMessageInfo() throws Exception { + return dynamicMethod(MethodToInvoke.BUILD_MESSAGE_INFO); + } + + private static Map<Object, GeneratedMessageLite<?, ?>> defaultInstanceMap = + new ConcurrentHashMap<Object, GeneratedMessageLite<?, ?>>(); + + @SuppressWarnings("unchecked") + static <T extends GeneratedMessageLite<?, ?>> T getDefaultInstance(Class<T> clazz) { + T result = (T) defaultInstanceMap.get(clazz); + if (result == null) { + // Foo.class does not initialize the class so we need to force the initialization in order to + // get the default instance registered. + try { + Class.forName(clazz.getName(), true, clazz.getClassLoader()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Class initialization cannot fail.", e); + } + result = (T) defaultInstanceMap.get(clazz); + } + if (result == null) { + // On some Samsung devices, this still doesn't return a valid value for some reason. We add a + // reflective fallback to keep the device running. See b/114675342. + result = (T) UnsafeUtil.allocateInstance(clazz).getDefaultInstanceForType(); + // A sanity check to ensure that <clinit> was actually invoked. + if (result == null) { + throw new IllegalStateException(); + } + defaultInstanceMap.put(clazz, result); + } + return result; + } + + protected static <T extends GeneratedMessageLite<?, ?>> void registerDefaultInstance( + Class<T> clazz, T defaultInstance) { + defaultInstanceMap.put(clazz, defaultInstance); + } + protected static Object newMessageInfo( + MessageLite defaultInstance, String info, Object[] objects) { + return new RawMessageInfo(defaultInstance, info, objects); + } /** * Merge some unknown fields into the {@link UnknownFieldSetLite} for this message. @@ -437,12 +409,7 @@ public abstract class GeneratedMessageLite< } private void mergeFromInstance(MessageType dest, MessageType src) { - // BEGIN EXPERIMENTAL - // Protobuf.getInstance().schemaFor(dest).mergeFrom(dest, src); - // END EXPERIMENTAL - // BEGIN REGULAR - dest.visit(MergeFromVisitor.INSTANCE, src); - // END REGULAR + Protobuf.getInstance().schemaFor(dest).mergeFrom(dest, src); } @Override @@ -454,36 +421,26 @@ public abstract class GeneratedMessageLite< public BuilderType mergeFrom( byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { - // BEGIN REGULAR - return super.mergeFrom(input, offset, length, extensionRegistry); - // END REGULAR - // BEGIN EXPERIMENTAL - // copyOnWrite(); - // try { - // Protobuf.getInstance().schemaFor(instance).mergeFrom( - // instance, input, offset, offset + length, - // new ArrayDecoders.Registers(extensionRegistry)); - // } catch (InvalidProtocolBufferException e) { - // throw e; - // } catch (IndexOutOfBoundsException e) { - // throw InvalidProtocolBufferException.truncatedMessage(); - // } catch (IOException e) { - // throw new RuntimeException("Reading from byte array should not throw IOException.", e); - // } - // return (BuilderType) this; - // END EXPERIMENTAL + copyOnWrite(); + try { + Protobuf.getInstance().schemaFor(instance).mergeFrom( + instance, input, offset, offset + length, + new ArrayDecoders.Registers(extensionRegistry)); + } catch (InvalidProtocolBufferException e) { + throw e; + } catch (IndexOutOfBoundsException e) { + throw InvalidProtocolBufferException.truncatedMessage(); + } catch (IOException e) { + throw new RuntimeException("Reading from byte array should not throw IOException.", e); + } + return (BuilderType) this; } @Override public BuilderType mergeFrom( byte[] input, int offset, int length) throws InvalidProtocolBufferException { - // BEGIN REGULAR - return super.mergeFrom(input, offset, length); - // END REGULAR - // BEGIN EXPERIMENTAL - // return mergeFrom(input, offset, length, ExtensionRegistryLite.getEmptyRegistry()); - // END EXPERIMENTAL + return mergeFrom(input, offset, length, ExtensionRegistryLite.getEmptyRegistry()); } @Override @@ -493,15 +450,10 @@ public abstract class GeneratedMessageLite< throws IOException { copyOnWrite(); try { - // BEGIN REGULAR - instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry); - // END REGULAR - // BEGIN EXPERIMENTAL - // // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use - // // fast path. - // Protobuf.getInstance().schemaFor(instance).mergeFrom( - // instance, CodedInputStreamReader.forCodedInput(input), extensionRegistry); - // END EXPERIMENTAL + // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use + // fast path. + Protobuf.getInstance().schemaFor(instance).mergeFrom( + instance, CodedInputStreamReader.forCodedInput(input), extensionRegistry); } catch (RuntimeException e) { if (e.getCause() instanceof IOException) { throw (IOException) e.getCause(); @@ -553,14 +505,6 @@ public abstract class GeneratedMessageLite< extensions.mergeFrom(((ExtendableMessage) other).extensions); } - // BEGIN REGULAR - @Override - final void visit(Visitor visitor, MessageType other) { - super.visit(visitor, other); - extensions = visitor.visitExtensions(extensions, other.extensions); - } - // END REGULAR - /** * Parse an unknown field or an extension. For use by generated code only. * @@ -898,14 +842,6 @@ public abstract class GeneratedMessageLite< return extensions.isInitialized(); } - @Override - protected final void makeImmutable() { - super.makeImmutable(); - // BEGIN REGULAR - extensions.makeImmutable(); - // END REGULAR - } - /** * Used by subclasses to serialize extensions. Extension ranges may be interleaved with field * numbers, but we must write them in canonical (sorted by field number) order. ExtensionWriter @@ -1479,13 +1415,7 @@ public abstract class GeneratedMessageLite< if (memoizedIsInitialized == 0) { return false; } - // BEGIN EXPERIMENTAL - // boolean isInitialized = Protobuf.getInstance().schemaFor(message).isInitialized(message); - // END EXPERIMENTAL - // BEGIN REGULAR - boolean isInitialized = - message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.FALSE) != null; - // END REGULAR + boolean isInitialized = Protobuf.getInstance().schemaFor(message).isInitialized(message); if (shouldMemoize) { message.dynamicMethod( MethodToInvoke.SET_MEMOIZED_IS_INITIALIZED, isInitialized ? message : null); @@ -1593,23 +1523,16 @@ public abstract class GeneratedMessageLite< @SuppressWarnings("unchecked") // Guaranteed by protoc T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE); try { - // BEGIN REGULAR - result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry); - // END REGULAR - // BEGIN EXPERIMENTAL - // // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use - // // fast path. - // Protobuf.getInstance().schemaFor(result).mergeFrom( - // result, CodedInputStreamReader.forCodedInput(input), extensionRegistry); - // END EXPERIMENTAL + // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use + // fast path. + Protobuf.getInstance().schemaFor(result).mergeFrom( + result, CodedInputStreamReader.forCodedInput(input), extensionRegistry); result.makeImmutable(); - // BEGIN EXPERIMENTAL - // } catch (IOException e) { - // if (e.getCause() instanceof InvalidProtocolBufferException) { - // throw (InvalidProtocolBufferException) e.getCause(); - // } - // throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result); - // END EXPERIMENTAL + } catch (IOException e) { + if (e.getCause() instanceof InvalidProtocolBufferException) { + throw (InvalidProtocolBufferException) e.getCause(); + } + throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result); } catch (RuntimeException e) { if (e.getCause() instanceof InvalidProtocolBufferException) { throw (InvalidProtocolBufferException) e.getCause(); @@ -1623,42 +1546,25 @@ public abstract class GeneratedMessageLite< static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom( T instance, byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { - // BEGIN REGULAR - T message; + @SuppressWarnings("unchecked") // Guaranteed by protoc + T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE); try { - CodedInputStream cis = CodedInputStream.newInstance(input, offset, length); - message = parsePartialFrom(instance, cis, extensionRegistry); - try { - cis.checkLastTagWas(0); - } catch (InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(message); + Protobuf.getInstance().schemaFor(result).mergeFrom( + result, input, offset, offset + length, + new ArrayDecoders.Registers(extensionRegistry)); + result.makeImmutable(); + if (result.memoizedHashCode != 0) { + throw new RuntimeException(); } - return message; - } catch (InvalidProtocolBufferException e) { - throw e; + } catch (IOException e) { + if (e.getCause() instanceof InvalidProtocolBufferException) { + throw (InvalidProtocolBufferException) e.getCause(); + } + throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result); + } catch (IndexOutOfBoundsException e) { + throw InvalidProtocolBufferException.truncatedMessage().setUnfinishedMessage(result); } - // END REGULAR - // BEGIN EXPERIMENTAL - // @SuppressWarnings("unchecked") // Guaranteed by protoc - // T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE); - // try { - // Protobuf.getInstance().schemaFor(result).mergeFrom( - // result, input, offset, offset + length, - // new ArrayDecoders.Registers(extensionRegistry)); - // result.makeImmutable(); - // if (result.memoizedHashCode != 0) { - // throw new RuntimeException(); - // } - // } catch (IOException e) { - // if (e.getCause() instanceof InvalidProtocolBufferException) { - // throw (InvalidProtocolBufferException) e.getCause(); - // } - // throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result); - // } catch (IndexOutOfBoundsException e) { - // throw InvalidProtocolBufferException.truncatedMessage().setUnfinishedMessage(result); - // } - // return result; - // END EXPERIMENTAL + return result; } protected static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom( @@ -1825,701 +1731,4 @@ public abstract class GeneratedMessageLite< } return message; } - - // BEGIN REGULAR - /** - * An abstract visitor that the generated code calls into that we use to implement various - * features. Fields that are not members of oneofs are always visited. Members of a oneof are only - * visited when they are the set oneof case value on the "other" proto. The visitOneofNotSet - * method is invoked if other's oneof case is not set. - */ - protected interface Visitor { - boolean visitBoolean(boolean minePresent, boolean mine, boolean otherPresent, boolean other); - - int visitInt(boolean minePresent, int mine, boolean otherPresent, int other); - - double visitDouble(boolean minePresent, double mine, boolean otherPresent, double other); - - float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other); - - long visitLong(boolean minePresent, long mine, boolean otherPresent, long other); - - String visitString(boolean minePresent, String mine, boolean otherPresent, String other); - - ByteString visitByteString( - boolean minePresent, ByteString mine, boolean otherPresent, ByteString other); - - Object visitOneofBoolean(boolean minePresent, Object mine, Object other); - - Object visitOneofInt(boolean minePresent, Object mine, Object other); - - Object visitOneofDouble(boolean minePresent, Object mine, Object other); - - Object visitOneofFloat(boolean minePresent, Object mine, Object other); - - Object visitOneofLong(boolean minePresent, Object mine, Object other); - - Object visitOneofString(boolean minePresent, Object mine, Object other); - - Object visitOneofByteString(boolean minePresent, Object mine, Object other); - - Object visitOneofMessage(boolean minePresent, Object mine, Object other); - - void visitOneofNotSet(boolean minePresent); - - /** Message fields use null sentinals. */ - <T extends MessageLite> T visitMessage(T mine, T other); - - <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other); - - BooleanList visitBooleanList(BooleanList mine, BooleanList other); - - IntList visitIntList(IntList mine, IntList other); - - DoubleList visitDoubleList(DoubleList mine, DoubleList other); - - FloatList visitFloatList(FloatList mine, FloatList other); - - LongList visitLongList(LongList mine, LongList other); - - FieldSet<ExtensionDescriptor> visitExtensions( - FieldSet<ExtensionDescriptor> mine, FieldSet<ExtensionDescriptor> other); - - UnknownFieldSetLite visitUnknownFields(UnknownFieldSetLite mine, UnknownFieldSetLite other); - - <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other); - } - - /** Implements equals. Throws a {@link NotEqualsException} when not equal. */ - static class EqualsVisitor implements Visitor { - - static final class NotEqualsException extends RuntimeException {} - - static final EqualsVisitor INSTANCE = new EqualsVisitor(); - - static final NotEqualsException NOT_EQUALS = new NotEqualsException(); - - private EqualsVisitor() {} - - @Override - public boolean visitBoolean( - boolean minePresent, boolean mine, boolean otherPresent, boolean other) { - if (minePresent != otherPresent || mine != other) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) { - if (minePresent != otherPresent || mine != other) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public double visitDouble( - boolean minePresent, double mine, boolean otherPresent, double other) { - if (minePresent != otherPresent || mine != other) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) { - if (minePresent != otherPresent || mine != other) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) { - if (minePresent != otherPresent || mine != other) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public String visitString( - boolean minePresent, String mine, boolean otherPresent, String other) { - if (minePresent != otherPresent || !mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public ByteString visitByteString( - boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) { - if (minePresent != otherPresent || !mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) { - if (minePresent && mine.equals(other)) { - return mine; - } - throw NOT_EQUALS; - } - - @Override - public Object visitOneofInt(boolean minePresent, Object mine, Object other) { - if (minePresent && mine.equals(other)) { - return mine; - } - throw NOT_EQUALS; - } - - @Override - public Object visitOneofDouble(boolean minePresent, Object mine, Object other) { - if (minePresent && mine.equals(other)) { - return mine; - } - throw NOT_EQUALS; - } - - @Override - public Object visitOneofFloat(boolean minePresent, Object mine, Object other) { - if (minePresent && mine.equals(other)) { - return mine; - } - throw NOT_EQUALS; - } - - @Override - public Object visitOneofLong(boolean minePresent, Object mine, Object other) { - if (minePresent && mine.equals(other)) { - return mine; - } - throw NOT_EQUALS; - } - - @Override - public Object visitOneofString(boolean minePresent, Object mine, Object other) { - if (minePresent && mine.equals(other)) { - return mine; - } - throw NOT_EQUALS; - } - - @Override - public Object visitOneofByteString(boolean minePresent, Object mine, Object other) { - if (minePresent && mine.equals(other)) { - return mine; - } - throw NOT_EQUALS; - } - - @Override - public Object visitOneofMessage(boolean minePresent, Object mine, Object other) { - if (minePresent && ((GeneratedMessageLite<?, ?>) mine).equals(this, (MessageLite) other)) { - return mine; - } - throw NOT_EQUALS; - } - - @Override - public void visitOneofNotSet(boolean minePresent) { - if (minePresent) { - throw NOT_EQUALS; - } - } - - @Override - public <T extends MessageLite> T visitMessage(T mine, T other) { - if (mine == null && other == null) { - return null; - } - - if (mine == null || other == null) { - throw NOT_EQUALS; - } - - ((GeneratedMessageLite<?, ?>) mine).equals(this, other); - - return mine; - } - - @Override - public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) { - if (!mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public BooleanList visitBooleanList(BooleanList mine, BooleanList other) { - if (!mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public IntList visitIntList(IntList mine, IntList other) { - if (!mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public DoubleList visitDoubleList(DoubleList mine, DoubleList other) { - if (!mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public FloatList visitFloatList(FloatList mine, FloatList other) { - if (!mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public LongList visitLongList(LongList mine, LongList other) { - if (!mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public FieldSet<ExtensionDescriptor> visitExtensions( - FieldSet<ExtensionDescriptor> mine, FieldSet<ExtensionDescriptor> other) { - if (!mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public UnknownFieldSetLite visitUnknownFields( - UnknownFieldSetLite mine, UnknownFieldSetLite other) { - if (!mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - - @Override - public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) { - if (!mine.equals(other)) { - throw NOT_EQUALS; - } - return mine; - } - } - - /** Implements hashCode by accumulating state. */ - static class HashCodeVisitor implements Visitor { - - // The caller must ensure that the visitor is invoked parameterized with this and this such that - // other is this. This is required due to how oneof cases are handled. See the class comment - // on Visitor for more information. - - int hashCode = 0; - - @Override - public boolean visitBoolean( - boolean minePresent, boolean mine, boolean otherPresent, boolean other) { - hashCode = (53 * hashCode) + Internal.hashBoolean(mine); - return mine; - } - - @Override - public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) { - hashCode = (53 * hashCode) + mine; - return mine; - } - - @Override - public double visitDouble( - boolean minePresent, double mine, boolean otherPresent, double other) { - hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits(mine)); - return mine; - } - - @Override - public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) { - hashCode = (53 * hashCode) + Float.floatToIntBits(mine); - return mine; - } - - @Override - public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) { - hashCode = (53 * hashCode) + Internal.hashLong(mine); - return mine; - } - - @Override - public String visitString( - boolean minePresent, String mine, boolean otherPresent, String other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public ByteString visitByteString( - boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) { - hashCode = (53 * hashCode) + Internal.hashBoolean(((Boolean) mine)); - return mine; - } - - @Override - public Object visitOneofInt(boolean minePresent, Object mine, Object other) { - hashCode = (53 * hashCode) + (Integer) mine; - return mine; - } - - @Override - public Object visitOneofDouble(boolean minePresent, Object mine, Object other) { - hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits((Double) mine)); - return mine; - } - - @Override - public Object visitOneofFloat(boolean minePresent, Object mine, Object other) { - hashCode = (53 * hashCode) + Float.floatToIntBits((Float) mine); - return mine; - } - - @Override - public Object visitOneofLong(boolean minePresent, Object mine, Object other) { - hashCode = (53 * hashCode) + Internal.hashLong((Long) mine); - return mine; - } - - @Override - public Object visitOneofString(boolean minePresent, Object mine, Object other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public Object visitOneofByteString(boolean minePresent, Object mine, Object other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public Object visitOneofMessage(boolean minePresent, Object mine, Object other) { - return visitMessage((MessageLite) mine, (MessageLite) other); - } - - @Override - public void visitOneofNotSet(boolean minePresent) { - if (minePresent) { - throw new IllegalStateException(); // Can't happen if other == this. - } - } - - @Override - public <T extends MessageLite> T visitMessage(T mine, T other) { - final int protoHash; - if (mine != null) { - if (mine instanceof GeneratedMessageLite) { - protoHash = ((GeneratedMessageLite) mine).hashCode(this); - } else { - protoHash = mine.hashCode(); - } - } else { - protoHash = 37; - } - hashCode = (53 * hashCode) + protoHash; - return mine; - } - - @Override - public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public BooleanList visitBooleanList(BooleanList mine, BooleanList other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public IntList visitIntList(IntList mine, IntList other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public DoubleList visitDoubleList(DoubleList mine, DoubleList other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public FloatList visitFloatList(FloatList mine, FloatList other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public LongList visitLongList(LongList mine, LongList other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public FieldSet<ExtensionDescriptor> visitExtensions( - FieldSet<ExtensionDescriptor> mine, FieldSet<ExtensionDescriptor> other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public UnknownFieldSetLite visitUnknownFields( - UnknownFieldSetLite mine, UnknownFieldSetLite other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - - @Override - public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) { - hashCode = (53 * hashCode) + mine.hashCode(); - return mine; - } - } - - /** Implements field merging semantics over the visitor interface. */ - protected static class MergeFromVisitor implements Visitor { - - public static final MergeFromVisitor INSTANCE = new MergeFromVisitor(); - - private MergeFromVisitor() {} - - @Override - public boolean visitBoolean( - boolean minePresent, boolean mine, boolean otherPresent, boolean other) { - return otherPresent ? other : mine; - } - - @Override - public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) { - return otherPresent ? other : mine; - } - - @Override - public double visitDouble( - boolean minePresent, double mine, boolean otherPresent, double other) { - return otherPresent ? other : mine; - } - - @Override - public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) { - return otherPresent ? other : mine; - } - - @Override - public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) { - return otherPresent ? other : mine; - } - - @Override - public String visitString( - boolean minePresent, String mine, boolean otherPresent, String other) { - return otherPresent ? other : mine; - } - - @Override - public ByteString visitByteString( - boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) { - return otherPresent ? other : mine; - } - - @Override - public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) { - return other; - } - - @Override - public Object visitOneofInt(boolean minePresent, Object mine, Object other) { - return other; - } - - @Override - public Object visitOneofDouble(boolean minePresent, Object mine, Object other) { - return other; - } - - @Override - public Object visitOneofFloat(boolean minePresent, Object mine, Object other) { - return other; - } - - @Override - public Object visitOneofLong(boolean minePresent, Object mine, Object other) { - return other; - } - - @Override - public Object visitOneofString(boolean minePresent, Object mine, Object other) { - return other; - } - - @Override - public Object visitOneofByteString(boolean minePresent, Object mine, Object other) { - return other; - } - - @Override - public Object visitOneofMessage(boolean minePresent, Object mine, Object other) { - if (minePresent) { - return visitMessage((MessageLite) mine, (MessageLite) other); - } - return other; - } - - @Override - public void visitOneofNotSet(boolean minePresent) { - return; - } - - @SuppressWarnings("unchecked") // Guaranteed by runtime. - @Override - public <T extends MessageLite> T visitMessage(T mine, T other) { - if (mine != null && other != null) { - return (T) mine.toBuilder().mergeFrom(other).build(); - } - - return mine != null ? mine : other; - } - - @Override - public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) { - int size = mine.size(); - int otherSize = other.size(); - if (size > 0 && otherSize > 0) { - if (!mine.isModifiable()) { - mine = mine.mutableCopyWithCapacity(size + otherSize); - } - mine.addAll(other); - } - - return size > 0 ? mine : other; - } - - @Override - public BooleanList visitBooleanList(BooleanList mine, BooleanList other) { - int size = mine.size(); - int otherSize = other.size(); - if (size > 0 && otherSize > 0) { - if (!mine.isModifiable()) { - mine = mine.mutableCopyWithCapacity(size + otherSize); - } - mine.addAll(other); - } - - return size > 0 ? mine : other; - } - - @Override - public IntList visitIntList(IntList mine, IntList other) { - int size = mine.size(); - int otherSize = other.size(); - if (size > 0 && otherSize > 0) { - if (!mine.isModifiable()) { - mine = mine.mutableCopyWithCapacity(size + otherSize); - } - mine.addAll(other); - } - - return size > 0 ? mine : other; - } - - @Override - public DoubleList visitDoubleList(DoubleList mine, DoubleList other) { - int size = mine.size(); - int otherSize = other.size(); - if (size > 0 && otherSize > 0) { - if (!mine.isModifiable()) { - mine = mine.mutableCopyWithCapacity(size + otherSize); - } - mine.addAll(other); - } - - return size > 0 ? mine : other; - } - - @Override - public FloatList visitFloatList(FloatList mine, FloatList other) { - int size = mine.size(); - int otherSize = other.size(); - if (size > 0 && otherSize > 0) { - if (!mine.isModifiable()) { - mine = mine.mutableCopyWithCapacity(size + otherSize); - } - mine.addAll(other); - } - - return size > 0 ? mine : other; - } - - @Override - public LongList visitLongList(LongList mine, LongList other) { - int size = mine.size(); - int otherSize = other.size(); - if (size > 0 && otherSize > 0) { - if (!mine.isModifiable()) { - mine = mine.mutableCopyWithCapacity(size + otherSize); - } - mine.addAll(other); - } - - return size > 0 ? mine : other; - } - - @Override - public FieldSet<ExtensionDescriptor> visitExtensions( - FieldSet<ExtensionDescriptor> mine, FieldSet<ExtensionDescriptor> other) { - if (mine.isImmutable()) { - mine = mine.clone(); - } - mine.mergeFrom(other); - return mine; - } - - @Override - public UnknownFieldSetLite visitUnknownFields( - UnknownFieldSetLite mine, UnknownFieldSetLite other) { - return other == UnknownFieldSetLite.getDefaultInstance() - ? mine - : UnknownFieldSetLite.mutableCopyOf(mine, other); - } - - @Override - public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) { - if (!other.isEmpty()) { - if (!mine.isMutable()) { - mine = mine.mutableCopy(); - } - mine.mergeFrom(other); - } - return mine; - } - } - // END REGULAR } diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java index e9eb34f2f..0ed724384 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java @@ -459,6 +459,29 @@ public abstract class GeneratedMessageV3 extends AbstractMessage /** + * This class is used to make a generated protected method inaccessible from user's code (e.g., + * the {@link #newInstance} method below). When this class is used as a parameter's type in a + * generated protected method, the method is visible to user's code in the same package, but + * since the constructor of this class is private to protobuf runtime, user's code can't obtain + * an instance of this class and as such can't actually make a method call on the protected + * method. + */ + protected static final class UnusedPrivateParameter { + static final UnusedPrivateParameter INSTANCE = new UnusedPrivateParameter(); + + private UnusedPrivateParameter() { + } + } + + /** + * Creates a new instance of this message type. Overridden in the generated code. + */ + @SuppressWarnings({"unused"}) + protected Object newInstance(UnusedPrivateParameter unused) { + throw new UnsupportedOperationException("This method must be overridden by the subclass."); + } + + /** * Used by parsing constructors in generated classes. */ protected void makeExtensionsImmutable() { diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java index 713ccb583..15deb37c4 100644 --- a/java/core/src/main/java/com/google/protobuf/Internal.java +++ b/java/core/src/main/java/com/google/protobuf/Internal.java @@ -540,6 +540,24 @@ public final class Internal { } return valueConverter.doForward(oldValue); } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof Map.Entry)) { + return false; + } + @SuppressWarnings("unchecked") + Map.Entry<?, ?> other = (Map.Entry<?, ?>) o; + return getKey().equals(other.getKey()) && getValue().equals(getValue()); + } + + @Override + public int hashCode() { + return realEntry.hashCode(); + } } } diff --git a/java/core/src/main/java/com/google/protobuf/JavaType.java b/java/core/src/main/java/com/google/protobuf/JavaType.java new file mode 100755 index 000000000..770aa9ef1 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/JavaType.java @@ -0,0 +1,76 @@ +// 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; + +/** Enum that identifies the Java types required to store protobuf fields. */ +@ExperimentalApi +public enum JavaType { + VOID(Void.class, Void.class, null), + INT(int.class, Integer.class, 0), + LONG(long.class, Long.class, 0L), + FLOAT(float.class, Float.class, 0F), + DOUBLE(double.class, Double.class, 0D), + BOOLEAN(boolean.class, Boolean.class, false), + STRING(String.class, String.class, ""), + BYTE_STRING(ByteString.class, ByteString.class, ByteString.EMPTY), + ENUM(int.class, Integer.class, null), + MESSAGE(Object.class, Object.class, null); + + private final Class<?> type; + private final Class<?> boxedType; + private final Object defaultDefault; + + JavaType(Class<?> type, Class<?> boxedType, Object defaultDefault) { + this.type = type; + this.boxedType = boxedType; + this.defaultDefault = defaultDefault; + } + + /** The default default value for fields of this type, if it's a primitive type. */ + public Object getDefaultDefault() { + return defaultDefault; + } + + /** Gets the required type for a field that would hold a value of this type. */ + public Class<?> getType() { + return type; + } + + /** @return the boxedType */ + public Class<?> getBoxedType() { + return boxedType; + } + + /** Indicates whether or not this {@link JavaType} can be applied to a field of the given type. */ + public boolean isValidType(Class<?> t) { + return type.isAssignableFrom(t); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java index 5651e131b..d6b594d38 100644 --- a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java +++ b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java @@ -388,6 +388,18 @@ public class LazyFieldLite { } } + /** Writes this lazy field into a {@link Writer}. */ + void writeTo(Writer writer, int fieldNumber) throws IOException { + if (memoizedBytes != null) { + writer.writeBytes(fieldNumber, memoizedBytes); + } else if (delayedBytes != null) { + writer.writeBytes(fieldNumber, delayedBytes); + } else if (value != null) { + writer.writeMessage(fieldNumber, value); + } else { + writer.writeBytes(fieldNumber, ByteString.EMPTY); + } + } /** Might lazily parse the bytes that were previously passed in. Is thread-safe. */ protected void ensureInitialized(MessageLite defaultInstance) { diff --git a/java/core/src/main/java/com/google/protobuf/ListFieldSchema.java b/java/core/src/main/java/com/google/protobuf/ListFieldSchema.java new file mode 100755 index 000000000..ebc8561a7 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ListFieldSchema.java @@ -0,0 +1,190 @@ +// 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.Internal.ProtobufList; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Utility class that aids in properly manipulating list fields for either the lite or full runtime. + */ +abstract class ListFieldSchema { + // Disallow construction. + private ListFieldSchema() {} + + private static final ListFieldSchema FULL_INSTANCE = new ListFieldSchemaFull(); + private static final ListFieldSchema LITE_INSTANCE = new ListFieldSchemaLite(); + + abstract <L> List<L> mutableListAt(Object msg, long offset); + + abstract void makeImmutableListAt(Object msg, long offset); + + abstract <L> void mergeListsAt(Object msg, Object otherMsg, long offset); + + static ListFieldSchema full() { + return FULL_INSTANCE; + } + + static ListFieldSchema lite() { + return LITE_INSTANCE; + } + + /** Implementation for the full runtime. */ + private static final class ListFieldSchemaFull extends ListFieldSchema { + + private static final Class<?> UNMODIFIABLE_LIST_CLASS = + Collections.unmodifiableList(Collections.emptyList()).getClass(); + + @Override + <L> List<L> mutableListAt(Object message, long offset) { + return mutableListAt(message, offset, AbstractProtobufList.DEFAULT_CAPACITY); + } + + @Override + void makeImmutableListAt(Object message, long offset) { + List<?> list = (List<?>) UnsafeUtil.getObject(message, offset); + Object immutable = null; + if (list instanceof LazyStringList) { + immutable = ((LazyStringList) list).getUnmodifiableView(); + } else if (UNMODIFIABLE_LIST_CLASS.isAssignableFrom(list.getClass())) { + // already immutable + return; + } else if (list instanceof PrimitiveNonBoxingCollection && list instanceof ProtobufList) { + if (((ProtobufList<?>) list).isModifiable()) { + ((ProtobufList<?>) list).makeImmutable(); + } + return; + } else { + immutable = Collections.unmodifiableList((List<?>) list); + } + UnsafeUtil.putObject(message, offset, immutable); + } + + @SuppressWarnings("unchecked") + private static <L> List<L> mutableListAt(Object message, long offset, int additionalCapacity) { + List<L> list = getList(message, offset); + if (list.isEmpty()) { + if (list instanceof LazyStringList) { + list = (List<L>) new LazyStringArrayList(additionalCapacity); + } else if (list instanceof PrimitiveNonBoxingCollection && list instanceof ProtobufList) { + list = ((ProtobufList<L>) list).mutableCopyWithCapacity(additionalCapacity); + } else { + list = new ArrayList<L>(additionalCapacity); + } + UnsafeUtil.putObject(message, offset, list); + } else if (UNMODIFIABLE_LIST_CLASS.isAssignableFrom(list.getClass())) { + ArrayList<L> newList = new ArrayList<L>(list.size() + additionalCapacity); + newList.addAll(list); + list = newList; + UnsafeUtil.putObject(message, offset, list); + } else if (list instanceof UnmodifiableLazyStringList) { + LazyStringArrayList newList = new LazyStringArrayList(list.size() + additionalCapacity); + newList.addAll((UnmodifiableLazyStringList) list); + list = (List<L>) newList; + UnsafeUtil.putObject(message, offset, list); + } else if (list instanceof PrimitiveNonBoxingCollection + && list instanceof ProtobufList + && !((ProtobufList<L>) list).isModifiable()) { + list = ((ProtobufList<L>) list).mutableCopyWithCapacity(list.size() + additionalCapacity); + UnsafeUtil.putObject(message, offset, list); + } + return list; + } + + @Override + <E> void mergeListsAt(Object msg, Object otherMsg, long offset) { + List<E> other = getList(otherMsg, offset); + List<E> mine = mutableListAt(msg, offset, other.size()); + + int size = mine.size(); + int otherSize = other.size(); + if (size > 0 && otherSize > 0) { + mine.addAll(other); + } + + List<E> merged = size > 0 ? mine : other; + UnsafeUtil.putObject(msg, offset, merged); + } + + @SuppressWarnings("unchecked") + static <E> List<E> getList(Object message, long offset) { + return (List<E>) UnsafeUtil.getObject(message, offset); + } + } + + /** Implementation for the lite runtime. */ + private static final class ListFieldSchemaLite extends ListFieldSchema { + + @Override + <L> List<L> mutableListAt(Object message, long offset) { + ProtobufList<L> list = getProtobufList(message, offset); + if (!list.isModifiable()) { + int size = list.size(); + list = + list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + UnsafeUtil.putObject(message, offset, list); + } + return list; + } + + @Override + void makeImmutableListAt(Object message, long offset) { + ProtobufList<?> list = getProtobufList(message, offset); + list.makeImmutable(); + } + + @Override + <E> void mergeListsAt(Object msg, Object otherMsg, long offset) { + ProtobufList<E> mine = getProtobufList(msg, offset); + ProtobufList<E> other = getProtobufList(otherMsg, offset); + + int size = mine.size(); + int otherSize = other.size(); + if (size > 0 && otherSize > 0) { + if (!mine.isModifiable()) { + mine = mine.mutableCopyWithCapacity(size + otherSize); + } + mine.addAll(other); + } + + ProtobufList<E> merged = size > 0 ? mine : other; + UnsafeUtil.putObject(msg, offset, merged); + } + + @SuppressWarnings("unchecked") + static <E> ProtobufList<E> getProtobufList(Object message, long offset) { + return (ProtobufList<E>) UnsafeUtil.getObject(message, offset); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/ManifestSchemaFactory.java b/java/core/src/main/java/com/google/protobuf/ManifestSchemaFactory.java new file mode 100755 index 000000000..84ca9ae0f --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ManifestSchemaFactory.java @@ -0,0 +1,172 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.Internal.checkNotNull; + +/** + * Dynamically generates a manifest-based (i.e. table-based) schema for a given protobuf message. + */ +@ExperimentalApi +final class ManifestSchemaFactory implements SchemaFactory { + + private final MessageInfoFactory messageInfoFactory; + + public ManifestSchemaFactory() { + this(getDefaultMessageInfoFactory()); + } + + private ManifestSchemaFactory(MessageInfoFactory messageInfoFactory) { + this.messageInfoFactory = checkNotNull(messageInfoFactory, "messageInfoFactory"); + } + + @Override + public <T> Schema<T> createSchema(Class<T> messageType) { + SchemaUtil.requireGeneratedMessage(messageType); + + MessageInfo messageInfo = messageInfoFactory.messageInfoFor(messageType); + + // MessageSet has a special schema. + if (messageInfo.isMessageSetWireFormat()) { + if (GeneratedMessageLite.class.isAssignableFrom(messageType)) { + return MessageSetSchema.newSchema( + SchemaUtil.unknownFieldSetLiteSchema(), + ExtensionSchemas.lite(), + messageInfo.getDefaultInstance()); + } + return MessageSetSchema.newSchema( + SchemaUtil.proto2UnknownFieldSetSchema(), + ExtensionSchemas.full(), + messageInfo.getDefaultInstance()); + } + + return newSchema(messageType, messageInfo); + } + + private static <T> Schema<T> newSchema(Class<T> messageType, MessageInfo messageInfo) { + if (GeneratedMessageLite.class.isAssignableFrom(messageType)) { + return isProto2(messageInfo) + ? MessageSchema.newSchema( + messageType, + messageInfo, + NewInstanceSchemas.lite(), + ListFieldSchema.lite(), + SchemaUtil.unknownFieldSetLiteSchema(), + ExtensionSchemas.lite(), + MapFieldSchemas.lite()) + : MessageSchema.newSchema( + messageType, + messageInfo, + NewInstanceSchemas.lite(), + ListFieldSchema.lite(), + SchemaUtil.unknownFieldSetLiteSchema(), + /* extensionSchema= */ null, + MapFieldSchemas.lite()); + } + return isProto2(messageInfo) + ? MessageSchema.newSchema( + messageType, + messageInfo, + NewInstanceSchemas.full(), + ListFieldSchema.full(), + SchemaUtil.proto2UnknownFieldSetSchema(), + ExtensionSchemas.full(), + MapFieldSchemas.full()) + : MessageSchema.newSchema( + messageType, + messageInfo, + NewInstanceSchemas.full(), + ListFieldSchema.full(), + SchemaUtil.proto3UnknownFieldSetSchema(), + /* extensionSchema= */ null, + MapFieldSchemas.full()); + } + + private static boolean isProto2(MessageInfo messageInfo) { + return messageInfo.getSyntax() == ProtoSyntax.PROTO2; + } + + private static MessageInfoFactory getDefaultMessageInfoFactory() { + return new CompositeMessageInfoFactory( + GeneratedMessageInfoFactory.getInstance(), getDescriptorMessageInfoFactory()); + } + + private static class CompositeMessageInfoFactory implements MessageInfoFactory { + private MessageInfoFactory[] factories; + + CompositeMessageInfoFactory(MessageInfoFactory... factories) { + this.factories = factories; + } + + @Override + public boolean isSupported(Class<?> clazz) { + for (MessageInfoFactory factory : factories) { + if (factory.isSupported(clazz)) { + return true; + } + } + return false; + } + + @Override + public MessageInfo messageInfoFor(Class<?> clazz) { + for (MessageInfoFactory factory : factories) { + if (factory.isSupported(clazz)) { + return factory.messageInfoFor(clazz); + } + } + throw new UnsupportedOperationException( + "No factory is available for message type: " + clazz.getName()); + } + } + + private static final MessageInfoFactory EMPTY_FACTORY = + new MessageInfoFactory() { + @Override + public boolean isSupported(Class<?> clazz) { + return false; + } + + @Override + public MessageInfo messageInfoFor(Class<?> clazz) { + throw new IllegalStateException("This should never be called."); + } + }; + + private static MessageInfoFactory getDescriptorMessageInfoFactory() { + try { + Class<?> clazz = Class.forName("com.google.protobuf.DescriptorMessageInfoFactory"); + return (MessageInfoFactory) clazz.getDeclaredMethod("getInstance").invoke(null); + } catch (Exception e) { + return EMPTY_FACTORY; + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldSchema.java b/java/core/src/main/java/com/google/protobuf/MapFieldSchema.java new file mode 100755 index 000000000..195126e51 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/MapFieldSchema.java @@ -0,0 +1,63 @@ +// 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 java.util.Map; + +interface MapFieldSchema { + /** Returns the map data for mutation. */ + Map<?, ?> forMutableMapData(Object mapField); + + /** Returns the map data for read. */ + Map<?, ?> forMapData(Object mapField); + + /** Whether toImmutable() has been called on this map field. */ + boolean isImmutable(Object mapField); + + /** + * Returns an immutable instance of the map field. It may make the parameter immutable and return + * the parameter, or create an immutable copy. The status of the parameter after the call is + * undefined. + */ + Object toImmutable(Object mapField); + + /** Returns a new instance of the map field given a map default entry. */ + Object newMapField(Object mapDefaultEntry); + + /** Returns the metadata from a default entry. */ + MapEntryLite.Metadata<?, ?> forMapMetadata(Object mapDefaultEntry); + + /** Merges {@code srcMapField} into {@code destMapField}, and returns the merged instance. */ + Object mergeFrom(Object destMapField, Object srcMapField); + + /** Compute the serialized size for the map with a given field number. */ + int getSerializedSize(int fieldNumber, Object mapField, Object mapDefaultEntry); +} diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldSchemaFull.java b/java/core/src/main/java/com/google/protobuf/MapFieldSchemaFull.java new file mode 100755 index 000000000..1efaab3bc --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/MapFieldSchemaFull.java @@ -0,0 +1,112 @@ +// 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.MapEntryLite.Metadata; +import java.util.Map; + +class MapFieldSchemaFull implements MapFieldSchema { + @Override + public Map<?, ?> forMutableMapData(Object mapField) { + return ((MapField<?, ?>) mapField).getMutableMap(); + } + + @Override + public Map<?, ?> forMapData(Object mapField) { + return ((MapField<?, ?>) mapField).getMap(); + } + + @Override + public boolean isImmutable(Object mapField) { + return !((MapField<?, ?>) mapField).isMutable(); + } + + @Override + public Object toImmutable(Object mapField) { + ((MapField<?, ?>) mapField).makeImmutable(); + return mapField; + } + + @Override + public Object newMapField(Object mapDefaultEntry) { + return MapField.newMapField((MapEntry<?, ?>) mapDefaultEntry); + } + + @Override + public Metadata<?, ?> forMapMetadata(Object mapDefaultEntry) { + return ((MapEntry<?, ?>) mapDefaultEntry).getMetadata(); + } + + @Override + public Object mergeFrom(Object destMapField, Object srcMapField) { + return mergeFromFull(destMapField, srcMapField); + } + + @SuppressWarnings("unchecked") + private static <K, V> Object mergeFromFull(Object destMapField, Object srcMapField) { + MapField<K, V> mine = (MapField<K, V>) destMapField; + MapField<K, V> other = (MapField<K, V>) srcMapField; + if (!mine.isMutable()) { + mine.copy(); + } + mine.mergeFrom(other); + return mine; + } + + @Override + public int getSerializedSize(int number, Object mapField, Object mapDefaultEntry) { + return getSerializedSizeFull(number, mapField, mapDefaultEntry); + } + + @SuppressWarnings("unchecked") + private static <K, V> int getSerializedSizeFull( + int number, Object mapField, Object defaultEntryObject) { + // Full runtime allocates map fields lazily. + if (mapField == null) { + return 0; + } + + Map<K, V> map = ((MapField<K, V>) mapField).getMap(); + MapEntry<K, V> defaultEntry = (MapEntry<K, V>) defaultEntryObject; + if (map.isEmpty()) { + return 0; + } + int size = 0; + for (Map.Entry<K, V> entry : map.entrySet()) { + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeLengthDelimitedFieldSize( + MapEntryLite.computeSerializedSize( + defaultEntry.getMetadata(), entry.getKey(), entry.getValue())); + } + return size; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldSchemaLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldSchemaLite.java new file mode 100755 index 000000000..8a8c78de8 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/MapFieldSchemaLite.java @@ -0,0 +1,107 @@ +// 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.MapEntryLite.Metadata; +import java.util.Map; + +class MapFieldSchemaLite implements MapFieldSchema { + + @Override + public Map<?, ?> forMutableMapData(Object mapField) { + return (MapFieldLite<?, ?>) mapField; + } + + @Override + public Metadata<?, ?> forMapMetadata(Object mapDefaultEntry) { + return ((MapEntryLite<?, ?>) mapDefaultEntry).getMetadata(); + } + + @Override + public Map<?, ?> forMapData(Object mapField) { + return (MapFieldLite<?, ?>) mapField; + } + + @Override + public boolean isImmutable(Object mapField) { + return !((MapFieldLite<?, ?>) mapField).isMutable(); + } + + @Override + public Object toImmutable(Object mapField) { + ((MapFieldLite<?, ?>) mapField).makeImmutable(); + return mapField; + } + + @Override + public Object newMapField(Object unused) { + return MapFieldLite.emptyMapField().mutableCopy(); + } + + @Override + public Object mergeFrom(Object destMapField, Object srcMapField) { + return mergeFromLite(destMapField, srcMapField); + } + + @SuppressWarnings("unchecked") + private static <K, V> MapFieldLite<K, V> mergeFromLite(Object destMapField, Object srcMapField) { + MapFieldLite<K, V> mine = (MapFieldLite<K, V>) destMapField; + MapFieldLite<K, V> other = (MapFieldLite<K, V>) srcMapField; + if (!other.isEmpty()) { + if (!mine.isMutable()) { + mine = mine.mutableCopy(); + } + mine.mergeFrom(other); + } + return mine; + } + + @Override + public int getSerializedSize(int fieldNumber, Object mapField, Object mapDefaultEntry) { + return getSerializedSizeLite(fieldNumber, mapField, mapDefaultEntry); + } + + @SuppressWarnings("unchecked") + private static <K, V> int getSerializedSizeLite( + int fieldNumber, Object mapField, Object defaultEntry) { + MapFieldLite<K, V> mapFieldLite = (MapFieldLite<K, V>) mapField; + MapEntryLite<K, V> defaultEntryLite = (MapEntryLite<K, V>) defaultEntry; + + if (mapFieldLite.isEmpty()) { + return 0; + } + int size = 0; + for (Map.Entry<K, V> entry : mapFieldLite.entrySet()) { + size += defaultEntryLite.computeMessageSize(fieldNumber, entry.getKey(), entry.getValue()); + } + return size; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldSchemas.java b/java/core/src/main/java/com/google/protobuf/MapFieldSchemas.java new file mode 100755 index 000000000..b398c6102 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/MapFieldSchemas.java @@ -0,0 +1,53 @@ +// 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; + +final class MapFieldSchemas { + private static final MapFieldSchema FULL_SCHEMA = loadSchemaForFullRuntime(); + private static final MapFieldSchema LITE_SCHEMA = new MapFieldSchemaLite(); + + static MapFieldSchema full() { + return FULL_SCHEMA; + } + + static MapFieldSchema lite() { + return LITE_SCHEMA; + } + + private static MapFieldSchema loadSchemaForFullRuntime() { + try { + Class<?> clazz = Class.forName("com.google.protobuf.MapFieldSchemaFull"); + return (MapFieldSchema) clazz.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + return null; + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/MessageInfo.java b/java/core/src/main/java/com/google/protobuf/MessageInfo.java new file mode 100755 index 000000000..69e318696 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/MessageInfo.java @@ -0,0 +1,43 @@ +// 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; + +/** A MesageInfo object describes a proto message type. */ +interface MessageInfo { + /** Gets syntax for this type. */ + ProtoSyntax getSyntax(); + + /** Whether this type is MessageSet. */ + boolean isMessageSetWireFormat(); + + /** Gets the default instance of this type. */ + MessageLite getDefaultInstance(); +} diff --git a/java/core/src/main/java/com/google/protobuf/MessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/MessageInfoFactory.java new file mode 100755 index 000000000..005c26d05 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/MessageInfoFactory.java @@ -0,0 +1,41 @@ +// 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; + +/** A factory that creates {@link MessageInfo} instances for message types. */ +@ExperimentalApi +interface MessageInfoFactory { + /** Whether the message class is supported by this factory. */ + boolean isSupported(Class<?> clazz); + + /** Returns a information of the message class. */ + MessageInfo messageInfoFor(Class<?> clazz); +} diff --git a/java/core/src/main/java/com/google/protobuf/MessageSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSchema.java new file mode 100755 index 000000000..67584ed41 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/MessageSchema.java @@ -0,0 +1,5886 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.ArrayDecoders.decodeBoolList; +import static com.google.protobuf.ArrayDecoders.decodeBytes; +import static com.google.protobuf.ArrayDecoders.decodeBytesList; +import static com.google.protobuf.ArrayDecoders.decodeDouble; +import static com.google.protobuf.ArrayDecoders.decodeDoubleList; +import static com.google.protobuf.ArrayDecoders.decodeExtensionOrUnknownField; +import static com.google.protobuf.ArrayDecoders.decodeFixed32; +import static com.google.protobuf.ArrayDecoders.decodeFixed32List; +import static com.google.protobuf.ArrayDecoders.decodeFixed64; +import static com.google.protobuf.ArrayDecoders.decodeFixed64List; +import static com.google.protobuf.ArrayDecoders.decodeFloat; +import static com.google.protobuf.ArrayDecoders.decodeFloatList; +import static com.google.protobuf.ArrayDecoders.decodeGroupField; +import static com.google.protobuf.ArrayDecoders.decodeGroupList; +import static com.google.protobuf.ArrayDecoders.decodeMessageField; +import static com.google.protobuf.ArrayDecoders.decodeMessageList; +import static com.google.protobuf.ArrayDecoders.decodePackedBoolList; +import static com.google.protobuf.ArrayDecoders.decodePackedDoubleList; +import static com.google.protobuf.ArrayDecoders.decodePackedFixed32List; +import static com.google.protobuf.ArrayDecoders.decodePackedFixed64List; +import static com.google.protobuf.ArrayDecoders.decodePackedFloatList; +import static com.google.protobuf.ArrayDecoders.decodePackedSInt32List; +import static com.google.protobuf.ArrayDecoders.decodePackedSInt64List; +import static com.google.protobuf.ArrayDecoders.decodePackedVarint32List; +import static com.google.protobuf.ArrayDecoders.decodePackedVarint64List; +import static com.google.protobuf.ArrayDecoders.decodeSInt32List; +import static com.google.protobuf.ArrayDecoders.decodeSInt64List; +import static com.google.protobuf.ArrayDecoders.decodeString; +import static com.google.protobuf.ArrayDecoders.decodeStringList; +import static com.google.protobuf.ArrayDecoders.decodeStringListRequireUtf8; +import static com.google.protobuf.ArrayDecoders.decodeStringRequireUtf8; +import static com.google.protobuf.ArrayDecoders.decodeUnknownField; +import static com.google.protobuf.ArrayDecoders.decodeVarint32; +import static com.google.protobuf.ArrayDecoders.decodeVarint32List; +import static com.google.protobuf.ArrayDecoders.decodeVarint64; +import static com.google.protobuf.ArrayDecoders.decodeVarint64List; +import static com.google.protobuf.ArrayDecoders.skipField; + +import com.google.protobuf.ArrayDecoders.Registers; +import com.google.protobuf.ByteString.CodedBuilder; +import com.google.protobuf.FieldSet.FieldDescriptorLite; +import com.google.protobuf.Internal.EnumVerifier; +import com.google.protobuf.Internal.ProtobufList; +import com.google.protobuf.MapEntryLite.Metadata; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** Schema used for standard messages. */ +final class MessageSchema<T> implements Schema<T> { + private static final int INTS_PER_FIELD = 3; + private static final int OFFSET_BITS = 20; + private static final int OFFSET_MASK = 0XFFFFF; + private static final int FIELD_TYPE_MASK = 0x0FF00000; + private static final int REQUIRED_MASK = 0x10000000; + private static final int ENFORCE_UTF8_MASK = 0x20000000; + private static final int[] EMPTY_INT_ARRAY = new int[0]; + + /** An offset applied to the field type ID for scalar fields that are a member of a oneof. */ + static final int ONEOF_TYPE_OFFSET = 51 /* FieldType.MAP + 1 */; + + /** + * Keep a direct reference to the unsafe object so we don't need to go through the UnsafeUtil + * wrapper for every call. + */ + private static final sun.misc.Unsafe UNSAFE = UnsafeUtil.getUnsafe(); + + /** + * Holds all information for accessing the message fields. The layout is as follows (field + * positions are relative to the offset of the start of the field in the buffer): + * + * <p> + * + * <pre> + * [ 0 - 3] unused + * [ 4 - 31] field number + * [32 - 33] unused + * [34 - 34] whether UTF-8 enforcement should be applied to a string field. + * [35 - 35] whether the field is required + * [36 - 43] field type / for oneof: field type + {@link #ONEOF_TYPE_OFFSET} + * [44 - 63] field offset / oneof value field offset + * [64 - 69] unused + * [70 - 75] field presence mask shift (unused for oneof/repeated fields) + * [76 - 95] presence field offset / oneof case field offset / cached size field offset + * </pre> + */ + private final int[] buffer; + + /** + * Holds object references for fields. For each field entry in {@code buffer}, there are two + * corresponding entries in this array. The content is different from different field types: + * + * <pre> + * Map fields: + * objects[pos] = map default entry instance + * objects[pos + 1] = EnumVerifier if map value is enum, or message class reference if map + * value is message. + * Message fields: + * objects[pos] = null or cached message schema + * objects[pos + 1] = message class reference + * Enum fields: + * objects[pos] = null + * objects[pos + 1] = EnumVerifier + * </pre> + */ + private final Object[] objects; + + private final int minFieldNumber; + private final int maxFieldNumber; + + private final MessageLite defaultInstance; + private final boolean hasExtensions; + private final boolean lite; + private final boolean proto3; + // TODO(xiaofeng): Make both full-runtime and lite-runtime support cached field size. + private final boolean useCachedSizeField; + + /** Represents [checkInitialized positions, map field positions, repeated field offsets]. */ + private final int[] intArray; + + /** + * Values at indices 0 -> checkInitializedCount in intArray are positions to check for + * initialization. + */ + private final int checkInitializedCount; + + /** + * Values at indices checkInitializedCount -> repeatedFieldOffsetStart are map positions. + * Everything after that are repeated field offsets. + */ + private final int repeatedFieldOffsetStart; + + private final NewInstanceSchema newInstanceSchema; + private final ListFieldSchema listFieldSchema; + private final UnknownFieldSchema<?, ?> unknownFieldSchema; + private final ExtensionSchema<?> extensionSchema; + private final MapFieldSchema mapFieldSchema; + + private MessageSchema( + int[] buffer, + Object[] objects, + int minFieldNumber, + int maxFieldNumber, + MessageLite defaultInstance, + boolean proto3, + boolean useCachedSizeField, + int[] intArray, + int checkInitialized, + int mapFieldPositions, + NewInstanceSchema newInstanceSchema, + ListFieldSchema listFieldSchema, + UnknownFieldSchema<?, ?> unknownFieldSchema, + ExtensionSchema<?> extensionSchema, + MapFieldSchema mapFieldSchema) { + this.buffer = buffer; + this.objects = objects; + this.minFieldNumber = minFieldNumber; + this.maxFieldNumber = maxFieldNumber; + + this.lite = defaultInstance instanceof GeneratedMessageLite; + this.proto3 = proto3; + this.hasExtensions = extensionSchema != null && extensionSchema.hasExtensions(defaultInstance); + this.useCachedSizeField = useCachedSizeField; + + this.intArray = intArray; + this.checkInitializedCount = checkInitialized; + this.repeatedFieldOffsetStart = mapFieldPositions; + + this.newInstanceSchema = newInstanceSchema; + this.listFieldSchema = listFieldSchema; + this.unknownFieldSchema = unknownFieldSchema; + this.extensionSchema = extensionSchema; + this.defaultInstance = defaultInstance; + this.mapFieldSchema = mapFieldSchema; + } + + static <T> MessageSchema<T> newSchema( + Class<T> messageClass, + MessageInfo messageInfo, + NewInstanceSchema newInstanceSchema, + ListFieldSchema listFieldSchema, + UnknownFieldSchema<?, ?> unknownFieldSchema, + ExtensionSchema<?> extensionSchema, + MapFieldSchema mapFieldSchema) { + if (messageInfo instanceof RawMessageInfo) { + return newSchemaForRawMessageInfo( + (RawMessageInfo) messageInfo, + newInstanceSchema, + listFieldSchema, + unknownFieldSchema, + extensionSchema, + mapFieldSchema); + + } else { + return newSchemaForMessageInfo( + (StructuralMessageInfo) messageInfo, + newInstanceSchema, + listFieldSchema, + unknownFieldSchema, + extensionSchema, + mapFieldSchema); + } + } + + static <T> MessageSchema<T> newSchemaForRawMessageInfo( + RawMessageInfo messageInfo, + NewInstanceSchema newInstanceSchema, + ListFieldSchema listFieldSchema, + UnknownFieldSchema<?, ?> unknownFieldSchema, + ExtensionSchema<?> extensionSchema, + MapFieldSchema mapFieldSchema) { + final boolean isProto3 = messageInfo.getSyntax() == ProtoSyntax.PROTO3; + + String info = messageInfo.getStringInfo(); + final int length = info.length(); + int i = 0; + + int next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + final int flags = next; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + final int fieldCount = next; + + final int oneofCount; + final int hasBitsCount; + final int minFieldNumber; + final int maxFieldNumber; + final int numEntries; + final int mapFieldCount; + final int repeatedFieldCount; + final int checkInitialized; + final int[] intArray; + int objectsPosition; + if (fieldCount == 0) { + oneofCount = 0; + hasBitsCount = 0; + minFieldNumber = 0; + maxFieldNumber = 0; + numEntries = 0; + mapFieldCount = 0; + repeatedFieldCount = 0; + checkInitialized = 0; + intArray = EMPTY_INT_ARRAY; + objectsPosition = 0; + } else { + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + oneofCount = next; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + hasBitsCount = next; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + minFieldNumber = next; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + maxFieldNumber = next; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + numEntries = next; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + mapFieldCount = next; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + repeatedFieldCount = next; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + checkInitialized = next; + intArray = new int[checkInitialized + mapFieldCount + repeatedFieldCount]; + // Field objects are after a list of (oneof, oneofCase) pairs + a list of hasbits fields. + objectsPosition = oneofCount * 2 + hasBitsCount; + } + + final sun.misc.Unsafe unsafe = UNSAFE; + final Object[] messageInfoObjects = messageInfo.getObjects(); + int checkInitializedPosition = 0; + final Class<?> messageClass = messageInfo.getDefaultInstance().getClass(); + int[] buffer = new int[numEntries * INTS_PER_FIELD]; + Object[] objects = new Object[numEntries * 2]; + + int mapFieldIndex = checkInitialized; + int repeatedFieldIndex = checkInitialized + mapFieldCount; + + int bufferIndex = 0; + while (i < length) { + final int fieldNumber; + final int fieldTypeWithExtraBits; + final int fieldType; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + fieldNumber = next; + + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + fieldTypeWithExtraBits = next; + fieldType = fieldTypeWithExtraBits & 0xFF; + + if ((fieldTypeWithExtraBits & 0x400) != 0) { + intArray[checkInitializedPosition++] = bufferIndex; + } + + final int fieldOffset; + final int presenceMaskShift; + final int presenceFieldOffset; + + // Oneof + if (fieldType >= ONEOF_TYPE_OFFSET) { + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + int oneofIndex = next; + + final int oneofFieldType = fieldType - ONEOF_TYPE_OFFSET; + if (oneofFieldType == 9 /* FieldType.MESSAGE */ + || oneofFieldType == 17 /* FieldType.GROUP */) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++]; + } else if (oneofFieldType == 12 /* FieldType.ENUM */) { + // proto2 + if ((flags & 0x1) == 0x1) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++]; + } + } + + final java.lang.reflect.Field oneofField; + int index = oneofIndex * 2; + Object o = messageInfoObjects[index]; + if (o instanceof java.lang.reflect.Field) { + oneofField = (java.lang.reflect.Field) o; + } else { + oneofField = reflectField(messageClass, (String) o); + // Memoize java.lang.reflect.Field instances for oneof/hasbits fields, since they're + // potentially used for many Protobuf fields. Since there's a 1-1 mapping from the + // Protobuf field to the Java Field for non-oneofs, there's no benefit for memoizing + // those. + messageInfoObjects[index] = oneofField; + } + + fieldOffset = (int) unsafe.objectFieldOffset(oneofField); + + final java.lang.reflect.Field oneofCaseField; + index++; + o = messageInfoObjects[index]; + if (o instanceof java.lang.reflect.Field) { + oneofCaseField = (java.lang.reflect.Field) o; + } else { + oneofCaseField = reflectField(messageClass, (String) o); + messageInfoObjects[index] = oneofCaseField; + } + + presenceFieldOffset = (int) unsafe.objectFieldOffset(oneofCaseField); + presenceMaskShift = 0; + } else { + Field field = reflectField(messageClass, (String) messageInfoObjects[objectsPosition++]); + if (fieldType == 9 /* FieldType.MESSAGE */ || fieldType == 17 /* FieldType.GROUP */) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = field.getType(); + } else if (fieldType == 27 /* FieldType.MESSAGE_LIST */ + || fieldType == 49 /* FieldType.GROUP_LIST */) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++]; + } else if (fieldType == 12 /* FieldType.ENUM */ + || fieldType == 30 /* FieldType.ENUM_LIST */ + || fieldType == 44 /* FieldType.ENUM_LIST_PACKED */) { + if ((flags & 0x1) == 0x1) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++]; + } + } else if (fieldType == 50 /* FieldType.MAP */) { + intArray[mapFieldIndex++] = bufferIndex; + objects[bufferIndex / INTS_PER_FIELD * 2] = messageInfoObjects[objectsPosition++]; + if ((fieldTypeWithExtraBits & 0x800) != 0) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++]; + } + } + + fieldOffset = (int) unsafe.objectFieldOffset(field); + if ((flags & 0x1) == 0x1 && fieldType <= 17 /* FieldType.GROUP */) { + next = info.charAt(i++); + if (next >= 0xD800) { + int result = next & 0x1FFF; + int shift = 13; + while ((next = info.charAt(i++)) >= 0xD800) { + result |= (next & 0x1FFF) << shift; + shift += 13; + } + next = result | (next << shift); + } + int hasBitsIndex = next; + + final java.lang.reflect.Field hasBitsField; + int index = oneofCount * 2 + hasBitsIndex / 32; + Object o = messageInfoObjects[index]; + if (o instanceof java.lang.reflect.Field) { + hasBitsField = (java.lang.reflect.Field) o; + } else { + hasBitsField = reflectField(messageClass, (String) o); + messageInfoObjects[index] = hasBitsField; + } + + presenceFieldOffset = (int) unsafe.objectFieldOffset(hasBitsField); + presenceMaskShift = hasBitsIndex % 32; + } else { + presenceFieldOffset = 0; + presenceMaskShift = 0; + } + + if (fieldType >= 18 && fieldType <= 49) { + // Field types of repeated fields are in a consecutive range from 18 (DOUBLE_LIST) to + // 49 (GROUP_LIST). + intArray[repeatedFieldIndex++] = fieldOffset; + } + } + + buffer[bufferIndex++] = fieldNumber; + buffer[bufferIndex++] = + ((fieldTypeWithExtraBits & 0x200) != 0 ? ENFORCE_UTF8_MASK : 0) + | ((fieldTypeWithExtraBits & 0x100) != 0 ? REQUIRED_MASK : 0) + | (fieldType << OFFSET_BITS) + | fieldOffset; + buffer[bufferIndex++] = (presenceMaskShift << OFFSET_BITS) | presenceFieldOffset; + } + + return new MessageSchema<T>( + buffer, + objects, + minFieldNumber, + maxFieldNumber, + messageInfo.getDefaultInstance(), + isProto3, + /* useCachedSizeField= */ false, + intArray, + checkInitialized, + checkInitialized + mapFieldCount, + newInstanceSchema, + listFieldSchema, + unknownFieldSchema, + extensionSchema, + mapFieldSchema); + } + + private static java.lang.reflect.Field reflectField(Class<?> messageClass, String fieldName) { + try { + return messageClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + // Some Samsung devices lie about what fields are present via the getDeclaredField API so + // we do the for loop properly that they seem to have messed up... + java.lang.reflect.Field[] fields = messageClass.getDeclaredFields(); + for (java.lang.reflect.Field field : fields) { + if (fieldName.equals(field.getName())) { + return field; + } + } + + // If we make it here, the runtime still lies about what we know to be true at compile + // time. We throw to alert server monitoring for further remediation. + throw new RuntimeException( + "Field " + + fieldName + + " for " + + messageClass.getName() + + " not found. Known fields are " + + Arrays.toString(fields)); + } + } + + static <T> MessageSchema<T> newSchemaForMessageInfo( + StructuralMessageInfo messageInfo, + NewInstanceSchema newInstanceSchema, + ListFieldSchema listFieldSchema, + UnknownFieldSchema<?, ?> unknownFieldSchema, + ExtensionSchema<?> extensionSchema, + MapFieldSchema mapFieldSchema) { + final boolean isProto3 = messageInfo.getSyntax() == ProtoSyntax.PROTO3; + FieldInfo[] fis = messageInfo.getFields(); + final int minFieldNumber; + final int maxFieldNumber; + if (fis.length == 0) { + minFieldNumber = 0; + maxFieldNumber = 0; + } else { + minFieldNumber = fis[0].getFieldNumber(); + maxFieldNumber = fis[fis.length - 1].getFieldNumber(); + } + + final int numEntries = fis.length; + + int[] buffer = new int[numEntries * INTS_PER_FIELD]; + Object[] objects = new Object[numEntries * 2]; + + int mapFieldCount = 0; + int repeatedFieldCount = 0; + for (FieldInfo fi : fis) { + if (fi.getType() == FieldType.MAP) { + mapFieldCount++; + } else if (fi.getType().id() >= 18 && fi.getType().id() <= 49) { + // Field types of repeated fields are in a consecutive range from 18 (DOUBLE_LIST) to + // 49 (GROUP_LIST). + repeatedFieldCount++; + } + } + int[] mapFieldPositions = mapFieldCount > 0 ? new int[mapFieldCount] : null; + int[] repeatedFieldOffsets = repeatedFieldCount > 0 ? new int[repeatedFieldCount] : null; + mapFieldCount = 0; + repeatedFieldCount = 0; + + int[] checkInitialized = messageInfo.getCheckInitialized(); + if (checkInitialized == null) { + checkInitialized = EMPTY_INT_ARRAY; + } + int checkInitializedIndex = 0; + // Fill in the manifest data from the descriptors. + int fieldIndex = 0; + for (int bufferIndex = 0; fieldIndex < fis.length; bufferIndex += INTS_PER_FIELD) { + final FieldInfo fi = fis[fieldIndex]; + final int fieldNumber = fi.getFieldNumber(); + + // We found the entry for the next field. Store the entry in the manifest for + // this field and increment the field index. + storeFieldData(fi, buffer, bufferIndex, isProto3, objects); + + // Convert field number to index + if (checkInitializedIndex < checkInitialized.length + && checkInitialized[checkInitializedIndex] == fieldNumber) { + checkInitialized[checkInitializedIndex++] = bufferIndex; + } + + if (fi.getType() == FieldType.MAP) { + mapFieldPositions[mapFieldCount++] = bufferIndex; + } else if (fi.getType().id() >= 18 && fi.getType().id() <= 49) { + // Field types of repeated fields are in a consecutive range from 18 (DOUBLE_LIST) to + // 49 (GROUP_LIST). + repeatedFieldOffsets[repeatedFieldCount++] = + (int) UnsafeUtil.objectFieldOffset(fi.getField()); + } + + fieldIndex++; + } + + if (mapFieldPositions == null) { + mapFieldPositions = EMPTY_INT_ARRAY; + } + if (repeatedFieldOffsets == null) { + repeatedFieldOffsets = EMPTY_INT_ARRAY; + } + int[] combined = + new int[checkInitialized.length + mapFieldPositions.length + repeatedFieldOffsets.length]; + System.arraycopy(checkInitialized, 0, combined, 0, checkInitialized.length); + System.arraycopy( + mapFieldPositions, 0, combined, checkInitialized.length, mapFieldPositions.length); + System.arraycopy( + repeatedFieldOffsets, + 0, + combined, + checkInitialized.length + mapFieldPositions.length, + repeatedFieldOffsets.length); + + return new MessageSchema<T>( + buffer, + objects, + minFieldNumber, + maxFieldNumber, + messageInfo.getDefaultInstance(), + isProto3, + /* useCachedSizeField= */ true, + combined, + checkInitialized.length, + checkInitialized.length + mapFieldPositions.length, + newInstanceSchema, + listFieldSchema, + unknownFieldSchema, + extensionSchema, + mapFieldSchema); + } + + private static void storeFieldData( + FieldInfo fi, int[] buffer, int bufferIndex, boolean proto3, Object[] objects) { + final int fieldOffset; + final int typeId; + final int presenceMaskShift; + final int presenceFieldOffset; + + OneofInfo oneof = fi.getOneof(); + if (oneof != null) { + typeId = fi.getType().id() + ONEOF_TYPE_OFFSET; + fieldOffset = (int) UnsafeUtil.objectFieldOffset(oneof.getValueField()); + presenceFieldOffset = (int) UnsafeUtil.objectFieldOffset(oneof.getCaseField()); + presenceMaskShift = 0; + } else { + FieldType type = fi.getType(); + fieldOffset = (int) UnsafeUtil.objectFieldOffset(fi.getField()); + typeId = type.id(); + if (!proto3 && !type.isList() && !type.isMap()) { + presenceFieldOffset = (int) UnsafeUtil.objectFieldOffset(fi.getPresenceField()); + presenceMaskShift = Integer.numberOfTrailingZeros(fi.getPresenceMask()); + } else { + if (fi.getCachedSizeField() == null) { + presenceFieldOffset = 0; + presenceMaskShift = 0; + } else { + presenceFieldOffset = (int) UnsafeUtil.objectFieldOffset(fi.getCachedSizeField()); + presenceMaskShift = 0; + } + } + } + + buffer[bufferIndex] = fi.getFieldNumber(); + buffer[bufferIndex + 1] = + (fi.isEnforceUtf8() ? ENFORCE_UTF8_MASK : 0) + | (fi.isRequired() ? REQUIRED_MASK : 0) + | (typeId << OFFSET_BITS) + | fieldOffset; + buffer[bufferIndex + 2] = (presenceMaskShift << OFFSET_BITS) | presenceFieldOffset; + + Object messageFieldClass = fi.getMessageFieldClass(); + if (fi.getMapDefaultEntry() != null) { + objects[bufferIndex / INTS_PER_FIELD * 2] = fi.getMapDefaultEntry(); + if (messageFieldClass != null) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageFieldClass; + } else if (fi.getEnumVerifier() != null) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = fi.getEnumVerifier(); + } + } else { + if (messageFieldClass != null) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageFieldClass; + } else if (fi.getEnumVerifier() != null) { + objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = fi.getEnumVerifier(); + } + } + } + + @SuppressWarnings("unchecked") + @Override + public T newInstance() { + return (T) newInstanceSchema.newInstance(defaultInstance); + } + + @Override + public boolean equals(T message, T other) { + final int bufferLength = buffer.length; + for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) { + if (!equals(message, other, pos)) { + return false; + } + } + + Object messageUnknown = unknownFieldSchema.getFromMessage(message); + Object otherUnknown = unknownFieldSchema.getFromMessage(other); + if (!messageUnknown.equals(otherUnknown)) { + return false; + } + + if (hasExtensions) { + FieldSet<?> messageExtensions = extensionSchema.getExtensions(message); + FieldSet<?> otherExtensions = extensionSchema.getExtensions(other); + return messageExtensions.equals(otherExtensions); + } + return true; + } + + private boolean equals(T message, T other, int pos) { + final int typeAndOffset = typeAndOffsetAt(pos); + final long offset = offset(typeAndOffset); + + switch (type(typeAndOffset)) { + case 0: // DOUBLE: + return arePresentForEquals(message, other, pos) + && Double.doubleToLongBits(UnsafeUtil.getDouble(message, offset)) + == Double.doubleToLongBits(UnsafeUtil.getDouble(other, offset)); + case 1: // FLOAT: + return arePresentForEquals(message, other, pos) + && Float.floatToIntBits(UnsafeUtil.getFloat(message, offset)) + == Float.floatToIntBits(UnsafeUtil.getFloat(other, offset)); + case 2: // INT64: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset); + case 3: // UINT64: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset); + case 4: // INT32: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset); + case 5: // FIXED64: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset); + case 6: // FIXED32: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset); + case 7: // BOOL: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getBoolean(message, offset) == UnsafeUtil.getBoolean(other, offset); + case 8: // STRING: + return arePresentForEquals(message, other, pos) + && SchemaUtil.safeEquals( + UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset)); + case 9: // MESSAGE: + return arePresentForEquals(message, other, pos) + && SchemaUtil.safeEquals( + UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset)); + case 10: // BYTES: + return arePresentForEquals(message, other, pos) + && SchemaUtil.safeEquals( + UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset)); + case 11: // UINT32: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset); + case 12: // ENUM: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset); + case 13: // SFIXED32: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset); + case 14: // SFIXED64: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset); + case 15: // SINT32: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset); + case 16: // SINT64: + return arePresentForEquals(message, other, pos) + && UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset); + case 17: // GROUP: + return arePresentForEquals(message, other, pos) + && SchemaUtil.safeEquals( + UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset)); + + case 18: // DOUBLE_LIST: + case 19: // FLOAT_LIST: + case 20: // INT64_LIST: + case 21: // UINT64_LIST: + case 22: // INT32_LIST: + case 23: // FIXED64_LIST: + case 24: // FIXED32_LIST: + case 25: // BOOL_LIST: + case 26: // STRING_LIST: + case 27: // MESSAGE_LIST: + case 28: // BYTES_LIST: + case 29: // UINT32_LIST: + case 30: // ENUM_LIST: + case 31: // SFIXED32_LIST: + case 32: // SFIXED64_LIST: + case 33: // SINT32_LIST: + case 34: // SINT64_LIST: + case 35: // DOUBLE_LIST_PACKED: + case 36: // FLOAT_LIST_PACKED: + case 37: // INT64_LIST_PACKED: + case 38: // UINT64_LIST_PACKED: + case 39: // INT32_LIST_PACKED: + case 40: // FIXED64_LIST_PACKED: + case 41: // FIXED32_LIST_PACKED: + case 42: // BOOL_LIST_PACKED: + case 43: // UINT32_LIST_PACKED: + case 44: // ENUM_LIST_PACKED: + case 45: // SFIXED32_LIST_PACKED: + case 46: // SFIXED64_LIST_PACKED: + case 47: // SINT32_LIST_PACKED: + case 48: // SINT64_LIST_PACKED: + case 49: // GROUP_LIST: + return SchemaUtil.safeEquals( + UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset)); + case 50: // MAP: + return SchemaUtil.safeEquals( + UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset)); + case 51: // ONEOF_DOUBLE: + case 52: // ONEOF_FLOAT: + case 53: // ONEOF_INT64: + case 54: // ONEOF_UINT64: + case 55: // ONEOF_INT32: + case 56: // ONEOF_FIXED64: + case 57: // ONEOF_FIXED32: + case 58: // ONEOF_BOOL: + case 59: // ONEOF_STRING: + case 60: // ONEOF_MESSAGE: + case 61: // ONEOF_BYTES: + case 62: // ONEOF_UINT32: + case 63: // ONEOF_ENUM: + case 64: // ONEOF_SFIXED32: + case 65: // ONEOF_SFIXED64: + case 66: // ONEOF_SINT32: + case 67: // ONEOF_SINT64: + case 68: // ONEOF_GROUP: + return isOneofCaseEqual(message, other, pos) + && SchemaUtil.safeEquals( + UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset)); + default: + // Assume it's an empty entry - just go to the next entry. + return true; + } + } + + @Override + public int hashCode(T message) { + int hashCode = 0; + final int bufferLength = buffer.length; + for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) { + final int typeAndOffset = typeAndOffsetAt(pos); + final int entryNumber = numberAt(pos); + + final long offset = offset(typeAndOffset); + + switch (type(typeAndOffset)) { + case 0: // DOUBLE: + hashCode = + (hashCode * 53) + + Internal.hashLong( + Double.doubleToLongBits(UnsafeUtil.getDouble(message, offset))); + break; + case 1: // FLOAT: + hashCode = (hashCode * 53) + Float.floatToIntBits(UnsafeUtil.getFloat(message, offset)); + break; + case 2: // INT64: + hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset)); + break; + case 3: // UINT64: + hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset)); + break; + case 4: // INT32: + hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset)); + break; + case 5: // FIXED64: + hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset)); + break; + case 6: // FIXED32: + hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset)); + break; + case 7: // BOOL: + hashCode = (hashCode * 53) + Internal.hashBoolean(UnsafeUtil.getBoolean(message, offset)); + break; + case 8: // STRING: + hashCode = (hashCode * 53) + ((String) UnsafeUtil.getObject(message, offset)).hashCode(); + break; + case 9: // MESSAGE: + { + int protoHash = 37; + Object submessage = UnsafeUtil.getObject(message, offset); + if (submessage != null) { + protoHash = submessage.hashCode(); + } + hashCode = (53 * hashCode) + protoHash; + break; + } + case 10: // BYTES: + hashCode = (hashCode * 53) + UnsafeUtil.getObject(message, offset).hashCode(); + break; + case 11: // UINT32: + hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset)); + break; + case 12: // ENUM: + hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset)); + break; + case 13: // SFIXED32: + hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset)); + break; + case 14: // SFIXED64: + hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset)); + break; + case 15: // SINT32: + hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset)); + break; + case 16: // SINT64: + hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset)); + break; + + case 17: // GROUP: + { + int protoHash = 37; + Object submessage = UnsafeUtil.getObject(message, offset); + if (submessage != null) { + protoHash = submessage.hashCode(); + } + hashCode = (53 * hashCode) + protoHash; + break; + } + case 18: // DOUBLE_LIST: + case 19: // FLOAT_LIST: + case 20: // INT64_LIST: + case 21: // UINT64_LIST: + case 22: // INT32_LIST: + case 23: // FIXED64_LIST: + case 24: // FIXED32_LIST: + case 25: // BOOL_LIST: + case 26: // STRING_LIST: + case 27: // MESSAGE_LIST: + case 28: // BYTES_LIST: + case 29: // UINT32_LIST: + case 30: // ENUM_LIST: + case 31: // SFIXED32_LIST: + case 32: // SFIXED64_LIST: + case 33: // SINT32_LIST: + case 34: // SINT64_LIST: + case 35: // DOUBLE_LIST_PACKED: + case 36: // FLOAT_LIST_PACKED: + case 37: // INT64_LIST_PACKED: + case 38: // UINT64_LIST_PACKED: + case 39: // INT32_LIST_PACKED: + case 40: // FIXED64_LIST_PACKED: + case 41: // FIXED32_LIST_PACKED: + case 42: // BOOL_LIST_PACKED: + case 43: // UINT32_LIST_PACKED: + case 44: // ENUM_LIST_PACKED: + case 45: // SFIXED32_LIST_PACKED: + case 46: // SFIXED64_LIST_PACKED: + case 47: // SINT32_LIST_PACKED: + case 48: // SINT64_LIST_PACKED: + case 49: // GROUP_LIST: + hashCode = (hashCode * 53) + UnsafeUtil.getObject(message, offset).hashCode(); + break; + case 50: // MAP: + hashCode = (hashCode * 53) + UnsafeUtil.getObject(message, offset).hashCode(); + break; + case 51: // ONEOF_DOUBLE: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = + (hashCode * 53) + + Internal.hashLong(Double.doubleToLongBits(oneofDoubleAt(message, offset))); + } + break; + case 52: // ONEOF_FLOAT: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + Float.floatToIntBits(oneofFloatAt(message, offset)); + } + break; + case 53: // ONEOF_INT64: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset)); + } + break; + case 54: // ONEOF_UINT64: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset)); + } + break; + case 55: // ONEOF_INT32: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + (oneofIntAt(message, offset)); + } + break; + case 56: // ONEOF_FIXED64: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset)); + } + break; + case 57: // ONEOF_FIXED32: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + (oneofIntAt(message, offset)); + } + break; + case 58: // ONEOF_BOOL: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + Internal.hashBoolean(oneofBooleanAt(message, offset)); + } + break; + case 59: // ONEOF_STRING: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = + (hashCode * 53) + ((String) UnsafeUtil.getObject(message, offset)).hashCode(); + } + break; + case 60: // ONEOF_MESSAGE: + if (isOneofPresent(message, entryNumber, pos)) { + Object submessage = UnsafeUtil.getObject(message, offset); + hashCode = (53 * hashCode) + submessage.hashCode(); + } + break; + case 61: // ONEOF_BYTES: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + UnsafeUtil.getObject(message, offset).hashCode(); + } + break; + case 62: // ONEOF_UINT32: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + (oneofIntAt(message, offset)); + } + break; + case 63: // ONEOF_ENUM: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + (oneofIntAt(message, offset)); + } + break; + case 64: // ONEOF_SFIXED32: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + (oneofIntAt(message, offset)); + } + break; + case 65: // ONEOF_SFIXED64: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset)); + } + break; + case 66: // ONEOF_SINT32: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + (oneofIntAt(message, offset)); + } + break; + case 67: // ONEOF_SINT64: + if (isOneofPresent(message, entryNumber, pos)) { + hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset)); + } + break; + case 68: // ONEOF_GROUP: + if (isOneofPresent(message, entryNumber, pos)) { + Object submessage = UnsafeUtil.getObject(message, offset); + hashCode = (53 * hashCode) + submessage.hashCode(); + } + break; + default: + // Assume it's an empty entry - just go to the next entry. + break; + } + } + + hashCode = (hashCode * 53) + unknownFieldSchema.getFromMessage(message).hashCode(); + + if (hasExtensions) { + hashCode = (hashCode * 53) + extensionSchema.getExtensions(message).hashCode(); + } + + return hashCode; + } + + @Override + public void mergeFrom(T message, T other) { + if (other == null) { + throw new NullPointerException(); + } + for (int i = 0; i < buffer.length; i += INTS_PER_FIELD) { + // A separate method allows for better JIT optimizations + mergeSingleField(message, other, i); + } + + if (!proto3) { + SchemaUtil.mergeUnknownFields(unknownFieldSchema, message, other); + + if (hasExtensions) { + SchemaUtil.mergeExtensions(extensionSchema, message, other); + } + } + } + + private void mergeSingleField(T message, T other, int pos) { + final int typeAndOffset = typeAndOffsetAt(pos); + final long offset = offset(typeAndOffset); + final int number = numberAt(pos); + + switch (type(typeAndOffset)) { + case 0: // DOUBLE: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putDouble(message, offset, UnsafeUtil.getDouble(other, offset)); + setFieldPresent(message, pos); + } + break; + case 1: // FLOAT: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putFloat(message, offset, UnsafeUtil.getFloat(other, offset)); + setFieldPresent(message, pos); + } + break; + case 2: // INT64: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset)); + setFieldPresent(message, pos); + } + break; + case 3: // UINT64: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset)); + setFieldPresent(message, pos); + } + break; + case 4: // INT32: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset)); + setFieldPresent(message, pos); + } + break; + case 5: // FIXED64: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset)); + setFieldPresent(message, pos); + } + break; + case 6: // FIXED32: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset)); + setFieldPresent(message, pos); + } + break; + case 7: // BOOL: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putBoolean(message, offset, UnsafeUtil.getBoolean(other, offset)); + setFieldPresent(message, pos); + } + break; + case 8: // STRING: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putObject(message, offset, UnsafeUtil.getObject(other, offset)); + setFieldPresent(message, pos); + } + break; + case 9: // MESSAGE: + mergeMessage(message, other, pos); + break; + case 10: // BYTES: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putObject(message, offset, UnsafeUtil.getObject(other, offset)); + setFieldPresent(message, pos); + } + break; + case 11: // UINT32: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset)); + setFieldPresent(message, pos); + } + break; + case 12: // ENUM: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset)); + setFieldPresent(message, pos); + } + break; + case 13: // SFIXED32: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset)); + setFieldPresent(message, pos); + } + break; + case 14: // SFIXED64: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset)); + setFieldPresent(message, pos); + } + break; + case 15: // SINT32: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset)); + setFieldPresent(message, pos); + } + break; + case 16: // SINT64: + if (isFieldPresent(other, pos)) { + UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset)); + setFieldPresent(message, pos); + } + break; + case 17: // GROUP: + mergeMessage(message, other, pos); + break; + case 18: // DOUBLE_LIST: + case 19: // FLOAT_LIST: + case 20: // INT64_LIST: + case 21: // UINT64_LIST: + case 22: // INT32_LIST: + case 23: // FIXED64_LIST: + case 24: // FIXED32_LIST: + case 25: // BOOL_LIST: + case 26: // STRING_LIST: + case 27: // MESSAGE_LIST: + case 28: // BYTES_LIST: + case 29: // UINT32_LIST: + case 30: // ENUM_LIST: + case 31: // SFIXED32_LIST: + case 32: // SFIXED64_LIST: + case 33: // SINT32_LIST: + case 34: // SINT64_LIST: + case 35: // DOUBLE_LIST_PACKED: + case 36: // FLOAT_LIST_PACKED: + case 37: // INT64_LIST_PACKED: + case 38: // UINT64_LIST_PACKED: + case 39: // INT32_LIST_PACKED: + case 40: // FIXED64_LIST_PACKED: + case 41: // FIXED32_LIST_PACKED: + case 42: // BOOL_LIST_PACKED: + case 43: // UINT32_LIST_PACKED: + case 44: // ENUM_LIST_PACKED: + case 45: // SFIXED32_LIST_PACKED: + case 46: // SFIXED64_LIST_PACKED: + case 47: // SINT32_LIST_PACKED: + case 48: // SINT64_LIST_PACKED: + case 49: // GROUP_LIST: + listFieldSchema.mergeListsAt(message, other, offset); + break; + case 50: // MAP: + SchemaUtil.mergeMap(mapFieldSchema, message, other, offset); + break; + case 51: // ONEOF_DOUBLE: + case 52: // ONEOF_FLOAT: + case 53: // ONEOF_INT64: + case 54: // ONEOF_UINT64: + case 55: // ONEOF_INT32: + case 56: // ONEOF_FIXED64: + case 57: // ONEOF_FIXED32: + case 58: // ONEOF_BOOL: + case 59: // ONEOF_STRING: + if (isOneofPresent(other, number, pos)) { + UnsafeUtil.putObject(message, offset, UnsafeUtil.getObject(other, offset)); + setOneofPresent(message, number, pos); + } + break; + + case 60: // ONEOF_MESSAGE: + mergeOneofMessage(message, other, pos); + break; + case 61: // ONEOF_BYTES: + case 62: // ONEOF_UINT32: + case 63: // ONEOF_ENUM: + case 64: // ONEOF_SFIXED32: + case 65: // ONEOF_SFIXED64: + case 66: // ONEOF_SINT32: + case 67: // ONEOF_SINT64: + if (isOneofPresent(other, number, pos)) { + UnsafeUtil.putObject(message, offset, UnsafeUtil.getObject(other, offset)); + setOneofPresent(message, number, pos); + } + break; + case 68: // ONEOF_GROUP: + mergeOneofMessage(message, other, pos); + break; + default: + break; + } + } + + private void mergeMessage(T message, T other, int pos) { + final int typeAndOffset = typeAndOffsetAt(pos); + final long offset = offset(typeAndOffset); + + if (!isFieldPresent(other, pos)) { + return; + } + + Object mine = UnsafeUtil.getObject(message, offset); + Object theirs = UnsafeUtil.getObject(other, offset); + if (mine != null && theirs != null) { + Object merged = Internal.mergeMessage(mine, theirs); + UnsafeUtil.putObject(message, offset, merged); + setFieldPresent(message, pos); + } else if (theirs != null) { + UnsafeUtil.putObject(message, offset, theirs); + setFieldPresent(message, pos); + } + } + + private void mergeOneofMessage(T message, T other, int pos) { + int typeAndOffset = typeAndOffsetAt(pos); + int number = numberAt(pos); + long offset = offset(typeAndOffset); + + if (!isOneofPresent(other, number, pos)) { + return; + } + + Object mine = UnsafeUtil.getObject(message, offset); + Object theirs = UnsafeUtil.getObject(other, offset); + if (mine != null && theirs != null) { + Object merged = Internal.mergeMessage(mine, theirs); + UnsafeUtil.putObject(message, offset, merged); + setOneofPresent(message, number, pos); + } else if (theirs != null) { + UnsafeUtil.putObject(message, offset, theirs); + setOneofPresent(message, number, pos); + } + } + + @Override + public int getSerializedSize(T message) { + return proto3 ? getSerializedSizeProto3(message) : getSerializedSizeProto2(message); + } + + @SuppressWarnings("unchecked") + private int getSerializedSizeProto2(T message) { + int size = 0; + + final sun.misc.Unsafe unsafe = UNSAFE; + int currentPresenceFieldOffset = -1; + int currentPresenceField = 0; + for (int i = 0; i < buffer.length; i += INTS_PER_FIELD) { + final int typeAndOffset = typeAndOffsetAt(i); + final int number = numberAt(i); + + int fieldType = type(typeAndOffset); + int presenceMaskAndOffset = 0; + int presenceMask = 0; + if (fieldType <= 17) { + presenceMaskAndOffset = buffer[i + 2]; + final int presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK; + presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS); + if (presenceFieldOffset != currentPresenceFieldOffset) { + currentPresenceFieldOffset = presenceFieldOffset; + currentPresenceField = unsafe.getInt(message, (long) presenceFieldOffset); + } + } else if (useCachedSizeField + && fieldType >= FieldType.DOUBLE_LIST_PACKED.id() + && fieldType <= FieldType.SINT64_LIST_PACKED.id()) { + presenceMaskAndOffset = buffer[i + 2] & OFFSET_MASK; + } + + final long offset = offset(typeAndOffset); + + switch (fieldType) { + case 0: // DOUBLE: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeDoubleSize(number, 0); + } + break; + case 1: // FLOAT: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeFloatSize(number, 0); + } + break; + case 2: // INT64: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeInt64Size(number, unsafe.getLong(message, offset)); + } + break; + case 3: // UINT64: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeUInt64Size(number, unsafe.getLong(message, offset)); + } + break; + case 4: // INT32: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeInt32Size(number, unsafe.getInt(message, offset)); + } + break; + case 5: // FIXED64: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeFixed64Size(number, 0); + } + break; + case 6: // FIXED32: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeFixed32Size(number, 0); + } + break; + case 7: // BOOL: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeBoolSize(number, true); + } + break; + case 8: // STRING: + if ((currentPresenceField & presenceMask) != 0) { + Object value = unsafe.getObject(message, offset); + if (value instanceof ByteString) { + size += CodedOutputStream.computeBytesSize(number, (ByteString) value); + } else { + size += CodedOutputStream.computeStringSize(number, (String) value); + } + } + break; + case 9: // MESSAGE: + if ((currentPresenceField & presenceMask) != 0) { + Object value = unsafe.getObject(message, offset); + size += SchemaUtil.computeSizeMessage(number, value, getMessageFieldSchema(i)); + } + break; + case 10: // BYTES: + if ((currentPresenceField & presenceMask) != 0) { + ByteString value = (ByteString) unsafe.getObject(message, offset); + size += CodedOutputStream.computeBytesSize(number, value); + } + break; + case 11: // UINT32: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeUInt32Size(number, unsafe.getInt(message, offset)); + } + break; + case 12: // ENUM: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeEnumSize(number, unsafe.getInt(message, offset)); + } + break; + case 13: // SFIXED32: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeSFixed32Size(number, 0); + } + break; + case 14: // SFIXED64: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeSFixed64Size(number, 0); + } + break; + case 15: // SINT32: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeSInt32Size(number, unsafe.getInt(message, offset)); + } + break; + case 16: // SINT64: + if ((currentPresenceField & presenceMask) != 0) { + size += CodedOutputStream.computeSInt64Size(number, unsafe.getLong(message, offset)); + } + break; + case 17: // GROUP: + if ((currentPresenceField & presenceMask) != 0) { + size += + CodedOutputStream.computeGroupSize( + number, + (MessageLite) unsafe.getObject(message, offset), + getMessageFieldSchema(i)); + } + break; + case 18: // DOUBLE_LIST: + size += + SchemaUtil.computeSizeFixed64List( + number, (List<?>) unsafe.getObject(message, offset), false); + break; + case 19: // FLOAT_LIST: + size += + SchemaUtil.computeSizeFixed32List( + number, (List<?>) unsafe.getObject(message, offset), false); + break; + case 20: // INT64_LIST: + size += + SchemaUtil.computeSizeInt64List( + number, (List<Long>) unsafe.getObject(message, offset), false); + break; + case 21: // UINT64_LIST: + size += + SchemaUtil.computeSizeUInt64List( + number, (List<Long>) unsafe.getObject(message, offset), false); + break; + case 22: // INT32_LIST: + size += + SchemaUtil.computeSizeInt32List( + number, (List<Integer>) unsafe.getObject(message, offset), false); + break; + case 23: // FIXED64_LIST: + size += + SchemaUtil.computeSizeFixed64List( + number, (List<?>) unsafe.getObject(message, offset), false); + break; + case 24: // FIXED32_LIST: + size += + SchemaUtil.computeSizeFixed32List( + number, (List<?>) unsafe.getObject(message, offset), false); + break; + case 25: // BOOL_LIST: + size += + SchemaUtil.computeSizeBoolList( + number, (List<?>) unsafe.getObject(message, offset), false); + break; + case 26: // STRING_LIST: + size += + SchemaUtil.computeSizeStringList(number, (List<?>) unsafe.getObject(message, offset)); + break; + case 27: // MESSAGE_LIST: + size += + SchemaUtil.computeSizeMessageList( + number, (List<?>) unsafe.getObject(message, offset), getMessageFieldSchema(i)); + break; + case 28: // BYTES_LIST: + size += + SchemaUtil.computeSizeByteStringList( + number, (List<ByteString>) unsafe.getObject(message, offset)); + break; + case 29: // UINT32_LIST: + size += + SchemaUtil.computeSizeUInt32List( + number, (List<Integer>) unsafe.getObject(message, offset), false); + break; + case 30: // ENUM_LIST: + size += + SchemaUtil.computeSizeEnumList( + number, (List<Integer>) unsafe.getObject(message, offset), false); + break; + case 31: // SFIXED32_LIST: + size += + SchemaUtil.computeSizeFixed32List( + number, (List<Integer>) unsafe.getObject(message, offset), false); + break; + case 32: // SFIXED64_LIST: + size += + SchemaUtil.computeSizeFixed64List( + number, (List<Long>) unsafe.getObject(message, offset), false); + break; + case 33: // SINT32_LIST: + size += + SchemaUtil.computeSizeSInt32List( + number, (List<Integer>) unsafe.getObject(message, offset), false); + break; + case 34: // SINT64_LIST: + size += + SchemaUtil.computeSizeSInt64List( + number, (List<Long>) unsafe.getObject(message, offset), false); + break; + case 35: + { // DOUBLE_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed64ListNoTag( + (List<Double>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 36: + { // FLOAT_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed32ListNoTag( + (List<Float>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 37: + { // INT64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeInt64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 38: + { // UINT64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeUInt64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 39: + { // INT32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeInt32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 40: + { // FIXED64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 41: + { // FIXED32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 42: + { // BOOL_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeBoolListNoTag( + (List<Boolean>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 43: + { // UINT32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeUInt32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 44: + { // ENUM_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeEnumListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 45: + { // SFIXED32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 46: + { // SFIXED64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 47: + { // SINT32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeSInt32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 48: + { // SINT64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeSInt64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) presenceMaskAndOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 49: // GROUP_LIST: + size += + SchemaUtil.computeSizeGroupList( + number, + (List<MessageLite>) unsafe.getObject(message, offset), + getMessageFieldSchema(i)); + break; + case 50: // MAP: + // TODO(dweis): Use schema cache. + size += + mapFieldSchema.getSerializedSize( + number, unsafe.getObject(message, offset), getMapFieldDefaultEntry(i)); + break; + case 51: // ONEOF_DOUBLE: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeDoubleSize(number, 0); + } + break; + case 52: // ONEOF_FLOAT: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeFloatSize(number, 0); + } + break; + case 53: // ONEOF_INT64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeInt64Size(number, oneofLongAt(message, offset)); + } + break; + case 54: // ONEOF_UINT64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeUInt64Size(number, oneofLongAt(message, offset)); + } + break; + case 55: // ONEOF_INT32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeInt32Size(number, oneofIntAt(message, offset)); + } + break; + case 56: // ONEOF_FIXED64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeFixed64Size(number, 0); + } + break; + case 57: // ONEOF_FIXED32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeFixed32Size(number, 0); + } + break; + case 58: // ONEOF_BOOL: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeBoolSize(number, true); + } + break; + case 59: // ONEOF_STRING: + if (isOneofPresent(message, number, i)) { + Object value = unsafe.getObject(message, offset); + if (value instanceof ByteString) { + size += CodedOutputStream.computeBytesSize(number, (ByteString) value); + } else { + size += CodedOutputStream.computeStringSize(number, (String) value); + } + } + break; + case 60: // ONEOF_MESSAGE: + if (isOneofPresent(message, number, i)) { + Object value = unsafe.getObject(message, offset); + size += SchemaUtil.computeSizeMessage(number, value, getMessageFieldSchema(i)); + } + break; + case 61: // ONEOF_BYTES: + if (isOneofPresent(message, number, i)) { + size += + CodedOutputStream.computeBytesSize( + number, (ByteString) unsafe.getObject(message, offset)); + } + break; + case 62: // ONEOF_UINT32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeUInt32Size(number, oneofIntAt(message, offset)); + } + break; + case 63: // ONEOF_ENUM: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeEnumSize(number, oneofIntAt(message, offset)); + } + break; + case 64: // ONEOF_SFIXED32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeSFixed32Size(number, 0); + } + break; + case 65: // ONEOF_SFIXED64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeSFixed64Size(number, 0); + } + break; + case 66: // ONEOF_SINT32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeSInt32Size(number, oneofIntAt(message, offset)); + } + break; + case 67: // ONEOF_SINT64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeSInt64Size(number, oneofLongAt(message, offset)); + } + break; + case 68: // ONEOF_GROUP: + if (isOneofPresent(message, number, i)) { + size += + CodedOutputStream.computeGroupSize( + number, + (MessageLite) unsafe.getObject(message, offset), + getMessageFieldSchema(i)); + } + break; + default: + // Assume it's an empty entry. + } + } + + size += getUnknownFieldsSerializedSize(unknownFieldSchema, message); + + if (hasExtensions) { + size += extensionSchema.getExtensions(message).getSerializedSize(); + } + + return size; + } + + private int getSerializedSizeProto3(T message) { + final sun.misc.Unsafe unsafe = UNSAFE; + int size = 0; + for (int i = 0; i < buffer.length; i += INTS_PER_FIELD) { + final int typeAndOffset = typeAndOffsetAt(i); + final int fieldType = type(typeAndOffset); + final int number = numberAt(i); + + final long offset = offset(typeAndOffset); + final int cachedSizeOffset = + fieldType >= FieldType.DOUBLE_LIST_PACKED.id() + && fieldType <= FieldType.SINT64_LIST_PACKED.id() + ? buffer[i + 2] & OFFSET_MASK + : 0; + + switch (fieldType) { + case 0: // DOUBLE: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeDoubleSize(number, 0); + } + break; + case 1: // FLOAT: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeFloatSize(number, 0); + } + break; + case 2: // INT64: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeInt64Size(number, UnsafeUtil.getLong(message, offset)); + } + break; + case 3: // UINT64: + if (isFieldPresent(message, i)) { + size += + CodedOutputStream.computeUInt64Size(number, UnsafeUtil.getLong(message, offset)); + } + break; + case 4: // INT32: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeInt32Size(number, UnsafeUtil.getInt(message, offset)); + } + break; + case 5: // FIXED64: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeFixed64Size(number, 0); + } + break; + case 6: // FIXED32: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeFixed32Size(number, 0); + } + break; + case 7: // BOOL: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeBoolSize(number, true); + } + break; + case 8: // STRING: + if (isFieldPresent(message, i)) { + Object value = UnsafeUtil.getObject(message, offset); + if (value instanceof ByteString) { + size += CodedOutputStream.computeBytesSize(number, (ByteString) value); + } else { + size += CodedOutputStream.computeStringSize(number, (String) value); + } + } + break; + case 9: // MESSAGE: + if (isFieldPresent(message, i)) { + Object value = UnsafeUtil.getObject(message, offset); + size += SchemaUtil.computeSizeMessage(number, value, getMessageFieldSchema(i)); + } + break; + case 10: // BYTES: + if (isFieldPresent(message, i)) { + ByteString value = (ByteString) UnsafeUtil.getObject(message, offset); + size += CodedOutputStream.computeBytesSize(number, value); + } + break; + case 11: // UINT32: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeUInt32Size(number, UnsafeUtil.getInt(message, offset)); + } + break; + case 12: // ENUM: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeEnumSize(number, UnsafeUtil.getInt(message, offset)); + } + break; + case 13: // SFIXED32: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeSFixed32Size(number, 0); + } + break; + case 14: // SFIXED64: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeSFixed64Size(number, 0); + } + break; + case 15: // SINT32: + if (isFieldPresent(message, i)) { + size += CodedOutputStream.computeSInt32Size(number, UnsafeUtil.getInt(message, offset)); + } + break; + case 16: // SINT64: + if (isFieldPresent(message, i)) { + size += + CodedOutputStream.computeSInt64Size(number, UnsafeUtil.getLong(message, offset)); + } + break; + case 17: // GROUP: + if (isFieldPresent(message, i)) { + size += + CodedOutputStream.computeGroupSize( + number, + (MessageLite) UnsafeUtil.getObject(message, offset), + getMessageFieldSchema(i)); + } + break; + case 18: // DOUBLE_LIST: + size += SchemaUtil.computeSizeFixed64List(number, listAt(message, offset), false); + break; + case 19: // FLOAT_LIST: + size += SchemaUtil.computeSizeFixed32List(number, listAt(message, offset), false); + break; + case 20: // INT64_LIST: + size += + SchemaUtil.computeSizeInt64List(number, (List<Long>) listAt(message, offset), false); + break; + case 21: // UINT64_LIST: + size += + SchemaUtil.computeSizeUInt64List(number, (List<Long>) listAt(message, offset), false); + break; + case 22: // INT32_LIST: + size += + SchemaUtil.computeSizeInt32List( + number, (List<Integer>) listAt(message, offset), false); + break; + case 23: // FIXED64_LIST: + size += SchemaUtil.computeSizeFixed64List(number, listAt(message, offset), false); + break; + case 24: // FIXED32_LIST: + size += SchemaUtil.computeSizeFixed32List(number, listAt(message, offset), false); + break; + case 25: // BOOL_LIST: + size += SchemaUtil.computeSizeBoolList(number, listAt(message, offset), false); + break; + case 26: // STRING_LIST: + size += SchemaUtil.computeSizeStringList(number, listAt(message, offset)); + break; + case 27: // MESSAGE_LIST: + size += + SchemaUtil.computeSizeMessageList( + number, listAt(message, offset), getMessageFieldSchema(i)); + break; + case 28: // BYTES_LIST: + size += + SchemaUtil.computeSizeByteStringList( + number, (List<ByteString>) listAt(message, offset)); + break; + case 29: // UINT32_LIST: + size += + SchemaUtil.computeSizeUInt32List( + number, (List<Integer>) listAt(message, offset), false); + break; + case 30: // ENUM_LIST: + size += + SchemaUtil.computeSizeEnumList( + number, (List<Integer>) listAt(message, offset), false); + break; + case 31: // SFIXED32_LIST: + size += SchemaUtil.computeSizeFixed32List(number, listAt(message, offset), false); + break; + case 32: // SFIXED64_LIST: + size += SchemaUtil.computeSizeFixed64List(number, listAt(message, offset), false); + break; + case 33: // SINT32_LIST: + size += + SchemaUtil.computeSizeSInt32List( + number, (List<Integer>) listAt(message, offset), false); + break; + case 34: // SINT64_LIST: + size += + SchemaUtil.computeSizeSInt64List(number, (List<Long>) listAt(message, offset), false); + break; + case 35: + { // DOUBLE_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed64ListNoTag( + (List<Double>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 36: + { // FLOAT_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed32ListNoTag( + (List<Float>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 37: + { // INT64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeInt64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 38: + { // UINT64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeUInt64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 39: + { // INT32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeInt32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 40: + { // FIXED64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 41: + { // FIXED32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 42: + { // BOOL_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeBoolListNoTag( + (List<Boolean>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 43: + { // UINT32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeUInt32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 44: + { // ENUM_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeEnumListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 45: + { // SFIXED32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 46: + { // SFIXED64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeFixed64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 47: + { // SINT32_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeSInt32ListNoTag( + (List<Integer>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 48: + { // SINT64_LIST_PACKED: + int fieldSize = + SchemaUtil.computeSizeSInt64ListNoTag( + (List<Long>) unsafe.getObject(message, offset)); + if (fieldSize > 0) { + if (useCachedSizeField) { + unsafe.putInt(message, (long) cachedSizeOffset, fieldSize); + } + size += + CodedOutputStream.computeTagSize(number) + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + } + break; + } + case 49: // GROUP_LIST: + size += + SchemaUtil.computeSizeGroupList( + number, (List<MessageLite>) listAt(message, offset), getMessageFieldSchema(i)); + break; + case 50: // MAP: + // TODO(dweis): Use schema cache. + size += + mapFieldSchema.getSerializedSize( + number, UnsafeUtil.getObject(message, offset), getMapFieldDefaultEntry(i)); + break; + case 51: // ONEOF_DOUBLE: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeDoubleSize(number, 0); + } + break; + case 52: // ONEOF_FLOAT: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeFloatSize(number, 0); + } + break; + case 53: // ONEOF_INT64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeInt64Size(number, oneofLongAt(message, offset)); + } + break; + case 54: // ONEOF_UINT64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeUInt64Size(number, oneofLongAt(message, offset)); + } + break; + case 55: // ONEOF_INT32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeInt32Size(number, oneofIntAt(message, offset)); + } + break; + case 56: // ONEOF_FIXED64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeFixed64Size(number, 0); + } + break; + case 57: // ONEOF_FIXED32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeFixed32Size(number, 0); + } + break; + case 58: // ONEOF_BOOL: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeBoolSize(number, true); + } + break; + case 59: // ONEOF_STRING: + if (isOneofPresent(message, number, i)) { + Object value = UnsafeUtil.getObject(message, offset); + if (value instanceof ByteString) { + size += CodedOutputStream.computeBytesSize(number, (ByteString) value); + } else { + size += CodedOutputStream.computeStringSize(number, (String) value); + } + } + break; + case 60: // ONEOF_MESSAGE: + if (isOneofPresent(message, number, i)) { + Object value = UnsafeUtil.getObject(message, offset); + size += SchemaUtil.computeSizeMessage(number, value, getMessageFieldSchema(i)); + } + break; + case 61: // ONEOF_BYTES: + if (isOneofPresent(message, number, i)) { + size += + CodedOutputStream.computeBytesSize( + number, (ByteString) UnsafeUtil.getObject(message, offset)); + } + break; + case 62: // ONEOF_UINT32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeUInt32Size(number, oneofIntAt(message, offset)); + } + break; + case 63: // ONEOF_ENUM: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeEnumSize(number, oneofIntAt(message, offset)); + } + break; + case 64: // ONEOF_SFIXED32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeSFixed32Size(number, 0); + } + break; + case 65: // ONEOF_SFIXED64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeSFixed64Size(number, 0); + } + break; + case 66: // ONEOF_SINT32: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeSInt32Size(number, oneofIntAt(message, offset)); + } + break; + case 67: // ONEOF_SINT64: + if (isOneofPresent(message, number, i)) { + size += CodedOutputStream.computeSInt64Size(number, oneofLongAt(message, offset)); + } + break; + case 68: // ONEOF_GROUP: + if (isOneofPresent(message, number, i)) { + size += + CodedOutputStream.computeGroupSize( + number, + (MessageLite) UnsafeUtil.getObject(message, offset), + getMessageFieldSchema(i)); + } + break; + default: + // Assume it's an empty entry. + } + } + + size += getUnknownFieldsSerializedSize(unknownFieldSchema, message); + + return size; + } + + private <UT, UB> int getUnknownFieldsSerializedSize( + UnknownFieldSchema<UT, UB> schema, T message) { + UT unknowns = schema.getFromMessage(message); + return schema.getSerializedSize(unknowns); + } + + private static List<?> listAt(Object message, long offset) { + return (List<?>) UnsafeUtil.getObject(message, offset); + } + + @SuppressWarnings("unchecked") + @Override + // TODO(nathanmittler): Consider serializing oneof fields last so that only one entry per + // oneof is actually serialized. This would mean that we would violate the serialization order + // contract. It should also be noted that Go currently does this. + public void writeTo(T message, Writer writer) throws IOException { + if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) { + writeFieldsInDescendingOrder(message, writer); + } else { + if (proto3) { + writeFieldsInAscendingOrderProto3(message, writer); + } else { + writeFieldsInAscendingOrderProto2(message, writer); + } + } + } + + @SuppressWarnings("unchecked") + private void writeFieldsInAscendingOrderProto2(T message, Writer writer) throws IOException { + Iterator<? extends Map.Entry<?, ?>> extensionIterator = null; + Map.Entry nextExtension = null; + if (hasExtensions) { + FieldSet<?> extensions = extensionSchema.getExtensions(message); + if (!extensions.isEmpty()) { + extensionIterator = extensions.iterator(); + nextExtension = extensionIterator.next(); + } + } + int currentPresenceFieldOffset = -1; + int currentPresenceField = 0; + final int bufferLength = buffer.length; + final sun.misc.Unsafe unsafe = UNSAFE; + for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) { + final int typeAndOffset = typeAndOffsetAt(pos); + final int number = numberAt(pos); + final int fieldType = type(typeAndOffset); + + int presenceMaskAndOffset = 0; + int presenceMask = 0; + if (!proto3 && fieldType <= 17) { + presenceMaskAndOffset = buffer[pos + 2]; + final int presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK; + if (presenceFieldOffset != currentPresenceFieldOffset) { + currentPresenceFieldOffset = presenceFieldOffset; + currentPresenceField = unsafe.getInt(message, (long) presenceFieldOffset); + } + presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS); + } + + // Write any extensions that need to be written before the current field. + while (nextExtension != null && extensionSchema.extensionNumber(nextExtension) <= number) { + extensionSchema.serializeExtension(writer, nextExtension); + nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null; + } + final long offset = offset(typeAndOffset); + + switch (fieldType) { + case 0: // DOUBLE: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeDouble(number, doubleAt(message, offset)); + } + break; + case 1: // FLOAT: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeFloat(number, floatAt(message, offset)); + } + break; + case 2: // INT64: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeInt64(number, unsafe.getLong(message, offset)); + } + break; + case 3: // UINT64: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeUInt64(number, unsafe.getLong(message, offset)); + } + break; + case 4: // INT32: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeInt32(number, unsafe.getInt(message, offset)); + } + break; + case 5: // FIXED64: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeFixed64(number, unsafe.getLong(message, offset)); + } + break; + case 6: // FIXED32: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeFixed32(number, unsafe.getInt(message, offset)); + } + break; + case 7: // BOOL: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeBool(number, booleanAt(message, offset)); + } + break; + case 8: // STRING: + if ((currentPresenceField & presenceMask) != 0) { + writeString(number, unsafe.getObject(message, offset), writer); + } + break; + case 9: // MESSAGE: + if ((currentPresenceField & presenceMask) != 0) { + Object value = unsafe.getObject(message, offset); + writer.writeMessage(number, value, getMessageFieldSchema(pos)); + } + break; + case 10: // BYTES: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeBytes(number, (ByteString) unsafe.getObject(message, offset)); + } + break; + case 11: // UINT32: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeUInt32(number, unsafe.getInt(message, offset)); + } + break; + case 12: // ENUM: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeEnum(number, unsafe.getInt(message, offset)); + } + break; + case 13: // SFIXED32: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeSFixed32(number, unsafe.getInt(message, offset)); + } + break; + case 14: // SFIXED64: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeSFixed64(number, unsafe.getLong(message, offset)); + } + break; + case 15: // SINT32: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeSInt32(number, unsafe.getInt(message, offset)); + } + break; + case 16: // SINT64: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeSInt64(number, unsafe.getLong(message, offset)); + } + break; + case 17: // GROUP: + if ((currentPresenceField & presenceMask) != 0) { + writer.writeGroup( + number, unsafe.getObject(message, offset), getMessageFieldSchema(pos)); + } + break; + case 18: // DOUBLE_LIST: + SchemaUtil.writeDoubleList( + numberAt(pos), (List<Double>) unsafe.getObject(message, offset), writer, false); + break; + case 19: // FLOAT_LIST: + SchemaUtil.writeFloatList( + numberAt(pos), (List<Float>) unsafe.getObject(message, offset), writer, false); + break; + case 20: // INT64_LIST: + SchemaUtil.writeInt64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, false); + break; + case 21: // UINT64_LIST: + SchemaUtil.writeUInt64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, false); + break; + case 22: // INT32_LIST: + SchemaUtil.writeInt32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, false); + break; + case 23: // FIXED64_LIST: + SchemaUtil.writeFixed64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, false); + break; + case 24: // FIXED32_LIST: + SchemaUtil.writeFixed32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, false); + break; + case 25: // BOOL_LIST: + SchemaUtil.writeBoolList( + numberAt(pos), (List<Boolean>) unsafe.getObject(message, offset), writer, false); + break; + case 26: // STRING_LIST: + SchemaUtil.writeStringList( + numberAt(pos), (List<String>) unsafe.getObject(message, offset), writer); + break; + case 27: // MESSAGE_LIST: + SchemaUtil.writeMessageList( + numberAt(pos), + (List<?>) unsafe.getObject(message, offset), + writer, + getMessageFieldSchema(pos)); + break; + case 28: // BYTES_LIST: + SchemaUtil.writeBytesList( + numberAt(pos), (List<ByteString>) unsafe.getObject(message, offset), writer); + break; + case 29: // UINT32_LIST: + SchemaUtil.writeUInt32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, false); + break; + case 30: // ENUM_LIST: + SchemaUtil.writeEnumList( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, false); + break; + case 31: // SFIXED32_LIST: + SchemaUtil.writeSFixed32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, false); + break; + case 32: // SFIXED64_LIST: + SchemaUtil.writeSFixed64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, false); + break; + case 33: // SINT32_LIST: + SchemaUtil.writeSInt32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, false); + break; + case 34: // SINT64_LIST: + SchemaUtil.writeSInt64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, false); + break; + case 35: // DOUBLE_LIST_PACKED: + // TODO(xiaofeng): Make use of cached field size to speed up serialization. + SchemaUtil.writeDoubleList( + numberAt(pos), (List<Double>) unsafe.getObject(message, offset), writer, true); + break; + case 36: // FLOAT_LIST_PACKED: + SchemaUtil.writeFloatList( + numberAt(pos), (List<Float>) unsafe.getObject(message, offset), writer, true); + break; + case 37: // INT64_LIST_PACKED: + SchemaUtil.writeInt64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, true); + break; + case 38: // UINT64_LIST_PACKED: + SchemaUtil.writeUInt64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, true); + break; + case 39: // INT32_LIST_PACKED: + SchemaUtil.writeInt32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, true); + break; + case 40: // FIXED64_LIST_PACKED: + SchemaUtil.writeFixed64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, true); + break; + case 41: // FIXED32_LIST_PACKED: + SchemaUtil.writeFixed32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, true); + + break; + case 42: // BOOL_LIST_PACKED: + SchemaUtil.writeBoolList( + numberAt(pos), (List<Boolean>) unsafe.getObject(message, offset), writer, true); + break; + case 43: // UINT32_LIST_PACKED: + SchemaUtil.writeUInt32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, true); + break; + case 44: // ENUM_LIST_PACKED: + SchemaUtil.writeEnumList( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, true); + break; + case 45: // SFIXED32_LIST_PACKED: + SchemaUtil.writeSFixed32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, true); + break; + case 46: // SFIXED64_LIST_PACKED: + SchemaUtil.writeSFixed64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, true); + break; + case 47: // SINT32_LIST_PACKED: + SchemaUtil.writeSInt32List( + numberAt(pos), (List<Integer>) unsafe.getObject(message, offset), writer, true); + break; + case 48: // SINT64_LIST_PACKED: + SchemaUtil.writeSInt64List( + numberAt(pos), (List<Long>) unsafe.getObject(message, offset), writer, true); + break; + case 49: // GROUP_LIST: + SchemaUtil.writeGroupList( + numberAt(pos), + (List<?>) unsafe.getObject(message, offset), + writer, + getMessageFieldSchema(pos)); + break; + case 50: // MAP: + // TODO(dweis): Use schema cache. + writeMapHelper(writer, number, unsafe.getObject(message, offset), pos); + break; + case 51: // ONEOF_DOUBLE: + if (isOneofPresent(message, number, pos)) { + writer.writeDouble(number, oneofDoubleAt(message, offset)); + } + break; + case 52: // ONEOF_FLOAT: + if (isOneofPresent(message, number, pos)) { + writer.writeFloat(number, oneofFloatAt(message, offset)); + } + break; + case 53: // ONEOF_INT64: + if (isOneofPresent(message, number, pos)) { + writer.writeInt64(number, oneofLongAt(message, offset)); + } + break; + case 54: // ONEOF_UINT64: + if (isOneofPresent(message, number, pos)) { + writer.writeUInt64(number, oneofLongAt(message, offset)); + } + break; + case 55: // ONEOF_INT32: + if (isOneofPresent(message, number, pos)) { + writer.writeInt32(number, oneofIntAt(message, offset)); + } + break; + case 56: // ONEOF_FIXED64: + if (isOneofPresent(message, number, pos)) { + writer.writeFixed64(number, oneofLongAt(message, offset)); + } + break; + case 57: // ONEOF_FIXED32: + if (isOneofPresent(message, number, pos)) { + writer.writeFixed32(number, oneofIntAt(message, offset)); + } + break; + case 58: // ONEOF_BOOL: + if (isOneofPresent(message, number, pos)) { + writer.writeBool(number, oneofBooleanAt(message, offset)); + } + break; + case 59: // ONEOF_STRING: + if (isOneofPresent(message, number, pos)) { + writeString(number, unsafe.getObject(message, offset), writer); + } + break; + case 60: // ONEOF_MESSAGE: + if (isOneofPresent(message, number, pos)) { + Object value = unsafe.getObject(message, offset); + writer.writeMessage(number, value, getMessageFieldSchema(pos)); + } + break; + case 61: // ONEOF_BYTES: + if (isOneofPresent(message, number, pos)) { + writer.writeBytes(number, (ByteString) unsafe.getObject(message, offset)); + } + break; + case 62: // ONEOF_UINT32: + if (isOneofPresent(message, number, pos)) { + writer.writeUInt32(number, oneofIntAt(message, offset)); + } + break; + case 63: // ONEOF_ENUM: + if (isOneofPresent(message, number, pos)) { + writer.writeEnum(number, oneofIntAt(message, offset)); + } + break; + case 64: // ONEOF_SFIXED32: + if (isOneofPresent(message, number, pos)) { + writer.writeSFixed32(number, oneofIntAt(message, offset)); + } + break; + case 65: // ONEOF_SFIXED64: + if (isOneofPresent(message, number, pos)) { + writer.writeSFixed64(number, oneofLongAt(message, offset)); + } + break; + case 66: // ONEOF_SINT32: + if (isOneofPresent(message, number, pos)) { + writer.writeSInt32(number, oneofIntAt(message, offset)); + } + break; + case 67: // ONEOF_SINT64: + if (isOneofPresent(message, number, pos)) { + writer.writeSInt64(number, oneofLongAt(message, offset)); + } + break; + case 68: // ONEOF_GROUP: + if (isOneofPresent(message, number, pos)) { + writer.writeGroup( + number, unsafe.getObject(message, offset), getMessageFieldSchema(pos)); + } + break; + default: + // Assume it's an empty entry - just go to the next entry. + break; + } + } + while (nextExtension != null) { + extensionSchema.serializeExtension(writer, nextExtension); + nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null; + } + writeUnknownInMessageTo(unknownFieldSchema, message, writer); + } + + @SuppressWarnings("unchecked") + private void writeFieldsInAscendingOrderProto3(T message, Writer writer) throws IOException { + Iterator<? extends Map.Entry<?, ?>> extensionIterator = null; + Map.Entry nextExtension = null; + if (hasExtensions) { + FieldSet<?> extensions = extensionSchema.getExtensions(message); + if (!extensions.isEmpty()) { + extensionIterator = extensions.iterator(); + nextExtension = extensionIterator.next(); + } + } + + final int bufferLength = buffer.length; + for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) { + final int typeAndOffset = typeAndOffsetAt(pos); + final int number = numberAt(pos); + + // Write any extensions that need to be written before the current field. + while (nextExtension != null && extensionSchema.extensionNumber(nextExtension) <= number) { + extensionSchema.serializeExtension(writer, nextExtension); + nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null; + } + + switch (type(typeAndOffset)) { + case 0: // DOUBLE: + if (isFieldPresent(message, pos)) { + writer.writeDouble(number, doubleAt(message, offset(typeAndOffset))); + } + break; + case 1: // FLOAT: + if (isFieldPresent(message, pos)) { + writer.writeFloat(number, floatAt(message, offset(typeAndOffset))); + } + break; + case 2: // INT64: + if (isFieldPresent(message, pos)) { + writer.writeInt64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 3: // UINT64: + if (isFieldPresent(message, pos)) { + writer.writeUInt64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 4: // INT32: + if (isFieldPresent(message, pos)) { + writer.writeInt32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 5: // FIXED64: + if (isFieldPresent(message, pos)) { + writer.writeFixed64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 6: // FIXED32: + if (isFieldPresent(message, pos)) { + writer.writeFixed32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 7: // BOOL: + if (isFieldPresent(message, pos)) { + writer.writeBool(number, booleanAt(message, offset(typeAndOffset))); + } + break; + case 8: // STRING: + if (isFieldPresent(message, pos)) { + writeString(number, UnsafeUtil.getObject(message, offset(typeAndOffset)), writer); + } + break; + case 9: // MESSAGE: + if (isFieldPresent(message, pos)) { + Object value = UnsafeUtil.getObject(message, offset(typeAndOffset)); + writer.writeMessage(number, value, getMessageFieldSchema(pos)); + } + break; + case 10: // BYTES: + if (isFieldPresent(message, pos)) { + writer.writeBytes( + number, (ByteString) UnsafeUtil.getObject(message, offset(typeAndOffset))); + } + break; + case 11: // UINT32: + if (isFieldPresent(message, pos)) { + writer.writeUInt32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 12: // ENUM: + if (isFieldPresent(message, pos)) { + writer.writeEnum(number, intAt(message, offset(typeAndOffset))); + } + break; + case 13: // SFIXED32: + if (isFieldPresent(message, pos)) { + writer.writeSFixed32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 14: // SFIXED64: + if (isFieldPresent(message, pos)) { + writer.writeSFixed64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 15: // SINT32: + if (isFieldPresent(message, pos)) { + writer.writeSInt32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 16: // SINT64: + if (isFieldPresent(message, pos)) { + writer.writeSInt64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 17: // GROUP: + if (isFieldPresent(message, pos)) { + writer.writeGroup( + number, + UnsafeUtil.getObject(message, offset(typeAndOffset)), + getMessageFieldSchema(pos)); + } + break; + case 18: // DOUBLE_LIST: + SchemaUtil.writeDoubleList( + numberAt(pos), + (List<Double>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 19: // FLOAT_LIST: + SchemaUtil.writeFloatList( + numberAt(pos), + (List<Float>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 20: // INT64_LIST: + SchemaUtil.writeInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 21: // UINT64_LIST: + SchemaUtil.writeUInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 22: // INT32_LIST: + SchemaUtil.writeInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 23: // FIXED64_LIST: + SchemaUtil.writeFixed64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 24: // FIXED32_LIST: + SchemaUtil.writeFixed32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 25: // BOOL_LIST: + SchemaUtil.writeBoolList( + numberAt(pos), + (List<Boolean>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 26: // STRING_LIST: + SchemaUtil.writeStringList( + numberAt(pos), + (List<String>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer); + break; + case 27: // MESSAGE_LIST: + SchemaUtil.writeMessageList( + numberAt(pos), + (List<?>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + getMessageFieldSchema(pos)); + break; + case 28: // BYTES_LIST: + SchemaUtil.writeBytesList( + numberAt(pos), + (List<ByteString>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer); + break; + case 29: // UINT32_LIST: + SchemaUtil.writeUInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 30: // ENUM_LIST: + SchemaUtil.writeEnumList( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 31: // SFIXED32_LIST: + SchemaUtil.writeSFixed32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 32: // SFIXED64_LIST: + SchemaUtil.writeSFixed64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 33: // SINT32_LIST: + SchemaUtil.writeSInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 34: // SINT64_LIST: + SchemaUtil.writeSInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 35: // DOUBLE_LIST_PACKED: + // TODO(xiaofeng): Make use of cached field size to speed up serialization. + SchemaUtil.writeDoubleList( + numberAt(pos), + (List<Double>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 36: // FLOAT_LIST_PACKED: + SchemaUtil.writeFloatList( + numberAt(pos), + (List<Float>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 37: // INT64_LIST_PACKED: + SchemaUtil.writeInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 38: // UINT64_LIST_PACKED: + SchemaUtil.writeUInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 39: // INT32_LIST_PACKED: + SchemaUtil.writeInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 40: // FIXED64_LIST_PACKED: + SchemaUtil.writeFixed64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 41: // FIXED32_LIST_PACKED: + SchemaUtil.writeFixed32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + + break; + case 42: // BOOL_LIST_PACKED: + SchemaUtil.writeBoolList( + numberAt(pos), + (List<Boolean>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 43: // UINT32_LIST_PACKED: + SchemaUtil.writeUInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 44: // ENUM_LIST_PACKED: + SchemaUtil.writeEnumList( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 45: // SFIXED32_LIST_PACKED: + SchemaUtil.writeSFixed32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 46: // SFIXED64_LIST_PACKED: + SchemaUtil.writeSFixed64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 47: // SINT32_LIST_PACKED: + SchemaUtil.writeSInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 48: // SINT64_LIST_PACKED: + SchemaUtil.writeSInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 49: // GROUP_LIST: + SchemaUtil.writeGroupList( + numberAt(pos), + (List<?>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + getMessageFieldSchema(pos)); + break; + case 50: // MAP: + // TODO(dweis): Use schema cache. + writeMapHelper(writer, number, UnsafeUtil.getObject(message, offset(typeAndOffset)), pos); + break; + case 51: // ONEOF_DOUBLE: + if (isOneofPresent(message, number, pos)) { + writer.writeDouble(number, oneofDoubleAt(message, offset(typeAndOffset))); + } + break; + case 52: // ONEOF_FLOAT: + if (isOneofPresent(message, number, pos)) { + writer.writeFloat(number, oneofFloatAt(message, offset(typeAndOffset))); + } + break; + case 53: // ONEOF_INT64: + if (isOneofPresent(message, number, pos)) { + writer.writeInt64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 54: // ONEOF_UINT64: + if (isOneofPresent(message, number, pos)) { + writer.writeUInt64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 55: // ONEOF_INT32: + if (isOneofPresent(message, number, pos)) { + writer.writeInt32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 56: // ONEOF_FIXED64: + if (isOneofPresent(message, number, pos)) { + writer.writeFixed64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 57: // ONEOF_FIXED32: + if (isOneofPresent(message, number, pos)) { + writer.writeFixed32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 58: // ONEOF_BOOL: + if (isOneofPresent(message, number, pos)) { + writer.writeBool(number, oneofBooleanAt(message, offset(typeAndOffset))); + } + break; + case 59: // ONEOF_STRING: + if (isOneofPresent(message, number, pos)) { + writeString(number, UnsafeUtil.getObject(message, offset(typeAndOffset)), writer); + } + break; + case 60: // ONEOF_MESSAGE: + if (isOneofPresent(message, number, pos)) { + Object value = UnsafeUtil.getObject(message, offset(typeAndOffset)); + writer.writeMessage(number, value, getMessageFieldSchema(pos)); + } + break; + case 61: // ONEOF_BYTES: + if (isOneofPresent(message, number, pos)) { + writer.writeBytes( + number, (ByteString) UnsafeUtil.getObject(message, offset(typeAndOffset))); + } + break; + case 62: // ONEOF_UINT32: + if (isOneofPresent(message, number, pos)) { + writer.writeUInt32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 63: // ONEOF_ENUM: + if (isOneofPresent(message, number, pos)) { + writer.writeEnum(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 64: // ONEOF_SFIXED32: + if (isOneofPresent(message, number, pos)) { + writer.writeSFixed32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 65: // ONEOF_SFIXED64: + if (isOneofPresent(message, number, pos)) { + writer.writeSFixed64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 66: // ONEOF_SINT32: + if (isOneofPresent(message, number, pos)) { + writer.writeSInt32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 67: // ONEOF_SINT64: + if (isOneofPresent(message, number, pos)) { + writer.writeSInt64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 68: // ONEOF_GROUP: + if (isOneofPresent(message, number, pos)) { + writer.writeGroup( + number, + UnsafeUtil.getObject(message, offset(typeAndOffset)), + getMessageFieldSchema(pos)); + } + break; + default: + // Assume it's an empty entry - just go to the next entry. + break; + } + } + while (nextExtension != null) { + extensionSchema.serializeExtension(writer, nextExtension); + nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null; + } + writeUnknownInMessageTo(unknownFieldSchema, message, writer); + } + + @SuppressWarnings("unchecked") + private void writeFieldsInDescendingOrder(T message, Writer writer) throws IOException { + writeUnknownInMessageTo(unknownFieldSchema, message, writer); + + Iterator<? extends Map.Entry<?, ?>> extensionIterator = null; + Map.Entry nextExtension = null; + if (hasExtensions) { + FieldSet<?> extensions = extensionSchema.getExtensions(message); + if (!extensions.isEmpty()) { + extensionIterator = extensions.descendingIterator(); + nextExtension = extensionIterator.next(); + } + } + + for (int pos = buffer.length - INTS_PER_FIELD; pos >= 0; pos -= INTS_PER_FIELD) { + final int typeAndOffset = typeAndOffsetAt(pos); + final int number = numberAt(pos); + + // Write any extensions that need to be written before the current field. + while (nextExtension != null && extensionSchema.extensionNumber(nextExtension) > number) { + extensionSchema.serializeExtension(writer, nextExtension); + nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null; + } + + switch (type(typeAndOffset)) { + case 0: // DOUBLE: + if (isFieldPresent(message, pos)) { + writer.writeDouble(number, doubleAt(message, offset(typeAndOffset))); + } + break; + case 1: // FLOAT: + if (isFieldPresent(message, pos)) { + writer.writeFloat(number, floatAt(message, offset(typeAndOffset))); + } + break; + case 2: // INT64: + if (isFieldPresent(message, pos)) { + writer.writeInt64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 3: // UINT64: + if (isFieldPresent(message, pos)) { + writer.writeUInt64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 4: // INT32: + if (isFieldPresent(message, pos)) { + writer.writeInt32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 5: // FIXED64: + if (isFieldPresent(message, pos)) { + writer.writeFixed64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 6: // FIXED32: + if (isFieldPresent(message, pos)) { + writer.writeFixed32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 7: // BOOL: + if (isFieldPresent(message, pos)) { + writer.writeBool(number, booleanAt(message, offset(typeAndOffset))); + } + break; + case 8: // STRING: + if (isFieldPresent(message, pos)) { + writeString(number, UnsafeUtil.getObject(message, offset(typeAndOffset)), writer); + } + break; + case 9: // MESSAGE: + if (isFieldPresent(message, pos)) { + Object value = UnsafeUtil.getObject(message, offset(typeAndOffset)); + writer.writeMessage(number, value, getMessageFieldSchema(pos)); + } + break; + case 10: // BYTES: + if (isFieldPresent(message, pos)) { + writer.writeBytes( + number, (ByteString) UnsafeUtil.getObject(message, offset(typeAndOffset))); + } + break; + case 11: // UINT32: + if (isFieldPresent(message, pos)) { + writer.writeUInt32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 12: // ENUM: + if (isFieldPresent(message, pos)) { + writer.writeEnum(number, intAt(message, offset(typeAndOffset))); + } + break; + case 13: // SFIXED32: + if (isFieldPresent(message, pos)) { + writer.writeSFixed32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 14: // SFIXED64: + if (isFieldPresent(message, pos)) { + writer.writeSFixed64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 15: // SINT32: + if (isFieldPresent(message, pos)) { + writer.writeSInt32(number, intAt(message, offset(typeAndOffset))); + } + break; + case 16: // SINT64: + if (isFieldPresent(message, pos)) { + writer.writeSInt64(number, longAt(message, offset(typeAndOffset))); + } + break; + case 17: // GROUP: + if (isFieldPresent(message, pos)) { + writer.writeGroup( + number, + UnsafeUtil.getObject(message, offset(typeAndOffset)), + getMessageFieldSchema(pos)); + } + break; + case 18: // DOUBLE_LIST: + SchemaUtil.writeDoubleList( + numberAt(pos), + (List<Double>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 19: // FLOAT_LIST: + SchemaUtil.writeFloatList( + numberAt(pos), + (List<Float>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 20: // INT64_LIST: + SchemaUtil.writeInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 21: // UINT64_LIST: + SchemaUtil.writeUInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 22: // INT32_LIST: + SchemaUtil.writeInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 23: // FIXED64_LIST: + SchemaUtil.writeFixed64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 24: // FIXED32_LIST: + SchemaUtil.writeFixed32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 25: // BOOL_LIST: + SchemaUtil.writeBoolList( + numberAt(pos), + (List<Boolean>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 26: // STRING_LIST: + SchemaUtil.writeStringList( + numberAt(pos), + (List<String>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer); + break; + case 27: // MESSAGE_LIST: + SchemaUtil.writeMessageList( + numberAt(pos), + (List<?>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + getMessageFieldSchema(pos)); + break; + case 28: // BYTES_LIST: + SchemaUtil.writeBytesList( + numberAt(pos), + (List<ByteString>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer); + break; + case 29: // UINT32_LIST: + SchemaUtil.writeUInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 30: // ENUM_LIST: + SchemaUtil.writeEnumList( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 31: // SFIXED32_LIST: + SchemaUtil.writeSFixed32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 32: // SFIXED64_LIST: + SchemaUtil.writeSFixed64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 33: // SINT32_LIST: + SchemaUtil.writeSInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 34: // SINT64_LIST: + SchemaUtil.writeSInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + false); + break; + case 35: // DOUBLE_LIST_PACKED: + SchemaUtil.writeDoubleList( + numberAt(pos), + (List<Double>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 36: // FLOAT_LIST_PACKED: + SchemaUtil.writeFloatList( + numberAt(pos), + (List<Float>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 37: // INT64_LIST_PACKED: + SchemaUtil.writeInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 38: // UINT64_LIST_PACKED: + SchemaUtil.writeUInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 39: // INT32_LIST_PACKED: + SchemaUtil.writeInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 40: // FIXED64_LIST_PACKED: + SchemaUtil.writeFixed64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 41: // FIXED32_LIST_PACKED: + SchemaUtil.writeFixed32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + + break; + case 42: // BOOL_LIST_PACKED: + SchemaUtil.writeBoolList( + numberAt(pos), + (List<Boolean>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 43: // UINT32_LIST_PACKED: + SchemaUtil.writeUInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 44: // ENUM_LIST_PACKED: + SchemaUtil.writeEnumList( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 45: // SFIXED32_LIST_PACKED: + SchemaUtil.writeSFixed32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 46: // SFIXED64_LIST_PACKED: + SchemaUtil.writeSFixed64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 47: // SINT32_LIST_PACKED: + SchemaUtil.writeSInt32List( + numberAt(pos), + (List<Integer>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 48: // SINT64_LIST_PACKED: + SchemaUtil.writeSInt64List( + numberAt(pos), + (List<Long>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + true); + break; + case 49: // GROUP_LIST: + SchemaUtil.writeGroupList( + numberAt(pos), + (List<?>) UnsafeUtil.getObject(message, offset(typeAndOffset)), + writer, + getMessageFieldSchema(pos)); + break; + case 50: // MAP: + // TODO(dweis): Use schema cache. + writeMapHelper(writer, number, UnsafeUtil.getObject(message, offset(typeAndOffset)), pos); + break; + case 51: // ONEOF_DOUBLE: + if (isOneofPresent(message, number, pos)) { + writer.writeDouble(number, oneofDoubleAt(message, offset(typeAndOffset))); + } + break; + case 52: // ONEOF_FLOAT: + if (isOneofPresent(message, number, pos)) { + writer.writeFloat(number, oneofFloatAt(message, offset(typeAndOffset))); + } + break; + case 53: // ONEOF_INT64: + if (isOneofPresent(message, number, pos)) { + writer.writeInt64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 54: // ONEOF_UINT64: + if (isOneofPresent(message, number, pos)) { + writer.writeUInt64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 55: // ONEOF_INT32: + if (isOneofPresent(message, number, pos)) { + writer.writeInt32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 56: // ONEOF_FIXED64: + if (isOneofPresent(message, number, pos)) { + writer.writeFixed64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 57: // ONEOF_FIXED32: + if (isOneofPresent(message, number, pos)) { + writer.writeFixed32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 58: // ONEOF_BOOL: + if (isOneofPresent(message, number, pos)) { + writer.writeBool(number, oneofBooleanAt(message, offset(typeAndOffset))); + } + break; + case 59: // ONEOF_STRING: + if (isOneofPresent(message, number, pos)) { + writeString(number, UnsafeUtil.getObject(message, offset(typeAndOffset)), writer); + } + break; + case 60: // ONEOF_MESSAGE: + if (isOneofPresent(message, number, pos)) { + Object value = UnsafeUtil.getObject(message, offset(typeAndOffset)); + writer.writeMessage(number, value, getMessageFieldSchema(pos)); + } + break; + case 61: // ONEOF_BYTES: + if (isOneofPresent(message, number, pos)) { + writer.writeBytes( + number, (ByteString) UnsafeUtil.getObject(message, offset(typeAndOffset))); + } + break; + case 62: // ONEOF_UINT32: + if (isOneofPresent(message, number, pos)) { + writer.writeUInt32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 63: // ONEOF_ENUM: + if (isOneofPresent(message, number, pos)) { + writer.writeEnum(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 64: // ONEOF_SFIXED32: + if (isOneofPresent(message, number, pos)) { + writer.writeSFixed32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 65: // ONEOF_SFIXED64: + if (isOneofPresent(message, number, pos)) { + writer.writeSFixed64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 66: // ONEOF_SINT32: + if (isOneofPresent(message, number, pos)) { + writer.writeSInt32(number, oneofIntAt(message, offset(typeAndOffset))); + } + break; + case 67: // ONEOF_SINT64: + if (isOneofPresent(message, number, pos)) { + writer.writeSInt64(number, oneofLongAt(message, offset(typeAndOffset))); + } + break; + case 68: // ONEOF_GROUP: + if (isOneofPresent(message, number, pos)) { + writer.writeGroup( + number, + UnsafeUtil.getObject(message, offset(typeAndOffset)), + getMessageFieldSchema(pos)); + } + break; + default: + break; + } + } + while (nextExtension != null) { + extensionSchema.serializeExtension(writer, nextExtension); + nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null; + } + } + + @SuppressWarnings("unchecked") + private <K, V> void writeMapHelper(Writer writer, int number, Object mapField, int pos) + throws IOException { + if (mapField != null) { + writer.writeMap( + number, + (MapEntryLite.Metadata<K, V>) mapFieldSchema.forMapMetadata(getMapFieldDefaultEntry(pos)), + (Map<K, V>) mapFieldSchema.forMapData(mapField)); + } + } + + private <UT, UB> void writeUnknownInMessageTo( + UnknownFieldSchema<UT, UB> schema, T message, Writer writer) throws IOException { + schema.writeTo(schema.getFromMessage(message), writer); + } + + @Override + public void mergeFrom(T message, Reader reader, ExtensionRegistryLite extensionRegistry) + throws IOException { + if (extensionRegistry == null) { + throw new NullPointerException(); + } + mergeFromHelper(unknownFieldSchema, extensionSchema, message, reader, extensionRegistry); + } + + /** + * A helper method for wildcard capture of {@code unknownFieldSchema}. See: + * https://docs.oracle.com/javase/tutorial/java/generics/capture.html + */ + private <UT, UB, ET extends FieldDescriptorLite<ET>> void mergeFromHelper( + UnknownFieldSchema<UT, UB> unknownFieldSchema, + ExtensionSchema<ET> extensionSchema, + T message, + Reader reader, + ExtensionRegistryLite extensionRegistry) + throws IOException { + UB unknownFields = null; + FieldSet<ET> extensions = null; + try { + while (true) { + final int number = reader.getFieldNumber(); + final int pos = positionForFieldNumber(number); + if (pos < 0) { + if (number == Reader.READ_DONE) { + return; + } + // Check if it's an extension. + Object extension = + !hasExtensions + ? null + : extensionSchema.findExtensionByNumber( + extensionRegistry, defaultInstance, number); + if (extension != null) { + if (extensions == null) { + extensions = extensionSchema.getMutableExtensions(message); + } + unknownFields = + extensionSchema.parseExtension( + reader, + extension, + extensionRegistry, + extensions, + unknownFields, + unknownFieldSchema); + continue; + } + if (unknownFieldSchema.shouldDiscardUnknownFields(reader)) { + if (reader.skipField()) { + continue; + } + } else { + if (unknownFields == null) { + unknownFields = unknownFieldSchema.getBuilderFromMessage(message); + } + // Unknown field. + if (unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) { + continue; + } + } + // Done reading. + return; + } + final int typeAndOffset = typeAndOffsetAt(pos); + + try { + switch (type(typeAndOffset)) { + case 0: // DOUBLE: + UnsafeUtil.putDouble(message, offset(typeAndOffset), reader.readDouble()); + setFieldPresent(message, pos); + break; + case 1: // FLOAT: + UnsafeUtil.putFloat(message, offset(typeAndOffset), reader.readFloat()); + setFieldPresent(message, pos); + break; + case 2: // INT64: + UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readInt64()); + setFieldPresent(message, pos); + break; + case 3: // UINT64: + UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readUInt64()); + setFieldPresent(message, pos); + break; + case 4: // INT32: + UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readInt32()); + setFieldPresent(message, pos); + break; + case 5: // FIXED64: + UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readFixed64()); + setFieldPresent(message, pos); + break; + case 6: // FIXED32: + UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readFixed32()); + setFieldPresent(message, pos); + break; + case 7: // BOOL: + UnsafeUtil.putBoolean(message, offset(typeAndOffset), reader.readBool()); + setFieldPresent(message, pos); + break; + case 8: // STRING: + readString(message, typeAndOffset, reader); + setFieldPresent(message, pos); + break; + case 9: + { // MESSAGE: + if (isFieldPresent(message, pos)) { + Object mergedResult = + Internal.mergeMessage( + UnsafeUtil.getObject(message, offset(typeAndOffset)), + reader.readMessageBySchemaWithCheck( + (Schema<T>) getMessageFieldSchema(pos), extensionRegistry)); + UnsafeUtil.putObject(message, offset(typeAndOffset), mergedResult); + } else { + UnsafeUtil.putObject( + message, + offset(typeAndOffset), + reader.readMessageBySchemaWithCheck( + (Schema<T>) getMessageFieldSchema(pos), extensionRegistry)); + setFieldPresent(message, pos); + } + break; + } + case 10: // BYTES: + UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readBytes()); + setFieldPresent(message, pos); + break; + case 11: // UINT32: + UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readUInt32()); + setFieldPresent(message, pos); + break; + case 12: // ENUM: + { + int enumValue = reader.readEnum(); + EnumVerifier enumVerifier = getEnumFieldVerifier(pos); + if (enumVerifier == null || enumVerifier.isInRange(enumValue)) { + UnsafeUtil.putInt(message, offset(typeAndOffset), enumValue); + setFieldPresent(message, pos); + } else { + unknownFields = + SchemaUtil.storeUnknownEnum( + number, enumValue, unknownFields, unknownFieldSchema); + } + break; + } + case 13: // SFIXED32: + UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readSFixed32()); + setFieldPresent(message, pos); + break; + case 14: // SFIXED64: + UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readSFixed64()); + setFieldPresent(message, pos); + break; + case 15: // SINT32: + UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readSInt32()); + setFieldPresent(message, pos); + break; + case 16: // SINT64: + UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readSInt64()); + setFieldPresent(message, pos); + break; + case 17: + { // GROUP: + if (isFieldPresent(message, pos)) { + Object mergedResult = + Internal.mergeMessage( + UnsafeUtil.getObject(message, offset(typeAndOffset)), + reader.readGroupBySchemaWithCheck( + (Schema<T>) getMessageFieldSchema(pos), extensionRegistry)); + UnsafeUtil.putObject(message, offset(typeAndOffset), mergedResult); + } else { + UnsafeUtil.putObject( + message, + offset(typeAndOffset), + reader.readGroupBySchemaWithCheck( + (Schema<T>) getMessageFieldSchema(pos), extensionRegistry)); + setFieldPresent(message, pos); + } + break; + } + case 18: // DOUBLE_LIST: + reader.readDoubleList( + listFieldSchema.<Double>mutableListAt(message, offset(typeAndOffset))); + break; + case 19: // FLOAT_LIST: + reader.readFloatList( + listFieldSchema.<Float>mutableListAt(message, offset(typeAndOffset))); + break; + case 20: // INT64_LIST: + reader.readInt64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 21: // UINT64_LIST: + reader.readUInt64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 22: // INT32_LIST: + reader.readInt32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 23: // FIXED64_LIST: + reader.readFixed64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 24: // FIXED32_LIST: + reader.readFixed32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 25: // BOOL_LIST: + reader.readBoolList( + listFieldSchema.<Boolean>mutableListAt(message, offset(typeAndOffset))); + break; + case 26: // STRING_LIST: + readStringList(message, typeAndOffset, reader); + break; + case 27: + { // MESSAGE_LIST: + readMessageList( + message, + typeAndOffset, + reader, + (Schema<T>) getMessageFieldSchema(pos), + extensionRegistry); + break; + } + case 28: // BYTES_LIST: + reader.readBytesList( + listFieldSchema.<ByteString>mutableListAt(message, offset(typeAndOffset))); + break; + case 29: // UINT32_LIST: + reader.readUInt32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 30: // ENUM_LIST: + { + List<Integer> enumList = + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset)); + reader.readEnumList(enumList); + unknownFields = + SchemaUtil.filterUnknownEnumList( + number, + enumList, + getEnumFieldVerifier(pos), + unknownFields, + unknownFieldSchema); + break; + } + case 31: // SFIXED32_LIST: + reader.readSFixed32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 32: // SFIXED64_LIST: + reader.readSFixed64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 33: // SINT32_LIST: + reader.readSInt32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 34: // SINT64_LIST: + reader.readSInt64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 35: // DOUBLE_LIST_PACKED: + reader.readDoubleList( + listFieldSchema.<Double>mutableListAt(message, offset(typeAndOffset))); + break; + case 36: // FLOAT_LIST_PACKED: + reader.readFloatList( + listFieldSchema.<Float>mutableListAt(message, offset(typeAndOffset))); + break; + case 37: // INT64_LIST_PACKED: + reader.readInt64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 38: // UINT64_LIST_PACKED: + reader.readUInt64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 39: // INT32_LIST_PACKED: + reader.readInt32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 40: // FIXED64_LIST_PACKED: + reader.readFixed64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 41: // FIXED32_LIST_PACKED: + reader.readFixed32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 42: // BOOL_LIST_PACKED: + reader.readBoolList( + listFieldSchema.<Boolean>mutableListAt(message, offset(typeAndOffset))); + break; + case 43: // UINT32_LIST_PACKED: + reader.readUInt32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 44: // ENUM_LIST_PACKED: + { + List<Integer> enumList = + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset)); + reader.readEnumList(enumList); + unknownFields = + SchemaUtil.filterUnknownEnumList( + number, + enumList, + getEnumFieldVerifier(pos), + unknownFields, + unknownFieldSchema); + break; + } + case 45: // SFIXED32_LIST_PACKED: + reader.readSFixed32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 46: // SFIXED64_LIST_PACKED: + reader.readSFixed64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 47: // SINT32_LIST_PACKED: + reader.readSInt32List( + listFieldSchema.<Integer>mutableListAt(message, offset(typeAndOffset))); + break; + case 48: // SINT64_LIST_PACKED: + reader.readSInt64List( + listFieldSchema.<Long>mutableListAt(message, offset(typeAndOffset))); + break; + case 49: + { // GROUP_LIST: + readGroupList( + message, + offset(typeAndOffset), + reader, + (Schema<T>) getMessageFieldSchema(pos), + extensionRegistry); + break; + } + case 50: // MAP: + mergeMap(message, pos, getMapFieldDefaultEntry(pos), extensionRegistry, reader); + break; + case 51: // ONEOF_DOUBLE: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Double.valueOf(reader.readDouble())); + setOneofPresent(message, number, pos); + break; + case 52: // ONEOF_FLOAT: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Float.valueOf(reader.readFloat())); + setOneofPresent(message, number, pos); + break; + case 53: // ONEOF_INT64: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Long.valueOf(reader.readInt64())); + setOneofPresent(message, number, pos); + break; + case 54: // ONEOF_UINT64: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Long.valueOf(reader.readUInt64())); + setOneofPresent(message, number, pos); + break; + case 55: // ONEOF_INT32: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Integer.valueOf(reader.readInt32())); + setOneofPresent(message, number, pos); + break; + case 56: // ONEOF_FIXED64: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Long.valueOf(reader.readFixed64())); + setOneofPresent(message, number, pos); + break; + case 57: // ONEOF_FIXED32: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Integer.valueOf(reader.readFixed32())); + setOneofPresent(message, number, pos); + break; + case 58: // ONEOF_BOOL: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Boolean.valueOf(reader.readBool())); + setOneofPresent(message, number, pos); + break; + case 59: // ONEOF_STRING: + readString(message, typeAndOffset, reader); + setOneofPresent(message, number, pos); + break; + case 60: // ONEOF_MESSAGE: + if (isOneofPresent(message, number, pos)) { + Object mergedResult = + Internal.mergeMessage( + UnsafeUtil.getObject(message, offset(typeAndOffset)), + reader.readMessageBySchemaWithCheck( + getMessageFieldSchema(pos), extensionRegistry)); + UnsafeUtil.putObject(message, offset(typeAndOffset), mergedResult); + } else { + UnsafeUtil.putObject( + message, + offset(typeAndOffset), + reader.readMessageBySchemaWithCheck( + getMessageFieldSchema(pos), extensionRegistry)); + setFieldPresent(message, pos); + } + setOneofPresent(message, number, pos); + break; + case 61: // ONEOF_BYTES: + UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readBytes()); + setOneofPresent(message, number, pos); + break; + case 62: // ONEOF_UINT32: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Integer.valueOf(reader.readUInt32())); + setOneofPresent(message, number, pos); + break; + case 63: // ONEOF_ENUM: + { + int enumValue = reader.readEnum(); + EnumVerifier enumVerifier = getEnumFieldVerifier(pos); + if (enumVerifier == null || enumVerifier.isInRange(enumValue)) { + UnsafeUtil.putObject(message, offset(typeAndOffset), enumValue); + setOneofPresent(message, number, pos); + } else { + unknownFields = + SchemaUtil.storeUnknownEnum( + number, enumValue, unknownFields, unknownFieldSchema); + } + break; + } + case 64: // ONEOF_SFIXED32: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Integer.valueOf(reader.readSFixed32())); + setOneofPresent(message, number, pos); + break; + case 65: // ONEOF_SFIXED64: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Long.valueOf(reader.readSFixed64())); + setOneofPresent(message, number, pos); + break; + case 66: // ONEOF_SINT32: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Integer.valueOf(reader.readSInt32())); + setOneofPresent(message, number, pos); + break; + case 67: // ONEOF_SINT64: + UnsafeUtil.putObject( + message, offset(typeAndOffset), Long.valueOf(reader.readSInt64())); + setOneofPresent(message, number, pos); + break; + case 68: // ONEOF_GROUP: + UnsafeUtil.putObject( + message, + offset(typeAndOffset), + reader.readGroupBySchemaWithCheck(getMessageFieldSchema(pos), extensionRegistry)); + setOneofPresent(message, number, pos); + break; + default: + // Assume we've landed on an empty entry. Treat it as an unknown field. + if (unknownFields == null) { + unknownFields = unknownFieldSchema.newBuilder(); + } + if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) { + return; + } + break; + } + } catch (InvalidProtocolBufferException.InvalidWireTypeException e) { + // Treat fields with an invalid wire type as unknown fields + // (i.e. same as the default case). + if (unknownFieldSchema.shouldDiscardUnknownFields(reader)) { + if (!reader.skipField()) { + return; + } + } else { + if (unknownFields == null) { + unknownFields = unknownFieldSchema.getBuilderFromMessage(message); + } + if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) { + return; + } + } + } + } + } finally { + for (int i = checkInitializedCount; i < repeatedFieldOffsetStart; i++) { + unknownFields = + filterMapUnknownEnumValues(message, intArray[i], unknownFields, unknownFieldSchema); + } + if (unknownFields != null) { + unknownFieldSchema.setBuilderToMessage(message, unknownFields); + } + } + } + + @SuppressWarnings("ReferenceEquality") + static UnknownFieldSetLite getMutableUnknownFields(Object message) { + UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields; + if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) { + unknownFields = UnknownFieldSetLite.newInstance(); + ((GeneratedMessageLite) message).unknownFields = unknownFields; + } + return unknownFields; + } + + /** Decodes a map entry key or value. Stores result in registers.object1. */ + private int decodeMapEntryValue( + byte[] data, + int position, + int limit, + WireFormat.FieldType fieldType, + Class<?> messageType, + Registers registers) + throws IOException { + switch (fieldType) { + case BOOL: + position = decodeVarint64(data, position, registers); + registers.object1 = registers.long1 != 0; + break; + case BYTES: + position = decodeBytes(data, position, registers); + break; + case DOUBLE: + registers.object1 = decodeDouble(data, position); + position += 8; + break; + case FIXED32: + case SFIXED32: + registers.object1 = decodeFixed32(data, position); + position += 4; + break; + case FIXED64: + case SFIXED64: + registers.object1 = decodeFixed64(data, position); + position += 8; + break; + case FLOAT: + registers.object1 = decodeFloat(data, position); + position += 4; + break; + case ENUM: + case INT32: + case UINT32: + position = decodeVarint32(data, position, registers); + registers.object1 = registers.int1; + break; + case INT64: + case UINT64: + position = decodeVarint64(data, position, registers); + registers.object1 = registers.long1; + break; + case MESSAGE: + position = + decodeMessageField( + Protobuf.getInstance().schemaFor(messageType), data, position, limit, registers); + break; + case SINT32: + position = decodeVarint32(data, position, registers); + registers.object1 = CodedInputStream.decodeZigZag32(registers.int1); + break; + case SINT64: + position = decodeVarint64(data, position, registers); + registers.object1 = CodedInputStream.decodeZigZag64(registers.long1); + break; + case STRING: + position = decodeStringRequireUtf8(data, position, registers); + break; + default: + throw new RuntimeException("unsupported field type."); + } + return position; + } + + /** Decodes a map entry. */ + private <K, V> int decodeMapEntry( + byte[] data, + int position, + int limit, + MapEntryLite.Metadata<K, V> metadata, + Map<K, V> target, + Registers registers) + throws IOException { + position = decodeVarint32(data, position, registers); + final int length = registers.int1; + if (length < 0 || length > limit - position) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + final int end = position + length; + K key = metadata.defaultKey; + V value = metadata.defaultValue; + while (position < end) { + int tag = data[position++]; + if (tag < 0) { + position = decodeVarint32(tag, data, position, registers); + tag = registers.int1; + } + final int fieldNumber = tag >>> 3; + final int wireType = tag & 0x7; + switch (fieldNumber) { + case 1: + if (wireType == metadata.keyType.getWireType()) { + position = + decodeMapEntryValue(data, position, limit, metadata.keyType, null, registers); + key = (K) registers.object1; + continue; + } + break; + case 2: + if (wireType == metadata.valueType.getWireType()) { + position = + decodeMapEntryValue( + data, + position, + limit, + metadata.valueType, + metadata.defaultValue.getClass(), + registers); + value = (V) registers.object1; + continue; + } + break; + default: + break; + } + position = skipField(tag, data, position, limit, registers); + } + if (position != end) { + throw InvalidProtocolBufferException.parseFailure(); + } + target.put(key, value); + return end; + } + + @SuppressWarnings("ReferenceEquality") + private int parseRepeatedField( + T message, + byte[] data, + int position, + int limit, + int tag, + int number, + int wireType, + int bufferPosition, + long typeAndOffset, + int fieldType, + long fieldOffset, + Registers registers) + throws IOException { + ProtobufList<?> list = (ProtobufList<?>) UNSAFE.getObject(message, fieldOffset); + if (!list.isModifiable()) { + final int size = list.size(); + list = + list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + UNSAFE.putObject(message, fieldOffset, list); + } + switch (fieldType) { + case 18: // DOUBLE_LIST: + case 35: // DOUBLE_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedDoubleList(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_FIXED64) { + position = decodeDoubleList(tag, data, position, limit, list, registers); + } + break; + case 19: // FLOAT_LIST: + case 36: // FLOAT_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedFloatList(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_FIXED32) { + position = decodeFloatList(tag, data, position, limit, list, registers); + } + break; + case 20: // INT64_LIST: + case 21: // UINT64_LIST: + case 37: // INT64_LIST_PACKED: + case 38: // UINT64_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedVarint64List(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64List(tag, data, position, limit, list, registers); + } + break; + case 22: // INT32_LIST: + case 29: // UINT32_LIST: + case 39: // INT32_LIST_PACKED: + case 43: // UINT32_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedVarint32List(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32List(tag, data, position, limit, list, registers); + } + break; + case 23: // FIXED64_LIST: + case 32: // SFIXED64_LIST: + case 40: // FIXED64_LIST_PACKED: + case 46: // SFIXED64_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedFixed64List(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_FIXED64) { + position = decodeFixed64List(tag, data, position, limit, list, registers); + } + break; + case 24: // FIXED32_LIST: + case 31: // SFIXED32_LIST: + case 41: // FIXED32_LIST_PACKED: + case 45: // SFIXED32_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedFixed32List(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_FIXED32) { + position = decodeFixed32List(tag, data, position, limit, list, registers); + } + break; + case 25: // BOOL_LIST: + case 42: // BOOL_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedBoolList(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeBoolList(tag, data, position, limit, list, registers); + } + break; + case 26: // STRING_LIST: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + if ((typeAndOffset & ENFORCE_UTF8_MASK) == 0) { + position = decodeStringList(tag, data, position, limit, list, registers); + } else { + position = decodeStringListRequireUtf8(tag, data, position, limit, list, registers); + } + } + break; + case 27: // MESSAGE_LIST: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = + decodeMessageList( + getMessageFieldSchema(bufferPosition), + tag, + data, + position, + limit, + list, + registers); + } + break; + case 28: // BYTES_LIST: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodeBytesList(tag, data, position, limit, list, registers); + } + break; + case 30: // ENUM_LIST: + case 44: // ENUM_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedVarint32List(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32List(tag, data, position, limit, list, registers); + } else { + break; + } + UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields; + if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) { + // filterUnknownEnumList() expects the unknownFields parameter to be mutable or null. + // Since we don't know yet whether there exist unknown enum values, we'd better pass + // null to it instead of allocating a mutable instance. This is also needed to be + // consistent with the behavior of generated parser/builder. + unknownFields = null; + } + unknownFields = + SchemaUtil.filterUnknownEnumList( + number, + (ProtobufList<Integer>) list, + getEnumFieldVerifier(bufferPosition), + unknownFields, + (UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema); + if (unknownFields != null) { + ((GeneratedMessageLite) message).unknownFields = unknownFields; + } + break; + case 33: // SINT32_LIST: + case 47: // SINT32_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedSInt32List(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeSInt32List(tag, data, position, limit, list, registers); + } + break; + case 34: // SINT64_LIST: + case 48: // SINT64_LIST_PACKED: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodePackedSInt64List(data, position, list, registers); + } else if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeSInt64List(tag, data, position, limit, list, registers); + } + break; + case 49: // GROUP_LIST: + if (wireType == WireFormat.WIRETYPE_START_GROUP) { + position = + decodeGroupList( + getMessageFieldSchema(bufferPosition), + tag, + data, + position, + limit, + list, + registers); + } + break; + default: + break; + } + return position; + } + + private <K, V> int parseMapField( + T message, + byte[] data, + int position, + int limit, + int bufferPosition, + long fieldOffset, + Registers registers) + throws IOException { + final sun.misc.Unsafe unsafe = UNSAFE; + Object mapDefaultEntry = getMapFieldDefaultEntry(bufferPosition); + Object mapField = unsafe.getObject(message, fieldOffset); + if (mapFieldSchema.isImmutable(mapField)) { + Object oldMapField = mapField; + mapField = mapFieldSchema.newMapField(mapDefaultEntry); + mapFieldSchema.mergeFrom(mapField, oldMapField); + unsafe.putObject(message, fieldOffset, mapField); + } + return decodeMapEntry( + data, + position, + limit, + (Metadata<K, V>) mapFieldSchema.forMapMetadata(mapDefaultEntry), + (Map<K, V>) mapFieldSchema.forMutableMapData(mapField), + registers); + } + + private int parseOneofField( + T message, + byte[] data, + int position, + int limit, + int tag, + int number, + int wireType, + int typeAndOffset, + int fieldType, + long fieldOffset, + int bufferPosition, + Registers registers) + throws IOException { + final sun.misc.Unsafe unsafe = UNSAFE; + final long oneofCaseOffset = buffer[bufferPosition + 2] & OFFSET_MASK; + switch (fieldType) { + case 51: // ONEOF_DOUBLE: + if (wireType == WireFormat.WIRETYPE_FIXED64) { + unsafe.putObject(message, fieldOffset, decodeDouble(data, position)); + position += 8; + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 52: // ONEOF_FLOAT: + if (wireType == WireFormat.WIRETYPE_FIXED32) { + unsafe.putObject(message, fieldOffset, decodeFloat(data, position)); + position += 4; + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 53: // ONEOF_INT64: + case 54: // ONEOF_UINT64: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64(data, position, registers); + unsafe.putObject(message, fieldOffset, registers.long1); + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 55: // ONEOF_INT32: + case 62: // ONEOF_UINT32: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32(data, position, registers); + unsafe.putObject(message, fieldOffset, registers.int1); + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 56: // ONEOF_FIXED64: + case 65: // ONEOF_SFIXED64: + if (wireType == WireFormat.WIRETYPE_FIXED64) { + unsafe.putObject(message, fieldOffset, decodeFixed64(data, position)); + position += 8; + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 57: // ONEOF_FIXED32: + case 64: // ONEOF_SFIXED32: + if (wireType == WireFormat.WIRETYPE_FIXED32) { + unsafe.putObject(message, fieldOffset, decodeFixed32(data, position)); + position += 4; + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 58: // ONEOF_BOOL: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64(data, position, registers); + unsafe.putObject(message, fieldOffset, registers.long1 != 0); + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 59: // ONEOF_STRING: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodeVarint32(data, position, registers); + final int length = registers.int1; + if (length == 0) { + unsafe.putObject(message, fieldOffset, ""); + } else { + if ((typeAndOffset & ENFORCE_UTF8_MASK) != 0 + && !Utf8.isValidUtf8(data, position, position + length)) { + throw InvalidProtocolBufferException.invalidUtf8(); + } + final String value = new String(data, position, length, Internal.UTF_8); + unsafe.putObject(message, fieldOffset, value); + position += length; + } + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 60: // ONEOF_MESSAGE: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = + decodeMessageField( + getMessageFieldSchema(bufferPosition), data, position, limit, registers); + final Object oldValue = + unsafe.getInt(message, oneofCaseOffset) == number + ? unsafe.getObject(message, fieldOffset) + : null; + if (oldValue == null) { + unsafe.putObject(message, fieldOffset, registers.object1); + } else { + unsafe.putObject( + message, fieldOffset, Internal.mergeMessage(oldValue, registers.object1)); + } + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 61: // ONEOF_BYTES: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodeBytes(data, position, registers); + unsafe.putObject(message, fieldOffset, registers.object1); + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 63: // ONEOF_ENUM: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32(data, position, registers); + final int enumValue = registers.int1; + EnumVerifier enumVerifier = getEnumFieldVerifier(bufferPosition); + if (enumVerifier == null || enumVerifier.isInRange(enumValue)) { + unsafe.putObject(message, fieldOffset, enumValue); + unsafe.putInt(message, oneofCaseOffset, number); + } else { + // UnknownFieldSetLite requires varint to be represented as Long: + // https://cs.corp.google.com/piper///depot/google3/java/com/google/protobuf/UnknownFieldSetLite.java?l=202&rcl=167074986 + getMutableUnknownFields(message).storeField(tag, (long) enumValue); + } + } + break; + case 66: // ONEOF_SINT32: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32(data, position, registers); + unsafe.putObject(message, fieldOffset, CodedInputStream.decodeZigZag32(registers.int1)); + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 67: // ONEOF_SINT64: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64(data, position, registers); + unsafe.putObject(message, fieldOffset, CodedInputStream.decodeZigZag64(registers.long1)); + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + case 68: // ONEOF_GROUP: + if (wireType == WireFormat.WIRETYPE_START_GROUP) { + final int endTag = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP; + position = + decodeGroupField( + getMessageFieldSchema(bufferPosition), data, position, limit, endTag, registers); + final Object oldValue = + unsafe.getInt(message, oneofCaseOffset) == number + ? unsafe.getObject(message, fieldOffset) + : null; + if (oldValue == null) { + unsafe.putObject(message, fieldOffset, registers.object1); + } else { + unsafe.putObject( + message, fieldOffset, Internal.mergeMessage(oldValue, registers.object1)); + } + unsafe.putInt(message, oneofCaseOffset, number); + } + break; + default: + break; + } + return position; + } + + private Schema getMessageFieldSchema(int pos) { + final int index = pos / INTS_PER_FIELD * 2; + Schema schema = (Schema) objects[index]; + if (schema != null) { + return schema; + } + schema = Protobuf.getInstance().schemaFor((Class) objects[index + 1]); + objects[index] = schema; + return schema; + } + + private Object getMapFieldDefaultEntry(int pos) { + return objects[pos / INTS_PER_FIELD * 2]; + } + + private EnumVerifier getEnumFieldVerifier(int pos) { + return (EnumVerifier) objects[pos / INTS_PER_FIELD * 2 + 1]; + } + + /** + * Parses a proto2 message or group and returns the position after the message/group. If it's + * parsing a message (endGroup == 0), returns limit if parsing is successful; It it's parsing a + * group (endGroup != 0), parsing ends when a tag == endGroup is encountered and the position + * after that tag is returned. + */ + int parseProto2Message( + T message, byte[] data, int position, int limit, int endGroup, Registers registers) + throws IOException { + final sun.misc.Unsafe unsafe = UNSAFE; + int currentPresenceFieldOffset = -1; + int currentPresenceField = 0; + int tag = 0; + int oldNumber = -1; + int pos = 0; + while (position < limit) { + tag = data[position++]; + if (tag < 0) { + position = decodeVarint32(tag, data, position, registers); + tag = registers.int1; + } + final int number = tag >>> 3; + final int wireType = tag & 0x7; + if (number > oldNumber) { + pos = positionForFieldNumber(number, pos / INTS_PER_FIELD); + } else { + pos = positionForFieldNumber(number); + } + oldNumber = number; + if (pos == -1) { + // need to reset + pos = 0; + } else { + final int typeAndOffset = buffer[pos + 1]; + final int fieldType = type(typeAndOffset); + final long fieldOffset = offset(typeAndOffset); + if (fieldType <= 17) { + // Proto2 optional fields have has-bits. + final int presenceMaskAndOffset = buffer[pos + 2]; + final int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS); + final int presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK; + // We cache the 32-bit has-bits integer value and only write it back when parsing a field + // using a different has-bits integer. + if (presenceFieldOffset != currentPresenceFieldOffset) { + if (currentPresenceFieldOffset != -1) { + unsafe.putInt(message, (long) currentPresenceFieldOffset, currentPresenceField); + } + currentPresenceFieldOffset = presenceFieldOffset; + currentPresenceField = unsafe.getInt(message, (long) presenceFieldOffset); + } + switch (fieldType) { + case 0: // DOUBLE + if (wireType == WireFormat.WIRETYPE_FIXED64) { + UnsafeUtil.putDouble(message, fieldOffset, decodeDouble(data, position)); + position += 8; + currentPresenceField |= presenceMask; + continue; + } + break; + case 1: // FLOAT + if (wireType == WireFormat.WIRETYPE_FIXED32) { + UnsafeUtil.putFloat(message, fieldOffset, decodeFloat(data, position)); + position += 4; + currentPresenceField |= presenceMask; + continue; + } + break; + case 2: // INT64 + case 3: // UINT64 + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64(data, position, registers); + unsafe.putLong(message, fieldOffset, registers.long1); + currentPresenceField |= presenceMask; + continue; + } + break; + case 4: // INT32 + case 11: // UINT32 + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32(data, position, registers); + unsafe.putInt(message, fieldOffset, registers.int1); + currentPresenceField |= presenceMask; + continue; + } + break; + case 5: // FIXED64 + case 14: // SFIXED64 + if (wireType == WireFormat.WIRETYPE_FIXED64) { + unsafe.putLong(message, fieldOffset, decodeFixed64(data, position)); + position += 8; + currentPresenceField |= presenceMask; + continue; + } + break; + case 6: // FIXED32 + case 13: // SFIXED32 + if (wireType == WireFormat.WIRETYPE_FIXED32) { + unsafe.putInt(message, fieldOffset, decodeFixed32(data, position)); + position += 4; + currentPresenceField |= presenceMask; + continue; + } + break; + case 7: // BOOL + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64(data, position, registers); + UnsafeUtil.putBoolean(message, fieldOffset, registers.long1 != 0); + currentPresenceField |= presenceMask; + continue; + } + break; + case 8: // STRING + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + if ((typeAndOffset & ENFORCE_UTF8_MASK) == 0) { + position = decodeString(data, position, registers); + } else { + position = decodeStringRequireUtf8(data, position, registers); + } + unsafe.putObject(message, fieldOffset, registers.object1); + currentPresenceField |= presenceMask; + continue; + } + break; + case 9: // MESSAGE + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = + decodeMessageField( + getMessageFieldSchema(pos), data, position, limit, registers); + if ((currentPresenceField & presenceMask) == 0) { + unsafe.putObject(message, fieldOffset, registers.object1); + } else { + unsafe.putObject( + message, + fieldOffset, + Internal.mergeMessage( + unsafe.getObject(message, fieldOffset), registers.object1)); + } + currentPresenceField |= presenceMask; + continue; + } + break; + case 10: // BYTES + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodeBytes(data, position, registers); + unsafe.putObject(message, fieldOffset, registers.object1); + currentPresenceField |= presenceMask; + continue; + } + break; + case 12: // ENUM + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32(data, position, registers); + final int enumValue = registers.int1; + EnumVerifier enumVerifier = getEnumFieldVerifier(pos); + if (enumVerifier == null || enumVerifier.isInRange(enumValue)) { + unsafe.putInt(message, fieldOffset, enumValue); + currentPresenceField |= presenceMask; + } else { + // UnknownFieldSetLite requires varint to be represented as Long: + // https://cs.corp.google.com/piper///depot/google3/java/com/google/protobuf/UnknownFieldSetLite.java?l=202&rcl=167074986 + getMutableUnknownFields(message).storeField(tag, (long) enumValue); + } + continue; + } + break; + case 15: // SINT32 + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32(data, position, registers); + unsafe.putInt( + message, fieldOffset, CodedInputStream.decodeZigZag32(registers.int1)); + currentPresenceField |= presenceMask; + continue; + } + break; + case 16: // SINT64 + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64(data, position, registers); + unsafe.putLong( + message, fieldOffset, CodedInputStream.decodeZigZag64(registers.long1)); + + currentPresenceField |= presenceMask; + continue; + } + break; + case 17: // GROUP + if (wireType == WireFormat.WIRETYPE_START_GROUP) { + final int endTag = (number << 3) | WireFormat.WIRETYPE_END_GROUP; + position = + decodeGroupField( + getMessageFieldSchema(pos), data, position, limit, endTag, registers); + if ((currentPresenceField & presenceMask) == 0) { + unsafe.putObject(message, fieldOffset, registers.object1); + } else { + unsafe.putObject( + message, + fieldOffset, + Internal.mergeMessage( + unsafe.getObject(message, fieldOffset), registers.object1)); + } + + currentPresenceField |= presenceMask; + continue; + } + break; + default: + break; + } + } else if (fieldType == 27) { + // Handle repeated message fields. + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + ProtobufList<?> list = (ProtobufList<?>) unsafe.getObject(message, fieldOffset); + if (!list.isModifiable()) { + final int size = list.size(); + list = + list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + unsafe.putObject(message, fieldOffset, list); + } + position = + decodeMessageList( + getMessageFieldSchema(pos), tag, data, position, limit, list, registers); + continue; + } + } else if (fieldType <= 49) { + // Handle all other repeated fields. + final int oldPosition = position; + position = + parseRepeatedField( + message, + data, + position, + limit, + tag, + number, + wireType, + pos, + typeAndOffset, + fieldType, + fieldOffset, + registers); + if (position != oldPosition) { + continue; + } + } else if (fieldType == 50) { + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + final int oldPosition = position; + position = parseMapField(message, data, position, limit, pos, fieldOffset, registers); + if (position != oldPosition) { + continue; + } + } + } else { + final int oldPosition = position; + position = + parseOneofField( + message, + data, + position, + limit, + tag, + number, + wireType, + typeAndOffset, + fieldType, + fieldOffset, + pos, + registers); + if (position != oldPosition) { + continue; + } + } + } + if (tag == endGroup && endGroup != 0) { + break; + } + + if (hasExtensions + && registers.extensionRegistry != ExtensionRegistryLite.getEmptyRegistry()) { + position = decodeExtensionOrUnknownField( + tag, data, position, limit, message, defaultInstance, + (UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema, + registers); + } else { + position = decodeUnknownField( + tag, data, position, limit, getMutableUnknownFields(message), registers); + } + } + if (currentPresenceFieldOffset != -1) { + unsafe.putInt(message, (long) currentPresenceFieldOffset, currentPresenceField); + } + UnknownFieldSetLite unknownFields = null; + for (int i = checkInitializedCount; i < repeatedFieldOffsetStart; i++) { + unknownFields = + filterMapUnknownEnumValues( + message, + intArray[i], + unknownFields, + (UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema); + } + if (unknownFields != null) { + ((UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema) + .setBuilderToMessage(message, unknownFields); + } + if (endGroup == 0) { + if (position != limit) { + throw InvalidProtocolBufferException.parseFailure(); + } + } else { + if (position > limit || tag != endGroup) { + throw InvalidProtocolBufferException.parseFailure(); + } + } + return position; + } + + /** Parses a proto3 message and returns the limit if parsing is successful. */ + private int parseProto3Message( + T message, byte[] data, int position, int limit, Registers registers) throws IOException { + final sun.misc.Unsafe unsafe = UNSAFE; + int tag = 0; + int oldNumber = -1; + int pos = 0; + while (position < limit) { + tag = data[position++]; + if (tag < 0) { + position = decodeVarint32(tag, data, position, registers); + tag = registers.int1; + } + final int number = tag >>> 3; + final int wireType = tag & 0x7; + if (number > oldNumber) { + pos = positionForFieldNumber(number, pos / INTS_PER_FIELD); + } else { + pos = positionForFieldNumber(number); + } + oldNumber = number; + if (pos == -1) { + // need to reset + pos = 0; + } else { + final int typeAndOffset = buffer[pos + 1]; + final int fieldType = type(typeAndOffset); + final long fieldOffset = offset(typeAndOffset); + if (fieldType <= 17) { + switch (fieldType) { + case 0: // DOUBLE: + if (wireType == WireFormat.WIRETYPE_FIXED64) { + UnsafeUtil.putDouble(message, fieldOffset, decodeDouble(data, position)); + position += 8; + continue; + } + break; + case 1: // FLOAT: + if (wireType == WireFormat.WIRETYPE_FIXED32) { + UnsafeUtil.putFloat(message, fieldOffset, decodeFloat(data, position)); + position += 4; + continue; + } + break; + case 2: // INT64: + case 3: // UINT64: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64(data, position, registers); + unsafe.putLong(message, fieldOffset, registers.long1); + continue; + } + break; + case 4: // INT32: + case 11: // UINT32: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32(data, position, registers); + unsafe.putInt(message, fieldOffset, registers.int1); + continue; + } + break; + case 5: // FIXED64: + case 14: // SFIXED64: + if (wireType == WireFormat.WIRETYPE_FIXED64) { + unsafe.putLong(message, fieldOffset, decodeFixed64(data, position)); + position += 8; + continue; + } + break; + case 6: // FIXED32: + case 13: // SFIXED32: + if (wireType == WireFormat.WIRETYPE_FIXED32) { + unsafe.putInt(message, fieldOffset, decodeFixed32(data, position)); + position += 4; + continue; + } + break; + case 7: // BOOL: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64(data, position, registers); + UnsafeUtil.putBoolean(message, fieldOffset, registers.long1 != 0); + continue; + } + break; + case 8: // STRING: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + if ((typeAndOffset & ENFORCE_UTF8_MASK) == 0) { + position = decodeString(data, position, registers); + } else { + position = decodeStringRequireUtf8(data, position, registers); + } + unsafe.putObject(message, fieldOffset, registers.object1); + continue; + } + break; + case 9: // MESSAGE: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = + decodeMessageField( + getMessageFieldSchema(pos), data, position, limit, registers); + final Object oldValue = unsafe.getObject(message, fieldOffset); + if (oldValue == null) { + unsafe.putObject(message, fieldOffset, registers.object1); + } else { + unsafe.putObject( + message, fieldOffset, Internal.mergeMessage(oldValue, registers.object1)); + } + continue; + } + break; + case 10: // BYTES: + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = decodeBytes(data, position, registers); + unsafe.putObject(message, fieldOffset, registers.object1); + continue; + } + break; + case 12: // ENUM: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32(data, position, registers); + unsafe.putInt(message, fieldOffset, registers.int1); + continue; + } + break; + case 15: // SINT32: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint32(data, position, registers); + unsafe.putInt( + message, fieldOffset, CodedInputStream.decodeZigZag32(registers.int1)); + continue; + } + break; + case 16: // SINT64: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = decodeVarint64(data, position, registers); + unsafe.putLong( + message, fieldOffset, CodedInputStream.decodeZigZag64(registers.long1)); + continue; + } + break; + default: + break; + } + } else if (fieldType == 27) { + // Handle repeated message field. + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + ProtobufList<?> list = (ProtobufList<?>) unsafe.getObject(message, fieldOffset); + if (!list.isModifiable()) { + final int size = list.size(); + list = + list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + unsafe.putObject(message, fieldOffset, list); + } + position = + decodeMessageList( + getMessageFieldSchema(pos), tag, data, position, limit, list, registers); + continue; + } + } else if (fieldType <= 49) { + // Handle all other repeated fields. + final int oldPosition = position; + position = + parseRepeatedField( + message, + data, + position, + limit, + tag, + number, + wireType, + pos, + typeAndOffset, + fieldType, + fieldOffset, + registers); + if (position != oldPosition) { + continue; + } + } else if (fieldType == 50) { + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + final int oldPosition = position; + position = parseMapField(message, data, position, limit, pos, fieldOffset, registers); + if (position != oldPosition) { + continue; + } + } + } else { + final int oldPosition = position; + position = + parseOneofField( + message, + data, + position, + limit, + tag, + number, + wireType, + typeAndOffset, + fieldType, + fieldOffset, + pos, + registers); + if (position != oldPosition) { + continue; + } + } + } + position = decodeUnknownField( + tag, data, position, limit, getMutableUnknownFields(message), registers); + } + if (position != limit) { + throw InvalidProtocolBufferException.parseFailure(); + } + return position; + } + + @Override + public void mergeFrom(T message, byte[] data, int position, int limit, Registers registers) + throws IOException { + if (proto3) { + parseProto3Message(message, data, position, limit, registers); + } else { + parseProto2Message(message, data, position, limit, 0, registers); + } + } + + @Override + public void makeImmutable(T message) { + // Make all repeated/map fields immutable. + for (int i = checkInitializedCount; i < repeatedFieldOffsetStart; i++) { + long offset = offset(typeAndOffsetAt(intArray[i])); + Object mapField = UnsafeUtil.getObject(message, offset); + if (mapField == null) { + continue; + } + UnsafeUtil.putObject(message, offset, mapFieldSchema.toImmutable(mapField)); + } + final int length = intArray.length; + for (int i = repeatedFieldOffsetStart; i < length; i++) { + listFieldSchema.makeImmutableListAt(message, intArray[i]); + } + unknownFieldSchema.makeImmutable(message); + if (hasExtensions) { + extensionSchema.makeImmutable(message); + } + } + + @SuppressWarnings("unchecked") + private final <K, V> void mergeMap( + Object message, + int pos, + Object mapDefaultEntry, + ExtensionRegistryLite extensionRegistry, + Reader reader) + throws IOException { + long offset = offset(typeAndOffsetAt(pos)); + Object mapField = UnsafeUtil.getObject(message, offset); + // TODO(xiaofeng): Consider creating separate implementations for full and lite. In lite + // runtime map field will never be null but here we still need to check null because the + // code is shared by both full and lite. It might be better if full/lite uses different + // schema implementations. + if (mapField == null) { + mapField = mapFieldSchema.newMapField(mapDefaultEntry); + UnsafeUtil.putObject(message, offset, mapField); + } else if (mapFieldSchema.isImmutable(mapField)) { + Object oldMapField = mapField; + mapField = mapFieldSchema.newMapField(mapDefaultEntry); + mapFieldSchema.mergeFrom(mapField, oldMapField); + UnsafeUtil.putObject(message, offset, mapField); + } + reader.readMap( + (Map<K, V>) mapFieldSchema.forMutableMapData(mapField), + (Metadata<K, V>) mapFieldSchema.forMapMetadata(mapDefaultEntry), + extensionRegistry); + } + + private final <UT, UB> UB filterMapUnknownEnumValues( + Object message, int pos, UB unknownFields, UnknownFieldSchema<UT, UB> unknownFieldSchema) { + int fieldNumber = numberAt(pos); + long offset = offset(typeAndOffsetAt(pos)); + Object mapField = UnsafeUtil.getObject(message, offset); + if (mapField == null) { + return unknownFields; + } + EnumVerifier enumVerifier = getEnumFieldVerifier(pos); + if (enumVerifier == null) { + return unknownFields; + } + Map<?, ?> mapData = mapFieldSchema.forMutableMapData(mapField); + // Filter unknown enum values. + unknownFields = + filterUnknownEnumMap( + pos, fieldNumber, mapData, enumVerifier, unknownFields, unknownFieldSchema); + return unknownFields; + } + + @SuppressWarnings("unchecked") + private final <K, V, UT, UB> UB filterUnknownEnumMap( + int pos, + int number, + Map<K, V> mapData, + EnumVerifier enumVerifier, + UB unknownFields, + UnknownFieldSchema<UT, UB> unknownFieldSchema) { + Metadata<K, V> metadata = + (Metadata<K, V>) mapFieldSchema.forMapMetadata(getMapFieldDefaultEntry(pos)); + for (Iterator<Map.Entry<K, V>> it = mapData.entrySet().iterator(); it.hasNext(); ) { + Map.Entry<K, V> entry = it.next(); + if (!enumVerifier.isInRange((Integer) entry.getValue())) { + if (unknownFields == null) { + unknownFields = unknownFieldSchema.newBuilder(); + } + int entrySize = + MapEntryLite.computeSerializedSize(metadata, entry.getKey(), entry.getValue()); + CodedBuilder codedBuilder = ByteString.newCodedBuilder(entrySize); + CodedOutputStream codedOutput = codedBuilder.getCodedOutput(); + try { + MapEntryLite.writeTo(codedOutput, metadata, entry.getKey(), entry.getValue()); + } catch (IOException e) { + // Writing to ByteString CodedOutputStream should not throw IOException. + throw new RuntimeException(e); + } + unknownFieldSchema.addLengthDelimited(unknownFields, number, codedBuilder.build()); + it.remove(); + } + } + return unknownFields; + } + + @Override + public final boolean isInitialized(T message) { + int currentPresenceFieldOffset = -1; + int currentPresenceField = 0; + for (int i = 0; i < checkInitializedCount; i++) { + final int pos = intArray[i]; + final int number = numberAt(pos); + + final int typeAndOffset = typeAndOffsetAt(pos); + + int presenceMaskAndOffset = 0; + int presenceMask = 0; + if (!proto3) { + presenceMaskAndOffset = buffer[pos + 2]; + final int presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK; + presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS); + if (presenceFieldOffset != currentPresenceFieldOffset) { + currentPresenceFieldOffset = presenceFieldOffset; + currentPresenceField = UNSAFE.getInt(message, (long) presenceFieldOffset); + } + } + + if (isRequired(typeAndOffset)) { + if (!isFieldPresent(message, pos, currentPresenceField, presenceMask)) { + return false; + } + // If a required message field is set but has no required fields of it's own, we still + // proceed and check the message is initialized. It should be fairly cheap to check these + // messages but is worth documenting. + } + // Check nested message and groups. + switch (type(typeAndOffset)) { + case 9: // MESSAGE + case 17: // GROUP + if (isFieldPresent(message, pos, currentPresenceField, presenceMask) + && !isInitialized(message, typeAndOffset, getMessageFieldSchema(pos))) { + return false; + } + break; + case 27: // MESSAGE_LIST + case 49: // GROUP_LIST + if (!isListInitialized(message, typeAndOffset, pos)) { + return false; + } + break; + case 60: // ONEOF_MESSAGE + case 68: // ONEOF_GROUP + if (isOneofPresent(message, number, pos) + && !isInitialized(message, typeAndOffset, getMessageFieldSchema(pos))) { + return false; + } + break; + case 50: // MAP + if (!isMapInitialized(message, typeAndOffset, pos)) { + return false; + } + break; + default: + break; + } + } + + if (hasExtensions) { + if (!extensionSchema.getExtensions(message).isInitialized()) { + return false; + } + } + + return true; + } + + private static boolean isInitialized(Object message, int typeAndOffset, Schema schema) { + Object nested = UnsafeUtil.getObject(message, offset(typeAndOffset)); + return schema.isInitialized(nested); + } + + private <N> boolean isListInitialized(Object message, int typeAndOffset, int pos) { + @SuppressWarnings("unchecked") + List<N> list = (List<N>) UnsafeUtil.getObject(message, offset(typeAndOffset)); + if (list.isEmpty()) { + return true; + } + + Schema schema = getMessageFieldSchema(pos); + for (int i = 0; i < list.size(); i++) { + N nested = list.get(i); + if (!schema.isInitialized(nested)) { + return false; + } + } + return true; + } + + private boolean isMapInitialized(T message, int typeAndOffset, int pos) { + Map<?, ?> map = mapFieldSchema.forMapData(UnsafeUtil.getObject(message, offset(typeAndOffset))); + if (map.isEmpty()) { + return true; + } + Object mapDefaultEntry = getMapFieldDefaultEntry(pos); + MapEntryLite.Metadata<?, ?> metadata = mapFieldSchema.forMapMetadata(mapDefaultEntry); + if (metadata.valueType.getJavaType() != WireFormat.JavaType.MESSAGE) { + return true; + } + // TODO(dweis): Use schema cache. + Schema schema = null; + for (Object nested : map.values()) { + if (schema == null) { + schema = Protobuf.getInstance().schemaFor(nested.getClass()); + } + if (!schema.isInitialized(nested)) { + return false; + } + } + return true; + } + + private void writeString(int fieldNumber, Object value, Writer writer) throws IOException { + if (value instanceof String) { + writer.writeString(fieldNumber, (String) value); + } else { + writer.writeBytes(fieldNumber, (ByteString) value); + } + } + + private void readString(Object message, int typeAndOffset, Reader reader) throws IOException { + if (isEnforceUtf8(typeAndOffset)) { + // Enforce valid UTF-8 on the read. + UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readStringRequireUtf8()); + } else if (lite) { + // Lite messages use String fields to store strings. Read a string but do not + // enforce UTF-8 + UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readString()); + } else { + // Full runtime messages use Objects to store either a String or ByteString. Read + // the string as a ByteString and do not enforce UTF-8. + UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readBytes()); + } + } + + private void readStringList(Object message, int typeAndOffset, Reader reader) throws IOException { + if (isEnforceUtf8(typeAndOffset)) { + reader.readStringListRequireUtf8( + listFieldSchema.<String>mutableListAt(message, offset(typeAndOffset))); + } else { + reader.readStringList(listFieldSchema.<String>mutableListAt(message, offset(typeAndOffset))); + } + } + + private <E> void readMessageList( + Object message, + int typeAndOffset, + Reader reader, + Schema<E> schema, + ExtensionRegistryLite extensionRegistry) + throws IOException { + long offset = offset(typeAndOffset); + reader.readMessageList( + listFieldSchema.<E>mutableListAt(message, offset), schema, extensionRegistry); + } + + private <E> void readGroupList( + Object message, + long offset, + Reader reader, + Schema<E> schema, + ExtensionRegistryLite extensionRegistry) + throws IOException { + reader.readGroupList( + listFieldSchema.<E>mutableListAt(message, offset), schema, extensionRegistry); + } + + private int numberAt(int pos) { + return buffer[pos]; + } + + private int typeAndOffsetAt(int pos) { + return buffer[pos + 1]; + } + + private int presenceMaskAndOffsetAt(int pos) { + return buffer[pos + 2]; + } + + private static int type(int value) { + return (value & FIELD_TYPE_MASK) >>> OFFSET_BITS; + } + + private static boolean isRequired(int value) { + return (value & REQUIRED_MASK) != 0; + } + + private static boolean isEnforceUtf8(int value) { + return (value & ENFORCE_UTF8_MASK) != 0; + } + + private static long offset(int value) { + return value & OFFSET_MASK; + } + + private static <T> double doubleAt(T message, long offset) { + return UnsafeUtil.getDouble(message, offset); + } + + private static <T> float floatAt(T message, long offset) { + return UnsafeUtil.getFloat(message, offset); + } + + private static <T> int intAt(T message, long offset) { + return UnsafeUtil.getInt(message, offset); + } + + private static <T> long longAt(T message, long offset) { + return UnsafeUtil.getLong(message, offset); + } + + private static <T> boolean booleanAt(T message, long offset) { + return UnsafeUtil.getBoolean(message, offset); + } + + private static <T> double oneofDoubleAt(T message, long offset) { + return ((Double) UnsafeUtil.getObject(message, offset)).doubleValue(); + } + + private static <T> float oneofFloatAt(T message, long offset) { + return ((Float) UnsafeUtil.getObject(message, offset)).floatValue(); + } + + private static <T> int oneofIntAt(T message, long offset) { + return ((Integer) UnsafeUtil.getObject(message, offset)).intValue(); + } + + private static <T> long oneofLongAt(T message, long offset) { + return ((Long) UnsafeUtil.getObject(message, offset)).longValue(); + } + + private static <T> boolean oneofBooleanAt(T message, long offset) { + return ((Boolean) UnsafeUtil.getObject(message, offset)).booleanValue(); + } + + /** Returns true the field is present in both messages, or neither. */ + private boolean arePresentForEquals(T message, T other, int pos) { + return isFieldPresent(message, pos) == isFieldPresent(other, pos); + } + + private boolean isFieldPresent(T message, int pos, int presenceField, int presenceMask) { + if (proto3) { + return isFieldPresent(message, pos); + } else { + return (presenceField & presenceMask) != 0; + } + } + + private boolean isFieldPresent(T message, int pos) { + if (proto3) { + final int typeAndOffset = typeAndOffsetAt(pos); + final long offset = offset(typeAndOffset); + switch (type(typeAndOffset)) { + case 0: // DOUBLE: + return UnsafeUtil.getDouble(message, offset) != 0D; + case 1: // FLOAT: + return UnsafeUtil.getFloat(message, offset) != 0F; + case 2: // INT64: + return UnsafeUtil.getLong(message, offset) != 0L; + case 3: // UINT64: + return UnsafeUtil.getLong(message, offset) != 0L; + case 4: // INT32: + return UnsafeUtil.getInt(message, offset) != 0; + case 5: // FIXED64: + return UnsafeUtil.getLong(message, offset) != 0L; + case 6: // FIXED32: + return UnsafeUtil.getInt(message, offset) != 0; + case 7: // BOOL: + return UnsafeUtil.getBoolean(message, offset); + case 8: // STRING: + Object value = UnsafeUtil.getObject(message, offset); + if (value instanceof String) { + return !((String) value).isEmpty(); + } else if (value instanceof ByteString) { + return !ByteString.EMPTY.equals(value); + } else { + throw new IllegalArgumentException(); + } + case 9: // MESSAGE: + return UnsafeUtil.getObject(message, offset) != null; + case 10: // BYTES: + return !ByteString.EMPTY.equals(UnsafeUtil.getObject(message, offset)); + case 11: // UINT32: + return UnsafeUtil.getInt(message, offset) != 0; + case 12: // ENUM: + return UnsafeUtil.getInt(message, offset) != 0; + case 13: // SFIXED32: + return UnsafeUtil.getInt(message, offset) != 0; + case 14: // SFIXED64: + return UnsafeUtil.getLong(message, offset) != 0L; + case 15: // SINT32: + return UnsafeUtil.getInt(message, offset) != 0; + case 16: // SINT64: + return UnsafeUtil.getLong(message, offset) != 0L; + case 17: // GROUP: + return UnsafeUtil.getObject(message, offset) != null; + default: + throw new IllegalArgumentException(); + } + } else { + int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos); + final int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS); + return (UnsafeUtil.getInt(message, presenceMaskAndOffset & OFFSET_MASK) & presenceMask) != 0; + } + } + + private void setFieldPresent(T message, int pos) { + if (proto3) { + // Proto3 doesn't have presence fields + return; + } + int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos); + final int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS); + final long presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK; + UnsafeUtil.putInt( + message, + presenceFieldOffset, + UnsafeUtil.getInt(message, presenceFieldOffset) | presenceMask); + } + + private boolean isOneofPresent(T message, int fieldNumber, int pos) { + int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos); + return UnsafeUtil.getInt(message, presenceMaskAndOffset & OFFSET_MASK) == fieldNumber; + } + + private boolean isOneofCaseEqual(T message, T other, int pos) { + int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos); + return UnsafeUtil.getInt(message, presenceMaskAndOffset & OFFSET_MASK) + == UnsafeUtil.getInt(other, presenceMaskAndOffset & OFFSET_MASK); + } + + private void setOneofPresent(T message, int fieldNumber, int pos) { + int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos); + UnsafeUtil.putInt(message, presenceMaskAndOffset & OFFSET_MASK, fieldNumber); + } + + private int positionForFieldNumber(final int number) { + if (number >= minFieldNumber && number <= maxFieldNumber) { + return slowPositionForFieldNumber(number, 0); + } + return -1; + } + + private int positionForFieldNumber(final int number, final int min) { + if (number >= minFieldNumber && number <= maxFieldNumber) { + return slowPositionForFieldNumber(number, min); + } + return -1; + } + + private int slowPositionForFieldNumber(final int number, int min) { + int max = buffer.length / INTS_PER_FIELD - 1; + while (min <= max) { + // Find the midpoint address. + final int mid = (max + min) >>> 1; + final int pos = mid * INTS_PER_FIELD; + final int midFieldNumber = numberAt(pos); + if (number == midFieldNumber) { + // Found the field. + return pos; + } + if (number < midFieldNumber) { + // Search the lower half. + max = mid - 1; + } else { + // Search the upper half. + min = mid + 1; + } + } + return -1; + } + + int getSchemaSize() { + return buffer.length * 3; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java new file mode 100755 index 000000000..187dc8b8a --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java @@ -0,0 +1,392 @@ +// 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 java.io.IOException; +import java.util.Iterator; +import java.util.Map.Entry; + +/** Schema used for proto2 messages using message_set_wireformat. */ +final class MessageSetSchema<T> implements Schema<T> { + private final MessageLite defaultInstance; + private final UnknownFieldSchema<?, ?> unknownFieldSchema; + private final boolean hasExtensions; + private final ExtensionSchema<?> extensionSchema; + + private MessageSetSchema( + UnknownFieldSchema<?, ?> unknownFieldSchema, + ExtensionSchema<?> extensionSchema, + MessageLite defaultInstance) { + this.unknownFieldSchema = unknownFieldSchema; + this.hasExtensions = extensionSchema.hasExtensions(defaultInstance); + this.extensionSchema = extensionSchema; + this.defaultInstance = defaultInstance; + } + + static <T> MessageSetSchema<T> newSchema( + UnknownFieldSchema<?, ?> unknownFieldSchema, + ExtensionSchema<?> extensionSchema, + MessageLite defaultInstance) { + return new MessageSetSchema<T>(unknownFieldSchema, extensionSchema, defaultInstance); + } + + @SuppressWarnings("unchecked") + @Override + public T newInstance() { + return (T) defaultInstance.newBuilderForType().buildPartial(); + } + + @Override + public boolean equals(T message, T other) { + Object messageUnknown = unknownFieldSchema.getFromMessage(message); + Object otherUnknown = unknownFieldSchema.getFromMessage(other); + if (!messageUnknown.equals(otherUnknown)) { + return false; + } + if (hasExtensions) { + FieldSet<?> messageExtensions = extensionSchema.getExtensions(message); + FieldSet<?> otherExtensions = extensionSchema.getExtensions(other); + return messageExtensions.equals(otherExtensions); + } + return true; + } + + @Override + public int hashCode(T message) { + int hashCode = unknownFieldSchema.getFromMessage(message).hashCode(); + if (hasExtensions) { + FieldSet<?> extensions = extensionSchema.getExtensions(message); + hashCode = (hashCode * 53) + extensions.hashCode(); + } + return hashCode; + } + + @Override + public void mergeFrom(T message, T other) { + SchemaUtil.mergeUnknownFields(unknownFieldSchema, message, other); + if (hasExtensions) { + SchemaUtil.mergeExtensions(extensionSchema, message, other); + } + } + + @SuppressWarnings("unchecked") + @Override + public void writeTo(T message, Writer writer) throws IOException { + FieldSet<?> extensions = extensionSchema.getExtensions(message); + Iterator<?> iterator = extensions.iterator(); + while (iterator.hasNext()) { + Entry<?, ?> extension = (Entry<?, ?>) iterator.next(); + FieldSet.FieldDescriptorLite<?> fd = (FieldSet.FieldDescriptorLite<?>) extension.getKey(); + if (fd.getLiteJavaType() != WireFormat.JavaType.MESSAGE || fd.isRepeated() || fd.isPacked()) { + throw new IllegalStateException("Found invalid MessageSet item."); + } + if (extension instanceof LazyField.LazyEntry) { + writer.writeMessageSetItem( + fd.getNumber(), ((LazyField.LazyEntry) extension).getField().toByteString()); + } else { + writer.writeMessageSetItem(fd.getNumber(), extension.getValue()); + } + } + writeUnknownFieldsHelper(unknownFieldSchema, message, writer); + } + + /** + * A helper method for wildcard capture of {@code unknownFieldSchema}. See: + * https://docs.oracle.com/javase/tutorial/java/generics/capture.html + */ + private <UT, UB> void writeUnknownFieldsHelper( + UnknownFieldSchema<UT, UB> unknownFieldSchema, T message, Writer writer) throws IOException { + unknownFieldSchema.writeAsMessageSetTo(unknownFieldSchema.getFromMessage(message), writer); + } + + @SuppressWarnings("ReferenceEquality") + @Override + public void mergeFrom( + T message, byte[] data, int position, int limit, ArrayDecoders.Registers registers) + throws IOException { + UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields; + if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) { + unknownFields = UnknownFieldSetLite.newInstance(); + ((GeneratedMessageLite) message).unknownFields = unknownFields; + } + final FieldSet<GeneratedMessageLite.ExtensionDescriptor> extensions = + ((GeneratedMessageLite.ExtendableMessage<?, ?>) message).ensureExtensionsAreMutable(); + GeneratedMessageLite.GeneratedExtension<?, ?> extension = null; + while (position < limit) { + position = ArrayDecoders.decodeVarint32(data, position, registers); + final int startTag = registers.int1; + if (startTag != WireFormat.MESSAGE_SET_ITEM_TAG) { + if (WireFormat.getTagWireType(startTag) == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + extension = + (GeneratedMessageLite.GeneratedExtension<?, ?>) extensionSchema.findExtensionByNumber( + registers.extensionRegistry, defaultInstance, + WireFormat.getTagFieldNumber(startTag)); + if (extension != null) { + position = + ArrayDecoders.decodeMessageField( + Protobuf.getInstance().schemaFor( + extension.getMessageDefaultInstance().getClass()), + data, position, limit, registers); + extensions.setField(extension.descriptor, registers.object1); + } else { + position = + ArrayDecoders.decodeUnknownField( + startTag, data, position, limit, unknownFields, registers); + } + } else { + position = ArrayDecoders.skipField(startTag, data, position, limit, registers); + } + continue; + } + + int typeId = 0; + ByteString rawBytes = null; + + while (position < limit) { + position = ArrayDecoders.decodeVarint32(data, position, registers); + final int tag = registers.int1; + final int number = WireFormat.getTagFieldNumber(tag); + final int wireType = WireFormat.getTagWireType(tag); + switch (number) { + case WireFormat.MESSAGE_SET_TYPE_ID: + if (wireType == WireFormat.WIRETYPE_VARINT) { + position = ArrayDecoders.decodeVarint32(data, position, registers); + typeId = registers.int1; + extension = + (GeneratedMessageLite.GeneratedExtension<?, ?>) extensionSchema + .findExtensionByNumber(registers.extensionRegistry, defaultInstance, typeId); + continue; + } + break; + case WireFormat.MESSAGE_SET_MESSAGE: + if (extension != null) { + position = ArrayDecoders.decodeMessageField( + Protobuf.getInstance().schemaFor( + extension.getMessageDefaultInstance().getClass()), + data, position, limit, registers); + extensions.setField(extension.descriptor, registers.object1); + continue; + } else { + if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + position = ArrayDecoders.decodeBytes(data, position, registers); + rawBytes = (ByteString) registers.object1; + continue; + } + break; + } + default: + break; + } + if (tag == WireFormat.MESSAGE_SET_ITEM_END_TAG) { + break; + } + position = ArrayDecoders.skipField(tag, data, position, limit, registers); + } + + if (rawBytes != null) { + unknownFields.storeField( + WireFormat.makeTag(typeId, WireFormat.WIRETYPE_LENGTH_DELIMITED), rawBytes); + } + } + if (position != limit) { + throw InvalidProtocolBufferException.parseFailure(); + } + } + + @Override + public void mergeFrom(T message, Reader reader, ExtensionRegistryLite extensionRegistry) + throws IOException { + mergeFromHelper(unknownFieldSchema, extensionSchema, message, reader, extensionRegistry); + } + + /** + * A helper method for wildcard capture of {@code unknownFieldSchema}. See: + * https://docs.oracle.com/javase/tutorial/java/generics/capture.html + */ + @SuppressWarnings("unchecked") + private <UT, UB, ET extends FieldSet.FieldDescriptorLite<ET>> void mergeFromHelper( + UnknownFieldSchema<UT, UB> unknownFieldSchema, + ExtensionSchema<ET> extensionSchema, + T message, + Reader reader, + ExtensionRegistryLite extensionRegistry) + throws IOException { + UB unknownFields = unknownFieldSchema.getBuilderFromMessage(message); + FieldSet<ET> extensions = extensionSchema.getMutableExtensions(message); + try { + while (true) { + final int number = reader.getFieldNumber(); + if (number == Reader.READ_DONE) { + return; + } + if (parseMessageSetItemOrUnknownField( + reader, + extensionRegistry, + extensionSchema, + extensions, + unknownFieldSchema, + unknownFields)) { + continue; + } + // Done reading. + return; + } + } finally { + unknownFieldSchema.setBuilderToMessage(message, unknownFields); + } + } + + @Override + public void makeImmutable(T message) { + unknownFieldSchema.makeImmutable(message); + extensionSchema.makeImmutable(message); + } + + private <UT, UB, ET extends FieldSet.FieldDescriptorLite<ET>> + boolean parseMessageSetItemOrUnknownField( + Reader reader, + ExtensionRegistryLite extensionRegistry, + ExtensionSchema<ET> extensionSchema, + FieldSet<ET> extensions, + UnknownFieldSchema<UT, UB> unknownFieldSchema, + UB unknownFields) + throws IOException { + int startTag = reader.getTag(); + if (startTag != WireFormat.MESSAGE_SET_ITEM_TAG) { + if (WireFormat.getTagWireType(startTag) == WireFormat.WIRETYPE_LENGTH_DELIMITED) { + Object extension = + extensionSchema.findExtensionByNumber( + extensionRegistry, defaultInstance, WireFormat.getTagFieldNumber(startTag)); + if (extension != null) { + extensionSchema.parseLengthPrefixedMessageSetItem( + reader, extension, extensionRegistry, extensions); + return true; + } else { + return unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader); + } + } else { + return reader.skipField(); + } + } + + // 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" + Object 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. + loop: + while (true) { + final int number = reader.getFieldNumber(); + if (number == Reader.READ_DONE) { + break; + } + + final int tag = reader.getTag(); + if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) { + typeId = reader.readUInt32(); + extension = + extensionSchema.findExtensionByNumber(extensionRegistry, defaultInstance, typeId); + continue; + } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) { + if (extension != null) { + extensionSchema.parseLengthPrefixedMessageSetItem( + reader, extension, extensionRegistry, extensions); + continue; + } + // We haven't seen a type ID yet or we want parse message lazily. + rawBytes = reader.readBytes(); + continue; + } else { + if (!reader.skipField()) { + break loop; // End of group + } + } + } + + if (reader.getTag() != WireFormat.MESSAGE_SET_ITEM_END_TAG) { + throw InvalidProtocolBufferException.invalidEndTag(); + } + + // If there are any rawBytes left, it means the message content appears before the type ID. + if (rawBytes != null) { + if (extension != null) { // We known the type + // TODO(xiaofeng): Instead of reading into a temporary ByteString, maybe there is a way + // to read directly from Reader to the submessage? + extensionSchema.parseMessageSetItem(rawBytes, extension, extensionRegistry, extensions); + } else { + unknownFieldSchema.addLengthDelimited(unknownFields, typeId, rawBytes); + } + } + return true; + } + + @Override + public final boolean isInitialized(T message) { + FieldSet<?> extensions = extensionSchema.getExtensions(message); + return extensions.isInitialized(); + } + + @Override + public int getSerializedSize(T message) { + int size = 0; + + size += getUnknownFieldsSerializedSize(unknownFieldSchema, message); + + if (hasExtensions) { + size += extensionSchema.getExtensions(message).getMessageSetSerializedSize(); + } + + return size; + } + + private <UT, UB> int getUnknownFieldsSerializedSize( + UnknownFieldSchema<UT, UB> schema, T message) { + UT unknowns = schema.getFromMessage(message); + return schema.getSerializedSizeAsMessageSet(unknowns); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/NewInstanceSchema.java b/java/core/src/main/java/com/google/protobuf/NewInstanceSchema.java new file mode 100755 index 000000000..f2dbb8ef9 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/NewInstanceSchema.java @@ -0,0 +1,36 @@ +// 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; + +interface NewInstanceSchema { + /** Create a new message instance given the default instance of the message type. */ + Object newInstance(Object defaultInstance); +} diff --git a/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaFull.java b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaFull.java new file mode 100755 index 000000000..3433b657e --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaFull.java @@ -0,0 +1,39 @@ +// 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; + +final class NewInstanceSchemaFull implements NewInstanceSchema { + @Override + public Object newInstance(Object defaultInstance) { + return ((GeneratedMessageV3) defaultInstance) + .newInstance(GeneratedMessageV3.UnusedPrivateParameter.INSTANCE); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java new file mode 100755 index 000000000..9b9226676 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java @@ -0,0 +1,39 @@ +// 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; + +final class NewInstanceSchemaLite implements NewInstanceSchema { + @Override + public Object newInstance(Object defaultInstance) { + return ((GeneratedMessageLite) defaultInstance) + .dynamicMethod(GeneratedMessageLite.MethodToInvoke.NEW_MUTABLE_INSTANCE); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/NewInstanceSchemas.java b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemas.java new file mode 100755 index 000000000..eff45f67b --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemas.java @@ -0,0 +1,53 @@ +// 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; + +final class NewInstanceSchemas { + private static final NewInstanceSchema FULL_SCHEMA = loadSchemaForFullRuntime(); + private static final NewInstanceSchema LITE_SCHEMA = new NewInstanceSchemaLite(); + + static NewInstanceSchema full() { + return FULL_SCHEMA; + } + + static NewInstanceSchema lite() { + return LITE_SCHEMA; + } + + private static NewInstanceSchema loadSchemaForFullRuntime() { + try { + Class<?> clazz = Class.forName("com.google.protobuf.NewInstanceSchemaFull"); + return (NewInstanceSchema) clazz.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + return null; + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/OneofInfo.java b/java/core/src/main/java/com/google/protobuf/OneofInfo.java new file mode 100755 index 000000000..bc518fcad --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/OneofInfo.java @@ -0,0 +1,66 @@ +// 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 java.lang.reflect.Field; + +/** Information for a oneof within a protobuf message. */ +// TODO(nathanmittler): make this private once all of experimental code is migrated to protobuf. +@ExperimentalApi +final class OneofInfo { + private final int id; + private final Field caseField; + private final Field valueField; + + public OneofInfo(int id, Field caseField, Field valueField) { + this.id = id; + this.caseField = caseField; + this.valueField = valueField; + } + + /** + * Returns the unique identifier of the oneof within the message. This is really just an index + * starting at zero. + */ + public int getId() { + return id; + } + + /** The {@code int} field containing the field number of the currently active member. */ + public Field getCaseField() { + return caseField; + } + + /** The {@link Object} field containing the value of the currently active member. */ + public Field getValueField() { + return valueField; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/ProtoSyntax.java b/java/core/src/main/java/com/google/protobuf/ProtoSyntax.java new file mode 100755 index 000000000..851b839f6 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ProtoSyntax.java @@ -0,0 +1,38 @@ +// 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; + +/** Represents the syntax version of the message. */ +@ExperimentalApi +public enum ProtoSyntax { + PROTO2, + PROTO3; +} diff --git a/java/core/src/main/java/com/google/protobuf/Protobuf.java b/java/core/src/main/java/com/google/protobuf/Protobuf.java new file mode 100755 index 000000000..adaa7fa8f --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/Protobuf.java @@ -0,0 +1,152 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.Internal.checkNotNull; + +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Main runtime interface for protobuf. Applications should interact with this interface (rather + * than directly accessing internal APIs) in order to perform operations on protobuf messages. + */ +@ExperimentalApi +final class Protobuf { + private static final Protobuf INSTANCE = new Protobuf(); + + private final SchemaFactory schemaFactory; + + // TODO(nathanmittler): Consider using ClassValue instead. + private final ConcurrentMap<Class<?>, Schema<?>> schemaCache = + new ConcurrentHashMap<Class<?>, Schema<?>>(); + + /** Gets the singleton instance of the Protobuf runtime. */ + public static Protobuf getInstance() { + return INSTANCE; + } + + /** Writes the given message to the target {@link Writer}. */ + public <T> void writeTo(T message, Writer writer) throws IOException { + schemaFor(message).writeTo(message, writer); + } + + /** Reads fields from the given {@link Reader} and merges them into the message. */ + public <T> void mergeFrom(T message, Reader reader) throws IOException { + mergeFrom(message, reader, ExtensionRegistryLite.getEmptyRegistry()); + } + + /** Reads fields from the given {@link Reader} and merges them into the message. */ + public <T> void mergeFrom(T message, Reader reader, ExtensionRegistryLite extensionRegistry) + throws IOException { + schemaFor(message).mergeFrom(message, reader, extensionRegistry); + } + + /** Marks repeated/map/extension/unknown fields as immutable. */ + public <T> void makeImmutable(T message) { + schemaFor(message).makeImmutable(message); + } + + /** + * Checks if all required fields are set. TODO(xiaofeng): Make this package private when the tests + * are moved to protobuf package. + */ + public <T> boolean isInitialized(T message) { + return schemaFor(message).isInitialized(message); + } + + /** Gets the schema for the given message type. */ + public <T> Schema<T> schemaFor(Class<T> messageType) { + checkNotNull(messageType, "messageType"); + @SuppressWarnings("unchecked") + Schema<T> schema = (Schema<T>) schemaCache.get(messageType); + if (schema == null) { + schema = schemaFactory.createSchema(messageType); + @SuppressWarnings("unchecked") + Schema<T> previous = (Schema<T>) registerSchema(messageType, schema); + if (previous != null) { + // A new schema was registered by another thread. + schema = previous; + } + } + return schema; + } + + /** Gets the schema for the given message. */ + @SuppressWarnings("unchecked") + public <T> Schema<T> schemaFor(T message) { + return schemaFor((Class<T>) message.getClass()); + } + + /** + * Registers the given schema for the message type only if a schema was not already registered. + * + * @param messageType the type of message on which the schema operates. + * @param schema the schema for the message type. + * @return the previously registered schema, or {@code null} if the given schema was successfully + * registered. + */ + public Schema<?> registerSchema(Class<?> messageType, Schema<?> schema) { + checkNotNull(messageType, "messageType"); + checkNotNull(schema, "schema"); + return schemaCache.putIfAbsent(messageType, schema); + } + + /** + * Visible for testing only. Registers the given schema for the message type. If a schema was + * previously registered, it will be replaced by the provided schema. + * + * @param messageType the type of message on which the schema operates. + * @param schema the schema for the message type. + * @return the previously registered schema, or {@code null} if no schema was registered + * previously. + */ + public Schema<?> registerSchemaOverride(Class<?> messageType, Schema<?> schema) { + checkNotNull(messageType, "messageType"); + checkNotNull(schema, "schema"); + return schemaCache.put(messageType, schema); + } + + private Protobuf() { + schemaFactory = new ManifestSchemaFactory(); + } + + int getTotalSchemaSize() { + int result = 0; + for (Schema<?> schema : schemaCache.values()) { + if (schema instanceof MessageSchema) { + result += ((MessageSchema) schema).getSchemaSize(); + } + } + return result; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/ProtobufLists.java b/java/core/src/main/java/com/google/protobuf/ProtobufLists.java new file mode 100755 index 000000000..271c849b4 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ProtobufLists.java @@ -0,0 +1,94 @@ +// 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.Internal.BooleanList; +import com.google.protobuf.Internal.DoubleList; +import com.google.protobuf.Internal.FloatList; +import com.google.protobuf.Internal.IntList; +import com.google.protobuf.Internal.LongList; +import com.google.protobuf.Internal.ProtobufList; + +/** Utility class for construction of lists that extend {@link ProtobufList}. */ +@ExperimentalApi +final class ProtobufLists { + private ProtobufLists() {} + + public static <E> ProtobufList<E> emptyProtobufList() { + return ProtobufArrayList.emptyList(); + } + + public static <E> ProtobufList<E> mutableCopy(ProtobufList<E> list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + } + + public static BooleanList emptyBooleanList() { + return BooleanArrayList.emptyList(); + } + + public static BooleanList newBooleanList() { + return new BooleanArrayList(); + } + + public static IntList emptyIntList() { + return IntArrayList.emptyList(); + } + + public static IntList newIntList() { + return new IntArrayList(); + } + + public static LongList emptyLongList() { + return LongArrayList.emptyList(); + } + + public static LongList newLongList() { + return new LongArrayList(); + } + + public static FloatList emptyFloatList() { + return FloatArrayList.emptyList(); + } + + public static FloatList newFloatList() { + return new FloatArrayList(); + } + + public static DoubleList emptyDoubleList() { + return DoubleArrayList.emptyList(); + } + + public static DoubleList newDoubleList() { + return new DoubleArrayList(); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java b/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java new file mode 100755 index 000000000..3982d2e22 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java @@ -0,0 +1,226 @@ +// 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; + +/** + * RawMessageInfo stores the same amount of information as {@link MessageInfo} but in a more compact + * format. + */ +final class RawMessageInfo implements MessageInfo { + + private final MessageLite defaultInstance; + + /** + * The compact format packs everything in a String object and a Object[] array. The String object + * is encoded with field number, field type, hasbits offset, oneof index, etc., whereas the + * Object[] array contains field references, class references, instance references, etc. + * BEGIN GOOGLE-INTERNAL + * + * See + * https://docs.google.com/document/d/1_z6-tIa31Pq6MUi_79eA5S6214J13idRbAHTgn3vqXY/edit#heading=h.cifnozjwpoe9 + * for more information. + * END GOOGLE-INTERNAL + * + * <p>The String object encodes a sequence of integers into UTF-16 characters. For each int, it + * will be encoding into 1 to 3 UTF-16 characters depending on its unsigned value: + * + * <ul> + * <li>1 char: [c1: 0x0000 - 0xD7FF] = int of the same value. + * <li>2 chars: [c1: 0xE000 - 0xFFFF], [c2: 0x0000 - 0xD7FF] = (c2 << 13) | (c1 & 0x1FFF) + * <li>3 chars: [c1: 0xE000 - 0xFFFF], [c2: 0xE000 - 0xFFFF], [c3: 0x0000 - 0xD7FF] = (c3 << 26) + * | ((c2 & 0x1FFF) << 13) | (c1 & 0x1FFF) + * </ul> + * + * <p>Note that we don't use UTF-16 surrogate pairs [0xD800 - 0xDFFF] because they have to come in + * pairs to form a valid UTF-16char sequence and don't help us encode values more efficiently. + * + * <p>The integer sequence encoded in the String object has the following layout: + * + * <ul> + * <li>[0]: flags, flags & 0x1 = is proto2?, flags & 0x2 = is message?. + * <li>[1]: field count, if 0, this is the end of the integer sequence and the corresponding + * Object[] array should be null. + * <li>[2]: oneof count + * <li>[3]: hasbits count, how many hasbits integers are generated. + * <li>[4]: min field number + * <li>[5]: max field number + * <li>[6]: total number of entries need to allocate + * <li>[7]: map field count + * <li>[8]: repeated field count, this doesn't include map fields. + * <li>[9]: size of checkInitialized array + * <li>[...]: field entries + * </ul> + * + * <p>Each field entry starts with a field number and the field type: + * + * <ul> + * <li>[0]: field number + * <li>[1]: field type with extra bits: + * <ul> + * <li>v & 0xFF = field type as defined in the FieldType class + * <li>v & 0x100 = is required? + * <li>v & 0x200 = is checkUtf8? + * <li>v & 0x400 = needs isInitialized check? + * <li>v & 0x800 = is map field with proto2 enum value? + * </ul> + * </ul> + * + * If the file is proto2 and this is a singular field: + * + * <ul> + * <li>[2]: hasbits offset + * </ul> + * + * If the field is in an oneof: + * + * <ul> + * <li>[2]: oenof index + * </ul> + * + * For other types, the field entry only has field number and field type. + * + * <p>The Object[] array has 3 sections: + * + * <ul> + * <li>---- oneof section ---- + * <ul> + * <li>[0]: value field for oneof 1. + * <li>[1]: case field for oneof 1. + * <li>... + * <li>[.]: value field for oneof n. + * <li>[.]: case field for oneof n. + * </ul> + * <li>---- hasbits section ---- + * <ul> + * <li>[.]: hasbits field 1 + * <li>[.]: hasbits field 2 + * <li>... + * <li>[.]: hasbits field n + * </ul> + * <li>---- field section ---- + * <ul> + * <li>[...]: field entries + * </ul> + * </ul> + * + * <p>In the Object[] array, field entries are ordered in the same way as field entries in the + * String object. The size of each entry is determined by the field type. + * + * <ul> + * <li>Oneof field: + * <ul> + * <li>Oneof message field: + * <ul> + * <li>[0]: message class reference. + * </ul> + * <li>Oneof enum fieldin proto2: + * <ul> + * <li>[0]: EnumLiteMap + * </ul> + * <li>For all other oneof fields, field entry in the Object[] array is empty. + * </ul> + * <li>Repeated message field: + * <ul> + * <li>[0]: field reference + * <li>[1]: message class reference + * </ul> + * <li>Proto2 singular/repeated enum field: + * <ul> + * <li>[0]: field reference + * <li>[1]: EnumLiteMap + * </ul> + * <li>Map field with a proto2 enum value: + * <ul> + * <li>[0]: field reference + * <li>[1]: map default entry instance + * <li>[2]: EnumLiteMap + * </ul> + * <li>Map field with other value types: + * <ul> + * <li>[0]: field reference + * <li>[1]: map default entry instance + * </ul> + * <li>All other field type: + * <ul> + * <li>[0]: field reference + * </ul> + * </ul> + * + * <p>In order to read the field info from this compact format, a reader needs to progress through + * the String object and the Object[] array simultaneously. + */ + private final String info; + + private final Object[] objects; + private final int flags; + + RawMessageInfo(MessageLite defaultInstance, String info, Object[] objects) { + this.defaultInstance = defaultInstance; + this.info = info; + this.objects = objects; + int position = 0; + int value = (int) info.charAt(position++); + if (value < 0xD800) { + flags = value; + } else { + int result = value & 0x1FFF; + int shift = 13; + while ((value = info.charAt(position++)) >= 0xD800) { + result |= (value & 0x1FFF) << shift; + shift += 13; + } + flags = result | (value << shift); + } + } + + String getStringInfo() { + return info; + } + + Object[] getObjects() { + return objects; + } + + @Override + public MessageLite getDefaultInstance() { + return defaultInstance; + } + + @Override + public ProtoSyntax getSyntax() { + return (flags & 0x1) == 0x1 ? ProtoSyntax.PROTO2 : ProtoSyntax.PROTO3; + } + + @Override + public boolean isMessageSetWireFormat() { + return (flags & 0x2) == 0x2; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/Reader.java b/java/core/src/main/java/com/google/protobuf/Reader.java new file mode 100755 index 000000000..705096f2d --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/Reader.java @@ -0,0 +1,379 @@ +// 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 java.io.IOException; +import java.util.List; +import java.util.Map; + +/** A reader of fields from a serialized protobuf message. */ +// TODO(nathanmittler): Refactor to allow the reader to allocate properly sized lists. +@ExperimentalApi +interface Reader { + /** Value used to indicate that the end of input has been reached. */ + int READ_DONE = Integer.MAX_VALUE; + + /** Value used to indicate that the reader does not know the tag about the field. */ + int TAG_UNKNOWN = 0; + + boolean shouldDiscardUnknownFields(); + + /** + * Gets the field number for the current field being read. + * + * <p>TODO(liujisi): Rename it to make it more explicit about the side effect on the underlying + * buffer. + * + * @return the current field number or {@link #READ_DONE} if the end of input has been reached. + */ + int getFieldNumber() throws IOException; + + /** + * Gets the wire tag of the current field. + * + * @return the current wire tag or {@link #TAG_UNKNOWN} if the reader does not know the tag of the + * current field. + */ + int getTag(); + + /** + * Skips the current field and advances the reader to the next field. + * + * @return {@code true} if there are more fields or {@code false} if the end of input has been + * reached. + */ + boolean skipField() throws IOException; + + /** + * Reads and returns the next field of type {@code DOUBLE} and advances the reader to the next + * field. + */ + double readDouble() throws IOException; + + /** + * Reads and returns the next field of type {@code FLOAT} and advances the reader to the next + * field. + */ + float readFloat() throws IOException; + + /** + * Reads and returns the next field of type {@code UINT64} and advances the reader to the next + * field. + */ + long readUInt64() throws IOException; + + /** + * Reads and returns the next field of type {@code INT64} and advances the reader to the next + * field. + */ + long readInt64() throws IOException; + + /** + * Reads and returns the next field of type {@code INT32} and advances the reader to the next + * field. + */ + int readInt32() throws IOException; + + /** + * Reads and returns the next field of type {@code FIXED64} and advances the reader to the next + * field. + */ + long readFixed64() throws IOException; + + /** + * Reads and returns the next field of type {@code FIXED32} and advances the reader to the next + * field. + */ + int readFixed32() throws IOException; + + /** + * Reads and returns the next field of type {@code BOOL} and advances the reader to the next + * field. + */ + boolean readBool() throws IOException; + + /** + * Reads and returns the next field of type {@code STRING} and advances the reader to the next + * field. If the stream contains malformed UTF-8, replace the offending bytes with the standard + * UTF-8 replacement character. + */ + String readString() throws IOException; + + /** + * Reads and returns the next field of type {@code STRING} and advances the reader to the next + * field. If the stream contains malformed UTF-8, throw exception {@link + * InvalidProtocolBufferException}. + */ + String readStringRequireUtf8() throws IOException; + + // TODO(yilunchong): the lack of other opinions for whether to expose this on the interface + <T> T readMessageBySchemaWithCheck(Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException; + + /** + * Reads and returns the next field of type {@code MESSAGE} and advances the reader to the next + * field. + */ + <T> T readMessage(Class<T> clazz, ExtensionRegistryLite extensionRegistry) throws IOException; + + /** + * Reads and returns the next field of type {@code GROUP} and advances the reader to the next + * field. + * + * @deprecated groups fields are deprecated. + */ + @Deprecated + <T> T readGroup(Class<T> clazz, ExtensionRegistryLite extensionRegistry) throws IOException; + + // TODO(yilunchong): the lack of other opinions for whether to expose this on the interface + @Deprecated + <T> T readGroupBySchemaWithCheck(Schema<T> schema, ExtensionRegistryLite extensionRegistry) + throws IOException; + + /** + * Reads and returns the next field of type {@code BYTES} and advances the reader to the next + * field. + */ + ByteString readBytes() throws IOException; + + /** + * Reads and returns the next field of type {@code UINT32} and advances the reader to the next + * field. + */ + int readUInt32() throws IOException; + + /** + * Reads and returns the next field of type {@code ENUM} and advances the reader to the next + * field. + */ + int readEnum() throws IOException; + + /** + * Reads and returns the next field of type {@code SFIXED32} and advances the reader to the next + * field. + */ + int readSFixed32() throws IOException; + + /** + * Reads and returns the next field of type {@code SFIXED64} and advances the reader to the next + * field. + */ + long readSFixed64() throws IOException; + + /** + * Reads and returns the next field of type {@code SINT32} and advances the reader to the next + * field. + */ + int readSInt32() throws IOException; + + /** + * Reads and returns the next field of type {@code SINT64} and advances the reader to the next + * field. + */ + long readSInt64() throws IOException; + + /** + * Reads the next field of type {@code DOUBLE_LIST} or {@code DOUBLE_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readDoubleList(List<Double> target) throws IOException; + + /** + * Reads the next field of type {@code FLOAT_LIST} or {@code FLOAT_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readFloatList(List<Float> target) throws IOException; + + /** + * Reads the next field of type {@code UINT64_LIST} or {@code UINT64_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readUInt64List(List<Long> target) throws IOException; + + /** + * Reads the next field of type {@code INT64_LIST} or {@code INT64_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readInt64List(List<Long> target) throws IOException; + + /** + * Reads the next field of type {@code INT32_LIST} or {@code INT32_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readInt32List(List<Integer> target) throws IOException; + + /** + * Reads the next field of type {@code FIXED64_LIST} or {@code FIXED64_LIST_PACKED} and advances + * the reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readFixed64List(List<Long> target) throws IOException; + + /** + * Reads the next field of type {@code FIXED32_LIST} or {@code FIXED32_LIST_PACKED} and advances + * the reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readFixed32List(List<Integer> target) throws IOException; + + /** + * Reads the next field of type {@code BOOL_LIST} or {@code BOOL_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readBoolList(List<Boolean> target) throws IOException; + + /** + * Reads the next field of type {@code STRING_LIST} and advances the reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readStringList(List<String> target) throws IOException; + + /** + * Reads the next field of type {@code STRING_LIST} and advances the reader to the next field. If + * the stream contains malformed UTF-8, throw exception {@link InvalidProtocolBufferException}. + * + * @param target the list that will receive the read values. + */ + void readStringListRequireUtf8(List<String> target) throws IOException; + + /** + * Reads the next field of type {@code MESSAGE_LIST} and advances the reader to the next field. + * + * @param target the list that will receive the read values. + * @param targetType the type of the elements stored in the {@code target} list. + */ + <T> void readMessageList( + List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException; + + <T> void readMessageList( + List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry) + throws IOException; + + /** + * Reads the next field of type {@code GROUP_LIST} and advances the reader to the next field. + * + * @param target the list that will receive the read values. + * @param targetType the type of the elements stored in the {@code target} list. + * @deprecated groups fields are deprecated. + */ + @Deprecated + <T> void readGroupList( + List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry) + throws IOException; + + @Deprecated + <T> void readGroupList( + List<T> target, Schema<T> targetType, ExtensionRegistryLite extensionRegistry) + throws IOException; + + /** + * Reads the next field of type {@code BYTES_LIST} and advances the reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readBytesList(List<ByteString> target) throws IOException; + + /** + * Reads the next field of type {@code UINT32_LIST} or {@code UINT32_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readUInt32List(List<Integer> target) throws IOException; + + /** + * Reads the next field of type {@code ENUM_LIST} or {@code ENUM_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readEnumList(List<Integer> target) throws IOException; + + /** + * Reads the next field of type {@code SFIXED32_LIST} or {@code SFIXED32_LIST_PACKED} and advances + * the reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readSFixed32List(List<Integer> target) throws IOException; + + /** + * Reads the next field of type {@code SFIXED64_LIST} or {@code SFIXED64_LIST_PACKED} and advances + * the reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readSFixed64List(List<Long> target) throws IOException; + + /** + * Reads the next field of type {@code SINT32_LIST} or {@code SINT32_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readSInt32List(List<Integer> target) throws IOException; + + /** + * Reads the next field of type {@code SINT64_LIST} or {@code SINT64_LIST_PACKED} and advances the + * reader to the next field. + * + * @param target the list that will receive the read values. + */ + void readSInt64List(List<Long> target) throws IOException; + + /** + * Reads the next field of type {@code MAP} and advances the reader to the next field. + * + * @param target the mutable map that will receive the read values. + * @param mapDefaultEntry the default entry of the map field. + * @param extensionRegistry the extension registry for parsing message value fields. + */ + <K, V> void readMap( + Map<K, V> target, + MapEntryLite.Metadata<K, V> mapDefaultEntry, + ExtensionRegistryLite extensionRegistry) + throws IOException; +} diff --git a/java/core/src/main/java/com/google/protobuf/RopeByteString.java b/java/core/src/main/java/com/google/protobuf/RopeByteString.java index c3bec7b1a..f294df3df 100644 --- a/java/core/src/main/java/com/google/protobuf/RopeByteString.java +++ b/java/core/src/main/java/com/google/protobuf/RopeByteString.java @@ -445,6 +445,11 @@ final class RopeByteString extends ByteString { right.writeTo(output); } + @Override + void writeToReverse(ByteOutput output) throws IOException { + right.writeToReverse(output); + left.writeToReverse(output); + } @Override protected String toStringInternal(Charset charset) { diff --git a/java/core/src/main/java/com/google/protobuf/Schema.java b/java/core/src/main/java/com/google/protobuf/Schema.java new file mode 100755 index 000000000..d0e1e26e5 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/Schema.java @@ -0,0 +1,85 @@ +// 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.ArrayDecoders.Registers; +import java.io.IOException; + +/** + * A runtime schema for a single protobuf message. A schema provides operations on message instances + * such as serialization/deserialization. + */ +@ExperimentalApi +interface Schema<T> { + /** Writes the given message to the target {@link Writer}. */ + void writeTo(T message, Writer writer) throws IOException; + + /** + * Reads fields from the given {@link Reader} and merges them into the message. It doesn't make + * the message immutable after parsing is done. To make the message immutable, use {@link + * #makeImmutable}. + */ + void mergeFrom(T message, Reader reader, ExtensionRegistryLite extensionRegistry) + throws IOException; + + /** + * Like the above but parses from a byte[] without extensions. Entry point of fast path. Note that + * this method may throw IndexOutOfBoundsException if the input data is not valid protobuf wire + * format. Protobuf public API methods should catch and convert that exception to + * InvalidProtocolBufferException. + */ + void mergeFrom(T message, byte[] data, int position, int limit, Registers registers) + throws IOException; + + /** Marks repeated/map/extension/unknown fields as immutable. */ + void makeImmutable(T message); + + /** Checks whether all required fields are set. */ + boolean isInitialized(T message); + + /** Creates a new instance of the message class. */ + T newInstance(); + + /** Determine of the two messages are equal. */ + boolean equals(T message, T other); + + /** Compute a hashCode for the message. */ + int hashCode(T message); + + /** + * Merge values from {@code other} into {@code message}. This method doesn't make the message + * immutable. To make the message immutable after merging, use {@link #makeImmutable}. + */ + void mergeFrom(T message, T other); + + /** Compute the serialized size of the message. */ + int getSerializedSize(T message); +} diff --git a/java/core/src/main/java/com/google/protobuf/SchemaFactory.java b/java/core/src/main/java/com/google/protobuf/SchemaFactory.java new file mode 100755 index 000000000..cf38dd699 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/SchemaFactory.java @@ -0,0 +1,38 @@ +// 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; + +/** A factory that manufactures {@link Schema} instances for protobuf messages. */ +@ExperimentalApi +interface SchemaFactory { + /** Creates a schema instance for the given protobuf message type. */ + <T> Schema<T> createSchema(Class<T> messageType); +} diff --git a/java/core/src/main/java/com/google/protobuf/SchemaUtil.java b/java/core/src/main/java/com/google/protobuf/SchemaUtil.java new file mode 100755 index 000000000..50957fcfd --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/SchemaUtil.java @@ -0,0 +1,991 @@ +// 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.FieldSet.FieldDescriptorLite; +import com.google.protobuf.Internal.EnumLiteMap; +import com.google.protobuf.Internal.EnumVerifier; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.List; +import java.util.RandomAccess; + +/** Helper methods used by schemas. */ +@ExperimentalApi +final class SchemaUtil { + private static final Class<?> GENERATED_MESSAGE_CLASS = getGeneratedMessageClass(); + private static final UnknownFieldSchema<?, ?> PROTO2_UNKNOWN_FIELD_SET_SCHEMA = + getUnknownFieldSetSchema(false); + private static final UnknownFieldSchema<?, ?> PROTO3_UNKNOWN_FIELD_SET_SCHEMA = + getUnknownFieldSetSchema(true); + private static final UnknownFieldSchema<?, ?> UNKNOWN_FIELD_SET_LITE_SCHEMA = + new UnknownFieldSetLiteSchema(); + + private static final int DEFAULT_LOOK_UP_START_NUMBER = 40; + + private SchemaUtil() {} + + /** + * Requires that the given message extend {@link com.google.protobuf.GeneratedMessageV3} or {@link + * GeneratedMessageLite}. + */ + public static void requireGeneratedMessage(Class<?> messageType) { + if (!GeneratedMessageLite.class.isAssignableFrom(messageType) + && GENERATED_MESSAGE_CLASS != null + && !GENERATED_MESSAGE_CLASS.isAssignableFrom(messageType)) { + throw new IllegalArgumentException( + "Message classes must extend GeneratedMessage or GeneratedMessageLite"); + } + } + + public static void writeDouble(int fieldNumber, double value, Writer writer) throws IOException { + if (Double.compare(value, 0.0) != 0) { + writer.writeDouble(fieldNumber, value); + } + } + + public static void writeFloat(int fieldNumber, float value, Writer writer) throws IOException { + if (Float.compare(value, 0.0f) != 0) { + writer.writeFloat(fieldNumber, value); + } + } + + public static void writeInt64(int fieldNumber, long value, Writer writer) throws IOException { + if (value != 0) { + writer.writeInt64(fieldNumber, value); + } + } + + public static void writeUInt64(int fieldNumber, long value, Writer writer) throws IOException { + if (value != 0) { + writer.writeUInt64(fieldNumber, value); + } + } + + public static void writeSInt64(int fieldNumber, long value, Writer writer) throws IOException { + if (value != 0) { + writer.writeSInt64(fieldNumber, value); + } + } + + public static void writeFixed64(int fieldNumber, long value, Writer writer) throws IOException { + if (value != 0) { + writer.writeFixed64(fieldNumber, value); + } + } + + public static void writeSFixed64(int fieldNumber, long value, Writer writer) throws IOException { + if (value != 0) { + writer.writeSFixed64(fieldNumber, value); + } + } + + public static void writeInt32(int fieldNumber, int value, Writer writer) throws IOException { + if (value != 0) { + writer.writeInt32(fieldNumber, value); + } + } + + public static void writeUInt32(int fieldNumber, int value, Writer writer) throws IOException { + if (value != 0) { + writer.writeUInt32(fieldNumber, value); + } + } + + public static void writeSInt32(int fieldNumber, int value, Writer writer) throws IOException { + if (value != 0) { + writer.writeSInt32(fieldNumber, value); + } + } + + public static void writeFixed32(int fieldNumber, int value, Writer writer) throws IOException { + if (value != 0) { + writer.writeFixed32(fieldNumber, value); + } + } + + public static void writeSFixed32(int fieldNumber, int value, Writer writer) throws IOException { + if (value != 0) { + writer.writeSFixed32(fieldNumber, value); + } + } + + public static void writeEnum(int fieldNumber, int value, Writer writer) throws IOException { + if (value != 0) { + writer.writeEnum(fieldNumber, value); + } + } + + public static void writeBool(int fieldNumber, boolean value, Writer writer) throws IOException { + if (value) { + writer.writeBool(fieldNumber, true); + } + } + + public static void writeString(int fieldNumber, Object value, Writer writer) throws IOException { + if (value instanceof String) { + writeStringInternal(fieldNumber, (String) value, writer); + } else { + writeBytes(fieldNumber, (ByteString) value, writer); + } + } + + private static void writeStringInternal(int fieldNumber, String value, Writer writer) + throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeString(fieldNumber, value); + } + } + + public static void writeBytes(int fieldNumber, ByteString value, Writer writer) + throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeBytes(fieldNumber, value); + } + } + + public static void writeMessage(int fieldNumber, Object value, Writer writer) throws IOException { + if (value != null) { + writer.writeMessage(fieldNumber, value); + } + } + + public static void writeDoubleList( + int fieldNumber, List<Double> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeDoubleList(fieldNumber, value, packed); + } + } + + public static void writeFloatList( + int fieldNumber, List<Float> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeFloatList(fieldNumber, value, packed); + } + } + + public static void writeInt64List( + int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeInt64List(fieldNumber, value, packed); + } + } + + public static void writeUInt64List( + int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeUInt64List(fieldNumber, value, packed); + } + } + + public static void writeSInt64List( + int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeSInt64List(fieldNumber, value, packed); + } + } + + public static void writeFixed64List( + int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeFixed64List(fieldNumber, value, packed); + } + } + + public static void writeSFixed64List( + int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeSFixed64List(fieldNumber, value, packed); + } + } + + public static void writeInt32List( + int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeInt32List(fieldNumber, value, packed); + } + } + + public static void writeUInt32List( + int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeUInt32List(fieldNumber, value, packed); + } + } + + public static void writeSInt32List( + int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeSInt32List(fieldNumber, value, packed); + } + } + + public static void writeFixed32List( + int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeFixed32List(fieldNumber, value, packed); + } + } + + public static void writeSFixed32List( + int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeSFixed32List(fieldNumber, value, packed); + } + } + + public static void writeEnumList( + int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeEnumList(fieldNumber, value, packed); + } + } + + public static void writeBoolList( + int fieldNumber, List<Boolean> value, Writer writer, boolean packed) throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeBoolList(fieldNumber, value, packed); + } + } + + public static void writeStringList(int fieldNumber, List<String> value, Writer writer) + throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeStringList(fieldNumber, value); + } + } + + public static void writeBytesList(int fieldNumber, List<ByteString> value, Writer writer) + throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeBytesList(fieldNumber, value); + } + } + + public static void writeMessageList(int fieldNumber, List<?> value, Writer writer) + throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeMessageList(fieldNumber, value); + } + } + + public static void writeMessageList(int fieldNumber, List<?> value, Writer writer, Schema schema) + throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeMessageList(fieldNumber, value, schema); + } + } + + public static void writeLazyFieldList(int fieldNumber, List<?> value, Writer writer) + throws IOException { + if (value != null && !value.isEmpty()) { + for (Object item : value) { + ((LazyFieldLite) item).writeTo(writer, fieldNumber); + } + } + } + + public static void writeGroupList(int fieldNumber, List<?> value, Writer writer) + throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeGroupList(fieldNumber, value); + } + } + + public static void writeGroupList(int fieldNumber, List<?> value, Writer writer, Schema schema) + throws IOException { + if (value != null && !value.isEmpty()) { + writer.writeGroupList(fieldNumber, value, schema); + } + } + + static int computeSizeInt64ListNoTag(List<Long> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + + int size = 0; + + if (list instanceof LongArrayList) { + final LongArrayList primitiveList = (LongArrayList) list; + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeInt64SizeNoTag(primitiveList.getLong(i)); + } + } else { + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeInt64SizeNoTag(list.get(i)); + } + } + return size; + } + + static int computeSizeInt64List(int fieldNumber, List<Long> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = computeSizeInt64ListNoTag(list); + + if (packed) { + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(size); + } else { + return size + (list.size() * CodedOutputStream.computeTagSize(fieldNumber)); + } + } + + static int computeSizeUInt64ListNoTag(List<Long> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + + int size = 0; + + if (list instanceof LongArrayList) { + final LongArrayList primitiveList = (LongArrayList) list; + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeUInt64SizeNoTag(primitiveList.getLong(i)); + } + } else { + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeUInt64SizeNoTag(list.get(i)); + } + } + return size; + } + + static int computeSizeUInt64List(int fieldNumber, List<Long> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = computeSizeUInt64ListNoTag(list); + + if (packed) { + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(size); + } else { + return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); + } + } + + static int computeSizeSInt64ListNoTag(List<Long> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + + int size = 0; + + if (list instanceof LongArrayList) { + final LongArrayList primitiveList = (LongArrayList) list; + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeSInt64SizeNoTag(primitiveList.getLong(i)); + } + } else { + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeSInt64SizeNoTag(list.get(i)); + } + } + return size; + } + + static int computeSizeSInt64List(int fieldNumber, List<Long> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = computeSizeSInt64ListNoTag(list); + + if (packed) { + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(size); + } else { + return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); + } + } + + static int computeSizeEnumListNoTag(List<Integer> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + + int size = 0; + + if (list instanceof IntArrayList) { + final IntArrayList primitiveList = (IntArrayList) list; + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeEnumSizeNoTag(primitiveList.getInt(i)); + } + } else { + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeEnumSizeNoTag(list.get(i)); + } + } + return size; + } + + static int computeSizeEnumList(int fieldNumber, List<Integer> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = computeSizeEnumListNoTag(list); + + if (packed) { + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(size); + } else { + return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); + } + } + + static int computeSizeInt32ListNoTag(List<Integer> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + + int size = 0; + + if (list instanceof IntArrayList) { + final IntArrayList primitiveList = (IntArrayList) list; + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeInt32SizeNoTag(primitiveList.getInt(i)); + } + } else { + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeInt32SizeNoTag(list.get(i)); + } + } + return size; + } + + static int computeSizeInt32List(int fieldNumber, List<Integer> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = computeSizeInt32ListNoTag(list); + + if (packed) { + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(size); + } else { + return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); + } + } + + static int computeSizeUInt32ListNoTag(List<Integer> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + + int size = 0; + + if (list instanceof IntArrayList) { + final IntArrayList primitiveList = (IntArrayList) list; + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeUInt32SizeNoTag(primitiveList.getInt(i)); + } + } else { + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeUInt32SizeNoTag(list.get(i)); + } + } + return size; + } + + static int computeSizeUInt32List(int fieldNumber, List<Integer> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = computeSizeUInt32ListNoTag(list); + + if (packed) { + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(size); + } else { + return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); + } + } + + static int computeSizeSInt32ListNoTag(List<Integer> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + + int size = 0; + + if (list instanceof IntArrayList) { + final IntArrayList primitiveList = (IntArrayList) list; + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeSInt32SizeNoTag(primitiveList.getInt(i)); + } + } else { + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeSInt32SizeNoTag(list.get(i)); + } + } + return size; + } + + static int computeSizeSInt32List(int fieldNumber, List<Integer> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + + int size = computeSizeSInt32ListNoTag(list); + + if (packed) { + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(size); + } else { + return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); + } + } + + static int computeSizeFixed32ListNoTag(List<?> list) { + return list.size() * WireFormat.FIXED32_SIZE; + } + + static int computeSizeFixed32List(int fieldNumber, List<?> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + if (packed) { + int dataSize = length * WireFormat.FIXED32_SIZE; + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(dataSize); + } else { + return length * CodedOutputStream.computeFixed32Size(fieldNumber, 0); + } + } + + static int computeSizeFixed64ListNoTag(List<?> list) { + return list.size() * WireFormat.FIXED64_SIZE; + } + + static int computeSizeFixed64List(int fieldNumber, List<?> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + if (packed) { + final int dataSize = length * WireFormat.FIXED64_SIZE; + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(dataSize); + } else { + return length * CodedOutputStream.computeFixed64Size(fieldNumber, 0); + } + } + + static int computeSizeBoolListNoTag(List<?> list) { + // bools are 1 byte varints + return list.size(); + } + + static int computeSizeBoolList(int fieldNumber, List<?> list, boolean packed) { + final int length = list.size(); + if (length == 0) { + return 0; + } + if (packed) { + // bools are 1 byte varints + return CodedOutputStream.computeTagSize(fieldNumber) + + CodedOutputStream.computeLengthDelimitedFieldSize(length); + } else { + return length * CodedOutputStream.computeBoolSize(fieldNumber, true); + } + } + + static int computeSizeStringList(int fieldNumber, List<?> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = length * CodedOutputStream.computeTagSize(fieldNumber); + if (list instanceof LazyStringList) { + LazyStringList lazyList = ((LazyStringList) list); + for (int i = 0; i < length; i++) { + Object value = lazyList.getRaw(i); + if (value instanceof ByteString) { + size += CodedOutputStream.computeBytesSizeNoTag((ByteString) value); + } else { + size += CodedOutputStream.computeStringSizeNoTag((String) value); + } + } + } else { + for (int i = 0; i < length; i++) { + Object value = list.get(i); + if (value instanceof ByteString) { + size += CodedOutputStream.computeBytesSizeNoTag((ByteString) value); + } else { + size += CodedOutputStream.computeStringSizeNoTag((String) value); + } + } + } + return size; + } + + static int computeSizeMessage(int fieldNumber, Object value, Schema schema) { + if (value instanceof LazyFieldLite) { + return CodedOutputStream.computeLazyFieldSize(fieldNumber, (LazyFieldLite) value); + } else { + return CodedOutputStream.computeMessageSize(fieldNumber, (MessageLite) value, schema); + } + } + + static int computeSizeMessageList(int fieldNumber, List<?> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = length * CodedOutputStream.computeTagSize(fieldNumber); + for (int i = 0; i < length; i++) { + Object value = list.get(i); + if (value instanceof LazyFieldLite) { + size += CodedOutputStream.computeLazyFieldSizeNoTag((LazyFieldLite) value); + } else { + size += CodedOutputStream.computeMessageSizeNoTag((MessageLite) value); + } + } + return size; + } + + static int computeSizeMessageList(int fieldNumber, List<?> list, Schema schema) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = length * CodedOutputStream.computeTagSize(fieldNumber); + for (int i = 0; i < length; i++) { + Object value = list.get(i); + if (value instanceof LazyFieldLite) { + size += CodedOutputStream.computeLazyFieldSizeNoTag((LazyFieldLite) value); + } else { + size += CodedOutputStream.computeMessageSizeNoTag((MessageLite) value, schema); + } + } + return size; + } + + static int computeSizeByteStringList(int fieldNumber, List<ByteString> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = length * CodedOutputStream.computeTagSize(fieldNumber); + for (int i = 0; i < list.size(); i++) { + size += CodedOutputStream.computeBytesSizeNoTag(list.get(i)); + } + return size; + } + + static int computeSizeGroupList(int fieldNumber, List<MessageLite> list) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = 0; + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeGroupSize(fieldNumber, list.get(i)); + } + return size; + } + + static int computeSizeGroupList(int fieldNumber, List<MessageLite> list, Schema schema) { + final int length = list.size(); + if (length == 0) { + return 0; + } + int size = 0; + for (int i = 0; i < length; i++) { + size += CodedOutputStream.computeGroupSize(fieldNumber, list.get(i), schema); + } + return size; + } + + /** + * Determines whether to issue tableswitch or lookupswitch for the mergeFrom method. + * + * @see #shouldUseTableSwitch(int, int, int) + */ + public static boolean shouldUseTableSwitch(FieldInfo[] fields) { + // Determine whether to issue a tableswitch or a lookupswitch + // instruction. + if (fields.length == 0) { + return false; + } + + int lo = fields[0].getFieldNumber(); + int hi = fields[fields.length - 1].getFieldNumber(); + return shouldUseTableSwitch(lo, hi, fields.length); + } + + /** + * Determines whether to issue tableswitch or lookupswitch for the mergeFrom method. This is based + * on the <a href= + * "http://hg.openjdk.java.net/jdk8/jdk8/langtools/file/30db5e0aaf83/src/share/classes/com/sun/tools/javac/jvm/Gen.java#l1159"> + * logic in the JDK</a>. + * + * @param lo the lowest fieldNumber contained within the message. + * @param hi the higest fieldNumber contained within the message. + * @param numFields the total number of fields in the message. + * @return {@code true} if tableswitch should be used, rather than lookupswitch. + */ + public static boolean shouldUseTableSwitch(int lo, int hi, int numFields) { + if (hi < DEFAULT_LOOK_UP_START_NUMBER) { + return true; + } + long tableSpaceCost = ((long) hi - lo + 1); // words + long tableTimeCost = 3; // comparisons + long lookupSpaceCost = 3 + 2 * (long) numFields; + long lookupTimeCost = 3 + (long) numFields; + return tableSpaceCost + 3 * tableTimeCost <= lookupSpaceCost + 3 * lookupTimeCost; + } + + public static UnknownFieldSchema<?, ?> proto2UnknownFieldSetSchema() { + return PROTO2_UNKNOWN_FIELD_SET_SCHEMA; + } + + public static UnknownFieldSchema<?, ?> proto3UnknownFieldSetSchema() { + return PROTO3_UNKNOWN_FIELD_SET_SCHEMA; + } + + public static UnknownFieldSchema<?, ?> unknownFieldSetLiteSchema() { + return UNKNOWN_FIELD_SET_LITE_SCHEMA; + } + + private static UnknownFieldSchema<?, ?> getUnknownFieldSetSchema(boolean proto3) { + try { + Class<?> clz = getUnknownFieldSetSchemaClass(); + if (clz == null) { + return null; + } + return (UnknownFieldSchema) clz.getConstructor(boolean.class).newInstance(proto3); + } catch (Throwable t) { + return null; + } + } + + private static Class<?> getGeneratedMessageClass() { + try { + return Class.forName("com.google.protobuf.GeneratedMessageV3"); + } catch (Throwable e) { + return null; + } + } + + private static Class<?> getUnknownFieldSetSchemaClass() { + try { + return Class.forName("com.google.protobuf.UnknownFieldSetSchema"); + } catch (Throwable e) { + return null; + } + } + + static Object getMapDefaultEntry(Class<?> clazz, String name) { + try { + Class<?> holder = + Class.forName(clazz.getName() + "$" + toCamelCase(name, true) + "DefaultEntryHolder"); + Field[] fields = holder.getDeclaredFields(); + if (fields.length != 1) { + throw new IllegalStateException( + "Unable to look up map field default entry holder class for " + + name + + " in " + + clazz.getName()); + } + return UnsafeUtil.getStaticObject(fields[0]); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + static String toCamelCase(String name, boolean capNext) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < name.length(); ++i) { + char c = name.charAt(i); + // Matches protoc field name function: + if ('a' <= c && c <= 'z') { + if (capNext) { + sb.append((char) (c + ('A' - 'a'))); + } else { + sb.append(c); + } + capNext = false; + } else if ('A' <= c && c <= 'Z') { + if (i == 0 && !capNext) { + // Force first letter to lower-case unless explicitly told to capitalize it. + sb.append((char) (c - ('A' - 'a'))); + } else { + sb.append(c); + } + capNext = false; + } else if ('0' <= c && c <= '9') { + sb.append(c); + capNext = true; + } else { + capNext = true; + } + } + return sb.toString(); + } + + /** Returns true if both are null or both are {@link Object#equals}. */ + static boolean safeEquals(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } + + static <T> void mergeMap(MapFieldSchema mapFieldSchema, T message, T o, long offset) { + Object merged = + mapFieldSchema.mergeFrom( + UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(o, offset)); + UnsafeUtil.putObject(message, offset, merged); + } + + static <T, FT extends FieldDescriptorLite<FT>> void mergeExtensions( + ExtensionSchema<FT> schema, T message, T other) { + FieldSet<FT> otherExtensions = schema.getExtensions(other); + if (!otherExtensions.isEmpty()) { + FieldSet<FT> messageExtensions = schema.getMutableExtensions(message); + messageExtensions.mergeFrom(otherExtensions); + } + } + + static <T, UT, UB> void mergeUnknownFields( + UnknownFieldSchema<UT, UB> schema, T message, T other) { + UT messageUnknowns = schema.getFromMessage(message); + UT otherUnknowns = schema.getFromMessage(other); + UT merged = schema.merge(messageUnknowns, otherUnknowns); + schema.setToMessage(message, merged); + } + + /** Filters unrecognized enum values in a list. */ + static <UT, UB> UB filterUnknownEnumList( + int number, + List<Integer> enumList, + EnumLiteMap<?> enumMap, + UB unknownFields, + UnknownFieldSchema<UT, UB> unknownFieldSchema) { + if (enumMap == null) { + return unknownFields; + } + // TODO(dweis): Specialize for IntArrayList to avoid boxing. + if (enumList instanceof RandomAccess) { + int writePos = 0; + int size = enumList.size(); + for (int readPos = 0; readPos < size; ++readPos) { + int enumValue = enumList.get(readPos); + if (enumMap.findValueByNumber(enumValue) != null) { + if (readPos != writePos) { + enumList.set(writePos, enumValue); + } + ++writePos; + } else { + unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema); + } + } + if (writePos != size) { + enumList.subList(writePos, size).clear(); + } + } else { + for (Iterator<Integer> it = enumList.iterator(); it.hasNext(); ) { + int enumValue = it.next(); + if (enumMap.findValueByNumber(enumValue) == null) { + unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema); + it.remove(); + } + } + } + return unknownFields; + } + + /** Filters unrecognized enum values in a list. */ + static <UT, UB> UB filterUnknownEnumList( + int number, + List<Integer> enumList, + EnumVerifier enumVerifier, + UB unknownFields, + UnknownFieldSchema<UT, UB> unknownFieldSchema) { + if (enumVerifier == null) { + return unknownFields; + } + // TODO(dweis): Specialize for IntArrayList to avoid boxing. + if (enumList instanceof RandomAccess) { + int writePos = 0; + int size = enumList.size(); + for (int readPos = 0; readPos < size; ++readPos) { + int enumValue = enumList.get(readPos); + if (enumVerifier.isInRange(enumValue)) { + if (readPos != writePos) { + enumList.set(writePos, enumValue); + } + ++writePos; + } else { + unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema); + } + } + if (writePos != size) { + enumList.subList(writePos, size).clear(); + } + } else { + for (Iterator<Integer> it = enumList.iterator(); it.hasNext(); ) { + int enumValue = it.next(); + if (!enumVerifier.isInRange(enumValue)) { + unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema); + it.remove(); + } + } + } + return unknownFields; + } + + /** Stores an unrecognized enum value as an unknown value. */ + static <UT, UB> UB storeUnknownEnum( + int number, int enumValue, UB unknownFields, UnknownFieldSchema<UT, UB> unknownFieldSchema) { + if (unknownFields == null) { + unknownFields = unknownFieldSchema.newBuilder(); + } + unknownFieldSchema.addVarint(unknownFields, number, enumValue); + return unknownFields; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java index 6bd65d6f4..546e56e85 100644 --- a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java +++ b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java @@ -136,6 +136,8 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> { // The EntrySet is a stateless view of the Map. It's initialized the first // time it is requested and reused henceforth. private volatile EntrySet lazyEntrySet; + private Map<K, V> overflowEntriesDescending; + private volatile DescendingEntrySet lazyDescendingEntrySet; /** * @code arraySize Size of the array in which the lexicographically smallest mappings are stored. @@ -145,6 +147,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> { this.maxArraySize = arraySize; this.entryList = Collections.emptyList(); this.overflowEntries = Collections.emptyMap(); + this.overflowEntriesDescending = Collections.emptyMap(); } /** Make this map immutable from this point forward. */ @@ -158,6 +161,10 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> { overflowEntries.isEmpty() ? Collections.<K, V>emptyMap() : Collections.unmodifiableMap(overflowEntries); + overflowEntriesDescending = + overflowEntriesDescending.isEmpty() + ? Collections.<K, V>emptyMap() + : Collections.unmodifiableMap(overflowEntriesDescending); isImmutable = true; } } @@ -189,6 +196,11 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> { : overflowEntries.entrySet(); } + Iterable<Map.Entry<K, V>> getOverflowEntriesDescending() { + return overflowEntriesDescending.isEmpty() + ? EmptySet.<Map.Entry<K, V>>iterable() + : overflowEntriesDescending.entrySet(); + } @Override public int size() { @@ -344,6 +356,12 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> { return lazyEntrySet; } + Set<Map.Entry<K, V>> descendingEntrySet() { + if (lazyDescendingEntrySet == null) { + lazyDescendingEntrySet = new DescendingEntrySet(); + } + return lazyDescendingEntrySet; + } /** @throws UnsupportedOperationException if {@link #makeImmutable()} has has been called. */ private void checkMutable() { @@ -361,6 +379,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> { checkMutable(); if (overflowEntries.isEmpty() && !(overflowEntries instanceof TreeMap)) { overflowEntries = new TreeMap<K, V>(); + overflowEntriesDescending = ((TreeMap<K, V>) overflowEntries).descendingMap(); } return (SortedMap<K, V>) overflowEntries; } @@ -501,6 +520,12 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> { } } + private class DescendingEntrySet extends EntrySet { + @Override + public Iterator<java.util.Map.Entry<K, V>> iterator() { + return new DescendingEntryIterator(); + } + } /** * Iterator implementation that switches from the entry array to the overflow entries @@ -558,6 +583,46 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> { } /** + * Reverse Iterator implementation that switches from the entry array to the overflow entries + * appropriately. + */ + private class DescendingEntryIterator implements Iterator<Map.Entry<K, V>> { + + private int pos = entryList.size(); + private Iterator<Map.Entry<K, V>> lazyOverflowIterator; + + @Override + public boolean hasNext() { + return (pos > 0 && pos <= entryList.size()) || getOverflowIterator().hasNext(); + } + + @Override + public Map.Entry<K, V> next() { + if (getOverflowIterator().hasNext()) { + return getOverflowIterator().next(); + } + return entryList.get(--pos); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + /** + * It is important to create the overflow iterator only after the array entries have been + * iterated over because the overflow entry set changes when the client calls remove() on the + * array entries, which invalidates any existing iterators. + */ + private Iterator<Map.Entry<K, V>> getOverflowIterator() { + if (lazyOverflowIterator == null) { + lazyOverflowIterator = overflowEntriesDescending.entrySet().iterator(); + } + return lazyOverflowIterator; + } + } + + /** * Helper class that holds immutable instances of an Iterable/Iterator that we return when the * overflow entries is empty. This eliminates the creation of an Iterator object when there is * nothing to iterate over. diff --git a/java/core/src/main/java/com/google/protobuf/StructuralMessageInfo.java b/java/core/src/main/java/com/google/protobuf/StructuralMessageInfo.java new file mode 100755 index 000000000..a32b1430e --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/StructuralMessageInfo.java @@ -0,0 +1,167 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.Internal.checkNotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Information for the layout of a protobuf message class. This describes all of the fields + * contained within a message. + */ +@ExperimentalApi +final class StructuralMessageInfo implements MessageInfo { + private final ProtoSyntax syntax; + private final boolean messageSetWireFormat; + private final int[] checkInitialized; + private final FieldInfo[] fields; + private final MessageLite defaultInstance; + + /** + * Constructor. + * + * @param checkInitialized fields to check in isInitialized(). + * @param fields the set of fields for the message, in field number order. + */ + StructuralMessageInfo( + ProtoSyntax syntax, + boolean messageSetWireFormat, + int[] checkInitialized, + FieldInfo[] fields, + Object defaultInstance) { + this.syntax = syntax; + this.messageSetWireFormat = messageSetWireFormat; + this.checkInitialized = checkInitialized; + this.fields = fields; + this.defaultInstance = (MessageLite) checkNotNull(defaultInstance, "defaultInstance"); + } + + /** Gets the syntax for the message (e.g. PROTO2, PROTO3). */ + @Override + public ProtoSyntax getSyntax() { + return syntax; + } + + /** Indicates whether or not the message should be represented with message set wire format. */ + @Override + public boolean isMessageSetWireFormat() { + return messageSetWireFormat; + } + + /** An array of field numbers that need to be checked for isInitialized(). */ + public int[] getCheckInitialized() { + return checkInitialized; + } + + /** + * Gets the information for all fields within this message, sorted in ascending order by their + * field number. + */ + public FieldInfo[] getFields() { + return fields; + } + + @Override + public MessageLite getDefaultInstance() { + return defaultInstance; + } + + /** Helper method for creating a new builder for {@link MessageInfo}. */ + public static Builder newBuilder() { + return new Builder(); + } + + /** Helper method for creating a new builder for {@link MessageInfo}. */ + public static Builder newBuilder(int numFields) { + return new Builder(numFields); + } + + /** A builder of {@link MessageInfo} instances. */ + public static final class Builder { + private final List<FieldInfo> fields; + private ProtoSyntax syntax; + private boolean wasBuilt; + private boolean messageSetWireFormat; + private int[] checkInitialized = null; + private Object defaultInstance; + + public Builder() { + fields = new ArrayList<FieldInfo>(); + } + + public Builder(int numFields) { + fields = new ArrayList<FieldInfo>(numFields); + } + + public void withDefaultInstance(Object defaultInstance) { + this.defaultInstance = defaultInstance; + } + + public void withSyntax(ProtoSyntax syntax) { + this.syntax = checkNotNull(syntax, "syntax"); + } + + public void withMessageSetWireFormat(boolean messageSetWireFormat) { + this.messageSetWireFormat = messageSetWireFormat; + } + + public void withCheckInitialized(int[] checkInitialized) { + this.checkInitialized = checkInitialized; + } + + public void withField(FieldInfo field) { + if (wasBuilt) { + throw new IllegalStateException("Builder can only build once"); + } + fields.add(field); + } + + public StructuralMessageInfo build() { + if (wasBuilt) { + throw new IllegalStateException("Builder can only build once"); + } + if (syntax == null) { + throw new IllegalStateException("Must specify a proto syntax"); + } + wasBuilt = true; + Collections.sort(fields); + return new StructuralMessageInfo( + syntax, + messageSetWireFormat, + checkInitialized, + fields.toArray(new FieldInfo[0]), + defaultInstance); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java index f00c812fc..2326a05ff 100644 --- a/java/core/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java @@ -1247,6 +1247,18 @@ public final class TextFormat { SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES; private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null; + /** + * Set whether this parser will allow unknown fields. By default, an exception is thrown if an + * unknown field is encountered. If this is set, the parser will only log a warning. Allow + * unknown fields will also allow unknown extensions. + * + * <p>Use of this parameter is discouraged which may hide some errors (e.g. + * spelling error on field name). + */ + public Builder setAllowUnknownFields(boolean allowUnknownFields) { + this.allowUnknownFields = allowUnknownFields; + return this; + } /** * Set whether this parser will allow unknown extensions. By default, an @@ -1448,14 +1460,15 @@ public final class TextFormat { extension = target.findExtensionByName(extensionRegistry, name.toString()); if (extension == null) { - String message = (tokenizer.getPreviousLine() + 1) - + ":" - + (tokenizer.getPreviousColumn() + 1) - + ":\t" - + type.getFullName() - + ".[" - + name - + "]"; + String message = + (tokenizer.getPreviousLine() + 1) + + ":" + + (tokenizer.getPreviousColumn() + 1) + + ":\t" + + type.getFullName() + + ".[" + + name + + "]"; unknownFields.add(new UnknownField(message, UnknownField.Type.EXTENSION)); } else { if (extension.descriptor.getContainingType() != type) { @@ -1653,24 +1666,18 @@ public final class TextFormat { endToken = "}"; } - Message defaultInstance = (extension == null) ? null : extension.defaultInstance; - MessageReflection.MergeTarget subField = - target.newMergeTargetForField(field, defaultInstance); + Message defaultInstance = (extension == null) ? null : extension.defaultInstance; + MessageReflection.MergeTarget subField = + target.newMergeTargetForField(field, defaultInstance); - while (!tokenizer.tryConsume(endToken)) { - if (tokenizer.atEnd()) { - throw tokenizer.parseException("Expected \"" + endToken + "\"."); + while (!tokenizer.tryConsume(endToken)) { + if (tokenizer.atEnd()) { + throw tokenizer.parseException("Expected \"" + endToken + "\"."); + } + mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder, unknownFields); } - mergeField( - tokenizer, - extensionRegistry, - subField, - parseTreeBuilder, - unknownFields); - } - - value = subField.finish(); + value = subField.finish(); } else { switch (field.getType()) { case INT32: @@ -1776,6 +1783,7 @@ public final class TextFormat { } } + /** Skips the next field including the field's name and value. */ private void skipField(Tokenizer tokenizer) throws ParseException { if (tokenizer.tryConsume("[")) { diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java new file mode 100755 index 000000000..e736d5ce9 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java @@ -0,0 +1,133 @@ +// 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 java.io.IOException; + +@ExperimentalApi +abstract class UnknownFieldSchema<T, B> { + + /** Whether unknown fields should be dropped. */ + abstract boolean shouldDiscardUnknownFields(Reader reader); + + /** Adds a varint value to the unknown fields. */ + abstract void addVarint(B fields, int number, long value); + + /** Adds a fixed32 value to the unknown fields. */ + abstract void addFixed32(B fields, int number, int value); + + /** Adds a fixed64 value to the unknown fields. */ + abstract void addFixed64(B fields, int number, long value); + + /** Adds a length delimited value to the unknown fields. */ + abstract void addLengthDelimited(B fields, int number, ByteString value); + + /** Adds a group value to the unknown fields. */ + abstract void addGroup(B fields, int number, T subFieldSet); + + /** Create a new builder for unknown fields. */ + abstract B newBuilder(); + + /** Returns an immutable instance of the field container. */ + abstract T toImmutable(B fields); + + /** + * Sets the unknown fields into the message. Caller must take care of the mutability of the + * fields. + */ + abstract void setToMessage(Object message, T fields); + + /** Get the unknown fields from the message. */ + abstract T getFromMessage(Object message); + + /** Returns a builder for unknown fields in the message. */ + abstract B getBuilderFromMessage(Object message); + + /** Sets an unknown field builder into the message. */ + abstract void setBuilderToMessage(Object message, B builder); + + /** Marks unknown fields as immutable. */ + abstract void makeImmutable(Object message); + + /** Merges one field into the unknown fields. */ + final boolean mergeOneFieldFrom(B unknownFields, Reader reader) throws IOException { + int tag = reader.getTag(); + int fieldNumber = WireFormat.getTagFieldNumber(tag); + switch (WireFormat.getTagWireType(tag)) { + case WireFormat.WIRETYPE_VARINT: + addVarint(unknownFields, fieldNumber, reader.readInt64()); + return true; + case WireFormat.WIRETYPE_FIXED32: + addFixed32(unknownFields, fieldNumber, reader.readFixed32()); + return true; + case WireFormat.WIRETYPE_FIXED64: + addFixed64(unknownFields, fieldNumber, reader.readFixed64()); + return true; + case WireFormat.WIRETYPE_LENGTH_DELIMITED: + addLengthDelimited(unknownFields, fieldNumber, reader.readBytes()); + return true; + case WireFormat.WIRETYPE_START_GROUP: + final B subFields = newBuilder(); + int endGroupTag = WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); + mergeFrom(subFields, reader); + if (endGroupTag != reader.getTag()) { + throw InvalidProtocolBufferException.invalidEndTag(); + } + addGroup(unknownFields, fieldNumber, toImmutable(subFields)); + return true; + case WireFormat.WIRETYPE_END_GROUP: + return false; + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + + final void mergeFrom(B unknownFields, Reader reader) throws IOException { + while (true) { + if (reader.getFieldNumber() == Reader.READ_DONE + || !mergeOneFieldFrom(unknownFields, reader)) { + break; + } + } + } + + abstract void writeTo(T unknownFields, Writer writer) throws IOException; + + abstract void writeAsMessageSetTo(T unknownFields, Writer writer) throws IOException; + + /** Merges {@code source} into {@code destination} and returns the merged instance. */ + abstract T merge(T destination, T source); + + /** Get the serialized size for message set serialization. */ + abstract int getSerializedSizeAsMessageSet(T message); + + abstract int getSerializedSize(T unknowns); +} diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java index 39deec048..bde1303db 100644 --- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java +++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java @@ -59,6 +59,7 @@ public final class UnknownFieldSet implements MessageLite { private UnknownFieldSet() { fields = null; + fieldsDescending = null; } /** Create a new {@link Builder}. */ @@ -90,10 +91,14 @@ public final class UnknownFieldSet implements MessageLite { */ 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) { @@ -212,6 +217,35 @@ public final class UnknownFieldSet implements MessageLite { } } + /** 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() { @@ -328,6 +362,8 @@ public final class UnknownFieldSet implements MessageLite { 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; @@ -344,6 +380,8 @@ public final class UnknownFieldSet implements MessageLite { 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)); } @@ -808,6 +846,47 @@ public final class UnknownFieldSet implements MessageLite { } } + /** 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 diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java index 7c5ec6e98..2f6315c80 100644 --- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java +++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java @@ -168,6 +168,72 @@ public final class UnknownFieldSetLite { } } + /** Serializes the set and writes it to {@code writer} using {@code MessageSet} wire format. */ + void writeAsMessageSetTo(Writer writer) throws IOException { + if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) { + // Write fields in descending order. + for (int i = count - 1; i >= 0; i--) { + int fieldNumber = WireFormat.getTagFieldNumber(tags[i]); + writer.writeMessageSetItem(fieldNumber, objects[i]); + } + } else { + // Write fields in ascending order. + for (int i = 0; i < count; i++) { + int fieldNumber = WireFormat.getTagFieldNumber(tags[i]); + writer.writeMessageSetItem(fieldNumber, objects[i]); + } + } + } + + /** Serializes the set and writes it to {@code writer}. */ + public void writeTo(Writer writer) throws IOException { + if (count == 0) { + return; + } + + // TODO: tags are not sorted, so there's no write order guarantees + if (writer.fieldOrder() == Writer.FieldOrder.ASCENDING) { + for (int i = 0; i < count; ++i) { + writeField(tags[i], objects[i], writer); + } + } else { + for (int i = count - 1; i >= 0; --i) { + writeField(tags[i], objects[i], writer); + } + } + } + + private static void writeField(int tag, Object object, Writer writer) throws IOException { + int fieldNumber = WireFormat.getTagFieldNumber(tag); + switch (WireFormat.getTagWireType(tag)) { + case WireFormat.WIRETYPE_VARINT: + writer.writeInt64(fieldNumber, (Long) object); + break; + case WireFormat.WIRETYPE_FIXED32: + writer.writeFixed32(fieldNumber, (Integer) object); + break; + case WireFormat.WIRETYPE_FIXED64: + writer.writeFixed64(fieldNumber, (Long) object); + break; + case WireFormat.WIRETYPE_LENGTH_DELIMITED: + writer.writeBytes(fieldNumber, (ByteString) object); + break; + case WireFormat.WIRETYPE_START_GROUP: + if (writer.fieldOrder() == Writer.FieldOrder.ASCENDING) { + writer.writeStartGroup(fieldNumber); + ((UnknownFieldSetLite) object).writeTo(writer); + writer.writeEndGroup(fieldNumber); + } else { + writer.writeEndGroup(fieldNumber); + ((UnknownFieldSetLite) object).writeTo(writer); + writer.writeStartGroup(fieldNumber); + } + break; + default: + // TODO(liujisi): Change writeTo to throw IOException? + throw new RuntimeException(InvalidProtocolBufferException.invalidWireType()); + } + } /** * Get the number of bytes required to encode this field, including field number, using {@code diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java new file mode 100755 index 000000000..ffd723230 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java @@ -0,0 +1,140 @@ +// 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 java.io.IOException; + +class UnknownFieldSetLiteSchema + extends UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite> { + + UnknownFieldSetLiteSchema() {} + + @Override + boolean shouldDiscardUnknownFields(Reader reader) { + // We never drop unknown fields in lite. + return false; + } + + @Override + UnknownFieldSetLite newBuilder() { + return UnknownFieldSetLite.newInstance(); + } + + @Override + void addVarint(UnknownFieldSetLite fields, int number, long value) { + fields.storeField(WireFormat.makeTag(number, WireFormat.WIRETYPE_VARINT), value); + } + + @Override + void addFixed32(UnknownFieldSetLite fields, int number, int value) { + fields.storeField(WireFormat.makeTag(number, WireFormat.WIRETYPE_FIXED32), value); + } + + @Override + void addFixed64(UnknownFieldSetLite fields, int number, long value) { + fields.storeField(WireFormat.makeTag(number, WireFormat.WIRETYPE_FIXED64), value); + } + + @Override + void addLengthDelimited(UnknownFieldSetLite fields, int number, ByteString value) { + fields.storeField(WireFormat.makeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED), value); + } + + @Override + void addGroup(UnknownFieldSetLite fields, int number, UnknownFieldSetLite subFieldSet) { + fields.storeField(WireFormat.makeTag(number, WireFormat.WIRETYPE_START_GROUP), subFieldSet); + } + + @Override + UnknownFieldSetLite toImmutable(UnknownFieldSetLite fields) { + fields.makeImmutable(); + return fields; + } + + @Override + void setToMessage(Object message, UnknownFieldSetLite fields) { + ((GeneratedMessageLite<?, ?>) message).unknownFields = fields; + } + + @Override + UnknownFieldSetLite getFromMessage(Object message) { + return ((GeneratedMessageLite<?, ?>) message).unknownFields; + } + + @Override + UnknownFieldSetLite getBuilderFromMessage(Object message) { + UnknownFieldSetLite unknownFields = getFromMessage(message); + // When parsing into a lite message object, its UnknownFieldSet is either the default instance + // or mutable. It can't be in a state where it's immutable but not default instance. + if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) { + unknownFields = UnknownFieldSetLite.newInstance(); + setToMessage(message, unknownFields); + } + return unknownFields; + } + + @Override + void setBuilderToMessage(Object message, UnknownFieldSetLite fields) { + setToMessage(message, fields); + } + + @Override + void makeImmutable(Object message) { + getFromMessage(message).makeImmutable(); + } + + @Override + void writeTo(UnknownFieldSetLite fields, Writer writer) throws IOException { + fields.writeTo(writer); + } + + @Override + void writeAsMessageSetTo(UnknownFieldSetLite fields, Writer writer) throws IOException { + fields.writeAsMessageSetTo(writer); + } + + @Override + UnknownFieldSetLite merge(UnknownFieldSetLite message, UnknownFieldSetLite other) { + return other.equals(UnknownFieldSetLite.getDefaultInstance()) + ? message + : UnknownFieldSetLite.mutableCopyOf(message, other); + } + + @Override + int getSerializedSize(UnknownFieldSetLite unknowns) { + return unknowns.getSerializedSize(); + } + + @Override + int getSerializedSizeAsMessageSet(UnknownFieldSetLite unknowns) { + return unknowns.getSerializedSizeAsMessageSet(); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetSchema.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetSchema.java new file mode 100755 index 000000000..b838c4b54 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetSchema.java @@ -0,0 +1,132 @@ +// 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 java.io.IOException; + +class UnknownFieldSetSchema extends UnknownFieldSchema<UnknownFieldSet, UnknownFieldSet.Builder> { + + private final boolean proto3; + + public UnknownFieldSetSchema(boolean proto3) { + this.proto3 = proto3; + } + + @Override + boolean shouldDiscardUnknownFields(Reader reader) { + return reader.shouldDiscardUnknownFields(); + } + + @Override + UnknownFieldSet.Builder newBuilder() { + return UnknownFieldSet.newBuilder(); + } + + @Override + void addVarint(UnknownFieldSet.Builder fields, int number, long value) { + fields.mergeField(number, UnknownFieldSet.Field.newBuilder().addVarint(value).build()); + } + + @Override + void addFixed32(UnknownFieldSet.Builder fields, int number, int value) { + fields.mergeField(number, UnknownFieldSet.Field.newBuilder().addFixed32(value).build()); + } + + @Override + void addFixed64(UnknownFieldSet.Builder fields, int number, long value) { + fields.mergeField(number, UnknownFieldSet.Field.newBuilder().addFixed64(value).build()); + } + + @Override + void addLengthDelimited(UnknownFieldSet.Builder fields, int number, ByteString value) { + fields.mergeField(number, UnknownFieldSet.Field.newBuilder().addLengthDelimited(value).build()); + } + + @Override + void addGroup(UnknownFieldSet.Builder fields, int number, UnknownFieldSet subFieldSet) { + fields.mergeField(number, UnknownFieldSet.Field.newBuilder().addGroup(subFieldSet).build()); + } + + @Override + UnknownFieldSet toImmutable(UnknownFieldSet.Builder fields) { + return fields.build(); + } + + @Override + void writeTo(UnknownFieldSet message, Writer writer) throws IOException { + message.writeTo(writer); + } + + @Override + void writeAsMessageSetTo(UnknownFieldSet message, Writer writer) throws IOException { + message.writeAsMessageSetTo(writer); + } + + @Override + UnknownFieldSet getFromMessage(Object message) { + return ((GeneratedMessageV3) message).unknownFields; + } + + @Override + void setToMessage(Object message, UnknownFieldSet fields) { + ((GeneratedMessageV3) message).unknownFields = fields; + } + + @Override + UnknownFieldSet.Builder getBuilderFromMessage(Object message) { + return ((GeneratedMessageV3) message).unknownFields.toBuilder(); + } + + @Override + void setBuilderToMessage(Object message, UnknownFieldSet.Builder builder) { + ((GeneratedMessageV3) message).unknownFields = builder.build(); + } + + @Override + void makeImmutable(Object message) { + // Already immutable. + } + + @Override + UnknownFieldSet merge(UnknownFieldSet message, UnknownFieldSet other) { + return message.toBuilder().mergeFrom(other).build(); + } + + @Override + int getSerializedSize(UnknownFieldSet message) { + return message.getSerializedSize(); + } + + @Override + int getSerializedSizeAsMessageSet(UnknownFieldSet unknowns) { + return unknowns.getSerializedSizeAsMessageSet(); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/Writer.java b/java/core/src/main/java/com/google/protobuf/Writer.java new file mode 100755 index 000000000..3f95c325d --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/Writer.java @@ -0,0 +1,219 @@ +// 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 java.io.IOException; +import java.util.List; +import java.util.Map; + +/** A writer that performs serialization of protobuf message fields. */ +@ExperimentalApi +interface Writer { + + /** The order in which the fields are written by a {@link Writer}. */ + enum FieldOrder { + /** Fields are written in ascending order by field number. */ + ASCENDING, + + /** Fields are written in descending order by field number. */ + DESCENDING + } + + /** Indicates the order in which the fields are written by this {@link Writer}. */ + FieldOrder fieldOrder(); + + /** Writes a field of type {@link FieldType#SFIXED32}. */ + void writeSFixed32(int fieldNumber, int value) throws IOException; + + /** Writes a field of type {@link FieldType#INT64}. */ + void writeInt64(int fieldNumber, long value) throws IOException; + + /** Writes a field of type {@link FieldType#SFIXED64}. */ + void writeSFixed64(int fieldNumber, long value) throws IOException; + + /** Writes a field of type {@link FieldType#FLOAT}. */ + void writeFloat(int fieldNumber, float value) throws IOException; + + /** Writes a field of type {@link FieldType#DOUBLE}. */ + void writeDouble(int fieldNumber, double value) throws IOException; + + /** Writes a field of type {@link FieldType#ENUM}. */ + void writeEnum(int fieldNumber, int value) throws IOException; + + /** Writes a field of type {@link FieldType#UINT64}. */ + void writeUInt64(int fieldNumber, long value) throws IOException; + + /** Writes a field of type {@link FieldType#INT32}. */ + void writeInt32(int fieldNumber, int value) throws IOException; + + /** Writes a field of type {@link FieldType#FIXED64}. */ + void writeFixed64(int fieldNumber, long value) throws IOException; + + /** Writes a field of type {@link FieldType#FIXED32}. */ + void writeFixed32(int fieldNumber, int value) throws IOException; + + /** Writes a field of type {@link FieldType#BOOL}. */ + void writeBool(int fieldNumber, boolean value) throws IOException; + + /** Writes a field of type {@link FieldType#STRING}. */ + void writeString(int fieldNumber, String value) throws IOException; + + /** Writes a field of type {@link FieldType#BYTES}. */ + void writeBytes(int fieldNumber, ByteString value) throws IOException; + + /** Writes a field of type {@link FieldType#UINT32}. */ + void writeUInt32(int fieldNumber, int value) throws IOException; + + /** Writes a field of type {@link FieldType#SINT32}. */ + void writeSInt32(int fieldNumber, int value) throws IOException; + + /** Writes a field of type {@link FieldType#SINT64}. */ + void writeSInt64(int fieldNumber, long value) throws IOException; + + /** Writes a field of type {@link FieldType#MESSAGE}. */ + void writeMessage(int fieldNumber, Object value) throws IOException; + + /** Writes a field of type {@link FieldType#MESSAGE}. */ + void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException; + + /** + * Writes a field of type {@link FieldType#GROUP}. + * + * @deprecated groups fields are deprecated. + */ + @Deprecated + void writeGroup(int fieldNumber, Object value) throws IOException; + + /** + * Writes a field of type {@link FieldType#GROUP}. + * + * @deprecated groups fields are deprecated. + */ + @Deprecated + void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException; + + /** + * Writes a single start group tag. + * + * @deprecated groups fields are deprecated. + */ + @Deprecated + void writeStartGroup(int fieldNumber) throws IOException; + + /** + * Writes a single end group tag. + * + * @deprecated groups fields are deprecated. + */ + @Deprecated + void writeEndGroup(int fieldNumber) throws IOException; + + /** Writes a list field of type {@link FieldType#INT32}. */ + void writeInt32List(int fieldNumber, List<Integer> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#FIXED32}. */ + void writeFixed32List(int fieldNumber, List<Integer> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#INT64}. */ + void writeInt64List(int fieldNumber, List<Long> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#UINT64}. */ + void writeUInt64List(int fieldNumber, List<Long> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#FIXED64}. */ + void writeFixed64List(int fieldNumber, List<Long> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#FLOAT}. */ + void writeFloatList(int fieldNumber, List<Float> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#DOUBLE}. */ + void writeDoubleList(int fieldNumber, List<Double> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#ENUM}. */ + void writeEnumList(int fieldNumber, List<Integer> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#BOOL}. */ + void writeBoolList(int fieldNumber, List<Boolean> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#STRING}. */ + void writeStringList(int fieldNumber, List<String> value) throws IOException; + + /** Writes a list field of type {@link FieldType#BYTES}. */ + void writeBytesList(int fieldNumber, List<ByteString> value) throws IOException; + + /** Writes a list field of type {@link FieldType#UINT32}. */ + void writeUInt32List(int fieldNumber, List<Integer> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#SFIXED32}. */ + void writeSFixed32List(int fieldNumber, List<Integer> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#SFIXED64}. */ + void writeSFixed64List(int fieldNumber, List<Long> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#SINT32}. */ + void writeSInt32List(int fieldNumber, List<Integer> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#SINT64}. */ + void writeSInt64List(int fieldNumber, List<Long> value, boolean packed) throws IOException; + + /** Writes a list field of type {@link FieldType#MESSAGE}. */ + void writeMessageList(int fieldNumber, List<?> value) throws IOException; + + /** Writes a list field of type {@link FieldType#MESSAGE}. */ + void writeMessageList(int fieldNumber, List<?> value, Schema schema) throws IOException; + + /** + * Writes a list field of type {@link FieldType#GROUP}. + * + * @deprecated groups fields are deprecated. + */ + @Deprecated + void writeGroupList(int fieldNumber, List<?> value) throws IOException; + + /** + * Writes a list field of type {@link FieldType#GROUP}. + * + * @deprecated groups fields are deprecated. + */ + @Deprecated + void writeGroupList(int fieldNumber, List<?> value, Schema schema) throws IOException; + + /** + * Writes a message field in {@code MessageSet} wire-format. + * + * @param value A message instance or an opaque {@link ByteString} for an unknown field. + */ + void writeMessageSetItem(int fieldNumber, Object value) throws IOException; + + /** Writes a map field. */ + <K, V> void writeMap(int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map) + throws IOException; +} diff --git a/java/core/src/test/java/com/google/protobuf/AbstractProto2LiteSchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractProto2LiteSchemaTest.java new file mode 100755 index 000000000..5d3fd3bd6 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/AbstractProto2LiteSchemaTest.java @@ -0,0 +1,199 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + +import com.google.protobuf.testing.Proto2TestingLite.Proto2EmptyLite; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.TestEnum; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLiteWithMaps; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; +import org.junit.Test; + +/** Base class for tests using {@link Proto2MessageLite}. */ +public abstract class AbstractProto2LiteSchemaTest extends AbstractSchemaTest<Proto2MessageLite> { + + @Override + protected Proto2MessageLiteFactory messageFactory() { + return new Proto2MessageLiteFactory(10, 20, 2, 2); + } + + @Test + public void mergeOptionalMessageFields() throws Exception { + Proto2MessageLite message1 = + newBuilder() + .setFieldMessage10(newBuilder().setFieldInt643(123).clearFieldInt325().build()) + .build(); + Proto2MessageLite message2 = + newBuilder() + .setFieldMessage10(newBuilder().clearFieldInt643().setFieldInt325(456).build()) + .build(); + Proto2MessageLite message3 = + newBuilder() + .setFieldMessage10(newBuilder().setFieldInt643(789).clearFieldInt325().build()) + .build(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + message1.writeTo(output); + message2.writeTo(output); + message3.writeTo(output); + byte[] data = output.toByteArray(); + + Proto2MessageLite merged = + ExperimentalSerializationUtil.fromByteArray(data, Proto2MessageLite.class); + assertEquals(789, merged.getFieldMessage10().getFieldInt643()); + assertEquals(456, merged.getFieldMessage10().getFieldInt325()); + } + + @Test + public void oneofFieldsShouldRoundtrip() throws IOException { + roundtrip("Field 53", newBuilder().setFieldDouble53(100).build()); + roundtrip("Field 54", newBuilder().setFieldFloat54(100).build()); + roundtrip("Field 55", newBuilder().setFieldInt6455(100).build()); + roundtrip("Field 56", newBuilder().setFieldUint6456(100L).build()); + roundtrip("Field 57", newBuilder().setFieldInt3257(100).build()); + roundtrip("Field 58", newBuilder().setFieldFixed6458(100).build()); + roundtrip("Field 59", newBuilder().setFieldFixed3259(100).build()); + roundtrip("Field 60", newBuilder().setFieldBool60(true).build()); + roundtrip("Field 61", newBuilder().setFieldString61(data().getString()).build()); + roundtrip( + "Field 62", newBuilder().setFieldMessage62(newBuilder().setFieldDouble1(100)).build()); + roundtrip("Field 63", newBuilder().setFieldBytes63(data().getBytes()).build()); + roundtrip("Field 64", newBuilder().setFieldUint3264(100).build()); + roundtrip("Field 65", newBuilder().setFieldSfixed3265(100).build()); + roundtrip("Field 66", newBuilder().setFieldSfixed6466(100).build()); + roundtrip("Field 67", newBuilder().setFieldSint3267(100).build()); + roundtrip("Field 68", newBuilder().setFieldSint6468(100).build()); + roundtrip( + "Field 69", + newBuilder() + .setFieldGroup69( + Proto2MessageLite.FieldGroup69.newBuilder().setFieldInt3270(data().getInt())) + .build()); + } + + private Proto2MessageLite.Builder newBuilder() { + return messageFactory().newMessage().toBuilder(); + } + + @Override + protected List<Proto2MessageLite> newMessagesMissingRequiredFields() { + return messageFactory().newMessagesMissingRequiredFields(); + } + + @Test + public void mapsShouldRoundtrip() throws IOException { + roundtrip( + "Proto2MessageLiteWithMaps", + new Proto2MessageLiteFactory(2, 10, 2, 2).newMessageWithMaps(), + Protobuf.getInstance().schemaFor(Proto2MessageLiteWithMaps.class)); + } + + @Test + public void unknownFieldsUnrecognized() throws Exception { + Proto2MessageLite expectedMessage = messageFactory().newMessage(); + byte[] serializedBytes = expectedMessage.toByteArray(); + Proto2EmptyLite empty = + ExperimentalSerializationUtil.fromByteArray(serializedBytes, Proto2EmptyLite.class); + + // Merge serialized bytes into an empty message, then reserialize and merge it to a new + // Proto2Message. Make sure the two messages equal. + byte[] roundtripBytes = ExperimentalSerializationUtil.toByteArray(empty); + Proto2MessageLite roundtripMessage = + ExperimentalSerializationUtil.fromByteArray(roundtripBytes, Proto2MessageLite.class); + assertEquals(expectedMessage, roundtripMessage); + } + + @Test + public void unknownEnum() throws IOException { + // Use unknown fields to hold invalid enum values. + UnknownFieldSetLite unknowns = UnknownFieldSetLite.newInstance(); + final int outOfRange = 1000; + assertNull(TestEnum.forNumber(outOfRange)); + unknowns.storeField( + WireFormat.makeTag( + Proto2MessageLite.FIELD_ENUM_13_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) outOfRange); + unknowns.storeField( + WireFormat.makeTag( + Proto2MessageLite.FIELD_ENUM_LIST_30_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) TestEnum.ONE_VALUE); + unknowns.storeField( + WireFormat.makeTag( + Proto2MessageLite.FIELD_ENUM_LIST_30_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) outOfRange); + unknowns.storeField( + WireFormat.makeTag( + Proto2MessageLite.FIELD_ENUM_LIST_30_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) TestEnum.TWO_VALUE); + + { + // Construct a packed enum list. + int packedSize = + CodedOutputStream.computeUInt32SizeNoTag(TestEnum.ONE_VALUE) + + CodedOutputStream.computeUInt32SizeNoTag(outOfRange) + + CodedOutputStream.computeUInt32SizeNoTag(TestEnum.ONE_VALUE); + ByteString.CodedBuilder packedBuilder = ByteString.newCodedBuilder(packedSize); + CodedOutputStream packedOut = packedBuilder.getCodedOutput(); + packedOut.writeEnumNoTag(TestEnum.ONE_VALUE); + packedOut.writeEnumNoTag(outOfRange); + packedOut.writeEnumNoTag(TestEnum.TWO_VALUE); + unknowns.storeField( + WireFormat.makeTag( + Proto2MessageLite.FIELD_ENUM_LIST_PACKED_44_FIELD_NUMBER, + WireFormat.WIRETYPE_LENGTH_DELIMITED), + packedBuilder.build()); + } + int size = unknowns.getSerializedSize(); + byte[] output = new byte[size]; + CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); + unknowns.writeTo(codedOutput); + codedOutput.flush(); + + Proto2MessageLite parsed = + ExperimentalSerializationUtil.fromByteArray(output, Proto2MessageLite.class); + assertFalse("out-of-range singular enum should not be in message", parsed.hasFieldEnum13()); + assertEquals( + "out-of-range repeated enum should not be in message", 2, parsed.getFieldEnumList30Count()); + assertEquals(TestEnum.ONE, parsed.getFieldEnumList30(0)); + assertEquals(TestEnum.TWO, parsed.getFieldEnumList30(1)); + assertEquals( + "out-of-range packed repeated enum should not be in message", + 2, + parsed.getFieldEnumListPacked44Count()); + assertEquals(TestEnum.ONE, parsed.getFieldEnumListPacked44(0)); + assertEquals(TestEnum.TWO, parsed.getFieldEnumListPacked44(1)); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/AbstractProto2SchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractProto2SchemaTest.java new file mode 100755 index 000000000..0c1681866 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/AbstractProto2SchemaTest.java @@ -0,0 +1,224 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + +import com.google.protobuf.testing.Proto2Testing.Proto2Empty; +import com.google.protobuf.testing.Proto2Testing.Proto2Message; +import com.google.protobuf.testing.Proto2Testing.Proto2Message.TestEnum; +import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithMaps; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; +import org.junit.Test; + +/** Base class for tests using {@link Proto2Message}. */ +public abstract class AbstractProto2SchemaTest extends AbstractSchemaTest<Proto2Message> { + + @Override + protected Proto2MessageFactory messageFactory() { + return new Proto2MessageFactory(10, 20, 2, 2); + } + + @Test + public void mergeOptionalMessageFields() throws Exception { + Proto2Message message1 = + newBuilder() + .setFieldMessage10(newBuilder().setFieldInt643(123).clearFieldInt325().build()) + .build(); + Proto2Message message2 = + newBuilder() + .setFieldMessage10(newBuilder().clearFieldInt643().setFieldInt325(456).build()) + .build(); + Proto2Message message3 = + newBuilder() + .setFieldMessage10(newBuilder().setFieldInt643(789).clearFieldInt325().build()) + .build(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + message1.writeTo(output); + message2.writeTo(output); + message3.writeTo(output); + byte[] data = output.toByteArray(); + + Proto2Message merged = ExperimentalSerializationUtil.fromByteArray(data, Proto2Message.class); + assertEquals(789, merged.getFieldMessage10().getFieldInt643()); + assertEquals(456, merged.getFieldMessage10().getFieldInt325()); + } + + @Test + public void oneofFieldsShouldRoundtrip() throws IOException { + roundtrip("Field 53", newBuilder().setFieldDouble53(100).build()); + roundtrip("Field 54", newBuilder().setFieldFloat54(100).build()); + roundtrip("Field 55", newBuilder().setFieldInt6455(100).build()); + roundtrip("Field 56", newBuilder().setFieldUint6456(100L).build()); + roundtrip("Field 57", newBuilder().setFieldInt3257(100).build()); + roundtrip("Field 58", newBuilder().setFieldFixed6458(100).build()); + roundtrip("Field 59", newBuilder().setFieldFixed3259(100).build()); + roundtrip("Field 60", newBuilder().setFieldBool60(true).build()); + roundtrip("Field 61", newBuilder().setFieldString61(data().getString()).build()); + roundtrip( + "Field 62", newBuilder().setFieldMessage62(newBuilder().setFieldDouble1(100)).build()); + roundtrip("Field 63", newBuilder().setFieldBytes63(data().getBytes()).build()); + roundtrip("Field 64", newBuilder().setFieldUint3264(100).build()); + roundtrip("Field 65", newBuilder().setFieldSfixed3265(100).build()); + roundtrip("Field 66", newBuilder().setFieldSfixed6466(100).build()); + roundtrip("Field 67", newBuilder().setFieldSint3267(100).build()); + roundtrip("Field 68", newBuilder().setFieldSint6468(100).build()); + roundtrip( + "Field 69", + newBuilder() + .setFieldGroup69( + Proto2Message.FieldGroup69.newBuilder().setFieldInt3270(data().getInt())) + .build()); + } + + private Proto2Message.Builder newBuilder() { + return messageFactory().newMessage().toBuilder(); + } + + @Test + public void mapsShouldRoundtrip() throws IOException { + roundtrip( + "Proto2MessageWithMaps", + new Proto2MessageFactory(2, 10, 2, 2).newMessageWithMaps(), + Protobuf.getInstance().schemaFor(Proto2MessageWithMaps.class)); + } + + @Test + public void unknownFieldsUnrecognized() throws Exception { + Proto2Message expectedMessage = messageFactory().newMessage(); + byte[] serializedBytes = expectedMessage.toByteArray(); + Proto2Empty empty = + ExperimentalSerializationUtil.fromByteArray(serializedBytes, Proto2Empty.class); + + // Merge serialized bytes into an empty message, then reserialize and merge it to a new + // Proto2Message. Make sure the two messages equal. + byte[] roundtripBytes = ExperimentalSerializationUtil.toByteArray(empty); + assertEquals(serializedBytes.length, roundtripBytes.length); + Proto2Message roundtripMessage = + ExperimentalSerializationUtil.fromByteArray(roundtripBytes, Proto2Message.class); + assertEquals(expectedMessage, roundtripMessage); + } + + @Test + public void unknownEnum() throws IOException { + // Use unknown fields to hold invalid enum values. + UnknownFieldSetLite unknowns = UnknownFieldSetLite.newInstance(); + final int outOfRange = 1000; + assertNull(TestEnum.forNumber(outOfRange)); + unknowns.storeField( + WireFormat.makeTag(Proto2Message.FIELD_ENUM_13_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) outOfRange); + unknowns.storeField( + WireFormat.makeTag( + Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) TestEnum.ONE_VALUE); + unknowns.storeField( + WireFormat.makeTag( + Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) outOfRange); + unknowns.storeField( + WireFormat.makeTag( + Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) TestEnum.TWO_VALUE); + + { + // Construct a packed enum list. + int packedSize = + CodedOutputStream.computeUInt32SizeNoTag(TestEnum.ONE_VALUE) + + CodedOutputStream.computeUInt32SizeNoTag(outOfRange) + + CodedOutputStream.computeUInt32SizeNoTag(TestEnum.ONE_VALUE); + ByteString.CodedBuilder packedBuilder = ByteString.newCodedBuilder(packedSize); + CodedOutputStream packedOut = packedBuilder.getCodedOutput(); + packedOut.writeEnumNoTag(TestEnum.ONE_VALUE); + packedOut.writeEnumNoTag(outOfRange); + packedOut.writeEnumNoTag(TestEnum.TWO_VALUE); + unknowns.storeField( + WireFormat.makeTag( + Proto2Message.FIELD_ENUM_LIST_PACKED_44_FIELD_NUMBER, + WireFormat.WIRETYPE_LENGTH_DELIMITED), + packedBuilder.build()); + } + int size = unknowns.getSerializedSize(); + byte[] output = new byte[size]; + CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); + unknowns.writeTo(codedOutput); + codedOutput.flush(); + + Proto2Message parsed = ExperimentalSerializationUtil.fromByteArray(output, Proto2Message.class); + assertFalse("out-of-range singular enum should not be in message", parsed.hasFieldEnum13()); + { + List<Long> singularEnum = + parsed + .getUnknownFields() + .getField(Proto2Message.FIELD_ENUM_13_FIELD_NUMBER) + .getVarintList(); + assertEquals(1, singularEnum.size()); + assertEquals((Long) (long) outOfRange, singularEnum.get(0)); + } + { + List<Long> repeatedEnum = + parsed + .getUnknownFields() + .getField(Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER) + .getVarintList(); + assertEquals(1, repeatedEnum.size()); + assertEquals((Long) (long) outOfRange, repeatedEnum.get(0)); + } + { + List<Long> packedRepeatedEnum = + parsed + .getUnknownFields() + .getField(Proto2Message.FIELD_ENUM_LIST_PACKED_44_FIELD_NUMBER) + .getVarintList(); + assertEquals(1, packedRepeatedEnum.size()); + assertEquals((Long) (long) outOfRange, packedRepeatedEnum.get(0)); + } + assertEquals( + "out-of-range repeated enum should not be in message", 2, parsed.getFieldEnumList30Count()); + assertEquals(TestEnum.ONE, parsed.getFieldEnumList30(0)); + assertEquals(TestEnum.TWO, parsed.getFieldEnumList30(1)); + assertEquals( + "out-of-range packed repeated enum should not be in message", + 2, + parsed.getFieldEnumListPacked44Count()); + assertEquals(TestEnum.ONE, parsed.getFieldEnumListPacked44(0)); + assertEquals(TestEnum.TWO, parsed.getFieldEnumListPacked44(1)); + } + + @Override + protected List<Proto2Message> newMessagesMissingRequiredFields() { + return messageFactory().newMessagesMissingRequiredFields(); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/AbstractProto3LiteSchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractProto3LiteSchemaTest.java new file mode 100755 index 000000000..9cc04ec7c --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/AbstractProto3LiteSchemaTest.java @@ -0,0 +1,143 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertEquals; + +import com.google.protobuf.testing.Proto3TestingLite.Proto3EmptyLite; +import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLite; +import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLiteWithMaps; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; + +/** Base class for tests using {@link Proto3MessageLite}. */ +public abstract class AbstractProto3LiteSchemaTest extends AbstractSchemaTest<Proto3MessageLite> { + @Override + protected Proto3MessageLiteFactory messageFactory() { + return new Proto3MessageLiteFactory(10, 20, 2, 2); + } + + @Override + protected List<ByteBuffer> serializedBytesWithInvalidUtf8() throws IOException { + List<ByteBuffer> invalidBytes = new ArrayList<>(); + byte[] invalid = new byte[] {(byte) 0x80}; + { + ByteBuffer buffer = ByteBuffer.allocate(100); + CodedOutputStream codedOutput = CodedOutputStream.newInstance(buffer); + codedOutput.writeByteArray(Proto3MessageLite.FIELD_STRING_9_FIELD_NUMBER, invalid); + codedOutput.flush(); + buffer.flip(); + invalidBytes.add(buffer); + } + { + ByteBuffer buffer = ByteBuffer.allocate(100); + CodedOutputStream codedOutput = CodedOutputStream.newInstance(buffer); + codedOutput.writeByteArray(Proto3MessageLite.FIELD_STRING_LIST_26_FIELD_NUMBER, invalid); + codedOutput.flush(); + buffer.flip(); + invalidBytes.add(buffer); + } + return invalidBytes; + } + + @Test + public void mergeOptionalMessageFields() throws Exception { + Proto3MessageLite message1 = + newBuilder() + .setFieldMessage10(newBuilder().setFieldInt643(123).clearFieldInt325().build()) + .build(); + Proto3MessageLite message2 = + newBuilder() + .setFieldMessage10(newBuilder().clearFieldInt643().setFieldInt325(456).build()) + .build(); + Proto3MessageLite message3 = + newBuilder() + .setFieldMessage10(newBuilder().setFieldInt643(789).clearFieldInt325().build()) + .build(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + message1.writeTo(output); + message2.writeTo(output); + message3.writeTo(output); + byte[] data = output.toByteArray(); + + Proto3MessageLite merged = + ExperimentalSerializationUtil.fromByteArray(data, Proto3MessageLite.class); + assertEquals(789, merged.getFieldMessage10().getFieldInt643()); + assertEquals(456, merged.getFieldMessage10().getFieldInt325()); + } + + @Test + public void oneofFieldsShouldRoundtrip() throws IOException { + roundtrip("Field 53", newBuilder().setFieldDouble53(100).build()); + roundtrip("Field 54", newBuilder().setFieldFloat54(100).build()); + roundtrip("Field 55", newBuilder().setFieldInt6455(100).build()); + roundtrip("Field 56", newBuilder().setFieldUint6456(100L).build()); + roundtrip("Field 57", newBuilder().setFieldInt3257(100).build()); + roundtrip("Field 58", newBuilder().setFieldFixed6458(100).build()); + roundtrip("Field 59", newBuilder().setFieldFixed3259(100).build()); + roundtrip("Field 60", newBuilder().setFieldBool60(true).build()); + roundtrip("Field 61", newBuilder().setFieldString61(data().getString()).build()); + roundtrip( + "Field 62", newBuilder().setFieldMessage62(newBuilder().setFieldDouble1(100)).build()); + roundtrip("Field 63", newBuilder().setFieldBytes63(data().getBytes()).build()); + roundtrip("Field 64", newBuilder().setFieldUint3264(100).build()); + roundtrip("Field 65", newBuilder().setFieldSfixed3265(100).build()); + roundtrip("Field 66", newBuilder().setFieldSfixed6466(100).build()); + roundtrip("Field 67", newBuilder().setFieldSint3267(100).build()); + roundtrip("Field 68", newBuilder().setFieldSint6468(100).build()); + } + + @Test + public void retainUnknownFields() { + // Unknown fields are retained in lite runtime. + Proto3MessageLite expectedMessage = messageFactory().newMessage(); + Proto3EmptyLite empty = + ExperimentalSerializationUtil.fromByteArray( + expectedMessage.toByteArray(), Proto3EmptyLite.class); + assertEquals(expectedMessage.getSerializedSize(), empty.getSerializedSize()); + } + + @Test + public void mapsShouldRoundtrip() throws IOException { + roundtrip( + "Proto3MessageLiteWithMaps", + new Proto3MessageLiteFactory(2, 10, 2, 2).newMessageWithMaps(), + Protobuf.getInstance().schemaFor(Proto3MessageLiteWithMaps.class)); + } + + private static Proto3MessageLite.Builder newBuilder() { + return Proto3MessageLite.newBuilder(); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/AbstractProto3SchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractProto3SchemaTest.java new file mode 100755 index 000000000..358f1e3b1 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/AbstractProto3SchemaTest.java @@ -0,0 +1,151 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertEquals; + +import com.google.protobuf.testing.Proto3Testing.Proto3Empty; +import com.google.protobuf.testing.Proto3Testing.Proto3Message; +import com.google.protobuf.testing.Proto3Testing.Proto3MessageWithMaps; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; + +/** Base class for tests using {@link Proto3Message}. */ +public abstract class AbstractProto3SchemaTest extends AbstractSchemaTest<Proto3Message> { + @Override + protected Proto3MessageFactory messageFactory() { + return new Proto3MessageFactory(10, 20, 2, 2); + } + + @Override + protected List<ByteBuffer> serializedBytesWithInvalidUtf8() throws IOException { + List<ByteBuffer> invalidBytes = new ArrayList<>(); + byte[] invalid = new byte[] {(byte) 0x80}; + { + ByteBuffer buffer = ByteBuffer.allocate(100); + CodedOutputStream codedOutput = CodedOutputStream.newInstance(buffer); + codedOutput.writeByteArray(Proto3Message.FIELD_STRING_9_FIELD_NUMBER, invalid); + codedOutput.flush(); + buffer.flip(); + invalidBytes.add(buffer); + } + { + ByteBuffer buffer = ByteBuffer.allocate(100); + CodedOutputStream codedOutput = CodedOutputStream.newInstance(buffer); + codedOutput.writeByteArray(Proto3Message.FIELD_STRING_LIST_26_FIELD_NUMBER, invalid); + codedOutput.flush(); + buffer.flip(); + invalidBytes.add(buffer); + } + return invalidBytes; + } + + @Test + public void mergeOptionalMessageFields() throws Exception { + Proto3Message message1 = + newBuilder() + .setFieldMessage10(newBuilder().setFieldInt643(123).clearFieldInt325().build()) + .build(); + Proto3Message message2 = + newBuilder() + .setFieldMessage10(newBuilder().clearFieldInt643().setFieldInt325(456).build()) + .build(); + Proto3Message message3 = + newBuilder() + .setFieldMessage10(newBuilder().setFieldInt643(789).clearFieldInt325().build()) + .build(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + message1.writeTo(output); + message2.writeTo(output); + message3.writeTo(output); + byte[] data = output.toByteArray(); + + Proto3Message merged = ExperimentalSerializationUtil.fromByteArray(data, Proto3Message.class); + assertEquals(789, merged.getFieldMessage10().getFieldInt643()); + assertEquals(456, merged.getFieldMessage10().getFieldInt325()); + } + + @Test + public void oneofFieldsShouldRoundtrip() throws IOException { + roundtrip("Field 53", newBuilder().setFieldDouble53(100).build()); + roundtrip("Field 54", newBuilder().setFieldFloat54(100).build()); + roundtrip("Field 55", newBuilder().setFieldInt6455(100).build()); + roundtrip("Field 56", newBuilder().setFieldUint6456(100L).build()); + roundtrip("Field 57", newBuilder().setFieldInt3257(100).build()); + roundtrip("Field 58", newBuilder().setFieldFixed6458(100).build()); + roundtrip("Field 59", newBuilder().setFieldFixed3259(100).build()); + roundtrip("Field 60", newBuilder().setFieldBool60(true).build()); + roundtrip("Field 61", newBuilder().setFieldString61(data().getString()).build()); + roundtrip( + "Field 62", newBuilder().setFieldMessage62(newBuilder().setFieldDouble1(100)).build()); + roundtrip("Field 63", newBuilder().setFieldBytes63(data().getBytes()).build()); + roundtrip("Field 64", newBuilder().setFieldUint3264(100).build()); + roundtrip("Field 65", newBuilder().setFieldSfixed3265(100).build()); + roundtrip("Field 66", newBuilder().setFieldSfixed6466(100).build()); + roundtrip("Field 67", newBuilder().setFieldSint3267(100).build()); + roundtrip("Field 68", newBuilder().setFieldSint6468(100).build()); + } + + @Test + public void preserveUnknownFields() { + Proto3Message expectedMessage = messageFactory().newMessage(); + Proto3Empty empty = + ExperimentalSerializationUtil.fromByteArray( + expectedMessage.toByteArray(), Proto3Empty.class); + assertEquals(expectedMessage.getSerializedSize(), empty.getSerializedSize()); + assertEquals(expectedMessage.toByteString(), empty.toByteString()); + } + + @Test + public void preserveUnknownFieldsProto2() { + // Make sure we will be able to preserve valid proto2 wireformat, including those that are not + // supported in proto3, e.g. groups. + byte[] payload = new Proto2MessageFactory(10, 20, 2, 2).newMessage().toByteArray(); + Proto3Empty empty = ExperimentalSerializationUtil.fromByteArray(payload, Proto3Empty.class); + assertEquals(payload.length, empty.getSerializedSize()); + } + + @Test + public void mapsShouldRoundtrip() throws IOException { + roundtrip( + "Proto3MessageWithMaps", + new Proto3MessageFactory(2, 10, 2, 2).newMessageWithMaps(), + Protobuf.getInstance().schemaFor(Proto3MessageWithMaps.class)); + } + + private static Proto3Message.Builder newBuilder() { + return Proto3Message.newBuilder(); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/AbstractSchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractSchemaTest.java new file mode 100755 index 000000000..c69a4fd25 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/AbstractSchemaTest.java @@ -0,0 +1,157 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Before; +import org.junit.Test; + +public abstract class AbstractSchemaTest<T extends MessageLite> { + private Schema<T> schema; + + @Before + public void setup() { + schema = schema(); + registerSchemas(); + } + + // Subclass should override this method if it needs to register more than one schemas. + protected void registerSchemas() { + // Register this schema with the runtime to support processing of nested messages. + Protobuf.getInstance().registerSchemaOverride(schema.newInstance().getClass(), schema); + } + + protected abstract Schema<T> schema(); + + protected abstract ExperimentalMessageFactory<? extends T> messageFactory(); + + @SuppressWarnings("unused") + protected List<ByteBuffer> serializedBytesWithInvalidUtf8() throws IOException { + return Collections.emptyList(); + } + + @Test + public void randomMessageShouldRoundtrip() throws IOException { + roundtrip("", messageFactory().newMessage()); + } + + @Test + public void invalidUtf8StringParsing() throws IOException { + for (ByteBuffer invalidUtf8Bytes : serializedBytesWithInvalidUtf8()) { + Reader reader = BinaryReader.newInstance(invalidUtf8Bytes, /* bufferIsImmutable= */ true); + + T newMsg = schema.newInstance(); + try { + schema.mergeFrom(newMsg, reader, ExtensionRegistryLite.getEmptyRegistry()); + fail("should throw invalid "); + } catch (InvalidProtocolBufferException expected) { + } + } + } + + @Test + public void mergeFromByteArrayFastPathMayThrowIndexOutOfBoundsException() throws IOException { + if (!Android.isOnAndroidDevice()) { + // Skip this test if not on Android. + return; + } + byte[] data = messageFactory().newMessage().toByteArray(); + int exceptionCount = 0; + for (int i = 0; i <= data.length; i++) { + byte[] truncatedData = Arrays.copyOf(data, i); + try { + T message = schema.newInstance(); + // Test that this method throws the expected exceptions. + schema.mergeFrom(message, truncatedData, 0, i, new ArrayDecoders.Registers()); + } catch (InvalidProtocolBufferException e) { + // Ignore expected exceptions. + } catch (IndexOutOfBoundsException e) { + exceptionCount += 1; + } + } + assertNotEquals(0, exceptionCount); + } + + protected static final <M extends MessageLite> void roundtrip( + String failureMessage, M msg, Schema<M> schema) throws IOException { + byte[] serializedBytes = ExperimentalSerializationUtil.toByteArray(msg, schema); + assertEquals(failureMessage, msg.getSerializedSize(), serializedBytes.length); + + // Now read it back in and verify it matches the original. + if (Android.isOnAndroidDevice()) { + // Test the fast path on Android. + M newMsg = schema.newInstance(); + schema.mergeFrom( + newMsg, serializedBytes, 0, serializedBytes.length, new ArrayDecoders.Registers()); + schema.makeImmutable(newMsg); + assertEquals(failureMessage, msg, newMsg); + } + M newMsg = schema.newInstance(); + Reader reader = BinaryReader.newInstance(ByteBuffer.wrap(serializedBytes), true); + schema.mergeFrom(newMsg, reader, ExtensionRegistryLite.getEmptyRegistry()); + schema.makeImmutable(newMsg); + + assertEquals(failureMessage, msg, newMsg); + } + + protected final void roundtrip(String failureMessage, T msg) throws IOException { + roundtrip(failureMessage, msg, schema); + } + + protected final ExperimentalTestDataProvider data() { + return messageFactory().dataProvider(); + } + + protected List<T> newMessagesMissingRequiredFields() { + return Collections.emptyList(); + } + + @SuppressWarnings("unchecked") + @Test + public void testRequiredFields() throws Exception { + for (T msg : newMessagesMissingRequiredFields()) { + if (schema.isInitialized(msg)) { + assertEquals("", msg.toString()); + msg = (T) msg.toBuilder().build(); + } + assertFalse(schema.isInitialized(msg)); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/ArrayDecodersTest.java b/java/core/src/test/java/com/google/protobuf/ArrayDecodersTest.java new file mode 100755 index 000000000..037173b66 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/ArrayDecodersTest.java @@ -0,0 +1,236 @@ +// 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.ArrayDecoders.Registers; +import java.io.IOException; +import junit.framework.TestCase; + +public class ArrayDecodersTest extends TestCase { + + private static final int TAG = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); + private static final ByteString NEGATIVE_SIZE_0 = generateNegativeLength(0); + private static final ByteString NEGATIVE_SIZE_1 = generateNegativeLength(1); + + private Registers registers; + + @Override + public void setUp() { + registers = new Registers(); + registers.int1 = TAG; + } + + public void testException_decodeString() { + try { + ArrayDecoders.decodeString(NEGATIVE_SIZE_0.toByteArray(), 0, registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeStringRequireUtf8() { + try { + ArrayDecoders.decodeStringRequireUtf8(NEGATIVE_SIZE_0.toByteArray(), 0, registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeBytes() { + try { + ArrayDecoders.decodeBytes(NEGATIVE_SIZE_0.toByteArray(), 0, registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeStringList_first() { + try { + ArrayDecoders.decodeStringList( + TAG, + NEGATIVE_SIZE_0.toByteArray(), + 0, + NEGATIVE_SIZE_0.size(), + new ProtobufArrayList<Object>(), + registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeStringList_second() { + try { + ArrayDecoders.decodeStringList( + TAG, + NEGATIVE_SIZE_1.toByteArray(), + 0, + NEGATIVE_SIZE_1.size(), + new ProtobufArrayList<Object>(), + registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeStringListRequireUtf8_first() { + try { + ArrayDecoders.decodeStringListRequireUtf8( + TAG, + NEGATIVE_SIZE_0.toByteArray(), + 0, + NEGATIVE_SIZE_0.size(), + new ProtobufArrayList<Object>(), + registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeStringListRequireUtf8_second() { + try { + ArrayDecoders.decodeStringListRequireUtf8( + TAG, + NEGATIVE_SIZE_1.toByteArray(), + 0, + NEGATIVE_SIZE_1.size(), + new ProtobufArrayList<Object>(), + registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeBytesList_first() { + try { + ArrayDecoders.decodeBytesList( + TAG, + NEGATIVE_SIZE_0.toByteArray(), + 0, + NEGATIVE_SIZE_0.size(), + new ProtobufArrayList<Object>(), + registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeBytesList_second() { + try { + ArrayDecoders.decodeBytesList( + TAG, + NEGATIVE_SIZE_1.toByteArray(), + 0, + NEGATIVE_SIZE_1.size(), + new ProtobufArrayList<Object>(), + registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeUnknownField() { + try { + ArrayDecoders.decodeUnknownField( + TAG, + NEGATIVE_SIZE_0.toByteArray(), + 0, + NEGATIVE_SIZE_0.size(), + UnknownFieldSetLite.newInstance(), + registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + public void testException_decodeHugeField() { + byte[] badBytes = + new byte[] { + (byte) 0x80, (byte) 0xFF, (byte) 0xFF, (byte) 0xEF, 0x73, 0x74, 0x69, 0x6E, 0x67 + }; + try { + ArrayDecoders.decodeUnknownField( + TAG, badBytes, 0, badBytes.length, UnknownFieldSetLite.newInstance(), registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + + try { + ArrayDecoders.decodeBytes(badBytes, 0, registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + + byte[] badBytesList = + new byte[] { + 0x01, + 0x77, + 0x0A, + (byte) 0x80, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xEF, + 0x73, + 0x74, + 0x69, + 0x6E, + 0x67 + }; + try { + ArrayDecoders.decodeBytesList( + TAG, badBytesList, 0, badBytes.length, new ProtobufArrayList<>(), registers); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + + private static ByteString generateNegativeLength(int count) { + try { + ByteString.Output byteStringOutput = ByteString.newOutput(); + CodedOutputStream codedOutput = CodedOutputStream.newInstance(byteStringOutput); + + // Write out count - 1 valid 0 length fields; we only write out tags after the field since + // ArrayDecoders expects the first tag to already have been parsed. + for (int i = 0; i < count; i++) { + codedOutput.writeInt32NoTag(0); + codedOutput.writeInt32NoTag(TAG); + } + + // Write out a negative length + codedOutput.writeInt32NoTag(-1); + + codedOutput.flush(); + + return byteStringOutput.toByteString(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/BinaryProtocolTest.java b/java/core/src/test/java/com/google/protobuf/BinaryProtocolTest.java new file mode 100755 index 000000000..cda2998f5 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/BinaryProtocolTest.java @@ -0,0 +1,90 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertEquals; + +import com.google.protobuf.testing.Proto2Testing.Proto2Message; +import com.google.protobuf.testing.Proto3Testing.Proto3Message; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class BinaryProtocolTest { + @Before + public void setup() { + TestSchemas.registerGenericProto2Schemas(); + + Protobuf.getInstance() + .registerSchemaOverride(Proto3Message.class, TestSchemas.genericProto3Schema); + } + + @Test + public void proto3Roundtrip() throws Exception { + Proto3Message expected = new Proto3MessageFactory(5, 10, 2, 2).newMessage(); + byte[] expectedBytes = expected.toByteArray(); + + // Deserialize with BinaryReader and verify that the message matches the original. + Proto3Message result = + ExperimentalSerializationUtil.fromByteArray(expectedBytes, Proto3Message.class); + assertEquals(expected, result); + + // Now write it back out using BinaryWriter and verify the output length. + byte[] actualBytes = ExperimentalSerializationUtil.toByteArray(result); + Assert.assertEquals(expectedBytes.length, actualBytes.length); + + // Read back in the bytes and verify that it matches the original message. + Proto3Message actual = Proto3Message.parseFrom(actualBytes); + assertEquals(expected, actual); + } + + @Test + public void proto2Roundtrip() throws Exception { + Proto2Message expected = new Proto2MessageFactory(5, 10, 2, 2).newMessage(); + byte[] expectedBytes = expected.toByteArray(); + + // Deserialize with BinaryReader and verify that the message matches the original. + Proto2Message result = + ExperimentalSerializationUtil.fromByteArray(expectedBytes, Proto2Message.class); + assertEquals(expected, result); + + // Now write it back out using BinaryWriter and verify the output length. + byte[] actualBytes = ExperimentalSerializationUtil.toByteArray(result); + Assert.assertEquals(expectedBytes.length, actualBytes.length); + + // Read back in the bytes and verify that it matches the original message. + Proto2Message actual = Proto2Message.parseFrom(actualBytes); + assertEquals(expected, actual); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/CachedFieldSizeTest.java b/java/core/src/test/java/com/google/protobuf/CachedFieldSizeTest.java new file mode 100755 index 000000000..96319d93c --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/CachedFieldSizeTest.java @@ -0,0 +1,65 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertEquals; + +import protobuf_unittest.UnittestProto.TestPackedTypes; +import proto3_unittest.UnittestProto3; +import protobuf_unittest.TestCachedFieldSizeMessage; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class CachedFieldSizeTest { + // Regression test for b/74087933 + @Test + public void testCachedFieldSize() throws Exception { + TestCachedFieldSizeMessage.Builder builder = TestCachedFieldSizeMessage.newBuilder(); + builder.setProto2Child(TestUtil.getPackedSet()); + builder.setProto3Child( + UnittestProto3.TestPackedTypes.parseFrom(TestUtil.getPackedSet().toByteArray())); + TestCachedFieldSizeMessage message = builder.build(); + + // Serialize once to cache all field sizes. This will use the experimental runtime because + // the proto has optimize_for = CODE_SIZE. + message.toByteArray(); + // Serialize individual submessages. This will use the generated implementation. If the + // experimental runtime hasn't set the correct cached size, this will throw an exception. + byte[] data2 = message.getProto2Child().toByteArray(); + byte[] data3 = message.getProto3Child().toByteArray(); + + // Make sure the serialized data is correct. + assertEquals(message.getProto2Child(), TestPackedTypes.parseFrom(data2)); + assertEquals(message.getProto3Child(), UnittestProto3.TestPackedTypes.parseFrom(data3)); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/CodedAdapterTest.java b/java/core/src/test/java/com/google/protobuf/CodedAdapterTest.java new file mode 100755 index 000000000..a24b48b51 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/CodedAdapterTest.java @@ -0,0 +1,110 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertEquals; + +import com.google.protobuf.testing.Proto2Testing.Proto2Message; +import com.google.protobuf.testing.Proto3Testing.Proto3Message; +import java.io.IOException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class CodedAdapterTest { + @Before + public void setup() { + TestSchemas.registerGenericProto2Schemas(); + + Protobuf.getInstance() + .registerSchemaOverride(Proto3Message.class, TestSchemas.genericProto3Schema); + } + + @Test + public void proto3Roundtrip() throws Exception { + Proto3Message expected = new Proto3MessageFactory(5, 10, 2, 2).newMessage(); + byte[] expectedBytes = expected.toByteArray(); + + // Deserialize with BinaryReader and verify that the message matches the original. + Proto3Message result = fromByteArray(expectedBytes, Proto3Message.class); + assertEquals(expected, result); + + // Now write it back out using BinaryWriter and verify the output length. + byte[] actualBytes = toByteArray(result, expectedBytes.length); + + // Read back in the bytes and verify that it matches the original message. + Proto3Message actual = Proto3Message.parseFrom(actualBytes); + assertEquals(expected, actual); + } + + @Test + public void proto2Roundtrip() throws Exception { + Proto2Message expected = new Proto2MessageFactory(5, 10, 2, 2).newMessage(); + byte[] expectedBytes = expected.toByteArray(); + + // Deserialize with BinaryReader and verify that the message matches the original. + Proto2Message result = fromByteArray(expectedBytes, Proto2Message.class); + assertEquals(expected, result); + + // Now write it back out using BinaryWriter and verify the output length. + byte[] actualBytes = toByteArray(result, expectedBytes.length); + + // Read back in the bytes and verify that it matches the original message. + Proto2Message actual = Proto2Message.parseFrom(actualBytes); + assertEquals(expected, actual); + } + + public static <T> byte[] toByteArray(T msg, int size) throws Exception { + Schema<T> schema = Protobuf.getInstance().schemaFor(msg); + byte[] out = new byte[size]; + CodedOutputStreamWriter writer = + CodedOutputStreamWriter.forCodedOutput(CodedOutputStream.newInstance(out)); + schema.writeTo(msg, writer); + assertEquals(out.length, writer.getTotalBytesWritten()); + return out; + } + + public static <T> T fromByteArray(byte[] data, Class<T> messageType) { + Schema<T> schema = Protobuf.getInstance().schemaFor(messageType); + try { + T msg = schema.newInstance(); + schema.mergeFrom( + msg, + CodedInputStreamReader.forCodedInput(CodedInputStream.newInstance(data)), + ExtensionRegistryLite.EMPTY_REGISTRY_LITE); + return msg; + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java index 9c5d6dafb..532052cdb 100644 --- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java +++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java @@ -44,6 +44,7 @@ import java.io.InputStream; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import junit.framework.TestCase; /** @@ -1195,4 +1196,59 @@ public class CodedInputStreamTest extends TestCase { // Expected } } + + public void testMaliciousInputStream() throws Exception { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream); + codedOutputStream.writeByteArrayNoTag(new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5 }); + codedOutputStream.flush(); + final List<byte[]> maliciousCapture = new ArrayList<>(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()) { + @Override + public synchronized int read(byte[] b, int off, int len) { + maliciousCapture.add(b); + return super.read(b, off, len); + } + }; + + // test ByteString + + CodedInputStream codedInputStream = CodedInputStream.newInstance(inputStream, 1); + ByteString byteString = codedInputStream.readBytes(); + assertEquals(0x0, byteString.byteAt(0)); + maliciousCapture.get(1)[0] = 0x9; + assertEquals(0x0, byteString.byteAt(0)); + + // test ByteBuffer + + inputStream.reset(); + maliciousCapture.clear(); + codedInputStream = CodedInputStream.newInstance(inputStream, 1); + ByteBuffer byteBuffer = codedInputStream.readByteBuffer(); + assertEquals(0x0, byteBuffer.get(0)); + maliciousCapture.get(1)[0] = 0x9; + assertEquals(0x0, byteBuffer.get(0)); + + + // test byte[] + + inputStream.reset(); + maliciousCapture.clear(); + codedInputStream = CodedInputStream.newInstance(inputStream, 1); + byte[] byteArray = codedInputStream.readByteArray(); + assertEquals(0x0, byteArray[0]); + maliciousCapture.get(1)[0] = 0x9; + assertEquals(0x9, byteArray[0]); // MODIFICATION! Should we fix? + + // test rawBytes + + inputStream.reset(); + maliciousCapture.clear(); + codedInputStream = CodedInputStream.newInstance(inputStream, 1); + int length = codedInputStream.readRawVarint32(); + byteArray = codedInputStream.readRawBytes(length); + assertEquals(0x0, byteArray[0]); + maliciousCapture.get(1)[0] = 0x9; + assertEquals(0x9, byteArray[0]); // MODIFICATION! Should we fix? + } } diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java index 5f9132401..c222ff377 100644 --- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java +++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java @@ -30,6 +30,8 @@ package com.google.protobuf; +import protobuf_unittest.NestedExtension; +import protobuf_unittest.NonNestedExtension; import com.google.protobuf.DescriptorProtos.DescriptorProto; import com.google.protobuf.DescriptorProtos.EnumDescriptorProto; import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto; @@ -779,4 +781,23 @@ public class DescriptorsTest extends TestCase { assertEquals("FIELDNAME5", d.getFields().get(4).getJsonName()); assertEquals("@type", d.getFields().get(5).getJsonName()); } + + public void testExtensionRenamesKeywords() { + assertTrue(NonNestedExtension.if_ instanceof GeneratedMessage.GeneratedExtension); + assertTrue( + NestedExtension.MyNestedExtension.default_ + instanceof GeneratedMessage.GeneratedExtension); + + NonNestedExtension.MessageToBeExtended msg = + NonNestedExtension.MessageToBeExtended.newBuilder() + .setExtension(NonNestedExtension.if_, "!fi") + .build(); + assertEquals("!fi", msg.getExtension(NonNestedExtension.if_)); + + msg = + NonNestedExtension.MessageToBeExtended.newBuilder() + .setExtension(NestedExtension.MyNestedExtension.default_, 8) + .build(); + assertEquals(8, msg.getExtension(NestedExtension.MyNestedExtension.default_).intValue()); + } } diff --git a/java/core/src/test/java/com/google/protobuf/ExperimentalMessageFactory.java b/java/core/src/test/java/com/google/protobuf/ExperimentalMessageFactory.java new file mode 100755 index 000000000..60c8609cf --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/ExperimentalMessageFactory.java @@ -0,0 +1,40 @@ +// 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; + +/** Interface for a test factory for messages. */ +public interface ExperimentalMessageFactory<T extends MessageLite> { + /** Creates a new random message instance. */ + T newMessage(); + + /** Gets the underlying data provider. */ + ExperimentalTestDataProvider dataProvider(); +} diff --git a/java/core/src/test/java/com/google/protobuf/ExperimentalSerializationUtil.java b/java/core/src/test/java/com/google/protobuf/ExperimentalSerializationUtil.java new file mode 100755 index 000000000..05aaa6752 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/ExperimentalSerializationUtil.java @@ -0,0 +1,113 @@ +// 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 java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Queue; + +/** Utilities for serialization. */ +public class ExperimentalSerializationUtil { + + /** + * Serializes the given message to a byte array using {@link com.google.protobuf.BinaryWriter}. + */ + public static <T> byte[] toByteArray(T msg) throws IOException { + return toByteArray(msg, Protobuf.getInstance().schemaFor(msg)); + } + + /** + * Serializes the given message to a byte array using {@link com.google.protobuf.BinaryWriter} + * with a customized Schema. + */ + public static <T> byte[] toByteArray(T msg, Schema<T> schema) throws IOException { + BinaryWriter writer = BinaryWriter.newHeapInstance(BufferAllocator.unpooled()); + schema.writeTo(msg, writer); + + byte[] out = new byte[writer.getTotalBytesWritten()]; + int outPos = 0; + Queue<AllocatedBuffer> buffers = writer.complete(); + while (true) { + AllocatedBuffer buffer = buffers.poll(); + if (buffer == null) { + break; + } + int length = buffer.limit() - buffer.position(); + System.arraycopy( + buffer.array(), buffer.arrayOffset() + buffer.position(), out, outPos, length); + outPos += length; + } + if (out.length != outPos) { + throw new IllegalArgumentException("Failed to serialize test message"); + } + return out; + } + + /** Deserializes a message from the given byte array. */ + public static <T> T fromByteArray(byte[] data, Class<T> messageType) { + if (Android.isOnAndroidDevice()) { + return fromByteArrayFastPath(data, messageType); + } else { + return fromByteArray(data, messageType, ExtensionRegistryLite.getEmptyRegistry()); + } + } + + /** + * Deserializes a message from the given byte array using {@link com.google.protobuf.BinaryReader} + * with an extension registry and a customized Schema. + */ + public static <T> T fromByteArray( + byte[] data, Class<T> messageType, ExtensionRegistryLite extensionRegistry) { + try { + Schema<T> schema = Protobuf.getInstance().schemaFor(messageType); + T msg = schema.newInstance(); + schema.mergeFrom( + msg, BinaryReader.newInstance(ByteBuffer.wrap(data), true), extensionRegistry); + schema.makeImmutable(msg); + return msg; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** Deserializes a lite message from the given byte array using fast path. */ + private static <T> T fromByteArrayFastPath(byte[] data, Class<T> messageType) { + try { + Schema<T> schema = Protobuf.getInstance().schemaFor(messageType); + T msg = schema.newInstance(); + schema.mergeFrom(msg, data, 0, data.length, new ArrayDecoders.Registers()); + schema.makeImmutable(msg); + return msg; + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/ExperimentalTestDataProvider.java b/java/core/src/test/java/com/google/protobuf/ExperimentalTestDataProvider.java new file mode 100755 index 000000000..3ef93ac9f --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/ExperimentalTestDataProvider.java @@ -0,0 +1,189 @@ +// 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 java.util.Random; + +/** Utility class that provides data primitives for filling out protobuf messages. */ +public final class ExperimentalTestDataProvider { + private static final Random RANDOM = new Random(100); + + private final Varint32Provider varint32s = new Varint32Provider(); + private final Varint64Provider varint64s = new Varint64Provider(); + private final int stringLength; + + public ExperimentalTestDataProvider(int stringLength) { + this.stringLength = stringLength; + } + + public double getDouble() { + double value = 0.0; + while (Double.compare(0.0, value) == 0) { + value = RANDOM.nextDouble(); + } + return value; + } + + public float getFloat() { + float value = 0.0f; + while (Float.compare(0.0f, value) == 0) { + value = RANDOM.nextFloat(); + } + return value; + } + + public long getLong() { + return varint64s.getLong(); + } + + public int getInt() { + return varint32s.getInt(); + } + + public boolean getBool() { + return true; + } + + public int getEnum() { + return Math.abs(getInt()) % 3; + } + + public String getString() { + StringBuilder builder = new StringBuilder(stringLength); + for (int i = 0; i < stringLength; ++i) { + builder.append((char) (RANDOM.nextInt('z' - 'a') + 'a')); + } + return builder.toString(); + } + + public ByteString getBytes() { + return ByteString.copyFromUtf8(getString()); + } + + /** + * Iterator over integer values. Uses a simple distribution over 32-bit varints (generally + * favoring smaller values). + */ + private static final class Varint32Provider { + private static final int[][] VALUES = { + new int[] {1, 50, 100, 127}, // 1 byte values + new int[] {128, 500, 10000, 16383}, // 2 bytes values + new int[] {16384, 50000, 1000000, 2097151}, // 3 bytes values + new int[] {2097152, 10000000, 200000000, 268435455}, // 4 bytes values + new int[] {268435456, 0x30000000, 0x7FFFFFFF, 0xFFFFFFFF} // 5 bytes values + }; + + /** Number of samples that should be taken from each value array. */ + private static final int[] NUM_SAMPLES = {3, 2, 1, 1, 2}; + + /** + * The index into the {@link #VALUES} array that identifies the list of samples currently being + * iterated over. + */ + private int listIndex; + + /** The index of the next sample within a list. */ + private int sampleIndex; + + /** The number of successive samples that have been taken from the current list. */ + private int samplesTaken; + + public int getInt() { + if (samplesTaken++ > NUM_SAMPLES[listIndex]) { + // Done taking samples from this list. Go to the next one. + listIndex = (listIndex + 1) % VALUES.length; + sampleIndex = 0; + samplesTaken = 0; + } + + int value = VALUES[listIndex][sampleIndex]; + + // All lists are exactly 4 long (i.e. power of 2), so we can optimize the mod operation + // with masking. + sampleIndex = (sampleIndex + 1) & 3; + + return value; + } + } + + /** + * Iterator over integer values. Uses a simple distribution over 64-bit varints (generally + * favoring smaller values). + */ + private static final class Varint64Provider { + private static final long[][] VALUES = { + new long[] {1, 50, 100, 127}, + new long[] {128, 500, 10000, 16383}, + new long[] {16384, 50000, 1000000, 2097151}, + new long[] {2097152, 10000000, 200000000, 268435455}, + new long[] {268435456, 0x30000000, 0x7FFFFFFF, 34359738367L}, + new long[] {34359738368L, 2000000000000L, 4000000000000L, 4398046511103L}, + new long[] {4398046511104L, 200000000000000L, 500000000000000L, 562949953421311L}, + new long[] {0x4000000000000L, 0x5000000000000L, 0x6000000000000L, 0x0FFFFFFFFFFFFFFL}, + new long[] {0x100000000000000L, 0x3FFFFFFFFFFFFFFFL, 0x5FFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL}, + new long[] { + 0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL + } + }; + + /** Number of samples that should be taken from each value array. */ + private static final int[] NUM_SAMPLES = {4, 2, 2, 1, 1, 1, 1, 2, 2, 4}; + + /** + * The index into the {@link #VALUES} array that identifies the list of samples currently being + * iterated over. + */ + private int listIndex; + + /** The index of the next sample within a list. */ + private int sampleIndex; + + /** The number of successive samples that have been taken from the current list. */ + private int samplesTaken; + + public long getLong() { + if (samplesTaken++ > NUM_SAMPLES[listIndex]) { + // Done taking samples from this list. Go to the next one. + listIndex = (listIndex + 1) % VALUES.length; + sampleIndex = 0; + samplesTaken = 0; + } + + long value = VALUES[listIndex][sampleIndex]; + + // All lists are exactly 4 long (i.e. power of 2), so we can optimize the mod operation + // with masking. + sampleIndex = (sampleIndex + 1) & 3; + + return value; + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java index 30fd14794..3eb0cedc4 100644 --- a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java +++ b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java @@ -30,8 +30,6 @@ package com.google.protobuf; -import protobuf_unittest.NestedExtension; -import protobuf_unittest.NestedExtensionLite; import protobuf_unittest.NonNestedExtension; import protobuf_unittest.NonNestedExtensionLite; import java.lang.reflect.Method; @@ -71,8 +69,6 @@ public class ExtensionRegistryFactoryTest extends TestCase { void testAdd(); void testAdd_immutable(); - - void testExtensionRenamesKeywords(); } /** Test implementations for the non-Lite usage of ExtensionRegistryFactory. */ @@ -160,23 +156,6 @@ public class ExtensionRegistryFactoryTest extends TestCase { } catch (IllegalArgumentException expected) { } } - - @Override - public void testExtensionRenamesKeywords() { - assertTrue(NonNestedExtension.if_ instanceof GeneratedMessage.GeneratedExtension); - assertTrue(NestedExtension.MyNestedExtension.default_ instanceof GeneratedMessage.GeneratedExtension); - - NonNestedExtension.MessageToBeExtended msg = - NonNestedExtension.MessageToBeExtended.newBuilder() - .setExtension(NonNestedExtension.if_, "!fi") - .build(); - assertEquals("!fi", msg.getExtension(NonNestedExtension.if_)); - - msg = NonNestedExtension.MessageToBeExtended.newBuilder() - .setExtension(NestedExtension.MyNestedExtension.default_, 8) - .build(); - assertEquals(8, msg.getExtension(NestedExtension.MyNestedExtension.default_).intValue()); - } } /** Test implementations for the Lite usage of ExtensionRegistryFactory. */ @@ -223,23 +202,6 @@ public class ExtensionRegistryFactoryTest extends TestCase { } catch (UnsupportedOperationException expected) { } } - - @Override - public void testExtensionRenamesKeywords() { - assertTrue(NonNestedExtensionLite.package_ instanceof GeneratedMessageLite.GeneratedExtension); - assertTrue(NestedExtensionLite.MyNestedExtensionLite.private_ instanceof GeneratedMessageLite.GeneratedExtension); - - NonNestedExtensionLite.MessageLiteToBeExtended msg = - NonNestedExtensionLite.MessageLiteToBeExtended.newBuilder() - .setExtension(NonNestedExtensionLite.package_, true) - .build(); - assertTrue(msg.getExtension(NonNestedExtensionLite.package_)); - - msg = NonNestedExtensionLite.MessageLiteToBeExtended.newBuilder() - .setExtension(NestedExtensionLite.MyNestedExtensionLite.private_, 2.4) - .build(); - assertEquals(2.4, msg.getExtension(NestedExtensionLite.MyNestedExtensionLite.private_), 0.001); - } } /** Defines a suite of tests which the JUnit3 runner retrieves by reflection. */ @@ -311,7 +273,10 @@ public class ExtensionRegistryFactoryTest extends TestCase { resolveClass(loadedClass); } } - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException | SecurityException e) { + // Java 8+ would throw a SecurityException if we attempt to find a loaded class from + // java.lang.* package. We don't really care about those anyway, so just delegate to the + // parent class loader. loadedClass = super.loadClass(name, resolve); } return loadedClass; diff --git a/java/core/src/test/java/com/google/protobuf/MapLiteTest.java b/java/core/src/test/java/com/google/protobuf/MapLiteTest.java new file mode 100755 index 000000000..d18fd13e0 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/MapLiteTest.java @@ -0,0 +1,894 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertArrayEquals; + +import map_lite_test.MapTestProto.BizarroTestMap; +import map_lite_test.MapTestProto.TestMap; +import map_lite_test.MapTestProto.TestMap.MessageValue; +import map_lite_test.MapTestProto.TestMapOrBuilder; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import junit.framework.TestCase; + +/** Unit tests for map fields. */ +public final class MapLiteTest extends TestCase { + + private void setMapValues(TestMap.Builder builder) { + builder + .putInt32ToInt32Field(1, 11) + .putInt32ToInt32Field(2, 22) + .putInt32ToInt32Field(3, 33) + .putInt32ToStringField(1, "11") + .putInt32ToStringField(2, "22") + .putInt32ToStringField(3, "33") + .putInt32ToBytesField(1, TestUtil.toBytes("11")) + .putInt32ToBytesField(2, TestUtil.toBytes("22")) + .putInt32ToBytesField(3, TestUtil.toBytes("33")) + .putInt32ToEnumField(1, TestMap.EnumValue.FOO) + .putInt32ToEnumField(2, TestMap.EnumValue.BAR) + .putInt32ToEnumField(3, TestMap.EnumValue.BAZ) + .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build()) + .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build()) + .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build()) + .putStringToInt32Field("1", 11) + .putStringToInt32Field("2", 22) + .putStringToInt32Field("3", 33); + } + + public void testSetMapValues() { + TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder(); + setMapValues(usingMutableMapBuilder); + TestMap usingMutableMap = usingMutableMapBuilder.build(); + assertMapValuesSet(usingMutableMap); + + TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder(); + setMapValues(usingAccessorsBuilder); + TestMap usingAccessors = usingAccessorsBuilder.build(); + assertMapValuesSet(usingAccessors); + assertEquals(usingAccessors, usingMutableMap); + } + + private void copyMapValues(TestMap source, TestMap.Builder destination) { + destination + .putAllInt32ToInt32Field(source.getInt32ToInt32Field()) + .putAllInt32ToStringField(source.getInt32ToStringField()) + .putAllInt32ToBytesField(source.getInt32ToBytesField()) + .putAllInt32ToEnumField(source.getInt32ToEnumField()) + .putAllInt32ToMessageField(source.getInt32ToMessageField()) + .putAllStringToInt32Field(source.getStringToInt32Field()); + } + + private void assertMapValuesSet(TestMap message) { + assertEquals(3, message.getInt32ToInt32Field().size()); + assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); + assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); + + assertEquals(3, message.getInt32ToStringField().size()); + assertEquals("11", message.getInt32ToStringField().get(1)); + assertEquals("22", message.getInt32ToStringField().get(2)); + assertEquals("33", message.getInt32ToStringField().get(3)); + + assertEquals(3, message.getInt32ToBytesField().size()); + assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); + assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); + assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); + + assertEquals(3, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); + assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); + + assertEquals(3, message.getInt32ToMessageField().size()); + assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); + assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); + assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); + + assertEquals(3, message.getStringToInt32Field().size()); + assertEquals(11, message.getStringToInt32Field().get("1").intValue()); + assertEquals(22, message.getStringToInt32Field().get("2").intValue()); + assertEquals(33, message.getStringToInt32Field().get("3").intValue()); + } + + private void updateMapValues(TestMap.Builder builder) { + builder + .putInt32ToInt32Field(1, 111) + .removeInt32ToInt32Field(2) + .putInt32ToInt32Field(4, 44) + .putInt32ToStringField(1, "111") + .removeInt32ToStringField(2) + .putInt32ToStringField(4, "44") + .putInt32ToBytesField(1, TestUtil.toBytes("111")) + .removeInt32ToBytesField(2) + .putInt32ToBytesField(4, TestUtil.toBytes("44")) + .putInt32ToEnumField(1, TestMap.EnumValue.BAR) + .removeInt32ToEnumField(2) + .putInt32ToEnumField(4, TestMap.EnumValue.QUX) + .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build()) + .removeInt32ToMessageField(2) + .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build()) + .putStringToInt32Field("1", 111) + .removeStringToInt32Field("2") + .putStringToInt32Field("4", 44); + } + + public void testUpdateMapValues() { + TestMap.Builder mapBuilder = TestMap.newBuilder(); + setMapValues(mapBuilder); + TestMap map = mapBuilder.build(); + assertMapValuesSet(map); + + mapBuilder = map.toBuilder(); + updateMapValues(mapBuilder); + map = mapBuilder.build(); + assertMapValuesUpdated(map); + } + + private void assertMapValuesUpdated(TestMap message) { + assertEquals(3, message.getInt32ToInt32Field().size()); + assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); + assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); + + assertEquals(3, message.getInt32ToStringField().size()); + assertEquals("111", message.getInt32ToStringField().get(1)); + assertEquals("33", message.getInt32ToStringField().get(3)); + assertEquals("44", message.getInt32ToStringField().get(4)); + + assertEquals(3, message.getInt32ToBytesField().size()); + assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); + assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); + assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); + + assertEquals(3, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); + assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); + + assertEquals(3, message.getInt32ToMessageField().size()); + assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); + assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); + assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); + + assertEquals(3, message.getStringToInt32Field().size()); + assertEquals(111, message.getStringToInt32Field().get("1").intValue()); + assertEquals(33, message.getStringToInt32Field().get("3").intValue()); + assertEquals(44, message.getStringToInt32Field().get("4").intValue()); + } + + private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) { + assertEquals(0, testMapOrBuilder.getInt32ToInt32Field().size()); + assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount()); + assertEquals(0, testMapOrBuilder.getInt32ToStringField().size()); + assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount()); + assertEquals(0, testMapOrBuilder.getInt32ToBytesField().size()); + assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount()); + assertEquals(0, testMapOrBuilder.getInt32ToEnumField().size()); + assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount()); + assertEquals(0, testMapOrBuilder.getInt32ToMessageField().size()); + assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount()); + assertEquals(0, testMapOrBuilder.getStringToInt32Field().size()); + assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount()); + } + + public void testSanityCopyOnWrite() throws InvalidProtocolBufferException { + // Since builders are implemented as a thin wrapper around a message + // instance, we attempt to verify that we can't cause the builder to modify + // a produced message. + + TestMap.Builder builder = TestMap.newBuilder(); + TestMap message = builder.build(); + builder.putInt32ToInt32Field(1, 2); + assertTrue(message.getInt32ToInt32Field().isEmpty()); + assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); + message = builder.build(); + builder.putInt32ToInt32Field(2, 3); + assertEquals(newMap(1, 2), message.getInt32ToInt32Field()); + assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); + } + + public void testGetMapIsImmutable() { + TestMap.Builder builder = TestMap.newBuilder(); + assertMapsAreImmutable(builder); + assertMapsAreImmutable(builder.build()); + + setMapValues(builder); + assertMapsAreImmutable(builder); + assertMapsAreImmutable(builder.build()); + } + + private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) { + assertImmutable(testMapOrBuilder.getInt32ToInt32Field(), 1, 2); + assertImmutable(testMapOrBuilder.getInt32ToStringField(), 1, "2"); + assertImmutable(testMapOrBuilder.getInt32ToBytesField(), 1, TestUtil.toBytes("2")); + assertImmutable(testMapOrBuilder.getInt32ToEnumField(), 1, TestMap.EnumValue.FOO); + assertImmutable( + testMapOrBuilder.getInt32ToMessageField(), 1, MessageValue.getDefaultInstance()); + assertImmutable(testMapOrBuilder.getStringToInt32Field(), "1", 2); + } + + private <K, V> void assertImmutable(Map<K, V> map, K key, V value) { + try { + map.put(key, value); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + if (!map.isEmpty()) { + try { + map.entrySet().remove(map.entrySet().iterator().next()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + } + + public void testMapFieldClear() { + TestMap.Builder builder = TestMap.newBuilder().putInt32ToInt32Field(1, 2); + builder.clearInt32ToInt32Field(); + assertEquals(0, builder.getInt32ToInt32FieldCount()); + } + + public void testMutableMapLifecycle() { + TestMap.Builder builder = TestMap.newBuilder().putInt32ToInt32Field(1, 2); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); + builder.putInt32ToInt32Field(2, 3); + assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); + + builder.putInt32ToEnumField(1, TestMap.EnumValue.BAR); + assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField()); + assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField()); + builder.putInt32ToEnumField(2, TestMap.EnumValue.FOO); + assertEquals( + newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO), builder.getInt32ToEnumField()); + + builder.putInt32ToStringField(1, "1"); + assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField()); + assertEquals(newMap(1, "1"), builder.getInt32ToStringField()); + builder.putInt32ToStringField(2, "2"); + assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringField()); + + builder.putInt32ToMessageField(1, TestMap.MessageValue.getDefaultInstance()); + assertEquals( + newMap(1, TestMap.MessageValue.getDefaultInstance()), + builder.build().getInt32ToMessageField()); + assertEquals( + newMap(1, TestMap.MessageValue.getDefaultInstance()), builder.getInt32ToMessageField()); + builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance()); + assertEquals( + newMap( + 1, + TestMap.MessageValue.getDefaultInstance(), + 2, + TestMap.MessageValue.getDefaultInstance()), + builder.getInt32ToMessageField()); + } + + public void testGettersAndSetters() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + TestMap message = builder.build(); + assertMapValuesCleared(message); + + builder = message.toBuilder(); + setMapValues(builder); + message = builder.build(); + assertMapValuesSet(message); + + builder = message.toBuilder(); + updateMapValues(builder); + message = builder.build(); + assertMapValuesUpdated(message); + + builder = message.toBuilder(); + builder.clear(); + assertMapValuesCleared(builder); + message = builder.build(); + assertMapValuesCleared(message); + } + + public void testPutAll() throws Exception { + TestMap.Builder sourceBuilder = TestMap.newBuilder(); + setMapValues(sourceBuilder); + TestMap source = sourceBuilder.build(); + assertMapValuesSet(source); + + TestMap.Builder destination = TestMap.newBuilder(); + copyMapValues(source, destination); + assertMapValuesSet(destination.build()); + } + + public void testPutAllForUnknownEnumValues() throws Exception { + TestMap.Builder sourceBuilder = + TestMap.newBuilder() + .putInt32ToEnumFieldValue(0, 0) + .putInt32ToEnumFieldValue(1, 1) + .putAllInt32ToEnumFieldValue(newMap(2, 1000)); // unknown value. + TestMap source = sourceBuilder.build(); + + TestMap.Builder destinationBuilder = TestMap.newBuilder(); + destinationBuilder.putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue()); + TestMap destination = destinationBuilder.build(); + + assertEquals(0, destination.getInt32ToEnumFieldValue().get(0).intValue()); + assertEquals(1, destination.getInt32ToEnumFieldValue().get(1).intValue()); + assertEquals(1000, destination.getInt32ToEnumFieldValue().get(2).intValue()); + assertEquals(3, destination.getInt32ToEnumFieldCount()); + } + + public void testPutForUnknownEnumValues() throws Exception { + TestMap.Builder builder = + TestMap.newBuilder() + .putInt32ToEnumFieldValue(0, 0) + .putInt32ToEnumFieldValue(1, 1) + .putInt32ToEnumFieldValue(2, 1000); // unknown value. + TestMap message = builder.build(); + + assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0)); + assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1)); + assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2)); + assertEquals(3, message.getInt32ToEnumFieldCount()); + } + + public void testPutChecksNullKeysAndValues() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + + try { + builder.putInt32ToStringField(1, null); + fail(); + } catch (NullPointerException e) { + // expected. + } + + try { + builder.putInt32ToBytesField(1, null); + fail(); + } catch (NullPointerException e) { + // expected. + } + + try { + builder.putInt32ToEnumField(1, null); + fail(); + } catch (NullPointerException e) { + // expected. + } + + try { + builder.putInt32ToMessageField(1, null); + fail(); + } catch (NullPointerException e) { + // expected. + } + + try { + builder.putStringToInt32Field(null, 1); + fail(); + } catch (NullPointerException e) { + // expected. + } + } + + public void testSerializeAndParse() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.parser().parseFrom(message.toByteString()); + assertMapValuesSet(message); + + builder = message.toBuilder(); + updateMapValues(builder); + message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.parser().parseFrom(message.toByteString()); + assertMapValuesUpdated(message); + + builder = message.toBuilder(); + builder.clear(); + message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.parser().parseFrom(message.toByteString()); + assertMapValuesCleared(message); + } + + private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream); + bizarroMap.writeTo(output); + output.flush(); + return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray())); + } + + public void testParseError() throws Exception { + ByteString bytes = TestUtil.toBytes("SOME BYTES"); + String stringKey = "a string key"; + + TestMap map = + tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build()); + assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1)); + + map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build()); + assertEquals("", map.getInt32ToStringFieldOrDefault(0, null)); + + map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build()); + assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY); + + map = + tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build()); + assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null)); + + try { + tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build()); + fail(); + } catch (InvalidProtocolBufferException expected) { + assertTrue(expected.getUnfinishedMessage() instanceof TestMap); + map = (TestMap) expected.getUnfinishedMessage(); + assertTrue(map.getInt32ToMessageField().isEmpty()); + } + + map = + tryParseTestMap( + BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build()); + assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1)); + } + + public void testMergeFrom() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + TestMap.Builder other = TestMap.newBuilder(); + other.mergeFrom(message); + assertMapValuesSet(other.build()); + } + + public void testEqualsAndHashCode() throws Exception { + // Test that generated equals() and hashCode() will disregard the order + // of map entries when comparing/hashing map fields. + + // We can't control the order of elements in a HashMap. The best we can do + // here is to add elements in different order. + TestMap.Builder b1 = + TestMap.newBuilder() + .putInt32ToInt32Field(1, 2) + .putInt32ToInt32Field(3, 4) + .putInt32ToInt32Field(5, 6); + TestMap m1 = b1.build(); + + TestMap.Builder b2 = + TestMap.newBuilder() + .putInt32ToInt32Field(5, 6) + .putInt32ToInt32Field(1, 2) + .putInt32ToInt32Field(3, 4); + TestMap m2 = b2.build(); + + assertEquals(m1, m2); + assertEquals(m1.hashCode(), m2.hashCode()); + + // Make sure we did compare map fields. + b2.putInt32ToInt32Field(1, 0); + m2 = b2.build(); + assertFalse(m1.equals(m2)); + // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed + // to be different. + + // Regression test for b/18549190: if a map is a subset of the other map, + // equals() should return false. + b2.removeInt32ToInt32Field(1); + m2 = b2.build(); + assertFalse(m1.equals(m2)); + assertFalse(m2.equals(m1)); + } + + public void testUnknownEnumValues() throws Exception { + TestMap.Builder builder = + TestMap.newBuilder() + .putInt32ToEnumFieldValue(0, 0) + .putInt32ToEnumFieldValue(1, 1) + .putInt32ToEnumFieldValue(2, 1000); // unknown value. + TestMap message = builder.build(); + + assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(0)); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumField().get(2)); + + builder.putAllInt32ToEnumFieldValue(newMap(2, 1000)); // unknown value. + message = builder.build(); + assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumField().get(2)); + + // Unknown enum values should be preserved after: + // 1. Serialization and parsing. + // 2. toBuild(). + // 3. mergeFrom(). + message = TestMap.parseFrom(message.toByteString()); + assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue()); + builder = message.toBuilder(); + assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); + builder = TestMap.newBuilder().mergeFrom(message); + assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); + + // hashCode()/equals() should take unknown enum values into account. + builder.putAllInt32ToEnumFieldValue(newMap(2, 1001)); + TestMap message2 = builder.build(); + assertFalse(message.hashCode() == message2.hashCode()); + assertFalse(message.equals(message2)); + // Unknown values will be converted to UNRECOGNIZED so the resulted enum map + // should be the same. + assertEquals(message2.getInt32ToEnumField(), message.getInt32ToEnumField()); + } + + public void testIterationOrder() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + assertEquals( + Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32Field().keySet())); + } + + public void testGetMap() { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + assertEquals(message.getStringToInt32Field(), message.getStringToInt32FieldMap()); + assertEquals(message.getInt32ToBytesField(), message.getInt32ToBytesFieldMap()); + assertEquals(message.getInt32ToEnumField(), message.getInt32ToEnumFieldMap()); + assertEquals(message.getInt32ToEnumFieldValue(), message.getInt32ToEnumFieldValueMap()); + assertEquals(message.getInt32ToMessageField(), message.getInt32ToMessageFieldMap()); + } + + public void testContains() { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + assertMapContainsSetValues(builder); + assertMapContainsSetValues(builder.build()); + } + + private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) { + assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1)); + assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2)); + assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3)); + assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1)); + + assertTrue(testMapOrBuilder.containsInt32ToStringField(1)); + assertTrue(testMapOrBuilder.containsInt32ToStringField(2)); + assertTrue(testMapOrBuilder.containsInt32ToStringField(3)); + assertFalse(testMapOrBuilder.containsInt32ToStringField(-1)); + + assertTrue(testMapOrBuilder.containsInt32ToBytesField(1)); + assertTrue(testMapOrBuilder.containsInt32ToBytesField(2)); + assertTrue(testMapOrBuilder.containsInt32ToBytesField(3)); + assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1)); + + assertTrue(testMapOrBuilder.containsInt32ToEnumField(1)); + assertTrue(testMapOrBuilder.containsInt32ToEnumField(2)); + assertTrue(testMapOrBuilder.containsInt32ToEnumField(3)); + assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1)); + + assertTrue(testMapOrBuilder.containsInt32ToMessageField(1)); + assertTrue(testMapOrBuilder.containsInt32ToMessageField(2)); + assertTrue(testMapOrBuilder.containsInt32ToMessageField(3)); + assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1)); + + assertTrue(testMapOrBuilder.containsStringToInt32Field("1")); + assertTrue(testMapOrBuilder.containsStringToInt32Field("2")); + assertTrue(testMapOrBuilder.containsStringToInt32Field("3")); + assertFalse(testMapOrBuilder.containsStringToInt32Field("-1")); + } + + public void testCount() { + TestMap.Builder builder = TestMap.newBuilder(); + assertMapCounts(0, builder); + + setMapValues(builder); + assertMapCounts(3, builder); + + TestMap message = builder.build(); + assertMapCounts(3, message); + + builder = message.toBuilder().putInt32ToInt32Field(4, 44); + assertEquals(4, builder.getInt32ToInt32FieldCount()); + assertEquals(4, builder.build().getInt32ToInt32FieldCount()); + + // already present - should be unchanged + builder.putInt32ToInt32Field(4, 44); + assertEquals(4, builder.getInt32ToInt32FieldCount()); + } + + private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) { + assertEquals(expectedCount, testMapOrBuilder.getInt32ToInt32FieldCount()); + assertEquals(expectedCount, testMapOrBuilder.getInt32ToStringFieldCount()); + assertEquals(expectedCount, testMapOrBuilder.getInt32ToBytesFieldCount()); + assertEquals(expectedCount, testMapOrBuilder.getInt32ToEnumFieldCount()); + assertEquals(expectedCount, testMapOrBuilder.getInt32ToMessageFieldCount()); + assertEquals(expectedCount, testMapOrBuilder.getStringToInt32FieldCount()); + } + + public void testGetOrDefault() { + TestMap.Builder builder = TestMap.newBuilder(); + assertMapCounts(0, builder); + setMapValues(builder); + doTestGetOrDefault(builder); + doTestGetOrDefault(builder.build()); + } + + public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) { + assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)); + assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)); + + assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")); + assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null)); + + assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null)); + assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)); + + assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null)); + assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)); + + assertEquals( + TestMap.EnumValue.BAR.getNumber(), + testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1)); + assertEquals(-1, testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1)); + + assertEquals( + MessageValue.newBuilder().setValue(11).build(), + testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null)); + assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)); + + assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)); + assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)); + + try { + testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11); + fail(); + } catch (NullPointerException e) { + // expected + } + } + + public void testGetOrThrow() { + TestMap.Builder builder = TestMap.newBuilder(); + assertMapCounts(0, builder); + setMapValues(builder); + doTestGetOrDefault(builder); + doTestGetOrDefault(builder.build()); + } + + public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) { + assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)); + try { + testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1)); + + try { + testMapOrBuilder.getInt32ToStringFieldOrThrow(-1); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)); + + try { + testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)); + try { + testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals( + TestMap.EnumValue.BAR.getNumber(), testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2)); + try { + testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(-1); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals( + MessageValue.newBuilder().setValue(11).build(), + testMapOrBuilder.getInt32ToMessageFieldOrThrow(1)); + try { + testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1")); + try { + testMapOrBuilder.getStringToInt32FieldOrThrow("-1"); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + try { + testMapOrBuilder.getStringToInt32FieldOrThrow(null); + fail(); + } catch (NullPointerException e) { + // expected + } + } + + public void testPut() { + TestMap.Builder builder = TestMap.newBuilder(); + builder.putInt32ToInt32Field(1, 11); + assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1)); + + builder.putInt32ToStringField(1, "a"); + assertEquals("a", builder.getInt32ToStringFieldOrThrow(1)); + try { + builder.putInt32ToStringField(1, null); + fail(); + } catch (NullPointerException e) { + // expected + } + + builder.putInt32ToBytesField(1, TestUtil.toBytes("11")); + assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1)); + try { + builder.putInt32ToBytesField(1, null); + fail(); + } catch (NullPointerException e) { + // expected + } + + builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO); + assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1)); + try { + builder.putInt32ToEnumField(1, null); + fail(); + } catch (NullPointerException e) { + // expected + } + + builder.putStringToInt32Field("a", 1); + assertEquals(1, builder.getStringToInt32FieldOrThrow("a")); + try { + builder.putStringToInt32Field(null, -1); + } catch (NullPointerException e) { + // expected + } + } + + public void testRemove() { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1)); + for (int times = 0; times < 2; times++) { + builder.removeInt32ToInt32Field(1); + assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1)); + } + + assertEquals("11", builder.getInt32ToStringFieldOrThrow(1)); + for (int times = 0; times < 2; times++) { + builder.removeInt32ToStringField(1); + assertNull(builder.getInt32ToStringFieldOrDefault(1, null)); + } + + assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1)); + for (int times = 0; times < 2; times++) { + builder.removeInt32ToBytesField(1); + assertNull(builder.getInt32ToBytesFieldOrDefault(1, null)); + } + + assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1)); + for (int times = 0; times < 2; times++) { + builder.removeInt32ToEnumField(1); + assertNull(builder.getInt32ToEnumFieldOrDefault(1, null)); + } + + assertEquals(11, builder.getStringToInt32FieldOrThrow("1")); + for (int times = 0; times < 2; times++) { + builder.removeStringToInt32Field("1"); + assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1)); + } + + try { + builder.removeStringToInt32Field(null); + fail(); + } catch (NullPointerException e) { + // expected + } + } + + private static <K, V> Map<K, V> newMap(K key1, V value1) { + Map<K, V> map = new HashMap<>(); + map.put(key1, value1); + return map; + } + + private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) { + Map<K, V> map = new HashMap<>(); + map.put(key1, value1); + map.put(key2, value2); + return map; + } + + public void testMap_withNulls() { + TestMap.Builder builder = TestMap.newBuilder(); + + try { + builder.putStringToInt32Field(null, 3); + fail(); + } catch (NullPointerException expected) { + } + + try { + builder.putAllStringToInt32Field(newMap(null, 3, "hi", 4)); + fail(); + } catch (NullPointerException expected) { + } + + try { + builder.putInt32ToMessageField(3, null); + fail(); + } catch (NullPointerException expected) { + } + + try { + builder.putAllInt32ToMessageField( + MapLiteTest.<Integer, MessageValue>newMap(4, null, 5, null)); + fail(); + } catch (NullPointerException expected) { + } + + try { + builder.putAllInt32ToMessageField(null); + fail(); + } catch (NullPointerException expected) { + } + + assertArrayEquals(new byte[0], builder.build().toByteArray()); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/PackedFieldTest.java b/java/core/src/test/java/com/google/protobuf/PackedFieldTest.java new file mode 100755 index 000000000..2397d2ebc --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/PackedFieldTest.java @@ -0,0 +1,232 @@ +// 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.PackedFieldTestProto.TestAllTypes; +import com.google.protobuf.PackedFieldTestProto.TestAllTypes.NestedEnum; +import com.google.protobuf.PackedFieldTestProto.TestUnpackedTypes; +import junit.framework.TestCase; + +/** Tests primitive repeated fields in proto3 are packed in wire format. */ +public class PackedFieldTest extends TestCase { + static final ByteString expectedPackedRawBytes = + ByteString.copyFrom( + new byte[] { + (byte) 0xFA, + 0x01, + 0x01, + 0x01, // repeated int32 + (byte) 0x82, + 0x02, + 0x01, + 0x01, // repeated int64 + (byte) 0x8A, + 0x02, + 0x01, + 0x01, // repeated uint32 + (byte) 0x92, + 0x02, + 0x01, + 0x01, // repeated uint64 + (byte) 0x9A, + 0x02, + 0x01, + 0x02, // repeated sint32 + (byte) 0xA2, + 0x02, + 0x01, + 0x02, // repeated sint64 + (byte) 0xAA, + 0x02, + 0x04, + 0x01, + 0x00, + 0x00, + 0x00, // repeated fixed32 + (byte) 0xB2, + 0x02, + 0x08, + 0x01, + 0x00, + 0x00, + 0x00, // repeated fixed64 + 0x00, + 0x00, + 0x00, + 0x00, + (byte) 0xBA, + 0x02, + 0x04, + 0x01, + 0x00, + 0x00, + 0x00, // repeated sfixed32 + (byte) 0xC2, + 0x02, + 0x08, + 0x01, + 0x00, + 0x00, + 0x00, // repeated sfixed64 + 0x00, + 0x00, + 0x00, + 0x00, + (byte) 0xCA, + 0x02, + 0x04, + 0x00, + 0x00, + (byte) 0x80, + 0x3f, // repeated float + (byte) 0xD2, + 0x02, + 0x08, + 0x00, + 0x00, + 0x00, + 0x00, // repeated double + 0x00, + 0x00, + (byte) 0xf0, + 0x3f, + (byte) 0xDA, + 0x02, + 0x01, + 0x01, // repeated bool + (byte) 0x9A, + 0x03, + 0x01, + 0x01 // repeated nested enum + }); + + static final ByteString expectedUnpackedRawBytes = + ByteString.copyFrom( + new byte[] { + 0x08, + 0x01, // repeated int32 + 0x10, + 0x01, // repeated int64 + 0x18, + 0x01, // repeated uint32 + 0x20, + 0x01, // repeated uint64 + 0x28, + 0x02, // repeated sint32 + 0x30, + 0x02, // repeated sint64 + 0x3D, + 0x01, + 0x00, + 0x00, + 0x00, // repeated fixed32 + 0x41, + 0x01, + 0x00, + 0x00, + 0x00, // repeated fixed64 + 0x00, + 0x00, + 0x00, + 0x00, + 0x4D, + 0x01, + 0x00, + 0x00, + 0x00, // repeated sfixed32 + 0x51, + 0x01, + 0x00, + 0x00, + 0x00, // repeated sfixed64 + 0x00, + 0x00, + 0x00, + 0x00, + 0x5D, + 0x00, + 0x00, + (byte) 0x80, + 0x3f, // repeated float + 0x61, + 0x00, + 0x00, + 0x00, + 0x00, // repeated double + 0x00, + 0x00, + (byte) 0xf0, + 0x3f, + 0x68, + 0x01, // repeated bool + 0x70, + 0x01, // repeated nested enum + }); + + public void testPackedGeneratedMessage() throws Exception { + TestAllTypes message = TestAllTypes.parseFrom(expectedPackedRawBytes); + assertEquals(expectedPackedRawBytes, message.toByteString()); + } + + public void testPackedDynamicMessageSerialize() throws Exception { + DynamicMessage message = + DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), expectedPackedRawBytes); + assertEquals(expectedPackedRawBytes, message.toByteString()); + } + + public void testUnpackedGeneratedMessage() throws Exception { + TestUnpackedTypes message = TestUnpackedTypes.parseFrom(expectedUnpackedRawBytes); + assertEquals(expectedUnpackedRawBytes, message.toByteString()); + } + + public void testUnPackedDynamicMessageSerialize() throws Exception { + DynamicMessage message = + DynamicMessage.parseFrom(TestUnpackedTypes.getDescriptor(), expectedUnpackedRawBytes); + assertEquals(expectedUnpackedRawBytes, message.toByteString()); + } + + // Make sure we haven't screwed up the code generation for packing fields by default. + public void testPackedSerialization() throws Exception { + TestAllTypes message = + TestAllTypes.newBuilder() + .addRepeatedInt32(1234) + .addRepeatedNestedEnum(NestedEnum.BAR) + .build(); + + CodedInputStream in = CodedInputStream.newInstance(message.toByteArray()); + + while (!in.isAtEnd()) { + int tag = in.readTag(); + assertEquals(WireFormat.WIRETYPE_LENGTH_DELIMITED, WireFormat.getTagWireType(tag)); + in.skipField(tag); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java b/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java new file mode 100755 index 000000000..eb2dc3dd2 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java @@ -0,0 +1,191 @@ +// 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.UnittestLite.TestAllTypesLite; +import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; +import com.google.protobuf.UnittestLite.TestParsingMergeLite; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import junit.framework.TestCase; + +public class ParserLiteTest extends TestCase { + private void assertRoundTripEquals(MessageLite message, ExtensionRegistryLite registry) + throws Exception { + final byte[] data = message.toByteArray(); + final int offset = 20; + final int length = data.length; + final int padding = 30; + Parser<? extends MessageLite> parser = message.getParserForType(); + assertEquals(message, parser.parseFrom(data, registry)); + assertEquals( + message, + parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length, registry)); + assertEquals(message, parser.parseFrom(message.toByteString(), registry)); + assertEquals(message, parser.parseFrom(new ByteArrayInputStream(data), registry)); + assertEquals(message, parser.parseFrom(CodedInputStream.newInstance(data), registry)); + assertEquals( + message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry)); + } + + @SuppressWarnings("unchecked") + private void assertRoundTripEquals(MessageLite message) throws Exception { + final byte[] data = message.toByteArray(); + final int offset = 20; + final int length = data.length; + final int padding = 30; + + Parser<MessageLite> parser = (Parser<MessageLite>) message.getParserForType(); + assertEquals(message, parser.parseFrom(data)); + assertEquals( + message, parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length)); + assertEquals(message, parser.parseFrom(message.toByteString())); + assertEquals(message, parser.parseFrom(new ByteArrayInputStream(data))); + assertEquals(message, parser.parseFrom(CodedInputStream.newInstance(data))); + assertEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer())); + } + + private byte[] generatePaddingArray(byte[] data, int offset, int padding) { + byte[] result = new byte[offset + data.length + padding]; + System.arraycopy(data, 0, result, offset, data.length); + return result; + } + + public void testParseExtensionsLite() throws Exception { + assertRoundTripEquals( + TestUtilLite.getAllLiteExtensionsSet(), TestUtilLite.getExtensionRegistryLite()); + } + + public void testParsePacked() throws Exception { + assertRoundTripEquals(TestUtil.getPackedSet()); + assertRoundTripEquals(TestUtil.getPackedExtensionsSet(), TestUtil.getExtensionRegistry()); + } + + public void testParsePackedLite() throws Exception { + assertRoundTripEquals( + TestUtilLite.getLitePackedExtensionsSet(), TestUtilLite.getExtensionRegistryLite()); + } + + public void testParseDelimitedToLite() throws Exception { + // Write MessageLite with packed extension fields. + TestPackedExtensionsLite packedMessage = TestUtilLite.getLitePackedExtensionsSet(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + packedMessage.writeDelimitedTo(output); + packedMessage.writeDelimitedTo(output); + + InputStream input = new ByteArrayInputStream(output.toByteArray()); + assertEquals( + packedMessage, + packedMessage + .getParserForType() + .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite())); + assertEquals( + packedMessage, + packedMessage + .getParserForType() + .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite())); + } + + /** Helper method for {@link #testParsingMergeLite()}. */ + private void assertMessageMerged(TestAllTypesLite allTypes) throws Exception { + assertEquals(3, allTypes.getOptionalInt32()); + assertEquals(2, allTypes.getOptionalInt64()); + assertEquals("hello", allTypes.getOptionalString()); + } + + public void testParsingMergeLite() throws Exception { + // Build messages. + TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder(); + TestAllTypesLite msg1 = builder.setOptionalInt32(1).build(); + builder.clear(); + TestAllTypesLite msg2 = builder.setOptionalInt64(2).build(); + builder.clear(); + TestAllTypesLite msg3 = builder.setOptionalInt32(3).setOptionalString("hello").build(); + + // Build groups. + TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG1 = + TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg1).build(); + TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG2 = + TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg2).build(); + TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG3 = + TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg3).build(); + TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG1 = + TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg1).build(); + TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG2 = + TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg2).build(); + TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG3 = + TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg3).build(); + + // Assign and serialize RepeatedFieldsGenerator. + ByteString data = + TestParsingMergeLite.RepeatedFieldsGenerator.newBuilder() + .addField1(msg1) + .addField1(msg2) + .addField1(msg3) + .addField2(msg1) + .addField2(msg2) + .addField2(msg3) + .addField3(msg1) + .addField3(msg2) + .addField3(msg3) + .addGroup1(optionalG1) + .addGroup1(optionalG2) + .addGroup1(optionalG3) + .addGroup2(repeatedG1) + .addGroup2(repeatedG2) + .addGroup2(repeatedG3) + .addExt1(msg1) + .addExt1(msg2) + .addExt1(msg3) + .addExt2(msg1) + .addExt2(msg2) + .addExt2(msg3) + .build() + .toByteString(); + + // Parse TestParsingMergeLite. + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + UnittestLite.registerAllExtensions(registry); + TestParsingMergeLite parsingMerge = TestParsingMergeLite.parser().parseFrom(data, registry); + + // Required and optional fields should be merged. + assertMessageMerged(parsingMerge.getRequiredAllTypes()); + assertMessageMerged(parsingMerge.getOptionalAllTypes()); + assertMessageMerged(parsingMerge.getOptionalGroup().getOptionalGroupAllTypes()); + assertMessageMerged(parsingMerge.getExtension(TestParsingMergeLite.optionalExt)); + + // Repeated fields should not be merged. + assertEquals(3, parsingMerge.getRepeatedAllTypesCount()); + assertEquals(3, parsingMerge.getRepeatedGroupCount()); + assertEquals(3, parsingMerge.getExtensionCount(TestParsingMergeLite.repeatedExt)); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java b/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java new file mode 100755 index 000000000..dfda4b3cb --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java @@ -0,0 +1,171 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + +import com.google.protobuf.testing.Proto2Testing; +import com.google.protobuf.testing.Proto2Testing.Proto2Message; +import com.google.protobuf.testing.Proto2Testing.Proto2Message.TestEnum; +import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithExtensions; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Proto2ExtensionLookupSchemaTest { + private byte[] data; + private ExtensionRegistry extensionRegistry; + + @Before + public void setup() { + TestSchemas.registerGenericProto2Schemas(); + + Protobuf.getInstance().schemaFor(Proto2MessageWithExtensions.class); + data = new Proto2MessageFactory(10, 20, 1, 1).newMessage().toByteArray(); + extensionRegistry = ExtensionRegistry.newInstance(); + Proto2Testing.registerAllExtensions(extensionRegistry); + } + + @Test + public void testExtensions() throws Exception { + Proto2MessageWithExtensions base = + Proto2MessageWithExtensions.parseFrom(data, extensionRegistry); + + Proto2MessageWithExtensions message = + ExperimentalSerializationUtil.fromByteArray( + data, Proto2MessageWithExtensions.class, extensionRegistry); + assertEquals(base, message); + + Proto2MessageWithExtensions roundtripMessage = + ExperimentalSerializationUtil.fromByteArray( + ExperimentalSerializationUtil.toByteArray(message), + Proto2MessageWithExtensions.class, + extensionRegistry); + assertEquals(base, roundtripMessage); + } + + @Test + public void testUnknownEnum() throws Exception { + // Use unknown fields to hold invalid enum values. + UnknownFieldSetLite unknowns = UnknownFieldSetLite.newInstance(); + final int outOfRange = 1000; + assertNull(TestEnum.forNumber(outOfRange)); + unknowns.storeField( + WireFormat.makeTag(Proto2Message.FIELD_ENUM_13_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) outOfRange); + unknowns.storeField( + WireFormat.makeTag( + Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) TestEnum.ONE_VALUE); + unknowns.storeField( + WireFormat.makeTag( + Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) outOfRange); + unknowns.storeField( + WireFormat.makeTag( + Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT), + (long) TestEnum.TWO_VALUE); + + { + // Construct a packed enum list. + int packedSize = + CodedOutputStream.computeUInt32SizeNoTag(TestEnum.ONE_VALUE) + + CodedOutputStream.computeUInt32SizeNoTag(outOfRange) + + CodedOutputStream.computeUInt32SizeNoTag(TestEnum.ONE_VALUE); + ByteString.CodedBuilder packedBuilder = ByteString.newCodedBuilder(packedSize); + CodedOutputStream packedOut = packedBuilder.getCodedOutput(); + packedOut.writeEnumNoTag(TestEnum.ONE_VALUE); + packedOut.writeEnumNoTag(outOfRange); + packedOut.writeEnumNoTag(TestEnum.TWO_VALUE); + unknowns.storeField( + WireFormat.makeTag( + Proto2Message.FIELD_ENUM_LIST_PACKED_44_FIELD_NUMBER, + WireFormat.WIRETYPE_LENGTH_DELIMITED), + packedBuilder.build()); + } + int size = unknowns.getSerializedSize(); + byte[] output = new byte[size]; + CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); + unknowns.writeTo(codedOutput); + codedOutput.flush(); + + Proto2MessageWithExtensions parsed = + ExperimentalSerializationUtil.fromByteArray( + output, Proto2MessageWithExtensions.class, extensionRegistry); + assertFalse( + "out-of-range singular enum should not be in message", + parsed.hasExtension(Proto2Testing.fieldEnum13)); + { + List<Long> singularEnum = + parsed + .getUnknownFields() + .getField(Proto2Message.FIELD_ENUM_13_FIELD_NUMBER) + .getVarintList(); + assertEquals(1, singularEnum.size()); + assertEquals((Long) (long) outOfRange, singularEnum.get(0)); + } + { + List<Long> repeatedEnum = + parsed + .getUnknownFields() + .getField(Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER) + .getVarintList(); + assertEquals(1, repeatedEnum.size()); + assertEquals((Long) (long) outOfRange, repeatedEnum.get(0)); + } + { + List<Long> packedRepeatedEnum = + parsed + .getUnknownFields() + .getField(Proto2Message.FIELD_ENUM_LIST_PACKED_44_FIELD_NUMBER) + .getVarintList(); + assertEquals(1, packedRepeatedEnum.size()); + assertEquals((Long) (long) outOfRange, packedRepeatedEnum.get(0)); + } + assertEquals( + "out-of-range repeated enum should not be in message", + 2, + parsed.getExtension(Proto2Testing.fieldEnumList30).size()); + assertEquals(TestEnum.ONE, parsed.getExtension(Proto2Testing.fieldEnumList30, 0)); + assertEquals(TestEnum.TWO, parsed.getExtension(Proto2Testing.fieldEnumList30, 1)); + assertEquals( + "out-of-range packed repeated enum should not be in message", + 2, + parsed.getExtension(Proto2Testing.fieldEnumListPacked44).size()); + assertEquals(TestEnum.ONE, parsed.getExtension(Proto2Testing.fieldEnumListPacked44, 0)); + assertEquals(TestEnum.TWO, parsed.getExtension(Proto2Testing.fieldEnumListPacked44, 1)); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto2LiteSchemaTest.java b/java/core/src/test/java/com/google/protobuf/Proto2LiteSchemaTest.java new file mode 100755 index 000000000..8242f847e --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto2LiteSchemaTest.java @@ -0,0 +1,49 @@ +// 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.testing.Proto2TestingLite.Proto2MessageLite; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Proto2LiteSchemaTest extends AbstractProto2LiteSchemaTest { + + @Override + protected Schema<Proto2MessageLite> schema() { + return TestSchemasLite.genericProto2LiteSchema; + } + + @Override + protected void registerSchemas() { + TestSchemasLite.registerGenericProto2LiteSchemas(); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto2MessageFactory.java b/java/core/src/test/java/com/google/protobuf/Proto2MessageFactory.java new file mode 100755 index 000000000..b5c61ed99 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto2MessageFactory.java @@ -0,0 +1,555 @@ +// 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.testing.Proto2Testing.Proto2Message; +import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithMaps; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Creates instances of {@link Proto2Message} based on the tree configuration. */ +public final class Proto2MessageFactory implements ExperimentalMessageFactory<Proto2Message> { + private final int numRepeatedFields; + private final int branchingFactor; + private final Proto2MessageFactory nextLevel; + private final ExperimentalTestDataProvider data; + + public Proto2MessageFactory( + int numRepeatedFields, int stringLength, int branchingFactor, int treeDepth) { + this( + new ExperimentalTestDataProvider(stringLength), + numRepeatedFields, + branchingFactor, + treeDepth); + } + + private Proto2MessageFactory( + ExperimentalTestDataProvider data, + int numRepeatedFields, + int branchingFactor, + int treeDepth) { + this.numRepeatedFields = numRepeatedFields; + this.branchingFactor = branchingFactor; + this.data = data; + if (treeDepth > 0) { + nextLevel = new Proto2MessageFactory(data, numRepeatedFields, branchingFactor, treeDepth - 1); + } else { + nextLevel = null; + } + } + + @Override + public ExperimentalTestDataProvider dataProvider() { + return data; + } + + @Override + public Proto2Message newMessage() { + Proto2Message.Builder builder = Proto2Message.newBuilder(); + builder.setFieldDouble1(data.getDouble()); + builder.setFieldFloat2(data.getFloat()); + builder.setFieldInt643(data.getLong()); + builder.setFieldUint644(data.getLong()); + builder.setFieldInt325(data.getInt()); + builder.setFieldFixed646(data.getLong()); + builder.setFieldFixed327(data.getInt()); + builder.setFieldBool8(data.getBool()); + builder.setFieldString9(data.getString()); + // We don't populate the message field. Instead we apply the branching factor to the + // repeated message field below. + builder.setFieldBytes11(data.getBytes()); + builder.setFieldUint3212(data.getInt()); + builder.setFieldEnum13(Proto2Message.TestEnum.forNumber(data.getEnum())); + builder.setFieldSfixed3214(data.getInt()); + builder.setFieldSfixed6415(data.getLong()); + builder.setFieldSint3216(data.getInt()); + builder.setFieldSint6417(data.getLong()); + + for (int i = 0; i < numRepeatedFields; ++i) { + builder.addFieldDoubleList18(data.getDouble()); + builder.addFieldFloatList19(data.getFloat()); + builder.addFieldInt64List20(data.getLong()); + builder.addFieldUint64List21(data.getLong()); + builder.addFieldInt32List22(data.getInt()); + builder.addFieldFixed64List23(data.getLong()); + builder.addFieldFixed32List24(data.getInt()); + builder.addFieldBoolList25(data.getBool()); + builder.addFieldStringList26(data.getString()); + // Repeated message field is controlled by the branching factor below. + builder.addFieldBytesList28(data.getBytes()); + builder.addFieldUint32List29(data.getInt()); + builder.addFieldEnumList30(Proto2Message.TestEnum.forNumber(data.getEnum())); + builder.addFieldSfixed32List31(data.getInt()); + builder.addFieldSfixed64List32(data.getLong()); + builder.addFieldSint32List33(data.getInt()); + builder.addFieldSint64List34(data.getLong()); + + builder.addFieldDoubleListPacked35(data.getDouble()); + builder.addFieldFloatListPacked36(data.getFloat()); + builder.addFieldInt64ListPacked37(data.getLong()); + builder.addFieldUint64ListPacked38(data.getLong()); + builder.addFieldInt32ListPacked39(data.getInt()); + builder.addFieldFixed64ListPacked40(data.getLong()); + builder.addFieldFixed32ListPacked41(data.getInt()); + builder.addFieldBoolListPacked42(data.getBool()); + builder.addFieldUint32ListPacked43(data.getInt()); + builder.addFieldEnumListPacked44(Proto2Message.TestEnum.forNumber(data.getEnum())); + builder.addFieldSfixed32ListPacked45(data.getInt()); + builder.addFieldSfixed64ListPacked46(data.getLong()); + builder.addFieldSint32ListPacked47(data.getInt()); + builder.addFieldSint64ListPacked48(data.getLong()); + } + + builder.setFieldGroup49(Proto2Message.FieldGroup49.newBuilder().setFieldInt3250(data.getInt())); + + for (int i = 0; i < branchingFactor; ++i) { + builder.addFieldGroupList51( + Proto2Message.FieldGroupList51.newBuilder().setFieldInt3252(data.getInt())); + } + + // Set all required fields. + populateRequiredFields(builder, INCLUDE_ALL_REQUIRED_FIELDS); + + // Handle the branching factor. + if (nextLevel != null) { + for (int i = 0; i < branchingFactor; ++i) { + builder.addFieldMessageList27(nextLevel.newMessage()); + } + } + + return builder.build(); + } + + private interface MapValueProvider<T> { + public T getValue(); + } + + private final MapValueProvider<Integer> integerProvider = + new MapValueProvider<Integer>() { + @Override + public Integer getValue() { + return data.getInt(); + } + }; + private final MapValueProvider<Long> longProvider = + new MapValueProvider<Long>() { + @Override + public Long getValue() { + return data.getLong(); + } + }; + private final MapValueProvider<String> stringProvider = + new MapValueProvider<String>() { + @Override + public String getValue() { + return data.getString(); + } + }; + private final MapValueProvider<ByteString> bytesProvider = + new MapValueProvider<ByteString>() { + @Override + public ByteString getValue() { + return data.getBytes(); + } + }; + private final MapValueProvider<Boolean> booleanProvider = + new MapValueProvider<Boolean>() { + @Override + public Boolean getValue() { + return data.getBool(); + } + }; + private final MapValueProvider<Float> floatProvider = + new MapValueProvider<Float>() { + @Override + public Float getValue() { + return data.getFloat(); + } + }; + private final MapValueProvider<Double> doubleProvider = + new MapValueProvider<Double>() { + @Override + public Double getValue() { + return data.getDouble(); + } + }; + private final MapValueProvider<Proto2Message> messageProvider = + new MapValueProvider<Proto2Message>() { + @Override + public Proto2Message getValue() { + return newMessage(); + } + }; + private final MapValueProvider<Proto2Message.TestEnum> enumProvider = + new MapValueProvider<Proto2Message.TestEnum>() { + @Override + public Proto2Message.TestEnum getValue() { + return Proto2Message.TestEnum.forNumber(data.getEnum()); + } + }; + + private <V> Map<Integer, V> populateIntegerMap(MapValueProvider<V> provider) { + Map<Integer, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getInt(), provider.getValue()); + } + return map; + } + + private <V> Map<Long, V> populateLongMap(MapValueProvider<V> provider) { + Map<Long, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getLong(), provider.getValue()); + } + return map; + } + + private <V> Map<String, V> populateStringMap(MapValueProvider<V> provider) { + Map<String, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getString(), provider.getValue()); + } + return map; + } + + private <V> Map<Boolean, V> populateBooleanMap(MapValueProvider<V> provider) { + Map<Boolean, V> map = new HashMap<>(); + map.put(false, provider.getValue()); + map.put(true, provider.getValue()); + return map; + } + + public Proto2MessageWithMaps newMessageWithMaps() { + Proto2MessageWithMaps.Builder builder = Proto2MessageWithMaps.newBuilder(); + + builder.putAllFieldMapBoolBool1(populateBooleanMap(booleanProvider)); + builder.putAllFieldMapBoolBytes2(populateBooleanMap(bytesProvider)); + builder.putAllFieldMapBoolDouble3(populateBooleanMap(doubleProvider)); + builder.putAllFieldMapBoolEnum4(populateBooleanMap(enumProvider)); + builder.putAllFieldMapBoolFixed325(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolFixed646(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolFloat7(populateBooleanMap(floatProvider)); + builder.putAllFieldMapBoolInt328(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolInt649(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolMessage10(populateBooleanMap(messageProvider)); + builder.putAllFieldMapBoolSfixed3211(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolSfixed6412(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolSint3213(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolSint6414(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolString15(populateBooleanMap(stringProvider)); + builder.putAllFieldMapBoolUint3216(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolUint6417(populateBooleanMap(longProvider)); + builder.putAllFieldMapFixed32Bool18(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapFixed32Bytes19(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapFixed32Double20(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapFixed32Enum21(populateIntegerMap(enumProvider)); + builder.putAllFieldMapFixed32Fixed3222(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Fixed6423(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Float24(populateIntegerMap(floatProvider)); + builder.putAllFieldMapFixed32Int3225(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Int6426(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Message27(populateIntegerMap(messageProvider)); + builder.putAllFieldMapFixed32Sfixed3228(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Sfixed6429(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Sint3230(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Sint6431(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32String32(populateIntegerMap(stringProvider)); + builder.putAllFieldMapFixed32Uint3233(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Uint6434(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed64Bool35(populateLongMap(booleanProvider)); + builder.putAllFieldMapFixed64Bytes36(populateLongMap(bytesProvider)); + builder.putAllFieldMapFixed64Double37(populateLongMap(doubleProvider)); + builder.putAllFieldMapFixed64Enum38(populateLongMap(enumProvider)); + builder.putAllFieldMapFixed64Fixed3239(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Fixed6440(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Float41(populateLongMap(floatProvider)); + builder.putAllFieldMapFixed64Int3242(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Int6443(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Message44(populateLongMap(messageProvider)); + builder.putAllFieldMapFixed64Sfixed3245(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Sfixed6446(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Sint3247(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Sint6448(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64String49(populateLongMap(stringProvider)); + builder.putAllFieldMapFixed64Uint3250(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Uint6451(populateLongMap(longProvider)); + builder.putAllFieldMapInt32Bool52(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapInt32Bytes53(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapInt32Double54(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapInt32Enum55(populateIntegerMap(enumProvider)); + builder.putAllFieldMapInt32Fixed3256(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Fixed6457(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Float58(populateIntegerMap(floatProvider)); + builder.putAllFieldMapInt32Int3259(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Int6460(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Message61(populateIntegerMap(messageProvider)); + builder.putAllFieldMapInt32Sfixed3262(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Sfixed6463(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Sint3264(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Sint6465(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32String66(populateIntegerMap(stringProvider)); + builder.putAllFieldMapInt32Uint3267(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Uint6468(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt64Bool69(populateLongMap(booleanProvider)); + builder.putAllFieldMapInt64Bytes70(populateLongMap(bytesProvider)); + builder.putAllFieldMapInt64Double71(populateLongMap(doubleProvider)); + builder.putAllFieldMapInt64Enum72(populateLongMap(enumProvider)); + builder.putAllFieldMapInt64Fixed3273(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Fixed6474(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Float75(populateLongMap(floatProvider)); + builder.putAllFieldMapInt64Int3276(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Int6477(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Message78(populateLongMap(messageProvider)); + builder.putAllFieldMapInt64Sfixed3279(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Sfixed6480(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Sint3281(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Sint6482(populateLongMap(longProvider)); + builder.putAllFieldMapInt64String83(populateLongMap(stringProvider)); + builder.putAllFieldMapInt64Uint3284(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Uint6485(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed32Bool86(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapSfixed32Bytes87(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapSfixed32Double88(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapSfixed32Enum89(populateIntegerMap(enumProvider)); + builder.putAllFieldMapSfixed32Fixed3290(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Fixed6491(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Float92(populateIntegerMap(floatProvider)); + builder.putAllFieldMapSfixed32Int3293(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Int6494(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Message95(populateIntegerMap(messageProvider)); + builder.putAllFieldMapSfixed32Sfixed3296(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Sfixed6497(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Sint3298(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Sint6499(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32String100(populateIntegerMap(stringProvider)); + builder.putAllFieldMapSfixed32Uint32101(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Uint64102(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed64Bool103(populateLongMap(booleanProvider)); + builder.putAllFieldMapSfixed64Bytes104(populateLongMap(bytesProvider)); + builder.putAllFieldMapSfixed64Double105(populateLongMap(doubleProvider)); + builder.putAllFieldMapSfixed64Enum106(populateLongMap(enumProvider)); + builder.putAllFieldMapSfixed64Fixed32107(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Fixed64108(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Float109(populateLongMap(floatProvider)); + builder.putAllFieldMapSfixed64Int32110(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Int64111(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Message112(populateLongMap(messageProvider)); + builder.putAllFieldMapSfixed64Sfixed32113(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Sfixed64114(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Sint32115(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Sint64116(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64String117(populateLongMap(stringProvider)); + builder.putAllFieldMapSfixed64Uint32118(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Uint64119(populateLongMap(longProvider)); + builder.putAllFieldMapSint32Bool120(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapSint32Bytes121(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapSint32Double122(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapSint32Enum123(populateIntegerMap(enumProvider)); + builder.putAllFieldMapSint32Fixed32124(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Fixed64125(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Float126(populateIntegerMap(floatProvider)); + builder.putAllFieldMapSint32Int32127(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Int64128(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Message129(populateIntegerMap(messageProvider)); + builder.putAllFieldMapSint32Sfixed32130(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Sfixed64131(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Sint32132(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Sint64133(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32String134(populateIntegerMap(stringProvider)); + builder.putAllFieldMapSint32Uint32135(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Uint64136(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint64Bool137(populateLongMap(booleanProvider)); + builder.putAllFieldMapSint64Bytes138(populateLongMap(bytesProvider)); + builder.putAllFieldMapSint64Double139(populateLongMap(doubleProvider)); + builder.putAllFieldMapSint64Enum140(populateLongMap(enumProvider)); + builder.putAllFieldMapSint64Fixed32141(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Fixed64142(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Float143(populateLongMap(floatProvider)); + builder.putAllFieldMapSint64Int32144(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Int64145(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Message146(populateLongMap(messageProvider)); + builder.putAllFieldMapSint64Sfixed32147(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Sfixed64148(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Sint32149(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Sint64150(populateLongMap(longProvider)); + builder.putAllFieldMapSint64String151(populateLongMap(stringProvider)); + builder.putAllFieldMapSint64Uint32152(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Uint64153(populateLongMap(longProvider)); + builder.putAllFieldMapStringBool154(populateStringMap(booleanProvider)); + builder.putAllFieldMapStringBytes155(populateStringMap(bytesProvider)); + builder.putAllFieldMapStringDouble156(populateStringMap(doubleProvider)); + builder.putAllFieldMapStringEnum157(populateStringMap(enumProvider)); + builder.putAllFieldMapStringFixed32158(populateStringMap(integerProvider)); + builder.putAllFieldMapStringFixed64159(populateStringMap(longProvider)); + builder.putAllFieldMapStringFloat160(populateStringMap(floatProvider)); + builder.putAllFieldMapStringInt32161(populateStringMap(integerProvider)); + builder.putAllFieldMapStringInt64162(populateStringMap(longProvider)); + builder.putAllFieldMapStringMessage163(populateStringMap(messageProvider)); + builder.putAllFieldMapStringSfixed32164(populateStringMap(integerProvider)); + builder.putAllFieldMapStringSfixed64165(populateStringMap(longProvider)); + builder.putAllFieldMapStringSint32166(populateStringMap(integerProvider)); + builder.putAllFieldMapStringSint64167(populateStringMap(longProvider)); + builder.putAllFieldMapStringString168(populateStringMap(stringProvider)); + builder.putAllFieldMapStringUint32169(populateStringMap(integerProvider)); + builder.putAllFieldMapStringUint64170(populateStringMap(longProvider)); + builder.putAllFieldMapUint32Bool171(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapUint32Bytes172(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapUint32Double173(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapUint32Enum174(populateIntegerMap(enumProvider)); + builder.putAllFieldMapUint32Fixed32175(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Fixed64176(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Float177(populateIntegerMap(floatProvider)); + builder.putAllFieldMapUint32Int32178(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Int64179(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Message180(populateIntegerMap(messageProvider)); + builder.putAllFieldMapUint32Sfixed32181(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Sfixed64182(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Sint32183(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Sint64184(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32String185(populateIntegerMap(stringProvider)); + builder.putAllFieldMapUint32Uint32186(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Uint64187(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint64Bool188(populateLongMap(booleanProvider)); + builder.putAllFieldMapUint64Bytes189(populateLongMap(bytesProvider)); + builder.putAllFieldMapUint64Double190(populateLongMap(doubleProvider)); + builder.putAllFieldMapUint64Enum191(populateLongMap(enumProvider)); + builder.putAllFieldMapUint64Fixed32192(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Fixed64193(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Float194(populateLongMap(floatProvider)); + builder.putAllFieldMapUint64Int32195(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Int64196(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Message197(populateLongMap(messageProvider)); + builder.putAllFieldMapUint64Sfixed32198(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Sfixed64199(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Sint32200(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Sint64201(populateLongMap(longProvider)); + builder.putAllFieldMapUint64String202(populateLongMap(stringProvider)); + builder.putAllFieldMapUint64Uint32203(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Uint64204(populateLongMap(longProvider)); + + return builder.build(); + } + + public List<Proto2Message> newMessagesMissingRequiredFields() { + List<Proto2Message> results = new ArrayList<>(); + for (int i = 71; i <= 88; ++i) { + Proto2Message.Builder builder = Proto2Message.newBuilder(); + populateRequiredFields(builder, i); + results.add(builder.buildPartial()); + } + { + // A nested optional message field is missing required fields. + Proto2Message.Builder builder = Proto2Message.newBuilder(); + populateRequiredFields(builder, INCLUDE_ALL_REQUIRED_FIELDS); + builder.setFieldMessage10(Proto2Message.getDefaultInstance()); + results.add(builder.buildPartial()); + } + { + // A nested repeated message field is missing required fields. + Proto2Message.Builder builder = Proto2Message.newBuilder(); + populateRequiredFields(builder, INCLUDE_ALL_REQUIRED_FIELDS); + builder.addFieldMessageList27(Proto2Message.getDefaultInstance()); + results.add(builder.buildPartial()); + } + { + // A nested oneof message field is missing required fields. + Proto2Message.Builder builder = Proto2Message.newBuilder(); + populateRequiredFields(builder, INCLUDE_ALL_REQUIRED_FIELDS); + builder.setFieldMessage62(Proto2Message.getDefaultInstance()); + results.add(builder.buildPartial()); + } + return results; + } + + // 0 is not a valid field number so we use it to mean no fields are excluded. + private static final int INCLUDE_ALL_REQUIRED_FIELDS = 0; + + private void populateRequiredFields(Proto2Message.Builder builder, int excludedFieldNumber) { + if (excludedFieldNumber != 71) { + builder.setFieldRequiredDouble71(data.getDouble()); + } + if (excludedFieldNumber != 72) { + builder.setFieldRequiredFloat72(data.getFloat()); + } + if (excludedFieldNumber != 73) { + builder.setFieldRequiredInt6473(data.getLong()); + } + if (excludedFieldNumber != 74) { + builder.setFieldRequiredUint6474(data.getLong()); + } + if (excludedFieldNumber != 75) { + builder.setFieldRequiredInt3275(data.getInt()); + } + if (excludedFieldNumber != 76) { + builder.setFieldRequiredFixed6476(data.getLong()); + } + if (excludedFieldNumber != 77) { + builder.setFieldRequiredFixed3277(data.getInt()); + } + if (excludedFieldNumber != 78) { + builder.setFieldRequiredBool78(data.getBool()); + } + if (excludedFieldNumber != 79) { + builder.setFieldRequiredString79(data.getString()); + } + if (excludedFieldNumber != 80) { + builder.setFieldRequiredMessage80( + Proto2Message.RequiredNestedMessage.newBuilder().setValue(data.getInt())); + } + if (excludedFieldNumber != 81) { + builder.setFieldRequiredBytes81(data.getBytes()); + } + if (excludedFieldNumber != 82) { + builder.setFieldRequiredUint3282(data.getInt()); + } + if (excludedFieldNumber != 83) { + builder.setFieldRequiredEnum83(Proto2Message.TestEnum.forNumber(data.getEnum())); + } + if (excludedFieldNumber != 84) { + builder.setFieldRequiredSfixed3284(data.getInt()); + } + if (excludedFieldNumber != 85) { + builder.setFieldRequiredSfixed6485(data.getLong()); + } + if (excludedFieldNumber != 86) { + builder.setFieldRequiredSint3286(data.getInt()); + } + if (excludedFieldNumber != 87) { + builder.setFieldRequiredSint6487(data.getLong()); + } + if (excludedFieldNumber != 88) { + builder.setFieldRequiredGroup88( + Proto2Message.FieldRequiredGroup88.newBuilder().setFieldInt3289(data.getInt())); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto2MessageInfoFactory.java b/java/core/src/test/java/com/google/protobuf/Proto2MessageInfoFactory.java new file mode 100755 index 000000000..af671b22e --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto2MessageInfoFactory.java @@ -0,0 +1,892 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.FieldInfo.forField; +import static com.google.protobuf.FieldInfo.forFieldWithEnumVerifier; +import static com.google.protobuf.FieldInfo.forMapField; +import static com.google.protobuf.FieldInfo.forOneofMemberField; +import static com.google.protobuf.FieldInfo.forProto2OptionalField; +import static com.google.protobuf.FieldInfo.forProto2RequiredField; +import static com.google.protobuf.FieldInfo.forRepeatedMessageField; + +import com.google.protobuf.testing.Proto2Testing; +import com.google.protobuf.testing.Proto2Testing.Proto2Empty; +import com.google.protobuf.testing.Proto2Testing.Proto2Message; +import com.google.protobuf.testing.Proto2Testing.Proto2Message.FieldGroup49; +import com.google.protobuf.testing.Proto2Testing.Proto2Message.FieldGroup69; +import com.google.protobuf.testing.Proto2Testing.Proto2Message.FieldGroupList51; +import com.google.protobuf.testing.Proto2Testing.Proto2Message.FieldRequiredGroup88; +import com.google.protobuf.testing.Proto2Testing.Proto2Message.RequiredNestedMessage; +import com.google.protobuf.testing.Proto2Testing.Proto2Message.TestEnum; +import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithExtensions; +import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithMaps; +import java.lang.reflect.Field; + +/** A factory that generates a hard-coded message info for {@link Proto2Message}. */ +public final class Proto2MessageInfoFactory implements MessageInfoFactory { + private static final Proto2MessageInfoFactory INSTANCE = new Proto2MessageInfoFactory(); + + private Proto2MessageInfoFactory() {} + + public static Proto2MessageInfoFactory getInstance() { + return INSTANCE; + } + + @Override + public boolean isSupported(Class<?> clazz) { + return true; + } + + @Override + public MessageInfo messageInfoFor(Class<?> clazz) { + if (Proto2Message.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto2Message(); + } else if (FieldGroup49.class.isAssignableFrom(clazz)) { + return newMessageInfoForFieldGroup49(); + } else if (FieldGroupList51.class.isAssignableFrom(clazz)) { + return newMessageInfoForFieldGroupList51(); + } else if (FieldGroup69.class.isAssignableFrom(clazz)) { + return newMessageInfoForFieldGroup69(); + } else if (FieldRequiredGroup88.class.isAssignableFrom(clazz)) { + return newMessageInfoForFieldRequiredGroup88(); + } else if (RequiredNestedMessage.class.isAssignableFrom(clazz)) { + return newMessageInfoForRequiredNestedMessage(); + } else if (Proto2Empty.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto2Empty(); + } else if (Proto2MessageWithExtensions.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto2MessageWithExtensions(); + } else if (Proto2Testing.FieldGroup49.class.isAssignableFrom(clazz)) { + return newMessageInfoForExtensionFieldGroup49(); + } else if (Proto2Testing.FieldGroupList51.class.isAssignableFrom(clazz)) { + return newMessageInfoForExtensionFieldGroupList51(); + } else if (Proto2Testing.Proto2MessageWithMaps.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto2MessageWithMaps(); + } else { + throw new IllegalArgumentException("Unsupported class: " + clazz.getName()); + } + } + + /** + * Creates a new hard-coded info for {@link Proto2Message}. Each time this is called, we manually + * go through the entire process of what a message would do if it self-registered its own info, + * including looking up each field by name. This is done for benchmarking purposes, so that we get + * a more accurate representation of the time it takes to perform this process. + */ + private static StructuralMessageInfo newMessageInfoForProto2Message() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(50); + builder.withCheckInitialized( + new int[] { + 10, 27, 62, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + }); + lookupFieldsByName(builder); + return builder.build(); + } + + private static void lookupFieldsByName(StructuralMessageInfo.Builder builder) { + Field bitField0 = field("bitField0_"); + + builder.withDefaultInstance(Proto2Message.getDefaultInstance()); + builder.withSyntax(ProtoSyntax.PROTO2); + builder.withField( + forProto2OptionalField( + field("fieldDouble1_"), 1, FieldType.DOUBLE, bitField0, 0x00000001, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldFloat2_"), 2, FieldType.FLOAT, bitField0, 0x00000002, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldInt643_"), 3, FieldType.INT64, bitField0, 0x00000004, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldUint644_"), 4, FieldType.UINT64, bitField0, 0x00000008, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldInt325_"), 5, FieldType.INT32, bitField0, 0x00000010, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldFixed646_"), 6, FieldType.FIXED64, bitField0, 0x00000020, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldFixed327_"), 7, FieldType.FIXED32, bitField0, 0x00000040, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldBool8_"), 8, FieldType.BOOL, bitField0, 0x00000080, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldString9_"), 9, FieldType.STRING, bitField0, 0x00000100, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldMessage10_"), 10, FieldType.MESSAGE, bitField0, 0x00000200, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldBytes11_"), 11, FieldType.BYTES, bitField0, 0x00000400, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldUint3212_"), 12, FieldType.UINT32, bitField0, 0x00000800, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldEnum13_"), + 13, + FieldType.ENUM, + bitField0, + 0x00001000, + false, + asVerifier(TestEnum.internalGetValueMap()))); + builder.withField( + forProto2OptionalField( + field("fieldSfixed3214_"), 14, FieldType.SFIXED32, bitField0, 0x00002000, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldSfixed6415_"), 15, FieldType.SFIXED64, bitField0, 0x00004000, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldSint3216_"), 16, FieldType.SINT32, bitField0, 0x00008000, false, null)); + builder.withField( + forProto2OptionalField( + field("fieldSint6417_"), 17, FieldType.SINT64, bitField0, 0x00010000, false, null)); + builder.withField(forField(field("fieldDoubleList18_"), 18, FieldType.DOUBLE_LIST, false)); + builder.withField(forField(field("fieldFloatList19_"), 19, FieldType.FLOAT_LIST, false)); + builder.withField(forField(field("fieldInt64List20_"), 20, FieldType.INT64_LIST, false)); + builder.withField(forField(field("fieldUint64List21_"), 21, FieldType.UINT64_LIST, false)); + builder.withField(forField(field("fieldInt32List22_"), 22, FieldType.INT32_LIST, false)); + builder.withField(forField(field("fieldFixed64List23_"), 23, FieldType.FIXED64_LIST, false)); + builder.withField(forField(field("fieldFixed32List24_"), 24, FieldType.FIXED32_LIST, false)); + builder.withField(forField(field("fieldBoolList25_"), 25, FieldType.BOOL_LIST, false)); + builder.withField(forField(field("fieldStringList26_"), 26, FieldType.STRING_LIST, false)); + builder.withField( + forRepeatedMessageField( + field("fieldMessageList27_"), 27, FieldType.MESSAGE_LIST, Proto2Message.class)); + builder.withField(forField(field("fieldBytesList28_"), 28, FieldType.BYTES_LIST, false)); + builder.withField(forField(field("fieldUint32List29_"), 29, FieldType.UINT32_LIST, false)); + builder.withField( + forFieldWithEnumVerifier( + field("fieldEnumList30_"), + 30, + FieldType.ENUM_LIST, + asVerifier(TestEnum.internalGetValueMap()))); + builder.withField(forField(field("fieldSfixed32List31_"), 31, FieldType.SFIXED32_LIST, false)); + builder.withField(forField(field("fieldSfixed64List32_"), 32, FieldType.SFIXED64_LIST, false)); + builder.withField(forField(field("fieldSint32List33_"), 33, FieldType.SINT32_LIST, false)); + builder.withField(forField(field("fieldSint64List34_"), 34, FieldType.SINT64_LIST, false)); + builder.withField( + forField(field("fieldDoubleListPacked35_"), 35, FieldType.DOUBLE_LIST_PACKED, false)); + builder.withField( + forField(field("fieldFloatListPacked36_"), 36, FieldType.FLOAT_LIST_PACKED, false)); + builder.withField( + forField(field("fieldInt64ListPacked37_"), 37, FieldType.INT64_LIST_PACKED, false)); + builder.withField( + forField(field("fieldUint64ListPacked38_"), 38, FieldType.UINT64_LIST_PACKED, false)); + builder.withField( + forField(field("fieldInt32ListPacked39_"), 39, FieldType.INT32_LIST_PACKED, false)); + builder.withField( + forField(field("fieldFixed64ListPacked40_"), 40, FieldType.FIXED64_LIST_PACKED, false)); + builder.withField( + forField(field("fieldFixed32ListPacked41_"), 41, FieldType.FIXED32_LIST_PACKED, false)); + builder.withField( + forField(field("fieldBoolListPacked42_"), 42, FieldType.BOOL_LIST_PACKED, false)); + builder.withField( + forField(field("fieldUint32ListPacked43_"), 43, FieldType.UINT32_LIST_PACKED, false)); + builder.withField( + forFieldWithEnumVerifier( + field("fieldEnumListPacked44_"), + 44, + FieldType.ENUM_LIST_PACKED, + asVerifier(TestEnum.internalGetValueMap()))); + builder.withField( + forField(field("fieldSfixed32ListPacked45_"), 45, FieldType.SFIXED32_LIST_PACKED, false)); + builder.withField( + forField(field("fieldSfixed64ListPacked46_"), 46, FieldType.SFIXED64_LIST_PACKED, false)); + builder.withField( + forField(field("fieldSint32ListPacked47_"), 47, FieldType.SINT32_LIST_PACKED, false)); + builder.withField( + forField(field("fieldSint64ListPacked48_"), 48, FieldType.SINT64_LIST_PACKED, false)); + + builder.withField( + forProto2OptionalField( + field("fieldGroup49_"), 49, FieldType.GROUP, bitField0, 0x00020000, false, null)); + builder.withField( + forRepeatedMessageField( + field("fieldGroupList51_"), + 51, + FieldType.GROUP_LIST, + Proto2Message.FieldGroupList51.class)); + + OneofInfo oneof = new OneofInfo(0, field("testOneofCase_"), field("testOneof_")); + builder.withField(forOneofMemberField(53, FieldType.DOUBLE, oneof, Double.class, false, null)); + builder.withField(forOneofMemberField(54, FieldType.FLOAT, oneof, Float.class, false, null)); + builder.withField(forOneofMemberField(55, FieldType.INT64, oneof, Long.class, false, null)); + builder.withField(forOneofMemberField(56, FieldType.UINT64, oneof, Long.class, false, null)); + builder.withField(forOneofMemberField(57, FieldType.INT32, oneof, Integer.class, false, null)); + builder.withField(forOneofMemberField(58, FieldType.FIXED64, oneof, Long.class, false, null)); + builder.withField( + forOneofMemberField(59, FieldType.FIXED32, oneof, Integer.class, false, null)); + builder.withField(forOneofMemberField(60, FieldType.BOOL, oneof, Boolean.class, false, null)); + builder.withField(forOneofMemberField(61, FieldType.STRING, oneof, String.class, false, null)); + builder.withField( + forOneofMemberField(62, FieldType.MESSAGE, oneof, Proto2Message.class, false, null)); + builder.withField( + forOneofMemberField(63, FieldType.BYTES, oneof, ByteString.class, false, null)); + builder.withField(forOneofMemberField(64, FieldType.UINT32, oneof, Integer.class, false, null)); + builder.withField( + forOneofMemberField(65, FieldType.SFIXED32, oneof, Integer.class, false, null)); + builder.withField(forOneofMemberField(66, FieldType.SFIXED64, oneof, Long.class, false, null)); + builder.withField(forOneofMemberField(67, FieldType.SINT32, oneof, Integer.class, false, null)); + builder.withField(forOneofMemberField(68, FieldType.SINT64, oneof, Long.class, false, null)); + builder.withField( + forOneofMemberField( + 69, FieldType.GROUP, oneof, Proto2Message.FieldGroup69.class, false, null)); + + Field bitField1 = field("bitField1_"); + builder.withField( + forProto2RequiredField( + field("fieldRequiredDouble71_"), + 71, + FieldType.DOUBLE, + bitField1, + 0x00000008, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredFloat72_"), + 72, + FieldType.FLOAT, + bitField1, + 0x00000010, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredInt6473_"), + 73, + FieldType.INT64, + bitField1, + 0x00000020, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredUint6474_"), + 74, + FieldType.UINT64, + bitField1, + 0x00000040, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredInt3275_"), + 75, + FieldType.INT32, + bitField1, + 0x00000080, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredFixed6476_"), + 76, + FieldType.FIXED64, + bitField1, + 0x00000100, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredFixed3277_"), + 77, + FieldType.FIXED32, + bitField1, + 0x00000200, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredBool78_"), 78, FieldType.BOOL, bitField1, 0x00000400, false, null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredString79_"), + 79, + FieldType.STRING, + bitField1, + 0x00000800, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredMessage80_"), + 80, + FieldType.MESSAGE, + bitField1, + 0x00001000, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredBytes81_"), + 81, + FieldType.BYTES, + bitField1, + 0x00002000, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredUint3282_"), + 82, + FieldType.UINT32, + bitField1, + 0x00004000, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredEnum83_"), + 83, + FieldType.ENUM, + bitField1, + 0x00008000, + false, + asVerifier(TestEnum.internalGetValueMap()))); + builder.withField( + forProto2RequiredField( + field("fieldRequiredSfixed3284_"), + 84, + FieldType.SFIXED32, + bitField1, + 0x00010000, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredSfixed6485_"), + 85, + FieldType.SFIXED64, + bitField1, + 0x00020000, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredSint3286_"), + 86, + FieldType.SINT32, + bitField1, + 0x00040000, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredSint6487_"), + 87, + FieldType.SINT64, + bitField1, + 0x00080000, + false, + null)); + builder.withField( + forProto2RequiredField( + field("fieldRequiredGroup88_"), + 88, + FieldType.GROUP, + bitField1, + 0x00100000, + false, + null)); + } + + private static StructuralMessageInfo newMessageInfoForFieldGroup49() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(FieldGroup49.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(FieldGroup49.class, "fieldInt3250_"), + 50, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForFieldGroupList51() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(FieldGroupList51.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(FieldGroupList51.class, "fieldInt3252_"), + 52, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForFieldGroup69() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(FieldGroup69.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(FieldGroup69.class, "fieldInt3270_"), + 70, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForRequiredNestedMessage() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(RequiredNestedMessage.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(RequiredNestedMessage.class, "value_"), + 1, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForFieldRequiredGroup88() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(FieldRequiredGroup88.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(FieldRequiredGroup88.class, "fieldInt3289_"), + 89, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForProto2Empty() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForProto2MessageWithExtensions() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(0); + builder.withSyntax(ProtoSyntax.PROTO2); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForExtensionFieldGroup49() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(Proto2Testing.FieldGroup49.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(Proto2Testing.FieldGroup49.class, "fieldInt3250_"), + 50, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForExtensionFieldGroupList51() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(Proto2Testing.FieldGroupList51.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(Proto2Testing.FieldGroupList51.class, "fieldInt3252_"), + 52, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForProto2MessageWithMaps() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(); + builder.withCheckInitialized( + new int[] { + 10, 27, 44, 61, 78, 95, 112, 129, 146, 163, 180, 197, + }); + builder.withSyntax(ProtoSyntax.PROTO2); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_bool_1", 1)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_bytes_2", 2)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_double_3", 3)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_enum_4", 4)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_fixed32_5", 5)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_fixed64_6", 6)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_float_7", 7)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_int32_8", 8)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_int64_9", 9)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_message_10", 10)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_sfixed32_11", 11)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_sfixed64_12", 12)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_sint32_13", 13)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_sint64_14", 14)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_string_15", 15)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_uint32_16", 16)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_uint64_17", 17)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_bool_18", 18)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_bytes_19", 19)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_double_20", 20)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_enum_21", 21)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_fixed32_22", 22)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_fixed64_23", 23)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_float_24", 24)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_int32_25", 25)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_int64_26", 26)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_message_27", 27)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_sfixed32_28", 28)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_sfixed64_29", 29)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_sint32_30", 30)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_sint64_31", 31)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_string_32", 32)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_uint32_33", 33)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_uint64_34", 34)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_bool_35", 35)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_bytes_36", 36)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_double_37", 37)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_enum_38", 38)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_fixed32_39", 39)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_fixed64_40", 40)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_float_41", 41)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_int32_42", 42)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_int64_43", 43)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_message_44", 44)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_sfixed32_45", 45)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_sfixed64_46", 46)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_sint32_47", 47)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_sint64_48", 48)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_string_49", 49)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_uint32_50", 50)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_uint64_51", 51)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_bool_52", 52)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_bytes_53", 53)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_double_54", 54)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_enum_55", 55)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_fixed32_56", 56)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_fixed64_57", 57)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_float_58", 58)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_int32_59", 59)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_int64_60", 60)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_message_61", 61)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_sfixed32_62", 62)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_sfixed64_63", 63)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_sint32_64", 64)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_sint64_65", 65)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_string_66", 66)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_uint32_67", 67)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_uint64_68", 68)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_bool_69", 69)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_bytes_70", 70)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_double_71", 71)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_enum_72", 72)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_fixed32_73", 73)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_fixed64_74", 74)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_float_75", 75)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_int32_76", 76)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_int64_77", 77)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_message_78", 78)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_sfixed32_79", 79)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_sfixed64_80", 80)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_sint32_81", 81)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_sint64_82", 82)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_string_83", 83)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_uint32_84", 84)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_uint64_85", 85)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_bool_86", 86)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_bytes_87", 87)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_double_88", 88)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_enum_89", 89)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_fixed32_90", 90)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_fixed64_91", 91)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_float_92", 92)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_int32_93", 93)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_int64_94", 94)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_message_95", 95)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_sfixed32_96", 96)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_sfixed64_97", 97)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_sint32_98", 98)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_sint64_99", 99)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_string_100", 100)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_uint32_101", 101)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_uint64_102", 102)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_bool_103", 103)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_bytes_104", 104)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_double_105", 105)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_enum_106", 106)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_fixed32_107", 107)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_fixed64_108", 108)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_float_109", 109)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_int32_110", 110)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_int64_111", 111)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_message_112", 112)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_sfixed32_113", 113)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_sfixed64_114", 114)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_sint32_115", 115)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_sint64_116", 116)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_string_117", 117)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_uint32_118", 118)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_uint64_119", 119)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_bool_120", 120)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_bytes_121", 121)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_double_122", 122)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_enum_123", 123)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_fixed32_124", 124)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_fixed64_125", 125)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_float_126", 126)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_int32_127", 127)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_int64_128", 128)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_message_129", 129)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_sfixed32_130", 130)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_sfixed64_131", 131)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_sint32_132", 132)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_sint64_133", 133)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_string_134", 134)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_uint32_135", 135)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_uint64_136", 136)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_bool_137", 137)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_bytes_138", 138)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_double_139", 139)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_enum_140", 140)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_fixed32_141", 141)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_fixed64_142", 142)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_float_143", 143)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_int32_144", 144)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_int64_145", 145)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_message_146", 146)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_sfixed32_147", 147)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_sfixed64_148", 148)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_sint32_149", 149)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_sint64_150", 150)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_string_151", 151)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_uint32_152", 152)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_uint64_153", 153)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_bool_154", 154)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_bytes_155", 155)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_double_156", 156)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_enum_157", 157)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_fixed32_158", 158)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_fixed64_159", 159)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_float_160", 160)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_int32_161", 161)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_int64_162", 162)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_message_163", 163)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_sfixed32_164", 164)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_sfixed64_165", 165)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_sint32_166", 166)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_sint64_167", 167)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_string_168", 168)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_uint32_169", 169)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_uint64_170", 170)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_bool_171", 171)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_bytes_172", 172)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_double_173", 173)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_enum_174", 174)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_fixed32_175", 175)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_fixed64_176", 176)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_float_177", 177)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_int32_178", 178)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_int64_179", 179)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_message_180", 180)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_sfixed32_181", 181)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_sfixed64_182", 182)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_sint32_183", 183)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_sint64_184", 184)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_string_185", 185)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_uint32_186", 186)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_uint64_187", 187)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_bool_188", 188)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_bytes_189", 189)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_double_190", 190)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_enum_191", 191)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_fixed32_192", 192)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_fixed64_193", 193)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_float_194", 194)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_int32_195", 195)); + builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_int64_196", 196)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_message_197", 197)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_sfixed32_198", 198)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_sfixed64_199", 199)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_sint32_200", 200)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_sint64_201", 201)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_string_202", 202)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_uint32_203", 203)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_uint64_204", 204)); + + return builder.build(); + } + + private static FieldInfo mapFieldInfo(Class<?> clazz, String fieldName, int fieldNumber) { + try { + return forMapField( + field(clazz, SchemaUtil.toCamelCase(fieldName, false) + "_"), + fieldNumber, + SchemaUtil.getMapDefaultEntry(clazz, fieldName), + fieldName.contains("_enum_") ? asVerifier(TestEnum.internalGetValueMap()) : null); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + + private static Field field(String name) { + return field(Proto2Message.class, name); + } + + private static Field field(Class<?> clazz, String name) { + try { + return clazz.getDeclaredField(name); + } catch (NoSuchFieldException | SecurityException e) { + throw new RuntimeException(e); + } + } + + private static Internal.EnumVerifier asVerifier(final Internal.EnumLiteMap<?> map) { + return new Internal.EnumVerifier() { + @Override + public boolean isInRange(int number) { + return map.findValueByNumber(number) != null; + } + }; + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto2MessageLiteFactory.java b/java/core/src/test/java/com/google/protobuf/Proto2MessageLiteFactory.java new file mode 100755 index 000000000..2da349424 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto2MessageLiteFactory.java @@ -0,0 +1,558 @@ +// 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.testing.Proto2TestingLite.Proto2MessageLite; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLiteWithMaps; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Creates instances of {@link Proto2MessageLite} based on the tree configuration. */ +public final class Proto2MessageLiteFactory + implements ExperimentalMessageFactory<Proto2MessageLite> { + private final int numRepeatedFields; + private final int branchingFactor; + private final Proto2MessageLiteFactory nextLevel; + private final ExperimentalTestDataProvider data; + + public Proto2MessageLiteFactory( + int numRepeatedFields, int stringLength, int branchingFactor, int treeDepth) { + this( + new ExperimentalTestDataProvider(stringLength), + numRepeatedFields, + branchingFactor, + treeDepth); + } + + private Proto2MessageLiteFactory( + ExperimentalTestDataProvider data, + int numRepeatedFields, + int branchingFactor, + int treeDepth) { + this.numRepeatedFields = numRepeatedFields; + this.branchingFactor = branchingFactor; + this.data = data; + if (treeDepth > 0) { + nextLevel = + new Proto2MessageLiteFactory(data, numRepeatedFields, branchingFactor, treeDepth - 1); + } else { + nextLevel = null; + } + } + + @Override + public ExperimentalTestDataProvider dataProvider() { + return data; + } + + @Override + public Proto2MessageLite newMessage() { + Proto2MessageLite.Builder builder = Proto2MessageLite.newBuilder(); + builder.setFieldDouble1(data.getDouble()); + builder.setFieldFloat2(data.getFloat()); + builder.setFieldInt643(data.getLong()); + builder.setFieldUint644(data.getLong()); + builder.setFieldInt325(data.getInt()); + builder.setFieldFixed646(data.getLong()); + builder.setFieldFixed327(data.getInt()); + builder.setFieldBool8(data.getBool()); + builder.setFieldString9(data.getString()); + // We don't populate the message field. Instead we apply the branching factor to the + // repeated message field below. + builder.setFieldBytes11(data.getBytes()); + builder.setFieldUint3212(data.getInt()); + builder.setFieldEnum13(Proto2MessageLite.TestEnum.forNumber(data.getEnum())); + builder.setFieldSfixed3214(data.getInt()); + builder.setFieldSfixed6415(data.getLong()); + builder.setFieldSint3216(data.getInt()); + builder.setFieldSint6417(data.getLong()); + + for (int i = 0; i < numRepeatedFields; ++i) { + builder.addFieldDoubleList18(data.getDouble()); + builder.addFieldFloatList19(data.getFloat()); + builder.addFieldInt64List20(data.getLong()); + builder.addFieldUint64List21(data.getLong()); + builder.addFieldInt32List22(data.getInt()); + builder.addFieldFixed64List23(data.getLong()); + builder.addFieldFixed32List24(data.getInt()); + builder.addFieldBoolList25(data.getBool()); + builder.addFieldStringList26(data.getString()); + // Repeated message field is controlled by the branching factor below. + builder.addFieldBytesList28(data.getBytes()); + builder.addFieldUint32List29(data.getInt()); + builder.addFieldEnumList30(Proto2MessageLite.TestEnum.forNumber(data.getEnum())); + builder.addFieldSfixed32List31(data.getInt()); + builder.addFieldSfixed64List32(data.getLong()); + builder.addFieldSint32List33(data.getInt()); + builder.addFieldSint64List34(data.getLong()); + + builder.addFieldDoubleListPacked35(data.getDouble()); + builder.addFieldFloatListPacked36(data.getFloat()); + builder.addFieldInt64ListPacked37(data.getLong()); + builder.addFieldUint64ListPacked38(data.getLong()); + builder.addFieldInt32ListPacked39(data.getInt()); + builder.addFieldFixed64ListPacked40(data.getLong()); + builder.addFieldFixed32ListPacked41(data.getInt()); + builder.addFieldBoolListPacked42(data.getBool()); + builder.addFieldUint32ListPacked43(data.getInt()); + builder.addFieldEnumListPacked44(Proto2MessageLite.TestEnum.forNumber(data.getEnum())); + builder.addFieldSfixed32ListPacked45(data.getInt()); + builder.addFieldSfixed64ListPacked46(data.getLong()); + builder.addFieldSint32ListPacked47(data.getInt()); + builder.addFieldSint64ListPacked48(data.getLong()); + } + + builder.setFieldGroup49( + Proto2MessageLite.FieldGroup49.newBuilder().setFieldInt3250(data.getInt())); + + for (int i = 0; i < branchingFactor; ++i) { + builder.addFieldGroupList51( + Proto2MessageLite.FieldGroupList51.newBuilder().setFieldInt3252(data.getInt())); + } + + // Set all required fields. + populateRequiredFields(builder, INCLUDE_ALL_REQUIRED_FIELDS); + + // Handle the branching factor. + if (nextLevel != null) { + for (int i = 0; i < branchingFactor; ++i) { + builder.addFieldMessageList27(nextLevel.newMessage()); + } + } + + return builder.build(); + } + + private interface MapValueProvider<T> { + public T getValue(); + } + + private final MapValueProvider<Integer> integerProvider = + new MapValueProvider<Integer>() { + @Override + public Integer getValue() { + return data.getInt(); + } + }; + private final MapValueProvider<Long> longProvider = + new MapValueProvider<Long>() { + @Override + public Long getValue() { + return data.getLong(); + } + }; + private final MapValueProvider<String> stringProvider = + new MapValueProvider<String>() { + @Override + public String getValue() { + return data.getString(); + } + }; + private final MapValueProvider<ByteString> bytesProvider = + new MapValueProvider<ByteString>() { + @Override + public ByteString getValue() { + return data.getBytes(); + } + }; + private final MapValueProvider<Boolean> booleanProvider = + new MapValueProvider<Boolean>() { + @Override + public Boolean getValue() { + return data.getBool(); + } + }; + private final MapValueProvider<Float> floatProvider = + new MapValueProvider<Float>() { + @Override + public Float getValue() { + return data.getFloat(); + } + }; + private final MapValueProvider<Double> doubleProvider = + new MapValueProvider<Double>() { + @Override + public Double getValue() { + return data.getDouble(); + } + }; + private final MapValueProvider<Proto2MessageLite> messageProvider = + new MapValueProvider<Proto2MessageLite>() { + @Override + public Proto2MessageLite getValue() { + return newMessage(); + } + }; + private final MapValueProvider<Proto2MessageLite.TestEnum> enumProvider = + new MapValueProvider<Proto2MessageLite.TestEnum>() { + @Override + public Proto2MessageLite.TestEnum getValue() { + return Proto2MessageLite.TestEnum.forNumber(data.getEnum()); + } + }; + + private <V> Map<Integer, V> populateIntegerMap(MapValueProvider<V> provider) { + Map<Integer, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getInt(), provider.getValue()); + } + return map; + } + + private <V> Map<Long, V> populateLongMap(MapValueProvider<V> provider) { + Map<Long, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getLong(), provider.getValue()); + } + return map; + } + + private <V> Map<String, V> populateStringMap(MapValueProvider<V> provider) { + Map<String, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getString(), provider.getValue()); + } + return map; + } + + private <V> Map<Boolean, V> populateBooleanMap(MapValueProvider<V> provider) { + Map<Boolean, V> map = new HashMap<>(); + map.put(false, provider.getValue()); + map.put(true, provider.getValue()); + return map; + } + + public Proto2MessageLiteWithMaps newMessageWithMaps() { + Proto2MessageLiteWithMaps.Builder builder = Proto2MessageLiteWithMaps.newBuilder(); + + builder.putAllFieldMapBoolBool1(populateBooleanMap(booleanProvider)); + builder.putAllFieldMapBoolBytes2(populateBooleanMap(bytesProvider)); + builder.putAllFieldMapBoolDouble3(populateBooleanMap(doubleProvider)); + builder.putAllFieldMapBoolEnum4(populateBooleanMap(enumProvider)); + builder.putAllFieldMapBoolFixed325(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolFixed646(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolFloat7(populateBooleanMap(floatProvider)); + builder.putAllFieldMapBoolInt328(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolInt649(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolMessage10(populateBooleanMap(messageProvider)); + builder.putAllFieldMapBoolSfixed3211(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolSfixed6412(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolSint3213(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolSint6414(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolString15(populateBooleanMap(stringProvider)); + builder.putAllFieldMapBoolUint3216(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolUint6417(populateBooleanMap(longProvider)); + builder.putAllFieldMapFixed32Bool18(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapFixed32Bytes19(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapFixed32Double20(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapFixed32Enum21(populateIntegerMap(enumProvider)); + builder.putAllFieldMapFixed32Fixed3222(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Fixed6423(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Float24(populateIntegerMap(floatProvider)); + builder.putAllFieldMapFixed32Int3225(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Int6426(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Message27(populateIntegerMap(messageProvider)); + builder.putAllFieldMapFixed32Sfixed3228(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Sfixed6429(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Sint3230(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Sint6431(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32String32(populateIntegerMap(stringProvider)); + builder.putAllFieldMapFixed32Uint3233(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Uint6434(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed64Bool35(populateLongMap(booleanProvider)); + builder.putAllFieldMapFixed64Bytes36(populateLongMap(bytesProvider)); + builder.putAllFieldMapFixed64Double37(populateLongMap(doubleProvider)); + builder.putAllFieldMapFixed64Enum38(populateLongMap(enumProvider)); + builder.putAllFieldMapFixed64Fixed3239(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Fixed6440(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Float41(populateLongMap(floatProvider)); + builder.putAllFieldMapFixed64Int3242(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Int6443(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Message44(populateLongMap(messageProvider)); + builder.putAllFieldMapFixed64Sfixed3245(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Sfixed6446(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Sint3247(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Sint6448(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64String49(populateLongMap(stringProvider)); + builder.putAllFieldMapFixed64Uint3250(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Uint6451(populateLongMap(longProvider)); + builder.putAllFieldMapInt32Bool52(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapInt32Bytes53(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapInt32Double54(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapInt32Enum55(populateIntegerMap(enumProvider)); + builder.putAllFieldMapInt32Fixed3256(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Fixed6457(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Float58(populateIntegerMap(floatProvider)); + builder.putAllFieldMapInt32Int3259(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Int6460(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Message61(populateIntegerMap(messageProvider)); + builder.putAllFieldMapInt32Sfixed3262(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Sfixed6463(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Sint3264(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Sint6465(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32String66(populateIntegerMap(stringProvider)); + builder.putAllFieldMapInt32Uint3267(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Uint6468(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt64Bool69(populateLongMap(booleanProvider)); + builder.putAllFieldMapInt64Bytes70(populateLongMap(bytesProvider)); + builder.putAllFieldMapInt64Double71(populateLongMap(doubleProvider)); + builder.putAllFieldMapInt64Enum72(populateLongMap(enumProvider)); + builder.putAllFieldMapInt64Fixed3273(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Fixed6474(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Float75(populateLongMap(floatProvider)); + builder.putAllFieldMapInt64Int3276(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Int6477(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Message78(populateLongMap(messageProvider)); + builder.putAllFieldMapInt64Sfixed3279(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Sfixed6480(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Sint3281(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Sint6482(populateLongMap(longProvider)); + builder.putAllFieldMapInt64String83(populateLongMap(stringProvider)); + builder.putAllFieldMapInt64Uint3284(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Uint6485(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed32Bool86(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapSfixed32Bytes87(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapSfixed32Double88(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapSfixed32Enum89(populateIntegerMap(enumProvider)); + builder.putAllFieldMapSfixed32Fixed3290(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Fixed6491(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Float92(populateIntegerMap(floatProvider)); + builder.putAllFieldMapSfixed32Int3293(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Int6494(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Message95(populateIntegerMap(messageProvider)); + builder.putAllFieldMapSfixed32Sfixed3296(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Sfixed6497(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Sint3298(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Sint6499(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32String100(populateIntegerMap(stringProvider)); + builder.putAllFieldMapSfixed32Uint32101(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Uint64102(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed64Bool103(populateLongMap(booleanProvider)); + builder.putAllFieldMapSfixed64Bytes104(populateLongMap(bytesProvider)); + builder.putAllFieldMapSfixed64Double105(populateLongMap(doubleProvider)); + builder.putAllFieldMapSfixed64Enum106(populateLongMap(enumProvider)); + builder.putAllFieldMapSfixed64Fixed32107(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Fixed64108(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Float109(populateLongMap(floatProvider)); + builder.putAllFieldMapSfixed64Int32110(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Int64111(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Message112(populateLongMap(messageProvider)); + builder.putAllFieldMapSfixed64Sfixed32113(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Sfixed64114(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Sint32115(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Sint64116(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64String117(populateLongMap(stringProvider)); + builder.putAllFieldMapSfixed64Uint32118(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Uint64119(populateLongMap(longProvider)); + builder.putAllFieldMapSint32Bool120(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapSint32Bytes121(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapSint32Double122(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapSint32Enum123(populateIntegerMap(enumProvider)); + builder.putAllFieldMapSint32Fixed32124(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Fixed64125(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Float126(populateIntegerMap(floatProvider)); + builder.putAllFieldMapSint32Int32127(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Int64128(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Message129(populateIntegerMap(messageProvider)); + builder.putAllFieldMapSint32Sfixed32130(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Sfixed64131(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Sint32132(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Sint64133(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32String134(populateIntegerMap(stringProvider)); + builder.putAllFieldMapSint32Uint32135(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Uint64136(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint64Bool137(populateLongMap(booleanProvider)); + builder.putAllFieldMapSint64Bytes138(populateLongMap(bytesProvider)); + builder.putAllFieldMapSint64Double139(populateLongMap(doubleProvider)); + builder.putAllFieldMapSint64Enum140(populateLongMap(enumProvider)); + builder.putAllFieldMapSint64Fixed32141(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Fixed64142(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Float143(populateLongMap(floatProvider)); + builder.putAllFieldMapSint64Int32144(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Int64145(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Message146(populateLongMap(messageProvider)); + builder.putAllFieldMapSint64Sfixed32147(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Sfixed64148(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Sint32149(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Sint64150(populateLongMap(longProvider)); + builder.putAllFieldMapSint64String151(populateLongMap(stringProvider)); + builder.putAllFieldMapSint64Uint32152(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Uint64153(populateLongMap(longProvider)); + builder.putAllFieldMapStringBool154(populateStringMap(booleanProvider)); + builder.putAllFieldMapStringBytes155(populateStringMap(bytesProvider)); + builder.putAllFieldMapStringDouble156(populateStringMap(doubleProvider)); + builder.putAllFieldMapStringEnum157(populateStringMap(enumProvider)); + builder.putAllFieldMapStringFixed32158(populateStringMap(integerProvider)); + builder.putAllFieldMapStringFixed64159(populateStringMap(longProvider)); + builder.putAllFieldMapStringFloat160(populateStringMap(floatProvider)); + builder.putAllFieldMapStringInt32161(populateStringMap(integerProvider)); + builder.putAllFieldMapStringInt64162(populateStringMap(longProvider)); + builder.putAllFieldMapStringMessage163(populateStringMap(messageProvider)); + builder.putAllFieldMapStringSfixed32164(populateStringMap(integerProvider)); + builder.putAllFieldMapStringSfixed64165(populateStringMap(longProvider)); + builder.putAllFieldMapStringSint32166(populateStringMap(integerProvider)); + builder.putAllFieldMapStringSint64167(populateStringMap(longProvider)); + builder.putAllFieldMapStringString168(populateStringMap(stringProvider)); + builder.putAllFieldMapStringUint32169(populateStringMap(integerProvider)); + builder.putAllFieldMapStringUint64170(populateStringMap(longProvider)); + builder.putAllFieldMapUint32Bool171(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapUint32Bytes172(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapUint32Double173(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapUint32Enum174(populateIntegerMap(enumProvider)); + builder.putAllFieldMapUint32Fixed32175(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Fixed64176(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Float177(populateIntegerMap(floatProvider)); + builder.putAllFieldMapUint32Int32178(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Int64179(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Message180(populateIntegerMap(messageProvider)); + builder.putAllFieldMapUint32Sfixed32181(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Sfixed64182(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Sint32183(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Sint64184(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32String185(populateIntegerMap(stringProvider)); + builder.putAllFieldMapUint32Uint32186(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Uint64187(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint64Bool188(populateLongMap(booleanProvider)); + builder.putAllFieldMapUint64Bytes189(populateLongMap(bytesProvider)); + builder.putAllFieldMapUint64Double190(populateLongMap(doubleProvider)); + builder.putAllFieldMapUint64Enum191(populateLongMap(enumProvider)); + builder.putAllFieldMapUint64Fixed32192(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Fixed64193(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Float194(populateLongMap(floatProvider)); + builder.putAllFieldMapUint64Int32195(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Int64196(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Message197(populateLongMap(messageProvider)); + builder.putAllFieldMapUint64Sfixed32198(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Sfixed64199(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Sint32200(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Sint64201(populateLongMap(longProvider)); + builder.putAllFieldMapUint64String202(populateLongMap(stringProvider)); + builder.putAllFieldMapUint64Uint32203(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Uint64204(populateLongMap(longProvider)); + + return builder.build(); + } + + public List<Proto2MessageLite> newMessagesMissingRequiredFields() { + List<Proto2MessageLite> results = new ArrayList<>(); + for (int i = 71; i <= 88; ++i) { + Proto2MessageLite.Builder builder = Proto2MessageLite.newBuilder(); + populateRequiredFields(builder, i); + results.add(builder.buildPartial()); + } + { + // A nested optional message field is missing required fields. + Proto2MessageLite.Builder builder = Proto2MessageLite.newBuilder(); + populateRequiredFields(builder, INCLUDE_ALL_REQUIRED_FIELDS); + builder.setFieldMessage10(Proto2MessageLite.getDefaultInstance()); + results.add(builder.buildPartial()); + } + { + // A nested repeated message field is missing required fields. + Proto2MessageLite.Builder builder = Proto2MessageLite.newBuilder(); + populateRequiredFields(builder, INCLUDE_ALL_REQUIRED_FIELDS); + builder.addFieldMessageList27(Proto2MessageLite.getDefaultInstance()); + results.add(builder.buildPartial()); + } + { + // A nested oneof message field is missing required fields. + Proto2MessageLite.Builder builder = Proto2MessageLite.newBuilder(); + populateRequiredFields(builder, INCLUDE_ALL_REQUIRED_FIELDS); + builder.setFieldMessage62(Proto2MessageLite.getDefaultInstance()); + results.add(builder.buildPartial()); + } + return results; + } + + // 0 is not a valid field number so we use it to mean no fields are excluded. + private static final int INCLUDE_ALL_REQUIRED_FIELDS = 0; + + private void populateRequiredFields(Proto2MessageLite.Builder builder, int excludedFieldNumber) { + if (excludedFieldNumber != 71) { + builder.setFieldRequiredDouble71(data.getDouble()); + } + if (excludedFieldNumber != 72) { + builder.setFieldRequiredFloat72(data.getFloat()); + } + if (excludedFieldNumber != 73) { + builder.setFieldRequiredInt6473(data.getLong()); + } + if (excludedFieldNumber != 74) { + builder.setFieldRequiredUint6474(data.getLong()); + } + if (excludedFieldNumber != 75) { + builder.setFieldRequiredInt3275(data.getInt()); + } + if (excludedFieldNumber != 76) { + builder.setFieldRequiredFixed6476(data.getLong()); + } + if (excludedFieldNumber != 77) { + builder.setFieldRequiredFixed3277(data.getInt()); + } + if (excludedFieldNumber != 78) { + builder.setFieldRequiredBool78(data.getBool()); + } + if (excludedFieldNumber != 79) { + builder.setFieldRequiredString79(data.getString()); + } + if (excludedFieldNumber != 80) { + builder.setFieldRequiredMessage80( + Proto2MessageLite.RequiredNestedMessage.newBuilder().setValue(data.getInt())); + } + if (excludedFieldNumber != 81) { + builder.setFieldRequiredBytes81(data.getBytes()); + } + if (excludedFieldNumber != 82) { + builder.setFieldRequiredUint3282(data.getInt()); + } + if (excludedFieldNumber != 83) { + builder.setFieldRequiredEnum83(Proto2MessageLite.TestEnum.forNumber(data.getEnum())); + } + if (excludedFieldNumber != 84) { + builder.setFieldRequiredSfixed3284(data.getInt()); + } + if (excludedFieldNumber != 85) { + builder.setFieldRequiredSfixed6485(data.getLong()); + } + if (excludedFieldNumber != 86) { + builder.setFieldRequiredSint3286(data.getInt()); + } + if (excludedFieldNumber != 87) { + builder.setFieldRequiredSint6487(data.getLong()); + } + if (excludedFieldNumber != 88) { + builder.setFieldRequiredGroup88( + Proto2MessageLite.FieldRequiredGroup88.newBuilder().setFieldInt3289(data.getInt())); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto2SchemaTest.java b/java/core/src/test/java/com/google/protobuf/Proto2SchemaTest.java new file mode 100755 index 000000000..098e7fe18 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto2SchemaTest.java @@ -0,0 +1,49 @@ +// 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.testing.Proto2Testing.Proto2Message; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Proto2SchemaTest extends AbstractProto2SchemaTest { + + @Override + protected Schema<Proto2Message> schema() { + return TestSchemas.genericProto2Schema; + } + + @Override + protected void registerSchemas() { + TestSchemas.registerGenericProto2Schemas(); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java b/java/core/src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java new file mode 100755 index 000000000..57ac0695e --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java @@ -0,0 +1,111 @@ +// 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 protobuf_unittest.UnittestProto; +import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; +import junit.framework.TestCase; + +/** Unit tests for proto2 that treats unknown enum values as unknown fields. */ +public class Proto2UnknownEnumValueTest extends TestCase { + FieldDescriptor singularField = + TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum"); + FieldDescriptor repeatedField = + TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum"); + byte[] payload = buildPayloadWithUnknownEnumValues(); + + private byte[] buildPayloadWithUnknownEnumValues() { + // Builds a payload with unknown enum values. + UnknownFieldSet.Builder builder = UnknownFieldSet.newBuilder(); + builder.addField( + singularField.getNumber(), + UnknownFieldSet.Field.newBuilder() + .addVarint(TestAllTypes.NestedEnum.BAR.getNumber()) + .addVarint(1901 /* unknown enum value */) + .build()); + builder.addField( + repeatedField.getNumber(), + UnknownFieldSet.Field.newBuilder() + .addVarint(TestAllTypes.NestedEnum.FOO.getNumber()) + .addVarint(1902 /* unknown enum value */) + .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber()) + .addVarint(1903 /* unknown enum value */) + .build()); + return builder.build().toByteArray(); + } + + public void testUnknownEnumValues() throws Exception { + TestAllTypes message = TestAllTypes.parseFrom(payload); + + // Known enum values should be preserved. + assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum()); + assertEquals(2, message.getRepeatedNestedEnumList().size()); + assertEquals(TestAllTypes.NestedEnum.FOO, message.getRepeatedNestedEnum(0)); + assertEquals(TestAllTypes.NestedEnum.BAZ, message.getRepeatedNestedEnum(1)); + + // Unknown enum values should be found in UnknownFieldSet. + UnknownFieldSet unknown = message.getUnknownFields(); + assertEquals( + 1901, unknown.getField(singularField.getNumber()).getVarintList().get(0).longValue()); + assertEquals( + 1902, unknown.getField(repeatedField.getNumber()).getVarintList().get(0).longValue()); + assertEquals( + 1903, unknown.getField(repeatedField.getNumber()).getVarintList().get(1).longValue()); + } + + public void testExtensionUnknownEnumValues() throws Exception { + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + UnittestProto.registerAllExtensions(registry); + TestAllExtensions message = TestAllExtensions.parseFrom(payload, registry); + + assertEquals( + TestAllTypes.NestedEnum.BAR, + message.getExtension(UnittestProto.optionalNestedEnumExtension)); + assertEquals(2, message.getExtension(UnittestProto.repeatedNestedEnumExtension).size()); + assertEquals( + TestAllTypes.NestedEnum.FOO, + message.getExtension(UnittestProto.repeatedNestedEnumExtension, 0)); + assertEquals( + TestAllTypes.NestedEnum.BAZ, + message.getExtension(UnittestProto.repeatedNestedEnumExtension, 1)); + + // Unknown enum values should be found in UnknownFieldSet. + UnknownFieldSet unknown = message.getUnknownFields(); + assertEquals( + 1901, unknown.getField(singularField.getNumber()).getVarintList().get(0).longValue()); + assertEquals( + 1902, unknown.getField(repeatedField.getNumber()).getVarintList().get(0).longValue()); + assertEquals( + 1903, unknown.getField(repeatedField.getNumber()).getVarintList().get(1).longValue()); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto3LiteSchemaTest.java b/java/core/src/test/java/com/google/protobuf/Proto3LiteSchemaTest.java new file mode 100755 index 000000000..ac9d6df70 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto3LiteSchemaTest.java @@ -0,0 +1,49 @@ +// 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.testing.Proto3TestingLite.Proto3MessageLite; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Proto3LiteSchemaTest extends AbstractProto3LiteSchemaTest { + + @Override + protected Schema<Proto3MessageLite> schema() { + return TestSchemasLite.genericProto3LiteSchema; + } + + @Override + protected void registerSchemas() { + TestSchemasLite.registerGenericProto3LiteSchemas(); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto3MessageFactory.java b/java/core/src/test/java/com/google/protobuf/Proto3MessageFactory.java new file mode 100755 index 000000000..33d5fe0fc --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto3MessageFactory.java @@ -0,0 +1,450 @@ +// 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.testing.Proto3Testing.Proto3Message; +import com.google.protobuf.testing.Proto3Testing.Proto3MessageWithMaps; +import java.util.HashMap; +import java.util.Map; + +/** Creates instances of {@link Proto3Message} based on the tree configuration. */ +public final class Proto3MessageFactory implements ExperimentalMessageFactory<Proto3Message> { + private final int numRepeatedFields; + private final int branchingFactor; + private final Proto3MessageFactory nextLevel; + private final ExperimentalTestDataProvider data; + + public Proto3MessageFactory( + int numRepeatedFields, int stringLength, int branchingFactor, int treeDepth) { + this( + new ExperimentalTestDataProvider(stringLength), + numRepeatedFields, + branchingFactor, + treeDepth); + } + + private Proto3MessageFactory( + ExperimentalTestDataProvider data, + int numRepeatedFields, + int branchingFactor, + int treeDepth) { + this.numRepeatedFields = numRepeatedFields; + this.branchingFactor = branchingFactor; + this.data = data; + if (treeDepth > 0) { + nextLevel = new Proto3MessageFactory(data, numRepeatedFields, branchingFactor, treeDepth - 1); + } else { + nextLevel = null; + } + } + + @Override + public ExperimentalTestDataProvider dataProvider() { + return data; + } + + @Override + public Proto3Message newMessage() { + Proto3Message.Builder builder = Proto3Message.newBuilder(); + builder.setFieldDouble1(data.getDouble()); + builder.setFieldFloat2(data.getFloat()); + builder.setFieldInt643(data.getLong()); + builder.setFieldUint644(data.getLong()); + builder.setFieldInt325(data.getInt()); + builder.setFieldFixed646(data.getLong()); + builder.setFieldFixed327(data.getInt()); + builder.setFieldBool8(data.getBool()); + builder.setFieldString9(data.getString()); + // We don't populate the message field. Instead we apply the branching factor to the + // repeated message field below. + builder.setFieldBytes11(data.getBytes()); + builder.setFieldUint3212(data.getInt()); + builder.setFieldEnum13Value(data.getEnum()); + builder.setFieldSfixed3214(data.getInt()); + builder.setFieldSfixed6415(data.getLong()); + builder.setFieldSint3216(data.getInt()); + builder.setFieldSint6417(data.getLong()); + + for (int i = 0; i < numRepeatedFields; ++i) { + builder.addFieldDoubleList18(data.getDouble()); + builder.addFieldFloatList19(data.getFloat()); + builder.addFieldInt64List20(data.getLong()); + builder.addFieldUint64List21(data.getLong()); + builder.addFieldInt32List22(data.getInt()); + builder.addFieldFixed64List23(data.getLong()); + builder.addFieldFixed32List24(data.getInt()); + builder.addFieldBoolList25(data.getBool()); + builder.addFieldStringList26(data.getString()); + // Repeated message field is controlled by the branching factor below. + builder.addFieldBytesList28(data.getBytes()); + builder.addFieldUint32List29(data.getInt()); + builder.addFieldEnumList30Value(data.getEnum()); + builder.addFieldSfixed32List31(data.getInt()); + builder.addFieldSfixed64List32(data.getLong()); + builder.addFieldSint32List33(data.getInt()); + builder.addFieldSint64List34(data.getLong()); + + builder.addFieldDoubleListPacked35(data.getDouble()); + builder.addFieldFloatListPacked36(data.getFloat()); + builder.addFieldInt64ListPacked37(data.getLong()); + builder.addFieldUint64ListPacked38(data.getLong()); + builder.addFieldInt32ListPacked39(data.getInt()); + builder.addFieldFixed64ListPacked40(data.getLong()); + builder.addFieldFixed32ListPacked41(data.getInt()); + builder.addFieldBoolListPacked42(data.getBool()); + builder.addFieldUint32ListPacked43(data.getInt()); + builder.addFieldEnumListPacked44Value(data.getEnum()); + builder.addFieldSfixed32ListPacked45(data.getInt()); + builder.addFieldSfixed64ListPacked46(data.getLong()); + builder.addFieldSint32ListPacked47(data.getInt()); + builder.addFieldSint64ListPacked48(data.getLong()); + } + + // Handle the branching factor. + if (nextLevel != null) { + for (int i = 0; i < branchingFactor; ++i) { + builder.addFieldMessageList27(nextLevel.newMessage()); + } + } + + return builder.build(); + } + + private interface MapValueProvider<T> { + public T getValue(); + } + + private final MapValueProvider<Integer> integerProvider = + new MapValueProvider<Integer>() { + @Override + public Integer getValue() { + return data.getInt(); + } + }; + private final MapValueProvider<Long> longProvider = + new MapValueProvider<Long>() { + @Override + public Long getValue() { + return data.getLong(); + } + }; + private final MapValueProvider<String> stringProvider = + new MapValueProvider<String>() { + @Override + public String getValue() { + return data.getString(); + } + }; + private final MapValueProvider<ByteString> bytesProvider = + new MapValueProvider<ByteString>() { + @Override + public ByteString getValue() { + return data.getBytes(); + } + }; + private final MapValueProvider<Boolean> booleanProvider = + new MapValueProvider<Boolean>() { + @Override + public Boolean getValue() { + return data.getBool(); + } + }; + private final MapValueProvider<Float> floatProvider = + new MapValueProvider<Float>() { + @Override + public Float getValue() { + return data.getFloat(); + } + }; + private final MapValueProvider<Double> doubleProvider = + new MapValueProvider<Double>() { + @Override + public Double getValue() { + return data.getDouble(); + } + }; + private final MapValueProvider<Proto3Message> messageProvider = + new MapValueProvider<Proto3Message>() { + @Override + public Proto3Message getValue() { + return newMessage(); + } + }; + private final MapValueProvider<Proto3Message.TestEnum> enumProvider = + new MapValueProvider<Proto3Message.TestEnum>() { + @Override + public Proto3Message.TestEnum getValue() { + return Proto3Message.TestEnum.forNumber(data.getEnum()); + } + }; + + private <V> Map<Integer, V> populateIntegerMap(MapValueProvider<V> provider) { + Map<Integer, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getInt(), provider.getValue()); + } + return map; + } + + private <V> Map<Long, V> populateLongMap(MapValueProvider<V> provider) { + Map<Long, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getLong(), provider.getValue()); + } + return map; + } + + private <V> Map<String, V> populateStringMap(MapValueProvider<V> provider) { + Map<String, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getString(), provider.getValue()); + } + return map; + } + + private <V> Map<Boolean, V> populateBooleanMap(MapValueProvider<V> provider) { + Map<Boolean, V> map = new HashMap<>(); + map.put(false, provider.getValue()); + map.put(true, provider.getValue()); + return map; + } + + public Proto3MessageWithMaps newMessageWithMaps() { + Proto3MessageWithMaps.Builder builder = Proto3MessageWithMaps.newBuilder(); + + builder.putAllFieldMapBoolBool1(populateBooleanMap(booleanProvider)); + builder.putAllFieldMapBoolBytes2(populateBooleanMap(bytesProvider)); + builder.putAllFieldMapBoolDouble3(populateBooleanMap(doubleProvider)); + builder.putAllFieldMapBoolEnum4(populateBooleanMap(enumProvider)); + builder.putAllFieldMapBoolFixed325(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolFixed646(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolFloat7(populateBooleanMap(floatProvider)); + builder.putAllFieldMapBoolInt328(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolInt649(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolMessage10(populateBooleanMap(messageProvider)); + builder.putAllFieldMapBoolSfixed3211(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolSfixed6412(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolSint3213(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolSint6414(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolString15(populateBooleanMap(stringProvider)); + builder.putAllFieldMapBoolUint3216(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolUint6417(populateBooleanMap(longProvider)); + builder.putAllFieldMapFixed32Bool18(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapFixed32Bytes19(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapFixed32Double20(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapFixed32Enum21(populateIntegerMap(enumProvider)); + builder.putAllFieldMapFixed32Fixed3222(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Fixed6423(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Float24(populateIntegerMap(floatProvider)); + builder.putAllFieldMapFixed32Int3225(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Int6426(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Message27(populateIntegerMap(messageProvider)); + builder.putAllFieldMapFixed32Sfixed3228(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Sfixed6429(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Sint3230(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Sint6431(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32String32(populateIntegerMap(stringProvider)); + builder.putAllFieldMapFixed32Uint3233(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Uint6434(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed64Bool35(populateLongMap(booleanProvider)); + builder.putAllFieldMapFixed64Bytes36(populateLongMap(bytesProvider)); + builder.putAllFieldMapFixed64Double37(populateLongMap(doubleProvider)); + builder.putAllFieldMapFixed64Enum38(populateLongMap(enumProvider)); + builder.putAllFieldMapFixed64Fixed3239(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Fixed6440(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Float41(populateLongMap(floatProvider)); + builder.putAllFieldMapFixed64Int3242(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Int6443(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Message44(populateLongMap(messageProvider)); + builder.putAllFieldMapFixed64Sfixed3245(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Sfixed6446(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Sint3247(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Sint6448(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64String49(populateLongMap(stringProvider)); + builder.putAllFieldMapFixed64Uint3250(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Uint6451(populateLongMap(longProvider)); + builder.putAllFieldMapInt32Bool52(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapInt32Bytes53(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapInt32Double54(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapInt32Enum55(populateIntegerMap(enumProvider)); + builder.putAllFieldMapInt32Fixed3256(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Fixed6457(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Float58(populateIntegerMap(floatProvider)); + builder.putAllFieldMapInt32Int3259(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Int6460(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Message61(populateIntegerMap(messageProvider)); + builder.putAllFieldMapInt32Sfixed3262(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Sfixed6463(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Sint3264(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Sint6465(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32String66(populateIntegerMap(stringProvider)); + builder.putAllFieldMapInt32Uint3267(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Uint6468(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt64Bool69(populateLongMap(booleanProvider)); + builder.putAllFieldMapInt64Bytes70(populateLongMap(bytesProvider)); + builder.putAllFieldMapInt64Double71(populateLongMap(doubleProvider)); + builder.putAllFieldMapInt64Enum72(populateLongMap(enumProvider)); + builder.putAllFieldMapInt64Fixed3273(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Fixed6474(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Float75(populateLongMap(floatProvider)); + builder.putAllFieldMapInt64Int3276(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Int6477(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Message78(populateLongMap(messageProvider)); + builder.putAllFieldMapInt64Sfixed3279(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Sfixed6480(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Sint3281(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Sint6482(populateLongMap(longProvider)); + builder.putAllFieldMapInt64String83(populateLongMap(stringProvider)); + builder.putAllFieldMapInt64Uint3284(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Uint6485(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed32Bool86(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapSfixed32Bytes87(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapSfixed32Double88(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapSfixed32Enum89(populateIntegerMap(enumProvider)); + builder.putAllFieldMapSfixed32Fixed3290(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Fixed6491(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Float92(populateIntegerMap(floatProvider)); + builder.putAllFieldMapSfixed32Int3293(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Int6494(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Message95(populateIntegerMap(messageProvider)); + builder.putAllFieldMapSfixed32Sfixed3296(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Sfixed6497(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Sint3298(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Sint6499(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32String100(populateIntegerMap(stringProvider)); + builder.putAllFieldMapSfixed32Uint32101(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Uint64102(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed64Bool103(populateLongMap(booleanProvider)); + builder.putAllFieldMapSfixed64Bytes104(populateLongMap(bytesProvider)); + builder.putAllFieldMapSfixed64Double105(populateLongMap(doubleProvider)); + builder.putAllFieldMapSfixed64Enum106(populateLongMap(enumProvider)); + builder.putAllFieldMapSfixed64Fixed32107(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Fixed64108(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Float109(populateLongMap(floatProvider)); + builder.putAllFieldMapSfixed64Int32110(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Int64111(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Message112(populateLongMap(messageProvider)); + builder.putAllFieldMapSfixed64Sfixed32113(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Sfixed64114(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Sint32115(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Sint64116(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64String117(populateLongMap(stringProvider)); + builder.putAllFieldMapSfixed64Uint32118(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Uint64119(populateLongMap(longProvider)); + builder.putAllFieldMapSint32Bool120(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapSint32Bytes121(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapSint32Double122(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapSint32Enum123(populateIntegerMap(enumProvider)); + builder.putAllFieldMapSint32Fixed32124(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Fixed64125(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Float126(populateIntegerMap(floatProvider)); + builder.putAllFieldMapSint32Int32127(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Int64128(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Message129(populateIntegerMap(messageProvider)); + builder.putAllFieldMapSint32Sfixed32130(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Sfixed64131(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Sint32132(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Sint64133(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32String134(populateIntegerMap(stringProvider)); + builder.putAllFieldMapSint32Uint32135(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Uint64136(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint64Bool137(populateLongMap(booleanProvider)); + builder.putAllFieldMapSint64Bytes138(populateLongMap(bytesProvider)); + builder.putAllFieldMapSint64Double139(populateLongMap(doubleProvider)); + builder.putAllFieldMapSint64Enum140(populateLongMap(enumProvider)); + builder.putAllFieldMapSint64Fixed32141(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Fixed64142(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Float143(populateLongMap(floatProvider)); + builder.putAllFieldMapSint64Int32144(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Int64145(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Message146(populateLongMap(messageProvider)); + builder.putAllFieldMapSint64Sfixed32147(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Sfixed64148(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Sint32149(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Sint64150(populateLongMap(longProvider)); + builder.putAllFieldMapSint64String151(populateLongMap(stringProvider)); + builder.putAllFieldMapSint64Uint32152(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Uint64153(populateLongMap(longProvider)); + builder.putAllFieldMapStringBool154(populateStringMap(booleanProvider)); + builder.putAllFieldMapStringBytes155(populateStringMap(bytesProvider)); + builder.putAllFieldMapStringDouble156(populateStringMap(doubleProvider)); + builder.putAllFieldMapStringEnum157(populateStringMap(enumProvider)); + builder.putAllFieldMapStringFixed32158(populateStringMap(integerProvider)); + builder.putAllFieldMapStringFixed64159(populateStringMap(longProvider)); + builder.putAllFieldMapStringFloat160(populateStringMap(floatProvider)); + builder.putAllFieldMapStringInt32161(populateStringMap(integerProvider)); + builder.putAllFieldMapStringInt64162(populateStringMap(longProvider)); + builder.putAllFieldMapStringMessage163(populateStringMap(messageProvider)); + builder.putAllFieldMapStringSfixed32164(populateStringMap(integerProvider)); + builder.putAllFieldMapStringSfixed64165(populateStringMap(longProvider)); + builder.putAllFieldMapStringSint32166(populateStringMap(integerProvider)); + builder.putAllFieldMapStringSint64167(populateStringMap(longProvider)); + builder.putAllFieldMapStringString168(populateStringMap(stringProvider)); + builder.putAllFieldMapStringUint32169(populateStringMap(integerProvider)); + builder.putAllFieldMapStringUint64170(populateStringMap(longProvider)); + builder.putAllFieldMapUint32Bool171(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapUint32Bytes172(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapUint32Double173(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapUint32Enum174(populateIntegerMap(enumProvider)); + builder.putAllFieldMapUint32Fixed32175(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Fixed64176(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Float177(populateIntegerMap(floatProvider)); + builder.putAllFieldMapUint32Int32178(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Int64179(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Message180(populateIntegerMap(messageProvider)); + builder.putAllFieldMapUint32Sfixed32181(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Sfixed64182(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Sint32183(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Sint64184(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32String185(populateIntegerMap(stringProvider)); + builder.putAllFieldMapUint32Uint32186(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Uint64187(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint64Bool188(populateLongMap(booleanProvider)); + builder.putAllFieldMapUint64Bytes189(populateLongMap(bytesProvider)); + builder.putAllFieldMapUint64Double190(populateLongMap(doubleProvider)); + builder.putAllFieldMapUint64Enum191(populateLongMap(enumProvider)); + builder.putAllFieldMapUint64Fixed32192(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Fixed64193(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Float194(populateLongMap(floatProvider)); + builder.putAllFieldMapUint64Int32195(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Int64196(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Message197(populateLongMap(messageProvider)); + builder.putAllFieldMapUint64Sfixed32198(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Sfixed64199(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Sint32200(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Sint64201(populateLongMap(longProvider)); + builder.putAllFieldMapUint64String202(populateLongMap(stringProvider)); + builder.putAllFieldMapUint64Uint32203(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Uint64204(populateLongMap(longProvider)); + + return builder.build(); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto3MessageInfoFactory.java b/java/core/src/test/java/com/google/protobuf/Proto3MessageInfoFactory.java new file mode 100755 index 000000000..364071b35 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto3MessageInfoFactory.java @@ -0,0 +1,506 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.FieldInfo.forField; +import static com.google.protobuf.FieldInfo.forMapField; +import static com.google.protobuf.FieldInfo.forOneofMemberField; +import static com.google.protobuf.FieldInfo.forRepeatedMessageField; + +import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithMaps; +import com.google.protobuf.testing.Proto3Testing.Proto3Empty; +import com.google.protobuf.testing.Proto3Testing.Proto3Message; +import com.google.protobuf.testing.Proto3Testing.Proto3MessageWithMaps; +import java.lang.reflect.Field; + +/** A factory that generates a hard-coded info for {@link Proto3Message}. */ +public final class Proto3MessageInfoFactory implements MessageInfoFactory { + private static final Proto3MessageInfoFactory INSTANCE = new Proto3MessageInfoFactory(); + + private Proto3MessageInfoFactory() {} + + public static Proto3MessageInfoFactory getInstance() { + return INSTANCE; + } + + @Override + public boolean isSupported(Class<?> clazz) { + return true; + } + + @Override + public MessageInfo messageInfoFor(Class<?> clazz) { + if (Proto3Message.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto3Message(); + } else if (Proto3Empty.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto3Empty(); + } else if (Proto3MessageWithMaps.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto3MessageWithMaps(); + } else { + throw new IllegalArgumentException("Unsupported class: " + clazz.getName()); + } + } + + /** + * Creates a new hard-coded info for {@link Proto3Message}. Each time this is called, we manually + * go through the entire process of what a message would do if it self-registered its own info, + * including looking up each field by name. This is done for benchmarking purposes, so that we get + * a more accurate representation of the time it takes to perform this process. + */ + private static StructuralMessageInfo newMessageInfoForProto3Message() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(48); + lookupFieldsByName(builder); + return builder.build(); + } + + private static void lookupFieldsByName(StructuralMessageInfo.Builder builder) { + builder.withDefaultInstance(Proto3Message.getDefaultInstance()); + builder.withSyntax(ProtoSyntax.PROTO3); + builder.withField(forField(field("fieldDouble1_"), 1, FieldType.DOUBLE, true)); + builder.withField(forField(field("fieldFloat2_"), 2, FieldType.FLOAT, true)); + builder.withField(forField(field("fieldInt643_"), 3, FieldType.INT64, true)); + builder.withField(forField(field("fieldUint644_"), 4, FieldType.UINT64, true)); + builder.withField(forField(field("fieldInt325_"), 5, FieldType.INT32, true)); + builder.withField(forField(field("fieldFixed646_"), 6, FieldType.FIXED64, true)); + builder.withField(forField(field("fieldFixed327_"), 7, FieldType.FIXED32, true)); + builder.withField(forField(field("fieldBool8_"), 8, FieldType.BOOL, true)); + builder.withField(forField(field("fieldString9_"), 9, FieldType.STRING, true)); + builder.withField(forField(field("fieldMessage10_"), 10, FieldType.MESSAGE, true)); + builder.withField(forField(field("fieldBytes11_"), 11, FieldType.BYTES, true)); + builder.withField(forField(field("fieldUint3212_"), 12, FieldType.UINT32, true)); + builder.withField(forField(field("fieldEnum13_"), 13, FieldType.ENUM, true)); + builder.withField(forField(field("fieldSfixed3214_"), 14, FieldType.SFIXED32, true)); + builder.withField(forField(field("fieldSfixed6415_"), 15, FieldType.SFIXED64, true)); + builder.withField(forField(field("fieldSint3216_"), 16, FieldType.SINT32, true)); + builder.withField(forField(field("fieldSint6417_"), 17, FieldType.SINT64, true)); + builder.withField(forField(field("fieldDoubleList18_"), 18, FieldType.DOUBLE_LIST, true)); + builder.withField(forField(field("fieldFloatList19_"), 19, FieldType.FLOAT_LIST, true)); + builder.withField(forField(field("fieldInt64List20_"), 20, FieldType.INT64_LIST, true)); + builder.withField(forField(field("fieldUint64List21_"), 21, FieldType.UINT64_LIST, true)); + builder.withField(forField(field("fieldInt32List22_"), 22, FieldType.INT32_LIST, true)); + builder.withField(forField(field("fieldFixed64List23_"), 23, FieldType.FIXED64_LIST, true)); + builder.withField(forField(field("fieldFixed32List24_"), 24, FieldType.FIXED32_LIST, true)); + builder.withField(forField(field("fieldBoolList25_"), 25, FieldType.BOOL_LIST, true)); + builder.withField(forField(field("fieldStringList26_"), 26, FieldType.STRING_LIST, true)); + builder.withField( + forRepeatedMessageField( + field("fieldMessageList27_"), 27, FieldType.MESSAGE_LIST, Proto3Message.class)); + builder.withField(forField(field("fieldBytesList28_"), 28, FieldType.BYTES_LIST, true)); + builder.withField(forField(field("fieldUint32List29_"), 29, FieldType.UINT32_LIST, true)); + builder.withField(forField(field("fieldEnumList30_"), 30, FieldType.ENUM_LIST, true)); + builder.withField(forField(field("fieldSfixed32List31_"), 31, FieldType.SFIXED32_LIST, true)); + builder.withField(forField(field("fieldSfixed64List32_"), 32, FieldType.SFIXED64_LIST, true)); + builder.withField(forField(field("fieldSint32List33_"), 33, FieldType.SINT32_LIST, true)); + builder.withField(forField(field("fieldSint64List34_"), 34, FieldType.SINT64_LIST, true)); + builder.withField( + forField(field("fieldDoubleListPacked35_"), 35, FieldType.DOUBLE_LIST_PACKED, true)); + builder.withField( + forField(field("fieldFloatListPacked36_"), 36, FieldType.FLOAT_LIST_PACKED, true)); + builder.withField( + forField(field("fieldInt64ListPacked37_"), 37, FieldType.INT64_LIST_PACKED, true)); + builder.withField( + forField(field("fieldUint64ListPacked38_"), 38, FieldType.UINT64_LIST_PACKED, true)); + builder.withField( + forField(field("fieldInt32ListPacked39_"), 39, FieldType.INT32_LIST_PACKED, true)); + builder.withField( + forField(field("fieldFixed64ListPacked40_"), 40, FieldType.FIXED64_LIST_PACKED, true)); + builder.withField( + forField(field("fieldFixed32ListPacked41_"), 41, FieldType.FIXED32_LIST_PACKED, true)); + builder.withField( + forField(field("fieldBoolListPacked42_"), 42, FieldType.BOOL_LIST_PACKED, true)); + builder.withField( + forField(field("fieldUint32ListPacked43_"), 43, FieldType.UINT32_LIST_PACKED, true)); + builder.withField( + forField(field("fieldEnumListPacked44_"), 44, FieldType.ENUM_LIST_PACKED, true)); + builder.withField( + forField(field("fieldSfixed32ListPacked45_"), 45, FieldType.SFIXED32_LIST_PACKED, true)); + builder.withField( + forField(field("fieldSfixed64ListPacked46_"), 46, FieldType.SFIXED64_LIST_PACKED, true)); + builder.withField( + forField(field("fieldSint32ListPacked47_"), 47, FieldType.SINT32_LIST_PACKED, true)); + builder.withField( + forField(field("fieldSint64ListPacked48_"), 48, FieldType.SINT64_LIST_PACKED, true)); + + OneofInfo oneof = new OneofInfo(0, field("testOneofCase_"), field("testOneof_")); + builder.withField(forOneofMemberField(53, FieldType.DOUBLE, oneof, Double.class, true, null)); + builder.withField(forOneofMemberField(54, FieldType.FLOAT, oneof, Float.class, true, null)); + builder.withField(forOneofMemberField(55, FieldType.INT64, oneof, Long.class, true, null)); + builder.withField(forOneofMemberField(56, FieldType.UINT64, oneof, Long.class, true, null)); + builder.withField(forOneofMemberField(57, FieldType.INT32, oneof, Integer.class, true, null)); + builder.withField(forOneofMemberField(58, FieldType.FIXED64, oneof, Long.class, true, null)); + builder.withField(forOneofMemberField(59, FieldType.FIXED32, oneof, Integer.class, true, null)); + builder.withField(forOneofMemberField(60, FieldType.BOOL, oneof, Boolean.class, true, null)); + builder.withField(forOneofMemberField(61, FieldType.STRING, oneof, String.class, true, null)); + builder.withField( + forOneofMemberField(62, FieldType.MESSAGE, oneof, Proto3Message.class, true, null)); + builder.withField( + forOneofMemberField(63, FieldType.BYTES, oneof, ByteString.class, true, null)); + builder.withField(forOneofMemberField(64, FieldType.UINT32, oneof, Integer.class, true, null)); + builder.withField( + forOneofMemberField(65, FieldType.SFIXED32, oneof, Integer.class, true, null)); + builder.withField(forOneofMemberField(66, FieldType.SFIXED64, oneof, Long.class, true, null)); + builder.withField(forOneofMemberField(67, FieldType.SINT32, oneof, Integer.class, true, null)); + builder.withField(forOneofMemberField(68, FieldType.SINT64, oneof, Long.class, true, null)); + } + + private StructuralMessageInfo newMessageInfoForProto3Empty() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO3); + return builder.build(); + } + + private StructuralMessageInfo newMessageInfoForProto3MessageWithMaps() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(); + builder.withSyntax(ProtoSyntax.PROTO3); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_bool_1", 1)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_bytes_2", 2)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_double_3", 3)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_enum_4", 4)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_fixed32_5", 5)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_fixed64_6", 6)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_float_7", 7)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_int32_8", 8)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_int64_9", 9)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_message_10", 10)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_sfixed32_11", 11)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_sfixed64_12", 12)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_sint32_13", 13)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_sint64_14", 14)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_string_15", 15)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_uint32_16", 16)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_uint64_17", 17)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_bool_18", 18)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_bytes_19", 19)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_double_20", 20)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_enum_21", 21)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_fixed32_22", 22)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_fixed64_23", 23)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_float_24", 24)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_int32_25", 25)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_int64_26", 26)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_message_27", 27)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_sfixed32_28", 28)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_sfixed64_29", 29)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_sint32_30", 30)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_sint64_31", 31)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_string_32", 32)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_uint32_33", 33)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_uint64_34", 34)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_bool_35", 35)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_bytes_36", 36)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_double_37", 37)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_enum_38", 38)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_fixed32_39", 39)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_fixed64_40", 40)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_float_41", 41)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_int32_42", 42)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_int64_43", 43)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_message_44", 44)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_sfixed32_45", 45)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_sfixed64_46", 46)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_sint32_47", 47)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_sint64_48", 48)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_string_49", 49)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_uint32_50", 50)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_uint64_51", 51)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_bool_52", 52)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_bytes_53", 53)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_double_54", 54)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_enum_55", 55)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_fixed32_56", 56)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_fixed64_57", 57)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_float_58", 58)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_int32_59", 59)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_int64_60", 60)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_message_61", 61)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_sfixed32_62", 62)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_sfixed64_63", 63)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_sint32_64", 64)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_sint64_65", 65)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_string_66", 66)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_uint32_67", 67)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_uint64_68", 68)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_bool_69", 69)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_bytes_70", 70)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_double_71", 71)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_enum_72", 72)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_fixed32_73", 73)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_fixed64_74", 74)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_float_75", 75)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_int32_76", 76)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_int64_77", 77)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_message_78", 78)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_sfixed32_79", 79)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_sfixed64_80", 80)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_sint32_81", 81)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_sint64_82", 82)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_string_83", 83)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_uint32_84", 84)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_uint64_85", 85)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_bool_86", 86)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_bytes_87", 87)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_double_88", 88)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_enum_89", 89)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_fixed32_90", 90)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_fixed64_91", 91)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_float_92", 92)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_int32_93", 93)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_int64_94", 94)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_message_95", 95)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_sfixed32_96", 96)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_sfixed64_97", 97)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_sint32_98", 98)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_sint64_99", 99)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_string_100", 100)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_uint32_101", 101)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_uint64_102", 102)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_bool_103", 103)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_bytes_104", 104)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_double_105", 105)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_enum_106", 106)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_fixed32_107", 107)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_fixed64_108", 108)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_float_109", 109)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_int32_110", 110)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_int64_111", 111)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_message_112", 112)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_sfixed32_113", 113)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_sfixed64_114", 114)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_sint32_115", 115)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_sint64_116", 116)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_string_117", 117)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_uint32_118", 118)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_uint64_119", 119)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_bool_120", 120)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_bytes_121", 121)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_double_122", 122)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_enum_123", 123)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_fixed32_124", 124)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_fixed64_125", 125)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_float_126", 126)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_int32_127", 127)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_int64_128", 128)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_message_129", 129)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_sfixed32_130", 130)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_sfixed64_131", 131)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_sint32_132", 132)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_sint64_133", 133)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_string_134", 134)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_uint32_135", 135)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_uint64_136", 136)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_bool_137", 137)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_bytes_138", 138)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_double_139", 139)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_enum_140", 140)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_fixed32_141", 141)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_fixed64_142", 142)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_float_143", 143)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_int32_144", 144)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_int64_145", 145)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_message_146", 146)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_sfixed32_147", 147)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_sfixed64_148", 148)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_sint32_149", 149)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_sint64_150", 150)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_string_151", 151)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_uint32_152", 152)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_uint64_153", 153)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_bool_154", 154)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_bytes_155", 155)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_double_156", 156)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_enum_157", 157)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_fixed32_158", 158)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_fixed64_159", 159)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_float_160", 160)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_int32_161", 161)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_int64_162", 162)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_message_163", 163)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_sfixed32_164", 164)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_sfixed64_165", 165)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_sint32_166", 166)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_sint64_167", 167)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_string_168", 168)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_uint32_169", 169)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_uint64_170", 170)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_bool_171", 171)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_bytes_172", 172)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_double_173", 173)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_enum_174", 174)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_fixed32_175", 175)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_fixed64_176", 176)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_float_177", 177)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_int32_178", 178)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_int64_179", 179)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_message_180", 180)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_sfixed32_181", 181)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_sfixed64_182", 182)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_sint32_183", 183)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_sint64_184", 184)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_string_185", 185)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_uint32_186", 186)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_uint64_187", 187)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_bool_188", 188)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_bytes_189", 189)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_double_190", 190)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_enum_191", 191)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_fixed32_192", 192)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_fixed64_193", 193)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_float_194", 194)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_int32_195", 195)); + builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_int64_196", 196)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_message_197", 197)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_sfixed32_198", 198)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_sfixed64_199", 199)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_sint32_200", 200)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_sint64_201", 201)); + builder.withField( + mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_string_202", 202)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_uint32_203", 203)); + builder.withField( + mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_uint64_204", 204)); + return builder.build(); + } + + private static Field field(String name) { + return field(Proto3Message.class, name); + } + + private static Field field(Class<?> clazz, String name) { + try { + return clazz.getDeclaredField(name); + } catch (NoSuchFieldException | SecurityException e) { + throw new RuntimeException(e); + } + } + + private static FieldInfo mapFieldInfo(Class<?> clazz, String fieldName, int fieldNumber) { + try { + return forMapField( + field(clazz, SchemaUtil.toCamelCase(fieldName, false) + "_"), + fieldNumber, + SchemaUtil.getMapDefaultEntry(clazz, fieldName), + null); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteFactory.java b/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteFactory.java new file mode 100755 index 000000000..2f6947da4 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteFactory.java @@ -0,0 +1,452 @@ +// 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.testing.Proto3TestingLite.Proto3MessageLite; +import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLiteWithMaps; +import java.util.HashMap; +import java.util.Map; + +/** Creates instances of {@link Proto3MessageLite} based on the tree configuration. */ +public final class Proto3MessageLiteFactory + implements ExperimentalMessageFactory<Proto3MessageLite> { + private final int numRepeatedFields; + private final int branchingFactor; + private final Proto3MessageLiteFactory nextLevel; + private final ExperimentalTestDataProvider data; + + public Proto3MessageLiteFactory( + int numRepeatedFields, int stringLength, int branchingFactor, int treeDepth) { + this( + new ExperimentalTestDataProvider(stringLength), + numRepeatedFields, + branchingFactor, + treeDepth); + } + + private Proto3MessageLiteFactory( + ExperimentalTestDataProvider data, + int numRepeatedFields, + int branchingFactor, + int treeDepth) { + this.numRepeatedFields = numRepeatedFields; + this.branchingFactor = branchingFactor; + this.data = data; + if (treeDepth > 0) { + nextLevel = + new Proto3MessageLiteFactory(data, numRepeatedFields, branchingFactor, treeDepth - 1); + } else { + nextLevel = null; + } + } + + @Override + public ExperimentalTestDataProvider dataProvider() { + return data; + } + + @Override + public Proto3MessageLite newMessage() { + Proto3MessageLite.Builder builder = Proto3MessageLite.newBuilder(); + builder.setFieldDouble1(data.getDouble()); + builder.setFieldFloat2(data.getFloat()); + builder.setFieldInt643(data.getLong()); + builder.setFieldUint644(data.getLong()); + builder.setFieldInt325(data.getInt()); + builder.setFieldFixed646(data.getLong()); + builder.setFieldFixed327(data.getInt()); + builder.setFieldBool8(data.getBool()); + builder.setFieldString9(data.getString()); + // We don't populate the message field. Instead we apply the branching factor to the + // repeated message field below. + builder.setFieldBytes11(data.getBytes()); + builder.setFieldUint3212(data.getInt()); + builder.setFieldEnum13Value(data.getEnum()); + builder.setFieldSfixed3214(data.getInt()); + builder.setFieldSfixed6415(data.getLong()); + builder.setFieldSint3216(data.getInt()); + builder.setFieldSint6417(data.getLong()); + + for (int i = 0; i < numRepeatedFields; ++i) { + builder.addFieldDoubleList18(data.getDouble()); + builder.addFieldFloatList19(data.getFloat()); + builder.addFieldInt64List20(data.getLong()); + builder.addFieldUint64List21(data.getLong()); + builder.addFieldInt32List22(data.getInt()); + builder.addFieldFixed64List23(data.getLong()); + builder.addFieldFixed32List24(data.getInt()); + builder.addFieldBoolList25(data.getBool()); + builder.addFieldStringList26(data.getString()); + // Repeated message field is controlled by the branching factor below. + builder.addFieldBytesList28(data.getBytes()); + builder.addFieldUint32List29(data.getInt()); + builder.addFieldEnumList30Value(data.getEnum()); + builder.addFieldSfixed32List31(data.getInt()); + builder.addFieldSfixed64List32(data.getLong()); + builder.addFieldSint32List33(data.getInt()); + builder.addFieldSint64List34(data.getLong()); + + builder.addFieldDoubleListPacked35(data.getDouble()); + builder.addFieldFloatListPacked36(data.getFloat()); + builder.addFieldInt64ListPacked37(data.getLong()); + builder.addFieldUint64ListPacked38(data.getLong()); + builder.addFieldInt32ListPacked39(data.getInt()); + builder.addFieldFixed64ListPacked40(data.getLong()); + builder.addFieldFixed32ListPacked41(data.getInt()); + builder.addFieldBoolListPacked42(data.getBool()); + builder.addFieldUint32ListPacked43(data.getInt()); + builder.addFieldEnumListPacked44Value(data.getEnum()); + builder.addFieldSfixed32ListPacked45(data.getInt()); + builder.addFieldSfixed64ListPacked46(data.getLong()); + builder.addFieldSint32ListPacked47(data.getInt()); + builder.addFieldSint64ListPacked48(data.getLong()); + } + + // Handle the branching factor. + if (nextLevel != null) { + for (int i = 0; i < branchingFactor; ++i) { + builder.addFieldMessageList27(nextLevel.newMessage()); + } + } + + return builder.build(); + } + + private interface MapValueProvider<T> { + public T getValue(); + } + + private final MapValueProvider<Integer> integerProvider = + new MapValueProvider<Integer>() { + @Override + public Integer getValue() { + return data.getInt(); + } + }; + private final MapValueProvider<Long> longProvider = + new MapValueProvider<Long>() { + @Override + public Long getValue() { + return data.getLong(); + } + }; + private final MapValueProvider<String> stringProvider = + new MapValueProvider<String>() { + @Override + public String getValue() { + return data.getString(); + } + }; + private final MapValueProvider<ByteString> bytesProvider = + new MapValueProvider<ByteString>() { + @Override + public ByteString getValue() { + return data.getBytes(); + } + }; + private final MapValueProvider<Boolean> booleanProvider = + new MapValueProvider<Boolean>() { + @Override + public Boolean getValue() { + return data.getBool(); + } + }; + private final MapValueProvider<Float> floatProvider = + new MapValueProvider<Float>() { + @Override + public Float getValue() { + return data.getFloat(); + } + }; + private final MapValueProvider<Double> doubleProvider = + new MapValueProvider<Double>() { + @Override + public Double getValue() { + return data.getDouble(); + } + }; + private final MapValueProvider<Proto3MessageLite> messageProvider = + new MapValueProvider<Proto3MessageLite>() { + @Override + public Proto3MessageLite getValue() { + return newMessage(); + } + }; + private final MapValueProvider<Proto3MessageLite.TestEnum> enumProvider = + new MapValueProvider<Proto3MessageLite.TestEnum>() { + @Override + public Proto3MessageLite.TestEnum getValue() { + return Proto3MessageLite.TestEnum.forNumber(data.getEnum()); + } + }; + + private <V> Map<Integer, V> populateIntegerMap(MapValueProvider<V> provider) { + Map<Integer, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getInt(), provider.getValue()); + } + return map; + } + + private <V> Map<Long, V> populateLongMap(MapValueProvider<V> provider) { + Map<Long, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getLong(), provider.getValue()); + } + return map; + } + + private <V> Map<String, V> populateStringMap(MapValueProvider<V> provider) { + Map<String, V> map = new HashMap<>(); + for (int i = 0; i < numRepeatedFields; ++i) { + map.put(data.getString(), provider.getValue()); + } + return map; + } + + private <V> Map<Boolean, V> populateBooleanMap(MapValueProvider<V> provider) { + Map<Boolean, V> map = new HashMap<>(); + map.put(false, provider.getValue()); + map.put(true, provider.getValue()); + return map; + } + + public Proto3MessageLiteWithMaps newMessageWithMaps() { + Proto3MessageLiteWithMaps.Builder builder = Proto3MessageLiteWithMaps.newBuilder(); + + builder.putAllFieldMapBoolBool1(populateBooleanMap(booleanProvider)); + builder.putAllFieldMapBoolBytes2(populateBooleanMap(bytesProvider)); + builder.putAllFieldMapBoolDouble3(populateBooleanMap(doubleProvider)); + builder.putAllFieldMapBoolEnum4(populateBooleanMap(enumProvider)); + builder.putAllFieldMapBoolFixed325(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolFixed646(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolFloat7(populateBooleanMap(floatProvider)); + builder.putAllFieldMapBoolInt328(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolInt649(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolMessage10(populateBooleanMap(messageProvider)); + builder.putAllFieldMapBoolSfixed3211(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolSfixed6412(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolSint3213(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolSint6414(populateBooleanMap(longProvider)); + builder.putAllFieldMapBoolString15(populateBooleanMap(stringProvider)); + builder.putAllFieldMapBoolUint3216(populateBooleanMap(integerProvider)); + builder.putAllFieldMapBoolUint6417(populateBooleanMap(longProvider)); + builder.putAllFieldMapFixed32Bool18(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapFixed32Bytes19(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapFixed32Double20(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapFixed32Enum21(populateIntegerMap(enumProvider)); + builder.putAllFieldMapFixed32Fixed3222(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Fixed6423(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Float24(populateIntegerMap(floatProvider)); + builder.putAllFieldMapFixed32Int3225(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Int6426(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Message27(populateIntegerMap(messageProvider)); + builder.putAllFieldMapFixed32Sfixed3228(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Sfixed6429(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32Sint3230(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Sint6431(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed32String32(populateIntegerMap(stringProvider)); + builder.putAllFieldMapFixed32Uint3233(populateIntegerMap(integerProvider)); + builder.putAllFieldMapFixed32Uint6434(populateIntegerMap(longProvider)); + builder.putAllFieldMapFixed64Bool35(populateLongMap(booleanProvider)); + builder.putAllFieldMapFixed64Bytes36(populateLongMap(bytesProvider)); + builder.putAllFieldMapFixed64Double37(populateLongMap(doubleProvider)); + builder.putAllFieldMapFixed64Enum38(populateLongMap(enumProvider)); + builder.putAllFieldMapFixed64Fixed3239(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Fixed6440(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Float41(populateLongMap(floatProvider)); + builder.putAllFieldMapFixed64Int3242(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Int6443(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Message44(populateLongMap(messageProvider)); + builder.putAllFieldMapFixed64Sfixed3245(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Sfixed6446(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64Sint3247(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Sint6448(populateLongMap(longProvider)); + builder.putAllFieldMapFixed64String49(populateLongMap(stringProvider)); + builder.putAllFieldMapFixed64Uint3250(populateLongMap(integerProvider)); + builder.putAllFieldMapFixed64Uint6451(populateLongMap(longProvider)); + builder.putAllFieldMapInt32Bool52(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapInt32Bytes53(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapInt32Double54(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapInt32Enum55(populateIntegerMap(enumProvider)); + builder.putAllFieldMapInt32Fixed3256(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Fixed6457(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Float58(populateIntegerMap(floatProvider)); + builder.putAllFieldMapInt32Int3259(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Int6460(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Message61(populateIntegerMap(messageProvider)); + builder.putAllFieldMapInt32Sfixed3262(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Sfixed6463(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32Sint3264(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Sint6465(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt32String66(populateIntegerMap(stringProvider)); + builder.putAllFieldMapInt32Uint3267(populateIntegerMap(integerProvider)); + builder.putAllFieldMapInt32Uint6468(populateIntegerMap(longProvider)); + builder.putAllFieldMapInt64Bool69(populateLongMap(booleanProvider)); + builder.putAllFieldMapInt64Bytes70(populateLongMap(bytesProvider)); + builder.putAllFieldMapInt64Double71(populateLongMap(doubleProvider)); + builder.putAllFieldMapInt64Enum72(populateLongMap(enumProvider)); + builder.putAllFieldMapInt64Fixed3273(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Fixed6474(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Float75(populateLongMap(floatProvider)); + builder.putAllFieldMapInt64Int3276(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Int6477(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Message78(populateLongMap(messageProvider)); + builder.putAllFieldMapInt64Sfixed3279(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Sfixed6480(populateLongMap(longProvider)); + builder.putAllFieldMapInt64Sint3281(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Sint6482(populateLongMap(longProvider)); + builder.putAllFieldMapInt64String83(populateLongMap(stringProvider)); + builder.putAllFieldMapInt64Uint3284(populateLongMap(integerProvider)); + builder.putAllFieldMapInt64Uint6485(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed32Bool86(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapSfixed32Bytes87(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapSfixed32Double88(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapSfixed32Enum89(populateIntegerMap(enumProvider)); + builder.putAllFieldMapSfixed32Fixed3290(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Fixed6491(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Float92(populateIntegerMap(floatProvider)); + builder.putAllFieldMapSfixed32Int3293(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Int6494(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Message95(populateIntegerMap(messageProvider)); + builder.putAllFieldMapSfixed32Sfixed3296(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Sfixed6497(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32Sint3298(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Sint6499(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed32String100(populateIntegerMap(stringProvider)); + builder.putAllFieldMapSfixed32Uint32101(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSfixed32Uint64102(populateIntegerMap(longProvider)); + builder.putAllFieldMapSfixed64Bool103(populateLongMap(booleanProvider)); + builder.putAllFieldMapSfixed64Bytes104(populateLongMap(bytesProvider)); + builder.putAllFieldMapSfixed64Double105(populateLongMap(doubleProvider)); + builder.putAllFieldMapSfixed64Enum106(populateLongMap(enumProvider)); + builder.putAllFieldMapSfixed64Fixed32107(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Fixed64108(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Float109(populateLongMap(floatProvider)); + builder.putAllFieldMapSfixed64Int32110(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Int64111(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Message112(populateLongMap(messageProvider)); + builder.putAllFieldMapSfixed64Sfixed32113(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Sfixed64114(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64Sint32115(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Sint64116(populateLongMap(longProvider)); + builder.putAllFieldMapSfixed64String117(populateLongMap(stringProvider)); + builder.putAllFieldMapSfixed64Uint32118(populateLongMap(integerProvider)); + builder.putAllFieldMapSfixed64Uint64119(populateLongMap(longProvider)); + builder.putAllFieldMapSint32Bool120(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapSint32Bytes121(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapSint32Double122(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapSint32Enum123(populateIntegerMap(enumProvider)); + builder.putAllFieldMapSint32Fixed32124(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Fixed64125(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Float126(populateIntegerMap(floatProvider)); + builder.putAllFieldMapSint32Int32127(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Int64128(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Message129(populateIntegerMap(messageProvider)); + builder.putAllFieldMapSint32Sfixed32130(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Sfixed64131(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32Sint32132(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Sint64133(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint32String134(populateIntegerMap(stringProvider)); + builder.putAllFieldMapSint32Uint32135(populateIntegerMap(integerProvider)); + builder.putAllFieldMapSint32Uint64136(populateIntegerMap(longProvider)); + builder.putAllFieldMapSint64Bool137(populateLongMap(booleanProvider)); + builder.putAllFieldMapSint64Bytes138(populateLongMap(bytesProvider)); + builder.putAllFieldMapSint64Double139(populateLongMap(doubleProvider)); + builder.putAllFieldMapSint64Enum140(populateLongMap(enumProvider)); + builder.putAllFieldMapSint64Fixed32141(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Fixed64142(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Float143(populateLongMap(floatProvider)); + builder.putAllFieldMapSint64Int32144(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Int64145(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Message146(populateLongMap(messageProvider)); + builder.putAllFieldMapSint64Sfixed32147(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Sfixed64148(populateLongMap(longProvider)); + builder.putAllFieldMapSint64Sint32149(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Sint64150(populateLongMap(longProvider)); + builder.putAllFieldMapSint64String151(populateLongMap(stringProvider)); + builder.putAllFieldMapSint64Uint32152(populateLongMap(integerProvider)); + builder.putAllFieldMapSint64Uint64153(populateLongMap(longProvider)); + builder.putAllFieldMapStringBool154(populateStringMap(booleanProvider)); + builder.putAllFieldMapStringBytes155(populateStringMap(bytesProvider)); + builder.putAllFieldMapStringDouble156(populateStringMap(doubleProvider)); + builder.putAllFieldMapStringEnum157(populateStringMap(enumProvider)); + builder.putAllFieldMapStringFixed32158(populateStringMap(integerProvider)); + builder.putAllFieldMapStringFixed64159(populateStringMap(longProvider)); + builder.putAllFieldMapStringFloat160(populateStringMap(floatProvider)); + builder.putAllFieldMapStringInt32161(populateStringMap(integerProvider)); + builder.putAllFieldMapStringInt64162(populateStringMap(longProvider)); + builder.putAllFieldMapStringMessage163(populateStringMap(messageProvider)); + builder.putAllFieldMapStringSfixed32164(populateStringMap(integerProvider)); + builder.putAllFieldMapStringSfixed64165(populateStringMap(longProvider)); + builder.putAllFieldMapStringSint32166(populateStringMap(integerProvider)); + builder.putAllFieldMapStringSint64167(populateStringMap(longProvider)); + builder.putAllFieldMapStringString168(populateStringMap(stringProvider)); + builder.putAllFieldMapStringUint32169(populateStringMap(integerProvider)); + builder.putAllFieldMapStringUint64170(populateStringMap(longProvider)); + builder.putAllFieldMapUint32Bool171(populateIntegerMap(booleanProvider)); + builder.putAllFieldMapUint32Bytes172(populateIntegerMap(bytesProvider)); + builder.putAllFieldMapUint32Double173(populateIntegerMap(doubleProvider)); + builder.putAllFieldMapUint32Enum174(populateIntegerMap(enumProvider)); + builder.putAllFieldMapUint32Fixed32175(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Fixed64176(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Float177(populateIntegerMap(floatProvider)); + builder.putAllFieldMapUint32Int32178(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Int64179(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Message180(populateIntegerMap(messageProvider)); + builder.putAllFieldMapUint32Sfixed32181(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Sfixed64182(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32Sint32183(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Sint64184(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint32String185(populateIntegerMap(stringProvider)); + builder.putAllFieldMapUint32Uint32186(populateIntegerMap(integerProvider)); + builder.putAllFieldMapUint32Uint64187(populateIntegerMap(longProvider)); + builder.putAllFieldMapUint64Bool188(populateLongMap(booleanProvider)); + builder.putAllFieldMapUint64Bytes189(populateLongMap(bytesProvider)); + builder.putAllFieldMapUint64Double190(populateLongMap(doubleProvider)); + builder.putAllFieldMapUint64Enum191(populateLongMap(enumProvider)); + builder.putAllFieldMapUint64Fixed32192(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Fixed64193(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Float194(populateLongMap(floatProvider)); + builder.putAllFieldMapUint64Int32195(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Int64196(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Message197(populateLongMap(messageProvider)); + builder.putAllFieldMapUint64Sfixed32198(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Sfixed64199(populateLongMap(longProvider)); + builder.putAllFieldMapUint64Sint32200(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Sint64201(populateLongMap(longProvider)); + builder.putAllFieldMapUint64String202(populateLongMap(stringProvider)); + builder.putAllFieldMapUint64Uint32203(populateLongMap(integerProvider)); + builder.putAllFieldMapUint64Uint64204(populateLongMap(longProvider)); + + return builder.build(); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java b/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java new file mode 100755 index 000000000..66e406af7 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java @@ -0,0 +1,816 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.FieldInfo.forField; +import static com.google.protobuf.FieldInfo.forMapField; +import static com.google.protobuf.FieldInfo.forOneofMemberField; +import static com.google.protobuf.FieldInfo.forRepeatedMessageField; + +import com.google.protobuf.testing.Proto3TestingLite.Proto3EmptyLite; +import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLite; +import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLiteWithMaps; +import java.lang.reflect.Field; + +/** A factory that generates a hard-coded info for {@link Proto3MessageLite}. */ +public final class Proto3MessageLiteInfoFactory implements MessageInfoFactory { + private static final Proto3MessageLiteInfoFactory instanceForRawMessageInfo = + new Proto3MessageLiteInfoFactory(true); + private static final Proto3MessageLiteInfoFactory instanceForStructuralMessageInfo = + new Proto3MessageLiteInfoFactory(false); + + public static Proto3MessageLiteInfoFactory getInstanceForRawMessageInfo() { + return instanceForRawMessageInfo; + } + + public static Proto3MessageLiteInfoFactory getInstanceForStructuralMessageInfo() { + return instanceForStructuralMessageInfo; + } + + private final boolean produceRawMessageInfo; + + private Proto3MessageLiteInfoFactory(boolean produceRawMessageInfo) { + this.produceRawMessageInfo = produceRawMessageInfo; + } + + @Override + public boolean isSupported(Class<?> clazz) { + return true; + } + + @Override + public MessageInfo messageInfoFor(Class<?> clazz) { + return produceRawMessageInfo ? rawMessageInfoFor(clazz) : structuralMessageInfoFor(clazz); + } + + private MessageInfo rawMessageInfoFor(Class<?> clazz) { + if (Proto3MessageLite.class.isAssignableFrom(clazz)) { + return newRawMessageInfoForProto3MessageLite(); + } else { + throw new IllegalArgumentException("Unsupported class: " + clazz.getName()); + } + } + + private MessageInfo newRawMessageInfoForProto3MessageLite() { + java.lang.Object[] objects = + new java.lang.Object[] { + "testOneof_", + "testOneofCase_", + "fieldDouble1_", + "fieldFloat2_", + "fieldInt643_", + "fieldUint644_", + "fieldInt325_", + "fieldFixed646_", + "fieldFixed327_", + "fieldBool8_", + "fieldString9_", + "fieldMessage10_", + "fieldBytes11_", + "fieldUint3212_", + "fieldEnum13_", + "fieldSfixed3214_", + "fieldSfixed6415_", + "fieldSint3216_", + "fieldSint6417_", + "fieldDoubleList18_", + "fieldFloatList19_", + "fieldInt64List20_", + "fieldUint64List21_", + "fieldInt32List22_", + "fieldFixed64List23_", + "fieldFixed32List24_", + "fieldBoolList25_", + "fieldStringList26_", + "fieldMessageList27_", + Proto3MessageLite.class, + "fieldBytesList28_", + "fieldUint32List29_", + "fieldEnumList30_", + "fieldSfixed32List31_", + "fieldSfixed64List32_", + "fieldSint32List33_", + "fieldSint64List34_", + "fieldDoubleListPacked35_", + "fieldFloatListPacked36_", + "fieldInt64ListPacked37_", + "fieldUint64ListPacked38_", + "fieldInt32ListPacked39_", + "fieldFixed64ListPacked40_", + "fieldFixed32ListPacked41_", + "fieldBoolListPacked42_", + "fieldUint32ListPacked43_", + "fieldEnumListPacked44_", + "fieldSfixed32ListPacked45_", + "fieldSfixed64ListPacked46_", + "fieldSint32ListPacked47_", + "fieldSint64ListPacked48_", + Proto3MessageLite.class, + }; + // To update this after a proto change, run protoc on proto3_message_lite.proto and copy over + // the content of the generated buildMessageInfo() method here. + java.lang.String info = + "\u0000@\u0001\u0000\u0001D@\u0000\u001f\u0000\u0001\u0000\u0002\u0001\u0003\u0002" + + "\u0004\u0003\u0005\u0004\u0006\u0005\u0007\u0006\b\u0007\t\u0208\n\t\u000b\n\f\u000b" + + "\r\f\u000e\r\u000f\u000e\u0010\u000f\u0011\u0010\u0012\u0012\u0013\u0013\u0014\u0014" + + "\u0015\u0015\u0016\u0016\u0017\u0017\u0018\u0018\u0019\u0019\u001a\u021a\u001b\u001b" + + "\u001c\u001c\u001d\u001d\u001e\u001e\u001f\u001f !!\"\"##$$%%&&\'\'(())**++,,--" + + "..//0053\u000064\u000075\u000086\u000097\u0000:8\u0000;9\u0000<:\u0000=\u023b\u0000" + + "><\u0000?=\u0000@>\u0000A@\u0000BA\u0000CB\u0000DC\u0000"; + return new RawMessageInfo(Proto3MessageLite.getDefaultInstance(), info, objects); + } + + private MessageInfo structuralMessageInfoFor(Class<?> clazz) { + if (Proto3MessageLite.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto3MessageLite(); + } else if (Proto3EmptyLite.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto3EmptyLite(); + } else if (Proto3MessageLiteWithMaps.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto3MessageLiteWithMaps(); + } else { + throw new IllegalArgumentException("Unsupported class: " + clazz.getName()); + } + } + + /** + * Creates a new hard-coded info for {@link Proto3MessageLite}. Each time this is called, we + * manually go through the entire process of what a message would do if it self-registered its own + * info, including looking up each field by name. This is done for benchmarking purposes, so that + * we get a more accurate representation of the time it takes to perform this process. + */ + private static StructuralMessageInfo newMessageInfoForProto3MessageLite() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(48); + lookupFieldsByName(builder); + return builder.build(); + } + + private static void lookupFieldsByName(StructuralMessageInfo.Builder builder) { + builder.withDefaultInstance(Proto3MessageLite.getDefaultInstance()); + builder.withSyntax(ProtoSyntax.PROTO3); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldDouble1_"), 1, FieldType.DOUBLE, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldFloat2_"), 2, FieldType.FLOAT, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldInt643_"), 3, FieldType.INT64, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldUint644_"), 4, FieldType.UINT64, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldInt325_"), 5, FieldType.INT32, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldFixed646_"), 6, FieldType.FIXED64, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldFixed327_"), 7, FieldType.FIXED32, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldBool8_"), 8, FieldType.BOOL, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldString9_"), 9, FieldType.STRING, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldMessage10_"), 10, FieldType.MESSAGE, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldBytes11_"), 11, FieldType.BYTES, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldUint3212_"), 12, FieldType.UINT32, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldEnum13_"), 13, FieldType.ENUM, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldSfixed3214_"), 14, FieldType.SFIXED32, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldSfixed6415_"), 15, FieldType.SFIXED64, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldSint3216_"), 16, FieldType.SINT32, true)); + builder.withField( + forField(field(Proto3MessageLite.class, "fieldSint6417_"), 17, FieldType.SINT64, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldDoubleList18_"), 18, FieldType.DOUBLE_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldFloatList19_"), 19, FieldType.FLOAT_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldInt64List20_"), 20, FieldType.INT64_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldUint64List21_"), 21, FieldType.UINT64_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldInt32List22_"), 22, FieldType.INT32_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldFixed64List23_"), + 23, + FieldType.FIXED64_LIST, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldFixed32List24_"), + 24, + FieldType.FIXED32_LIST, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldBoolList25_"), 25, FieldType.BOOL_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldStringList26_"), 26, FieldType.STRING_LIST, true)); + builder.withField( + forRepeatedMessageField( + field(Proto3MessageLite.class, "fieldMessageList27_"), + 27, + FieldType.MESSAGE_LIST, + Proto3MessageLite.class)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldBytesList28_"), 28, FieldType.BYTES_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldUint32List29_"), 29, FieldType.UINT32_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldEnumList30_"), 30, FieldType.ENUM_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldSfixed32List31_"), + 31, + FieldType.SFIXED32_LIST, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldSfixed64List32_"), + 32, + FieldType.SFIXED64_LIST, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldSint32List33_"), 33, FieldType.SINT32_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldSint64List34_"), 34, FieldType.SINT64_LIST, true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldDoubleListPacked35_"), + 35, + FieldType.DOUBLE_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldFloatListPacked36_"), + 36, + FieldType.FLOAT_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldInt64ListPacked37_"), + 37, + FieldType.INT64_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldUint64ListPacked38_"), + 38, + FieldType.UINT64_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldInt32ListPacked39_"), + 39, + FieldType.INT32_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldFixed64ListPacked40_"), + 40, + FieldType.FIXED64_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldFixed32ListPacked41_"), + 41, + FieldType.FIXED32_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldBoolListPacked42_"), + 42, + FieldType.BOOL_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldUint32ListPacked43_"), + 43, + FieldType.UINT32_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldEnumListPacked44_"), + 44, + FieldType.ENUM_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldSfixed32ListPacked45_"), + 45, + FieldType.SFIXED32_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldSfixed64ListPacked46_"), + 46, + FieldType.SFIXED64_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldSint32ListPacked47_"), + 47, + FieldType.SINT32_LIST_PACKED, + true)); + builder.withField( + forField( + field(Proto3MessageLite.class, "fieldSint64ListPacked48_"), + 48, + FieldType.SINT64_LIST_PACKED, + true)); + + OneofInfo oneof = + new OneofInfo( + 0, + field(Proto3MessageLite.class, "testOneofCase_"), + field(Proto3MessageLite.class, "testOneof_")); + builder.withField(forOneofMemberField(53, FieldType.DOUBLE, oneof, Double.class, true, null)); + builder.withField(forOneofMemberField(54, FieldType.FLOAT, oneof, Float.class, true, null)); + builder.withField(forOneofMemberField(55, FieldType.INT64, oneof, Long.class, true, null)); + builder.withField(forOneofMemberField(56, FieldType.UINT64, oneof, Long.class, true, null)); + builder.withField(forOneofMemberField(57, FieldType.INT32, oneof, Integer.class, true, null)); + builder.withField(forOneofMemberField(58, FieldType.FIXED64, oneof, Long.class, true, null)); + builder.withField(forOneofMemberField(59, FieldType.FIXED32, oneof, Integer.class, true, null)); + builder.withField(forOneofMemberField(60, FieldType.BOOL, oneof, Boolean.class, true, null)); + builder.withField(forOneofMemberField(61, FieldType.STRING, oneof, String.class, true, null)); + builder.withField( + forOneofMemberField(62, FieldType.MESSAGE, oneof, Proto3MessageLite.class, true, null)); + builder.withField( + forOneofMemberField(63, FieldType.BYTES, oneof, ByteString.class, true, null)); + builder.withField(forOneofMemberField(64, FieldType.UINT32, oneof, Integer.class, true, null)); + builder.withField( + forOneofMemberField(65, FieldType.SFIXED32, oneof, Integer.class, true, null)); + builder.withField(forOneofMemberField(66, FieldType.SFIXED64, oneof, Long.class, true, null)); + builder.withField(forOneofMemberField(67, FieldType.SINT32, oneof, Integer.class, true, null)); + builder.withField(forOneofMemberField(68, FieldType.SINT64, oneof, Long.class, true, null)); + } + + private StructuralMessageInfo newMessageInfoForProto3EmptyLite() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO3); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForProto3MessageLiteWithMaps() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(); + builder.withSyntax(ProtoSyntax.PROTO2); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_bool_1", 1)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_bytes_2", 2)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_double_3", 3)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_enum_4", 4)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_fixed32_5", 5)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_fixed64_6", 6)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_float_7", 7)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_int32_8", 8)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_int64_9", 9)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_message_10", 10)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_sfixed32_11", 11)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_sfixed64_12", 12)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_sint32_13", 13)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_sint64_14", 14)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_string_15", 15)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_uint32_16", 16)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_uint64_17", 17)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_bool_18", 18)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_bytes_19", 19)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_double_20", 20)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_enum_21", 21)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_fixed32_22", 22)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_fixed64_23", 23)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_float_24", 24)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_int32_25", 25)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_int64_26", 26)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_message_27", 27)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_sfixed32_28", 28)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_sfixed64_29", 29)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_sint32_30", 30)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_sint64_31", 31)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_string_32", 32)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_uint32_33", 33)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_uint64_34", 34)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_bool_35", 35)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_bytes_36", 36)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_double_37", 37)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_enum_38", 38)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_fixed32_39", 39)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_fixed64_40", 40)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_float_41", 41)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_int32_42", 42)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_int64_43", 43)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_message_44", 44)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_sfixed32_45", 45)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_sfixed64_46", 46)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_sint32_47", 47)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_sint64_48", 48)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_string_49", 49)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_uint32_50", 50)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_uint64_51", 51)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_bool_52", 52)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_bytes_53", 53)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_double_54", 54)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_enum_55", 55)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_fixed32_56", 56)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_fixed64_57", 57)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_float_58", 58)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_int32_59", 59)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_int64_60", 60)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_message_61", 61)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_sfixed32_62", 62)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_sfixed64_63", 63)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_sint32_64", 64)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_sint64_65", 65)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_string_66", 66)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_uint32_67", 67)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_uint64_68", 68)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_bool_69", 69)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_bytes_70", 70)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_double_71", 71)); + builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_enum_72", 72)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_fixed32_73", 73)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_fixed64_74", 74)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_float_75", 75)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_int32_76", 76)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_int64_77", 77)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_message_78", 78)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_sfixed32_79", 79)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_sfixed64_80", 80)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_sint32_81", 81)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_sint64_82", 82)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_string_83", 83)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_uint32_84", 84)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_uint64_85", 85)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_bool_86", 86)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_bytes_87", 87)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_double_88", 88)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_enum_89", 89)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_fixed32_90", 90)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_fixed64_91", 91)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_float_92", 92)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_int32_93", 93)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_int64_94", 94)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_message_95", 95)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_sfixed32_96", 96)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_sfixed64_97", 97)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_sint32_98", 98)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_sint64_99", 99)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_string_100", 100)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_uint32_101", 101)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_uint64_102", 102)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_bool_103", 103)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_bytes_104", 104)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_double_105", 105)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_enum_106", 106)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_fixed32_107", 107)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_fixed64_108", 108)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_float_109", 109)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_int32_110", 110)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_int64_111", 111)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_message_112", 112)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_sfixed32_113", 113)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_sfixed64_114", 114)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_sint32_115", 115)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_sint64_116", 116)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_string_117", 117)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_uint32_118", 118)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_uint64_119", 119)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_bool_120", 120)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_bytes_121", 121)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_double_122", 122)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_enum_123", 123)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_fixed32_124", 124)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_fixed64_125", 125)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_float_126", 126)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_int32_127", 127)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_int64_128", 128)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_message_129", 129)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_sfixed32_130", 130)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_sfixed64_131", 131)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_sint32_132", 132)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_sint64_133", 133)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_string_134", 134)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_uint32_135", 135)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_uint64_136", 136)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_bool_137", 137)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_bytes_138", 138)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_double_139", 139)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_enum_140", 140)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_fixed32_141", 141)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_fixed64_142", 142)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_float_143", 143)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_int32_144", 144)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_int64_145", 145)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_message_146", 146)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_sfixed32_147", 147)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_sfixed64_148", 148)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_sint32_149", 149)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_sint64_150", 150)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_string_151", 151)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_uint32_152", 152)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_uint64_153", 153)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_bool_154", 154)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_bytes_155", 155)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_double_156", 156)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_enum_157", 157)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_fixed32_158", 158)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_fixed64_159", 159)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_float_160", 160)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_int32_161", 161)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_int64_162", 162)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_message_163", 163)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_sfixed32_164", 164)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_sfixed64_165", 165)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_sint32_166", 166)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_sint64_167", 167)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_string_168", 168)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_uint32_169", 169)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_uint64_170", 170)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_bool_171", 171)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_bytes_172", 172)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_double_173", 173)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_enum_174", 174)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_fixed32_175", 175)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_fixed64_176", 176)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_float_177", 177)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_int32_178", 178)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_int64_179", 179)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_message_180", 180)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_sfixed32_181", 181)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_sfixed64_182", 182)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_sint32_183", 183)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_sint64_184", 184)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_string_185", 185)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_uint32_186", 186)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_uint64_187", 187)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_bool_188", 188)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_bytes_189", 189)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_double_190", 190)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_enum_191", 191)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_fixed32_192", 192)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_fixed64_193", 193)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_float_194", 194)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_int32_195", 195)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_int64_196", 196)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_message_197", 197)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_sfixed32_198", 198)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_sfixed64_199", 199)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_sint32_200", 200)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_sint64_201", 201)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_string_202", 202)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_uint32_203", 203)); + builder.withField( + mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_uint64_204", 204)); + + return builder.build(); + } + + private static Field field(Class<?> clazz, String name) { + try { + return clazz.getDeclaredField(name); + } catch (NoSuchFieldException | SecurityException e) { + throw new RuntimeException(e); + } + } + + private static FieldInfo mapFieldInfo(Class<?> clazz, String fieldName, int fieldNumber) { + try { + return forMapField( + field(clazz, SchemaUtil.toCamelCase(fieldName, false) + "_"), + fieldNumber, + SchemaUtil.getMapDefaultEntry(clazz, fieldName), + null); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Proto3SchemaTest.java b/java/core/src/test/java/com/google/protobuf/Proto3SchemaTest.java new file mode 100755 index 000000000..5cd145be7 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Proto3SchemaTest.java @@ -0,0 +1,48 @@ +// 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.testing.Proto3Testing.Proto3Message; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Proto3SchemaTest extends AbstractProto3SchemaTest { + @Override + protected void registerSchemas() { + TestSchemas.registerGenericProto3Schemas(); + } + + @Override + protected Schema<Proto3Message> schema() { + return TestSchemas.genericProto3Schema; + } +} diff --git a/java/core/src/test/java/com/google/protobuf/TestSchemas.java b/java/core/src/test/java/com/google/protobuf/TestSchemas.java new file mode 100755 index 000000000..ab0ced4cd --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/TestSchemas.java @@ -0,0 +1,94 @@ +// 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.testing.Proto2Testing; +import com.google.protobuf.testing.Proto2Testing.Proto2Empty; +import com.google.protobuf.testing.Proto2Testing.Proto2Message; +import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithExtensions; +import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithMaps; +import com.google.protobuf.testing.Proto3Testing.Proto3Empty; +import com.google.protobuf.testing.Proto3Testing.Proto3Message; +import com.google.protobuf.testing.Proto3Testing.Proto3MessageWithMaps; + +/** Schemas to support testing. */ +public class TestSchemas { + public static final Schema<Proto2Message> genericProto2Schema = + new ManifestSchemaFactory().createSchema(Proto2Message.class); + public static final Schema<Proto3Message> genericProto3Schema = + new ManifestSchemaFactory().createSchema(Proto3Message.class); + + public static void registerGenericProto2Schemas() { + registerProto2Schemas(); + } + + public static void registerGenericProto3Schemas() { + registerProto3Schemas(); + } + + private static void registerProto2Schemas() { + Protobuf protobuf = Protobuf.getInstance(); + ManifestSchemaFactory factory = new ManifestSchemaFactory(); + protobuf.registerSchemaOverride(Proto2Message.class, factory.createSchema(Proto2Message.class)); + protobuf.registerSchemaOverride( + Proto2Message.FieldGroup49.class, factory.createSchema(Proto2Message.FieldGroup49.class)); + protobuf.registerSchemaOverride( + Proto2Message.FieldGroupList51.class, + factory.createSchema(Proto2Message.FieldGroupList51.class)); + protobuf.registerSchemaOverride( + Proto2Message.FieldGroup69.class, factory.createSchema(Proto2Message.FieldGroup69.class)); + protobuf.registerSchemaOverride( + Proto2Message.RequiredNestedMessage.class, + factory.createSchema(Proto2Message.RequiredNestedMessage.class)); + protobuf.registerSchemaOverride( + Proto2Message.FieldRequiredGroup88.class, + factory.createSchema(Proto2Message.FieldRequiredGroup88.class)); + protobuf.registerSchemaOverride(Proto2Empty.class, factory.createSchema(Proto2Empty.class)); + protobuf.registerSchemaOverride( + Proto2MessageWithExtensions.class, factory.createSchema(Proto2MessageWithExtensions.class)); + protobuf.registerSchemaOverride( + Proto2Testing.FieldGroup49.class, factory.createSchema(Proto2Testing.FieldGroup49.class)); + protobuf.registerSchemaOverride( + Proto2Testing.FieldGroupList51.class, + factory.createSchema(Proto2Testing.FieldGroupList51.class)); + protobuf.registerSchemaOverride( + Proto2MessageWithMaps.class, factory.createSchema(Proto2MessageWithMaps.class)); + } + + private static void registerProto3Schemas() { + Protobuf protobuf = Protobuf.getInstance(); + ManifestSchemaFactory factory = new ManifestSchemaFactory(); + protobuf.registerSchemaOverride(Proto3Message.class, factory.createSchema(Proto3Message.class)); + protobuf.registerSchemaOverride(Proto3Empty.class, factory.createSchema(Proto3Empty.class)); + protobuf.registerSchemaOverride( + Proto3MessageWithMaps.class, factory.createSchema(Proto3MessageWithMaps.class)); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/TestSchemasLite.java b/java/core/src/test/java/com/google/protobuf/TestSchemasLite.java new file mode 100755 index 000000000..28a89d72a --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/TestSchemasLite.java @@ -0,0 +1,103 @@ +// 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.testing.Proto2TestingLite; +import com.google.protobuf.testing.Proto2TestingLite.Proto2EmptyLite; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLiteWithExtensions; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLiteWithMaps; +import com.google.protobuf.testing.Proto3TestingLite.Proto3EmptyLite; +import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLite; +import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLiteWithMaps; + +/** Schemas to support testing. */ +public final class TestSchemasLite { + + public static final Schema<Proto2MessageLite> genericProto2LiteSchema = + new ManifestSchemaFactory().createSchema(Proto2MessageLite.class); + public static final Schema<Proto3MessageLite> genericProto3LiteSchema = + new ManifestSchemaFactory().createSchema(Proto3MessageLite.class); + + public static void registerGenericProto2LiteSchemas() { + registerProto2LiteSchemas(); + } + + public static void registerGenericProto3LiteSchemas() { + registerProto3LiteSchemas(); + } + + private static void registerProto2LiteSchemas() { + Protobuf protobuf = Protobuf.getInstance(); + ManifestSchemaFactory factory = new ManifestSchemaFactory(); + protobuf.registerSchemaOverride( + Proto2MessageLite.class, factory.createSchema(Proto2MessageLite.class)); + protobuf.registerSchemaOverride( + Proto2MessageLite.FieldGroup49.class, + factory.createSchema(Proto2MessageLite.FieldGroup49.class)); + protobuf.registerSchemaOverride( + Proto2MessageLite.FieldGroupList51.class, + factory.createSchema(Proto2MessageLite.FieldGroupList51.class)); + protobuf.registerSchemaOverride( + Proto2MessageLite.FieldGroup69.class, + factory.createSchema(Proto2MessageLite.FieldGroup69.class)); + protobuf.registerSchemaOverride( + Proto2MessageLite.RequiredNestedMessage.class, + factory.createSchema(Proto2MessageLite.RequiredNestedMessage.class)); + protobuf.registerSchemaOverride( + Proto2MessageLite.FieldRequiredGroup88.class, + factory.createSchema(Proto2MessageLite.FieldRequiredGroup88.class)); + protobuf.registerSchemaOverride( + Proto2EmptyLite.class, factory.createSchema(Proto2EmptyLite.class)); + protobuf.registerSchemaOverride( + Proto2MessageLiteWithExtensions.class, + factory.createSchema(Proto2MessageLiteWithExtensions.class)); + protobuf.registerSchemaOverride( + Proto2TestingLite.FieldGroup49.class, + factory.createSchema(Proto2TestingLite.FieldGroup49.class)); + protobuf.registerSchemaOverride( + Proto2TestingLite.FieldGroupList51.class, + factory.createSchema(Proto2TestingLite.FieldGroupList51.class)); + protobuf.registerSchemaOverride( + Proto2MessageLiteWithMaps.class, factory.createSchema(Proto2MessageLiteWithMaps.class)); + } + + private static void registerProto3LiteSchemas() { + Protobuf protobuf = Protobuf.getInstance(); + ManifestSchemaFactory factory = new ManifestSchemaFactory(); + protobuf.registerSchemaOverride( + Proto3MessageLite.class, factory.createSchema(Proto3MessageLite.class)); + protobuf.registerSchemaOverride( + Proto3EmptyLite.class, factory.createSchema(Proto3EmptyLite.class)); + protobuf.registerSchemaOverride( + Proto3MessageLiteWithMaps.class, factory.createSchema(Proto3MessageLiteWithMaps.class)); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java index 2fad0b957..3ed124348 100644 --- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java @@ -132,6 +132,9 @@ public class TextFormatTest extends TestCase { + " i: 456\n" + "}\n"; + private final TextFormat.Parser parserAllowingUnknownFields = + TextFormat.Parser.newBuilder().setAllowUnknownFields(true).build(); + private final TextFormat.Parser parserAllowingUnknownExtensions = TextFormat.Parser.newBuilder().setAllowUnknownExtensions(true).build(); @@ -502,6 +505,7 @@ public class TextFormatTest extends TestCase { assertEquals(2, builder.getOptionalInt64()); } + private void assertParseError(String error, String text) { // Test merge(). TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -521,6 +525,22 @@ public class TextFormatTest extends TestCase { } } + private void assertParseErrorWithUnknownFields(String error, String text) { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + try { + parserAllowingUnknownFields.merge(text, TestUtil.getFullExtensionRegistry(), builder); + fail("Expected parse exception."); + } catch (TextFormat.ParseException e) { + assertEquals(error, e.getMessage()); + } + } + + private TestAllTypes assertParseSuccessWithUnknownFields(String text) + throws TextFormat.ParseException { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + parserAllowingUnknownFields.merge(text, TestUtil.getFullExtensionRegistry(), builder); + return builder.build(); + } private void assertParseErrorWithUnknownExtensions(String error, String text) { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -1223,6 +1243,7 @@ public class TextFormatTest extends TestCase { // Set to allow unknown fields TextFormat.Parser parser = TextFormat.Parser.newBuilder() + .setAllowUnknownFields(true) .setParseInfoTreeBuilder(treeBuilder) .build(); diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java deleted file mode 100644 index a947d271b..000000000 --- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java +++ /dev/null @@ -1,601 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package com.google.protobuf; - -import static junit.framework.TestCase.assertEquals; - -import com.google.protobuf.UnittestLite.TestAllExtensionsLite; -import com.google.protobuf.UnittestLite.TestAllTypesLite; -import protobuf_unittest.UnittestProto; -import protobuf_unittest.UnittestProto.ForeignEnum; -import protobuf_unittest.UnittestProto.TestAllExtensions; -import protobuf_unittest.UnittestProto.TestAllTypes; -import protobuf_unittest.UnittestProto.TestEmptyMessage; -import protobuf_unittest.UnittestProto.TestPackedExtensions; -import protobuf_unittest.UnittestProto.TestPackedTypes; -import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash; -import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; -import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.Map; -import junit.framework.TestCase; - -/** - * Tests for {@link UnknownFieldSetLite}. - * - * @author dweis@google.com (Daniel Weis) - */ -public class UnknownFieldSetLiteTest extends TestCase { - @Override - public void setUp() throws Exception { - allFields = TestUtil.getAllSet(); - allFieldsData = allFields.toByteString(); - emptyMessage = TestEmptyMessage.parseFrom(allFieldsData); - unknownFields = emptyMessage.getUnknownFields(); - } - - TestAllTypes allFields; - ByteString allFieldsData; - - // Constructs a protocol buffer which contains fields with all the same - // numbers as allFieldsData except that each field is some other wire - // type. - private ByteString getBizarroData() throws Exception { - UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder(); - - UnknownFieldSet.Field varintField = UnknownFieldSet.Field.newBuilder().addVarint(1).build(); - UnknownFieldSet.Field fixed32Field = UnknownFieldSet.Field.newBuilder().addFixed32(1).build(); - - for (Map.Entry<Integer, UnknownFieldSet.Field> entry : unknownFields.asMap().entrySet()) { - if (entry.getValue().getVarintList().isEmpty()) { - // Original field is not a varint, so use a varint. - bizarroFields.addField(entry.getKey(), varintField); - } else { - // Original field *is* a varint, so use something else. - bizarroFields.addField(entry.getKey(), fixed32Field); - } - } - - return bizarroFields.build().toByteString(); - } - - // An empty message that has been parsed from allFieldsData. So, it has - // unknown fields of every type. - TestEmptyMessage emptyMessage; - UnknownFieldSet unknownFields; - - public void testDefaultInstance() { - UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance(); - - assertEquals(0, unknownFields.getSerializedSize()); - assertEquals(ByteString.EMPTY, toByteString(unknownFields)); - } - - public void testEmptyInstance() { - UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); - - assertEquals(0, instance.getSerializedSize()); - assertEquals(ByteString.EMPTY, toByteString(instance)); - assertEquals(UnknownFieldSetLite.getDefaultInstance(), instance); - } - - public void testMergeFieldFrom() throws IOException { - Foo foo = Foo.newBuilder().setValue(2).build(); - - CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); - - UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); - instance.mergeFieldFrom(input.readTag(), input); - - assertEquals(foo.toByteString(), toByteString(instance)); - } - - public void testSerializedSize() throws IOException { - Foo foo = Foo.newBuilder().setValue(2).build(); - - CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); - - UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); - instance.mergeFieldFrom(input.readTag(), input); - - assertEquals(foo.toByteString().size(), instance.getSerializedSize()); - } - - public void testHashCodeAfterDeserialization() throws IOException { - Foo foo = Foo.newBuilder().setValue(2).build(); - - Foo fooDeserialized = Foo.parseFrom(foo.toByteArray()); - - assertEquals(fooDeserialized, foo); - assertEquals(foo.hashCode(), fooDeserialized.hashCode()); - } - - public void testNewInstanceHashCode() { - UnknownFieldSetLite emptyFieldSet = UnknownFieldSetLite.getDefaultInstance(); - UnknownFieldSetLite paddedFieldSet = UnknownFieldSetLite.newInstance(); - - assertEquals(emptyFieldSet, paddedFieldSet); - assertEquals(emptyFieldSet.hashCode(), paddedFieldSet.hashCode()); - } - - public void testMergeVarintField() throws IOException { - UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); - unknownFields.mergeVarintField(10, 2); - - CodedInputStream input = - CodedInputStream.newInstance(toByteString(unknownFields).toByteArray()); - - int tag = input.readTag(); - assertEquals(10, WireFormat.getTagFieldNumber(tag)); - assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); - assertEquals(2, input.readUInt64()); - assertTrue(input.isAtEnd()); - } - - public void testMergeVarintField_negative() throws IOException { - UnknownFieldSetLite builder = UnknownFieldSetLite.newInstance(); - builder.mergeVarintField(10, -6); - - CodedInputStream input = CodedInputStream.newInstance(toByteString(builder).toByteArray()); - - int tag = input.readTag(); - assertEquals(10, WireFormat.getTagFieldNumber(tag)); - assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); - assertEquals(-6, input.readUInt64()); - assertTrue(input.isAtEnd()); - } - - public void testEqualsAndHashCode() { - UnknownFieldSetLite unknownFields1 = UnknownFieldSetLite.newInstance(); - unknownFields1.mergeVarintField(10, 2); - - UnknownFieldSetLite unknownFields2 = UnknownFieldSetLite.newInstance(); - unknownFields2.mergeVarintField(10, 2); - - assertEquals(unknownFields1, unknownFields2); - assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode()); - assertFalse(unknownFields1.equals(UnknownFieldSetLite.getDefaultInstance())); - assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode()); - } - - public void testMutableCopyOf() throws IOException { - UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); - unknownFields.mergeVarintField(10, 2); - unknownFields = UnknownFieldSetLite.mutableCopyOf(unknownFields, unknownFields); - unknownFields.checkMutable(); - - CodedInputStream input = - CodedInputStream.newInstance(toByteString(unknownFields).toByteArray()); - - int tag = input.readTag(); - assertEquals(10, WireFormat.getTagFieldNumber(tag)); - assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); - assertEquals(2, input.readUInt64()); - assertFalse(input.isAtEnd()); - input.readTag(); - assertEquals(10, WireFormat.getTagFieldNumber(tag)); - assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); - assertEquals(2, input.readUInt64()); - assertTrue(input.isAtEnd()); - } - - public void testMutableCopyOf_empty() { - UnknownFieldSetLite unknownFields = - UnknownFieldSetLite.mutableCopyOf( - UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance()); - unknownFields.checkMutable(); - - assertEquals(0, unknownFields.getSerializedSize()); - assertEquals(ByteString.EMPTY, toByteString(unknownFields)); - } - - public void testRoundTrips() throws InvalidProtocolBufferException { - Foo foo = - Foo.newBuilder() - .setValue(1) - .setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build()) - .setExtension(LiteEqualsAndHash.varint, 22) - .setExtension(LiteEqualsAndHash.fixed32, 44) - .setExtension(LiteEqualsAndHash.fixed64, 66L) - .setExtension( - LiteEqualsAndHash.myGroup, - LiteEqualsAndHash.MyGroup.newBuilder().setGroupValue("value").build()) - .build(); - - Foo copy = Foo.parseFrom(foo.toByteArray()); - - assertEquals(foo.getSerializedSize(), copy.getSerializedSize()); - assertFalse(foo.equals(copy)); - - Foo secondCopy = Foo.parseFrom(foo.toByteArray()); - assertEquals(copy, secondCopy); - - ExtensionRegistryLite extensionRegistry = ExtensionRegistryLite.newInstance(); - LiteEqualsAndHash.registerAllExtensions(extensionRegistry); - Foo copyOfCopy = Foo.parseFrom(copy.toByteArray(), extensionRegistry); - - assertEquals(foo, copyOfCopy); - } - - public void testMalformedBytes() throws Exception { - try { - Foo.parseFrom("this is a malformed protocol buffer".getBytes(Internal.UTF_8)); - fail(); - } catch (InvalidProtocolBufferException e) { - // Expected. - } - } - - public void testMissingStartGroupTag() throws IOException { - ByteString.Output byteStringOutput = ByteString.newOutput(); - CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); - output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); - output.writeTag(100, WireFormat.WIRETYPE_END_GROUP); - output.flush(); - - try { - Foo.parseFrom(byteStringOutput.toByteString()); - fail(); - } catch (InvalidProtocolBufferException e) { - // Expected. - } - } - - public void testMissingEndGroupTag() throws IOException { - ByteString.Output byteStringOutput = ByteString.newOutput(); - CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); - output.writeTag(100, WireFormat.WIRETYPE_START_GROUP); - output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); - output.flush(); - - try { - Foo.parseFrom(byteStringOutput.toByteString()); - fail(); - } catch (InvalidProtocolBufferException e) { - // Expected. - } - } - - public void testMismatchingGroupTags() throws IOException { - ByteString.Output byteStringOutput = ByteString.newOutput(); - CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); - output.writeTag(100, WireFormat.WIRETYPE_START_GROUP); - output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); - output.writeTag(101, WireFormat.WIRETYPE_END_GROUP); - output.flush(); - - try { - Foo.parseFrom(byteStringOutput.toByteString()); - fail(); - } catch (InvalidProtocolBufferException e) { - // Expected. - } - } - - public void testTruncatedInput() { - Foo foo = - Foo.newBuilder() - .setValue(1) - .setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build()) - .setExtension(LiteEqualsAndHash.varint, 22) - .setExtension( - LiteEqualsAndHash.myGroup, - LiteEqualsAndHash.MyGroup.newBuilder().setGroupValue("value").build()) - .build(); - - try { - Foo.parseFrom(foo.toByteString().substring(0, foo.toByteString().size() - 10)); - fail(); - } catch (InvalidProtocolBufferException e) { - // Expected. - } - } - - public void testMakeImmutable() throws Exception { - UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); - unknownFields.makeImmutable(); - - try { - unknownFields.mergeVarintField(1, 1); - fail(); - } catch (UnsupportedOperationException expected) { - } - - try { - unknownFields.mergeLengthDelimitedField(2, ByteString.copyFromUtf8("hello")); - fail(); - } catch (UnsupportedOperationException expected) { - } - - try { - unknownFields.mergeFieldFrom(1, CodedInputStream.newInstance(new byte[0])); - fail(); - } catch (UnsupportedOperationException expected) { - } - } - - public void testEndToEnd() throws Exception { - TestAllTypesLite testAllTypes = TestAllTypesLite.getDefaultInstance(); - try { - testAllTypes.unknownFields.checkMutable(); - fail(); - } catch (UnsupportedOperationException expected) { - } - - testAllTypes = TestAllTypesLite.parseFrom(new byte[0]); - try { - testAllTypes.unknownFields.checkMutable(); - fail(); - } catch (UnsupportedOperationException expected) { - } - - testAllTypes = TestAllTypesLite.newBuilder().build(); - try { - testAllTypes.unknownFields.checkMutable(); - fail(); - } catch (UnsupportedOperationException expected) { - } - - testAllTypes = TestAllTypesLite.newBuilder().setDefaultBool(true).build(); - try { - testAllTypes.unknownFields.checkMutable(); - fail(); - } catch (UnsupportedOperationException expected) { - } - - TestAllExtensionsLite testAllExtensions = - TestAllExtensionsLite.newBuilder() - .mergeFrom( - TestAllExtensionsLite.newBuilder() - .setExtension(UnittestLite.optionalInt32ExtensionLite, 2) - .build() - .toByteArray()) - .build(); - try { - testAllExtensions.unknownFields.checkMutable(); - fail(); - } catch (UnsupportedOperationException expected) { - } - } - - private ByteString toByteString(UnknownFieldSetLite unknownFields) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream); - try { - unknownFields.writeTo(output); - output.flush(); - } catch (IOException e) { - throw new RuntimeException(e); - } - return ByteString.copyFrom(byteArrayOutputStream.toByteArray()); - } - - public void testSerializeLite() throws Exception { - UnittestLite.TestEmptyMessageLite emptyMessageLite = - UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData); - assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize()); - ByteString data = emptyMessageLite.toByteString(); - TestAllTypes message = TestAllTypes.parseFrom(data); - TestUtil.assertAllFieldsSet(message); - assertEquals(allFieldsData, data); - } - - public void testAllExtensionsLite() throws Exception { - TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet(); - ByteString allExtensionsData = allExtensions.toByteString(); - UnittestLite.TestEmptyMessageLite emptyMessageLite = - UnittestLite.TestEmptyMessageLite.parser().parseFrom(allExtensionsData); - ByteString data = emptyMessageLite.toByteString(); - TestAllExtensions message = TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); - TestUtil.assertAllExtensionsSet(message); - assertEquals(allExtensionsData, data); - } - - public void testAllPackedFieldsLite() throws Exception { - TestPackedTypes allPackedFields = TestUtil.getPackedSet(); - ByteString allPackedData = allPackedFields.toByteString(); - UnittestLite.TestEmptyMessageLite emptyMessageLite = - UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData); - ByteString data = emptyMessageLite.toByteString(); - TestPackedTypes message = TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry()); - TestUtil.assertPackedFieldsSet(message); - assertEquals(allPackedData, data); - } - - public void testAllPackedExtensionsLite() throws Exception { - TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet(); - ByteString allPackedExtensionsData = allPackedExtensions.toByteString(); - UnittestLite.TestEmptyMessageLite emptyMessageLite = - UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData); - ByteString data = emptyMessageLite.toByteString(); - TestPackedExtensions message = - TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); - TestUtil.assertPackedExtensionsSet(message); - assertEquals(allPackedExtensionsData, data); - } - - public void testCopyFromLite() throws Exception { - UnittestLite.TestEmptyMessageLite emptyMessageLite = - UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData); - UnittestLite.TestEmptyMessageLite emptyMessageLite2 = - UnittestLite.TestEmptyMessageLite.newBuilder().mergeFrom(emptyMessageLite).build(); - assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString()); - } - - public void testMergeFromLite() throws Exception { - TestAllTypes message1 = - TestAllTypes.newBuilder() - .setOptionalInt32(1) - .setOptionalString("foo") - .addRepeatedString("bar") - .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ) - .build(); - - TestAllTypes message2 = - TestAllTypes.newBuilder() - .setOptionalInt64(2) - .setOptionalString("baz") - .addRepeatedString("qux") - .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ) - .build(); - - ByteString data1 = message1.toByteString(); - UnittestLite.TestEmptyMessageLite emptyMessageLite1 = - UnittestLite.TestEmptyMessageLite.parseFrom(data1); - ByteString data2 = message2.toByteString(); - UnittestLite.TestEmptyMessageLite emptyMessageLite2 = - UnittestLite.TestEmptyMessageLite.parseFrom(data2); - - message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build(); - emptyMessageLite1 = - UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1) - .mergeFrom(emptyMessageLite2) - .build(); - - data1 = emptyMessageLite1.toByteString(); - message2 = TestAllTypes.parseFrom(data1); - - assertEquals(message1, message2); - } - - public void testWrongTypeTreatedAsUnknownLite() throws Exception { - // Test that fields of the wrong wire type are treated like unknown fields - // when parsing. - - ByteString bizarroData = getBizarroData(); - TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData); - UnittestLite.TestEmptyMessageLite emptyMessageLite = - UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData); - ByteString data = emptyMessageLite.toByteString(); - TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data); - - assertEquals(allTypesMessage.toString(), allTypesMessage2.toString()); - } - - public void testUnknownExtensionsLite() throws Exception { - // Make sure fields are properly parsed to the UnknownFieldSet even when - // they are declared as extension numbers. - - UnittestLite.TestEmptyMessageWithExtensionsLite message = - UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData); - - assertEquals(allFieldsData, message.toByteString()); - } - - public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception { - // Test that fields of the wrong wire type are treated like unknown fields - // when parsing extensions. - - ByteString bizarroData = getBizarroData(); - TestAllExtensions allExtensionsMessage = TestAllExtensions.parseFrom(bizarroData); - UnittestLite.TestEmptyMessageLite emptyMessageLite = - UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData); - - // All fields should have been interpreted as unknown, so the byte strings - // should be the same. - assertEquals(emptyMessageLite.toByteString(), allExtensionsMessage.toByteString()); - } - - public void testParseUnknownEnumValueLite() throws Exception { - Descriptors.FieldDescriptor singularField = - TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum"); - Descriptors.FieldDescriptor repeatedField = - TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum"); - assertNotNull(singularField); - assertNotNull(repeatedField); - - ByteString data = - UnknownFieldSet.newBuilder() - .addField( - singularField.getNumber(), - UnknownFieldSet.Field.newBuilder() - .addVarint(TestAllTypes.NestedEnum.BAR.getNumber()) - .addVarint(5) // not valid - .build()) - .addField( - repeatedField.getNumber(), - UnknownFieldSet.Field.newBuilder() - .addVarint(TestAllTypes.NestedEnum.FOO.getNumber()) - .addVarint(4) // not valid - .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber()) - .addVarint(6) // not valid - .build()) - .build() - .toByteString(); - - UnittestLite.TestEmptyMessageLite emptyMessageLite = - UnittestLite.TestEmptyMessageLite.parseFrom(data); - data = emptyMessageLite.toByteString(); - - { - TestAllTypes message = TestAllTypes.parseFrom(data); - assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum()); - assertEquals( - Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ), - message.getRepeatedNestedEnumList()); - assertEquals( - Arrays.asList(5L), - message.getUnknownFields().getField(singularField.getNumber()).getVarintList()); - assertEquals( - Arrays.asList(4L, 6L), - message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList()); - } - - { - TestAllExtensions message = - TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); - assertEquals( - TestAllTypes.NestedEnum.BAR, - message.getExtension(UnittestProto.optionalNestedEnumExtension)); - assertEquals( - Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ), - message.getExtension(UnittestProto.repeatedNestedEnumExtension)); - assertEquals( - Arrays.asList(5L), - message.getUnknownFields().getField(singularField.getNumber()).getVarintList()); - assertEquals( - Arrays.asList(4L, 6L), - message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList()); - } - } - - public void testClearLite() throws Exception { - UnittestLite.TestEmptyMessageLite emptyMessageLite1 = - UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData); - UnittestLite.TestEmptyMessageLite emptyMessageLite2 = - UnittestLite.TestEmptyMessageLite.newBuilder().mergeFrom(emptyMessageLite1).clear().build(); - assertEquals(0, emptyMessageLite2.getSerializedSize()); - ByteString data = emptyMessageLite2.toByteString(); - assertEquals(0, data.size()); - } -} diff --git a/java/core/src/test/java/com/google/protobuf/Utf8Test.java b/java/core/src/test/java/com/google/protobuf/Utf8Test.java new file mode 100755 index 000000000..bc3c98510 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Utf8Test.java @@ -0,0 +1,232 @@ +// 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 java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Random; +import java.util.regex.Pattern; +import junit.framework.TestCase; + +/** Unit tests for {@link Utf8}. */ +public class Utf8Test extends TestCase { + private static final int NUM_CHARS = 16384; + + private static final Utf8.Processor safeProcessor = new Utf8.SafeProcessor(); + private static final Utf8.Processor unsafeProcessor = new Utf8.UnsafeProcessor(); + + public void testEncode() { + assertEncoding(randomString(0x80)); + assertEncoding(randomString(0x90)); + assertEncoding(randomString(0x800)); + assertEncoding(randomString(0x10000)); + assertEncoding(randomString(0x10ffff)); + } + + public void testEncode_insufficientSpace() { + assertEncoding_insufficientSpace(randomString(0x80)); + assertEncoding_insufficientSpace(randomString(0x90)); + assertEncoding_insufficientSpace(randomString(0x800)); + assertEncoding_insufficientSpace(randomString(0x10000)); + assertEncoding_insufficientSpace(randomString(0x10ffff)); + } + + public void testValid() { + assertIsValid(new byte[] {(byte) 0xE0, (byte) 0xB9, (byte) 0x96}, true); + assertIsValid(new byte[] {(byte) 0xF0, (byte) 0xB2, (byte) 0x83, (byte) 0xBC}, true); + } + + public void testOverlongIsInvalid() { + assertIsValid(new byte[] {(byte) 0xC0, (byte) 0x81}, false); + assertIsValid(new byte[] {(byte) 0xE0, (byte) 0x81, (byte) 0x81}, false); + assertIsValid(new byte[] {(byte) 0xF0, (byte) 0x81, (byte) 0x81, (byte) 0x81}, false); + } + + public void testMaxCodepointExceeded() { + // byte1 > 0xF4 + assertIsValid(new byte[] {(byte) 0xF5, (byte) 0x81, (byte) 0x81, (byte) 0x81}, false); + } + + public void testInvalidSurrogateCodepoint() { + assertIsValid(new byte[] {(byte) 0xED, (byte) 0xA1, (byte) 0x81}, false); + + // byte1 == 0xF0 && byte2 < 0x90 + assertIsValid(new byte[] {(byte) 0xF0, (byte) 0x81, (byte) 0x81, (byte) 0x81}, false); + // byte1 == 0xF4 && byte2 > 0x8F + assertIsValid(new byte[] {(byte) 0xF4, (byte) 0x90, (byte) 0x81, (byte) 0x81}, false); + } + + private static String randomString(int maxCodePoint) { + final long seed = 99; + final Random rnd = new Random(seed); + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < NUM_CHARS; j++) { + int codePoint; + do { + codePoint = rnd.nextInt(maxCodePoint); + } while (Utf8Utils.isSurrogate(codePoint)); + sb.appendCodePoint(codePoint); + } + return sb.toString(); + } + + private static void assertIsValid(byte[] data, boolean valid) { + assertEquals("isValidUtf8[ARRAY]", valid, safeProcessor.isValidUtf8(data, 0, data.length)); + assertEquals( + "isValidUtf8[ARRAY_UNSAFE]", valid, unsafeProcessor.isValidUtf8(data, 0, data.length)); + + ByteBuffer buffer = ByteBuffer.wrap(data); + assertEquals( + "isValidUtf8[NIO_HEAP]", + valid, + safeProcessor.isValidUtf8(buffer, buffer.position(), buffer.remaining())); + + // Direct buffers. + buffer = ByteBuffer.allocateDirect(data.length); + buffer.put(data); + buffer.flip(); + assertEquals( + "isValidUtf8[NIO_DEFAULT]", + valid, + safeProcessor.isValidUtf8(buffer, buffer.position(), buffer.remaining())); + assertEquals( + "isValidUtf8[NIO_UNSAFE]", + valid, + unsafeProcessor.isValidUtf8(buffer, buffer.position(), buffer.remaining())); + } + + private static void assertEncoding(String message) { + byte[] expected = message.getBytes(Internal.UTF_8); + byte[] output = encodeToByteArray(message, expected.length, safeProcessor); + assertTrue("encodeUtf8[ARRAY]", Arrays.equals(expected, output)); + + output = encodeToByteArray(message, expected.length, unsafeProcessor); + assertTrue("encodeUtf8[ARRAY_UNSAFE]", Arrays.equals(expected, output)); + + output = encodeToByteBuffer(message, expected.length, false, safeProcessor); + assertTrue("encodeUtf8[NIO_HEAP]", Arrays.equals(expected, output)); + + output = encodeToByteBuffer(message, expected.length, true, safeProcessor); + assertTrue("encodeUtf8[NIO_DEFAULT]", Arrays.equals(expected, output)); + + output = encodeToByteBuffer(message, expected.length, true, unsafeProcessor); + assertTrue("encodeUtf8[NIO_UNSAFE]", Arrays.equals(expected, output)); + } + + private void assertEncoding_insufficientSpace(String message) { + final int length = message.length() - 1; + Class<ArrayIndexOutOfBoundsException> clazz = ArrayIndexOutOfBoundsException.class; + + try { + encodeToByteArray(message, length, safeProcessor); + fail("Expected " + clazz.getSimpleName()); + } catch (Throwable t) { + // Expected + assertExceptionType(t, clazz); + // byte[] + safeProcessor will not exit early. We can't match the message since we don't + // know which char/index due to random input. + } + + try { + encodeToByteArray(message, length, unsafeProcessor); + fail("Expected " + clazz.getSimpleName()); + } catch (Throwable t) { + assertExceptionType(t, clazz); + // byte[] + unsafeProcessor will exit early, so we have can match the message. + assertExceptionMessage(t, length); + } + + try { + encodeToByteBuffer(message, length, false, safeProcessor); + fail("Expected " + clazz.getSimpleName()); + } catch (Throwable t) { + // Expected + assertExceptionType(t, clazz); + // ByteBuffer + safeProcessor will not exit early. We can't match the message since we don't + // know which char/index due to random input. + } + + try { + encodeToByteBuffer(message, length, true, safeProcessor); + fail("Expected " + clazz.getSimpleName()); + } catch (Throwable t) { + // Expected + assertExceptionType(t, clazz); + // ByteBuffer + safeProcessor will not exit early. We can't match the message since we don't + // know which char/index due to random input. + } + + try { + encodeToByteBuffer(message, length, true, unsafeProcessor); + fail("Expected " + clazz.getSimpleName()); + } catch (Throwable t) { + // Expected + assertExceptionType(t, clazz); + // Direct ByteBuffer + unsafeProcessor will exit early if it's not on Android, so we can + // match the message. On Android, a direct ByteBuffer will have hasArray() being true and + // it will take a different code path and produces a different message. + if (!Android.isOnAndroidDevice()) { + assertExceptionMessage(t, length); + } + } + } + + private static byte[] encodeToByteArray(String message, int length, Utf8.Processor processor) { + byte[] output = new byte[length]; + processor.encodeUtf8(message, output, 0, output.length); + return output; + } + + private static byte[] encodeToByteBuffer( + String message, int length, boolean direct, Utf8.Processor processor) { + ByteBuffer buffer = direct ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length); + + processor.encodeUtf8(message, buffer); + buffer.flip(); + + byte[] output = new byte[buffer.remaining()]; + buffer.get(output); + return output; + } + + private <T extends Throwable> void assertExceptionType(Throwable t, Class<T> expected) { + if (!expected.isAssignableFrom(t.getClass())) { + fail("Expected " + expected.getSimpleName() + ", but found " + t.getClass().getSimpleName()); + } + } + + private void assertExceptionMessage(Throwable t, int index) { + String pattern = "Failed writing (.) at index " + index; + assertTrue( + t.getMessage() + " does not match pattern " + pattern, + Pattern.matches(pattern, t.getMessage())); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/Utf8Utils.java b/java/core/src/test/java/com/google/protobuf/Utf8Utils.java new file mode 100755 index 000000000..dbd3d3961 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/Utf8Utils.java @@ -0,0 +1,193 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static java.lang.Character.MIN_HIGH_SURROGATE; +import static java.lang.Character.MIN_LOW_SURROGATE; +import static java.lang.Character.MIN_SURROGATE; + +import java.util.Random; + +/** Utilities for benchmarking UTF-8. */ +final class Utf8Utils { + private Utf8Utils() {} + + static class MaxCodePoint { + final int value; + + /** + * Convert the input string to a code point. Accepts regular decimal numerals, hex strings, and + * some symbolic names meaningful to humans. + */ + private static int decode(String userFriendly) { + try { + return Integer.decode(userFriendly); + } catch (NumberFormatException ignored) { + if (userFriendly.matches("(?i)(?:American|English|ASCII)")) { + // 1-byte UTF-8 sequences - "American" ASCII text + return 0x80; + } else if (userFriendly.matches("(?i)(?:Danish|Latin|Western.*European)")) { + // Mostly 1-byte UTF-8 sequences, mixed with occasional 2-byte + // sequences - "Western European" text + return 0x90; + } else if (userFriendly.matches("(?i)(?:Greek|Cyrillic|European|ISO.?8859)")) { + // Mostly 2-byte UTF-8 sequences - "European" text + return 0x800; + } else if (userFriendly.matches("(?i)(?:Chinese|Han|Asian|BMP)")) { + // Mostly 3-byte UTF-8 sequences - "Asian" text + return Character.MIN_SUPPLEMENTARY_CODE_POINT; + } else if (userFriendly.matches("(?i)(?:Cuneiform|rare|exotic|supplementary.*)")) { + // Mostly 4-byte UTF-8 sequences - "rare exotic" text + return Character.MAX_CODE_POINT; + } else { + throw new IllegalArgumentException("Can't decode codepoint " + userFriendly); + } + } + } + + public static MaxCodePoint valueOf(String userFriendly) { + return new MaxCodePoint(userFriendly); + } + + public MaxCodePoint(String userFriendly) { + value = decode(userFriendly); + } + } + + /** + * The Utf8 distribution of real data. The distribution is an array with length 4. + * "distribution[i]" means the total number of characters who are encoded with (i + 1) bytes. + * + * <p>GMM_UTF8_DISTRIBUTION is the distribution of gmm data set. GSR_UTF8_DISTRIBUTION is the + * distribution of gsreq/gsresp data set + */ + public enum Utf8Distribution { + GMM_UTF8_DISTRIBUTION { + @Override + public int[] getDistribution() { + return new int[] {53059, 104, 0, 0}; + } + }, + GSR_UTF8_DISTRIBUTION { + @Override + public int[] getDistribution() { + return new int[] {119458, 74, 2706, 0}; + } + }; + + public abstract int[] getDistribution(); + } + + /** + * Creates an array of random strings. + * + * @param stringCount the number of strings to be created. + * @param charCount the number of characters per string. + * @param maxCodePoint the maximum code point for the characters in the strings. + * @return an array of random strings. + */ + static String[] randomStrings(int stringCount, int charCount, MaxCodePoint maxCodePoint) { + final long seed = 99; + final Random rnd = new Random(seed); + String[] strings = new String[stringCount]; + for (int i = 0; i < stringCount; i++) { + strings[i] = randomString(rnd, charCount, maxCodePoint); + } + return strings; + } + + /** + * Creates a random string + * + * @param rnd the random generator. + * @param charCount the number of characters per string. + * @param maxCodePoint the maximum code point for the characters in the strings. + */ + static String randomString(Random rnd, int charCount, MaxCodePoint maxCodePoint) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < charCount; i++) { + int codePoint; + do { + codePoint = rnd.nextInt(maxCodePoint.value); + } while (Utf8Utils.isSurrogate(codePoint)); + sb.appendCodePoint(codePoint); + } + return sb.toString(); + } + + /** Character.isSurrogate was added in Java SE 7. */ + static boolean isSurrogate(int c) { + return Character.MIN_HIGH_SURROGATE <= c && c <= Character.MAX_LOW_SURROGATE; + } + + /** + * Creates an array of random strings according to UTF8 distribution. + * + * @param stringCount the number of strings to be created. + * @param charCount the number of characters per string. + */ + static String[] randomStringsWithDistribution( + int stringCount, int charCount, Utf8Distribution utf8Distribution) { + final int[] distribution = utf8Distribution.getDistribution(); + for (int i = 0; i < 3; i++) { + distribution[i + 1] += distribution[i]; + } + final long seed = 99; + final Random rnd = new Random(seed); + String[] strings = new String[stringCount]; + for (int i = 0; i < stringCount; i++) { + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < charCount; j++) { + int codePoint; + do { + codePoint = rnd.nextInt(distribution[3]); + if (codePoint < distribution[0]) { + // 1 bytes + sb.append(0x7F); + } else if (codePoint < distribution[1]) { + // 2 bytes + sb.append(0x7FF); + } else if (codePoint < distribution[2]) { + // 3 bytes + sb.append(MIN_SURROGATE - 1); + } else { + // 4 bytes + sb.append(MIN_HIGH_SURROGATE); + sb.append(MIN_LOW_SURROGATE); + } + } while (Utf8Utils.isSurrogate(codePoint)); + sb.appendCodePoint(codePoint); + } + strings[i] = sb.toString(); + } + return strings; + } +} diff --git a/java/core/src/test/java/com/google/protobuf/WireFormatLiteTest.java b/java/core/src/test/java/com/google/protobuf/WireFormatLiteTest.java new file mode 100755 index 000000000..a725d413f --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/WireFormatLiteTest.java @@ -0,0 +1,1023 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite; + +import com.google.protobuf.UnittestLite.ForeignEnumLite; +import com.google.protobuf.UnittestLite.TestAllExtensionsLite; +import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; +import map_test.MapForProto2TestProto; +import map_test.MapTestProto.TestMap; +import protobuf_unittest.UnittestMset.RawMessageSet; +import protobuf_unittest.UnittestMset.TestMessageSetExtension1; +import protobuf_unittest.UnittestMset.TestMessageSetExtension2; +import protobuf_unittest.UnittestProto; +import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; +import protobuf_unittest.UnittestProto.TestExtensionInsideTable; +import protobuf_unittest.UnittestProto.TestFieldOrderings; +import protobuf_unittest.UnittestProto.TestOneof2; +import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible; +import protobuf_unittest.UnittestProto.TestPackedExtensions; +import protobuf_unittest.UnittestProto.TestPackedTypes; +import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; +import proto3_unittest.UnittestProto3; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; +import junit.framework.TestCase; + +public class WireFormatLiteTest extends TestCase { + public void testSerializeExtensionsLite() throws Exception { + // TestAllTypes and TestAllExtensions should have compatible wire formats, + // so if we serialize a TestAllExtensions then parse it as TestAllTypes + // it should work. + + TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet(); + ByteString rawBytes = message.toByteString(); + assertEquals(rawBytes.size(), message.getSerializedSize()); + + TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes); + + TestUtil.assertAllFieldsSet(message2); + } + + public void testSerializePackedExtensionsLite() throws Exception { + // TestPackedTypes and TestPackedExtensions should have compatible wire + // formats; check that they serialize to the same string. + TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet(); + ByteString rawBytes = message.toByteString(); + + TestPackedTypes message2 = TestUtil.getPackedSet(); + ByteString rawBytes2 = message2.toByteString(); + + assertEquals(rawBytes, rawBytes2); + } + + public void testParseExtensionsLite() throws Exception { + // TestAllTypes and TestAllExtensions should have compatible wire formats, + // so if we serialize a TestAllTypes then parse it as TestAllExtensions + // it should work. + + TestAllTypes message = TestUtil.getAllSet(); + ByteString rawBytes = message.toByteString(); + + ExtensionRegistryLite registryLite = TestUtilLite.getExtensionRegistryLite(); + + TestAllExtensionsLite message2 = TestAllExtensionsLite.parseFrom(rawBytes, registryLite); + TestUtil.assertAllExtensionsSet(message2); + message2 = TestAllExtensionsLite.parseFrom(message.toByteArray(), registryLite); + TestUtil.assertAllExtensionsSet(message2); + } + + public void testParsePackedExtensionsLite() throws Exception { + // Ensure that packed extensions can be properly parsed. + TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet(); + ByteString rawBytes = message.toByteString(); + + ExtensionRegistryLite registry = TestUtilLite.getExtensionRegistryLite(); + + TestPackedExtensionsLite message2 = TestPackedExtensionsLite.parseFrom(rawBytes, registry); + TestUtil.assertPackedExtensionsSet(message2); + message2 = TestPackedExtensionsLite.parseFrom(message.toByteArray(), registry); + TestUtil.assertPackedExtensionsSet(message2); + } + + public void testSerialization() throws Exception { + TestAllTypes message = TestUtil.getAllSet(); + + ByteString rawBytes = message.toByteString(); + assertEquals(rawBytes.size(), message.getSerializedSize()); + + TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes); + + TestUtil.assertAllFieldsSet(message2); + } + + public void testSerializationPacked() throws Exception { + TestPackedTypes message = TestUtil.getPackedSet(); + + ByteString rawBytes = message.toByteString(); + assertEquals(rawBytes.size(), message.getSerializedSize()); + + TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes); + + TestUtil.assertPackedFieldsSet(message2); + } + + public void testSerializeExtensions() throws Exception { + // TestAllTypes and TestAllExtensions should have compatible wire formats, + // so if we serialize a TestAllExtensions then parse it as TestAllTypes + // it should work. + + TestAllExtensions message = TestUtil.getAllExtensionsSet(); + ByteString rawBytes = message.toByteString(); + assertEquals(rawBytes.size(), message.getSerializedSize()); + + TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes); + + TestUtil.assertAllFieldsSet(message2); + } + + public void testSerializePackedExtensions() throws Exception { + // TestPackedTypes and TestPackedExtensions should have compatible wire + // formats; check that they serialize to the same string. + TestPackedExtensions message = TestUtil.getPackedExtensionsSet(); + ByteString rawBytes = message.toByteString(); + + TestPackedTypes message2 = TestUtil.getPackedSet(); + ByteString rawBytes2 = message2.toByteString(); + + assertEquals(rawBytes, rawBytes2); + } + + public void testSerializationPackedWithoutGetSerializedSize() throws Exception { + // Write directly to an OutputStream, without invoking getSerializedSize() + // This used to be a bug where the size of a packed field was incorrect, + // since getSerializedSize() was never invoked. + TestPackedTypes message = TestUtil.getPackedSet(); + + // Directly construct a CodedOutputStream around the actual OutputStream, + // in case writeTo(OutputStream output) invokes getSerializedSize(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + CodedOutputStream codedOutput = CodedOutputStream.newInstance(outputStream); + + message.writeTo(codedOutput); + + codedOutput.flush(); + + TestPackedTypes message2 = TestPackedTypes.parseFrom(outputStream.toByteArray()); + + TestUtil.assertPackedFieldsSet(message2); + } + + public void testParseExtensions() throws Exception { + // TestAllTypes and TestAllExtensions should have compatible wire formats, + // so if we serialize a TestAllTypes then parse it as TestAllExtensions + // it should work. + + TestAllTypes message = TestUtil.getAllSet(); + ByteString rawBytes = message.toByteString(); + + ExtensionRegistryLite registry = TestUtil.getExtensionRegistry(); + + TestAllExtensions message2 = TestAllExtensions.parseFrom(rawBytes, registry); + + TestUtil.assertAllExtensionsSet(message2); + } + + public void testParsePackedExtensions() throws Exception { + // Ensure that packed extensions can be properly parsed. + TestPackedExtensions message = TestUtil.getPackedExtensionsSet(); + ByteString rawBytes = message.toByteString(); + + ExtensionRegistryLite registry = TestUtil.getExtensionRegistry(); + + TestPackedExtensions message2 = TestPackedExtensions.parseFrom(rawBytes, registry); + + TestUtil.assertPackedExtensionsSet(message2); + } + + public void testSerializeDelimited() throws Exception { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + TestUtil.getAllSet().writeDelimitedTo(output); + output.write(12); + TestUtil.getPackedSet().writeDelimitedTo(output); + output.write(34); + + ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); + + TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input)); + assertEquals(12, input.read()); + TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input)); + assertEquals(34, input.read()); + assertEquals(-1, input.read()); + + // We're at EOF, so parsing again should return null. + assertNull(TestAllTypes.parseDelimitedFrom(input)); + } + + private ExtensionRegistryLite getTestFieldOrderingsRegistry() { + ExtensionRegistryLite result = ExtensionRegistryLite.newInstance(); + result.add(UnittestProto.myExtensionInt); + result.add(UnittestProto.myExtensionString); + return result; + } + + public void testParseMultipleExtensionRanges() throws Exception { + // Make sure we can parse a message that contains multiple extensions + // ranges. + TestFieldOrderings source = + TestFieldOrderings.newBuilder() + .setMyInt(1) + .setMyString("foo") + .setMyFloat(1.0F) + .setExtension(UnittestProto.myExtensionInt, 23) + .setExtension(UnittestProto.myExtensionString, "bar") + .build(); + TestFieldOrderings dest = + TestFieldOrderings.parseFrom(source.toByteString(), getTestFieldOrderingsRegistry()); + assertEquals(source, dest); + } + + private static ExtensionRegistryLite getTestExtensionInsideTableRegistry() { + ExtensionRegistryLite result = ExtensionRegistryLite.newInstance(); + result.add(UnittestProto.testExtensionInsideTableExtension); + return result; + } + + public void testExtensionInsideTable() throws Exception { + // Make sure the extension within the range of table is parsed correctly in experimental + // runtime. + TestExtensionInsideTable source = + TestExtensionInsideTable.newBuilder() + .setField1(1) + .setExtension(UnittestProto.testExtensionInsideTableExtension, 23) + .build(); + TestExtensionInsideTable dest = + TestExtensionInsideTable.parseFrom( + source.toByteString(), getTestExtensionInsideTableRegistry()); + assertEquals(source, dest); + } + + private static final int UNKNOWN_TYPE_ID = 1550055; + private static final int TYPE_ID_1 = 1545008; + private static final int TYPE_ID_2 = 1547769; + + public void testSerializeMessageSetEagerly() throws Exception { + testSerializeMessageSetWithFlag(true); + } + + public void testSerializeMessageSetNotEagerly() throws Exception { + testSerializeMessageSetWithFlag(false); + } + + private void testSerializeMessageSetWithFlag(boolean eagerParsing) throws Exception { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream); + output.writeRawMessageSetExtension(UNKNOWN_TYPE_ID, ByteString.copyFromUtf8("bar")); + output.flush(); + byte[] messageSetBytes = byteArrayOutputStream.toByteArray(); + + ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); + // Set up a TestMessageSet with two known messages and an unknown one. + TestMessageSet messageSet = + TestMessageSet.newBuilder() + .setExtension( + TestMessageSetExtension1.messageSetExtension, + TestMessageSetExtension1.newBuilder().setI(123).build()) + .setExtension( + TestMessageSetExtension2.messageSetExtension, + TestMessageSetExtension2.newBuilder().setStr("foo").build()) + .mergeFrom(messageSetBytes) + .build(); + + ByteString data = messageSet.toByteString(); + + // Parse back using RawMessageSet and check the contents. + RawMessageSet raw = RawMessageSet.parseFrom(data); + + assertEquals(3, raw.getItemCount()); + assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId()); + assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId()); + assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId()); + + TestMessageSetExtension1 message1 = + TestMessageSetExtension1.parseFrom(raw.getItem(0).getMessage()); + assertEquals(123, message1.getI()); + + TestMessageSetExtension2 message2 = + TestMessageSetExtension2.parseFrom(raw.getItem(1).getMessage()); + assertEquals("foo", message2.getStr()); + + assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8()); + } + + public void testParseMessageSetEagerly() throws Exception { + testParseMessageSetWithFlag(true); + } + + public void testParseMessageSetNotEagerly() throws Exception { + testParseMessageSetWithFlag(false); + } + + private void testParseMessageSetWithFlag(boolean eagerParsing) throws Exception { + ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); + ExtensionRegistryLite extensionRegistry = ExtensionRegistryLite.newInstance(); + extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); + extensionRegistry.add(TestMessageSetExtension2.messageSetExtension); + + // Set up a RawMessageSet with two known messages and an unknown one. + RawMessageSet raw = + RawMessageSet.newBuilder() + .addItem( + RawMessageSet.Item.newBuilder() + .setTypeId(TYPE_ID_1) + .setMessage( + TestMessageSetExtension1.newBuilder().setI(123).build().toByteString()) + .build()) + .addItem( + RawMessageSet.Item.newBuilder() + .setTypeId(TYPE_ID_2) + .setMessage( + TestMessageSetExtension2.newBuilder().setStr("foo").build().toByteString()) + .build()) + .addItem( + RawMessageSet.Item.newBuilder() + .setTypeId(UNKNOWN_TYPE_ID) + .setMessage(ByteString.copyFromUtf8("bar")) + .build()) + .build(); + + ByteString data = raw.toByteString(); + + // Parse as a TestMessageSet and check the contents. + TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry); + + assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); + assertEquals( + "foo", messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr()); + } + + public void testParseMessageSetExtensionEagerly() throws Exception { + testParseMessageSetExtensionWithFlag(true); + } + + public void testParseMessageSetExtensionNotEagerly() throws Exception { + testParseMessageSetExtensionWithFlag(false); + } + + private void testParseMessageSetExtensionWithFlag(boolean eagerParsing) throws Exception { + ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); + ExtensionRegistryLite extensionRegistry = ExtensionRegistryLite.newInstance(); + extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); + + // Set up a RawMessageSet with a known messages. + int typeId1 = 1545008; + RawMessageSet raw = + RawMessageSet.newBuilder() + .addItem( + RawMessageSet.Item.newBuilder() + .setTypeId(typeId1) + .setMessage( + TestMessageSetExtension1.newBuilder().setI(123).build().toByteString()) + .build()) + .build(); + + ByteString data = raw.toByteString(); + + // Parse as a TestMessageSet and check the contents. + TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry); + assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); + } + + public void testMergeLazyMessageSetExtensionEagerly() throws Exception { + testMergeLazyMessageSetExtensionWithFlag(true); + } + + public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception { + testMergeLazyMessageSetExtensionWithFlag(false); + } + + private void testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing) throws Exception { + ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); + ExtensionRegistryLite extensionRegistry = ExtensionRegistryLite.newInstance(); + extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); + + // Set up a RawMessageSet with a known messages. + int typeId1 = 1545008; + RawMessageSet raw = + RawMessageSet.newBuilder() + .addItem( + RawMessageSet.Item.newBuilder() + .setTypeId(typeId1) + .setMessage( + TestMessageSetExtension1.newBuilder().setI(123).build().toByteString()) + .build()) + .build(); + + ByteString data = raw.toByteString(); + + // Parse as a TestMessageSet and store value into lazy field + TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry); + // Merge lazy field check the contents. + messageSet = messageSet.toBuilder().mergeFrom(data, extensionRegistry).build(); + assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); + } + + public void testMergeMessageSetExtensionEagerly() throws Exception { + testMergeMessageSetExtensionWithFlag(true); + } + + public void testMergeMessageSetExtensionNotEagerly() throws Exception { + testMergeMessageSetExtensionWithFlag(false); + } + + private void testMergeMessageSetExtensionWithFlag(boolean eagerParsing) throws Exception { + ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); + ExtensionRegistryLite extensionRegistry = ExtensionRegistryLite.newInstance(); + extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); + + // Set up a RawMessageSet with a known messages. + int typeId1 = 1545008; + RawMessageSet raw = + RawMessageSet.newBuilder() + .addItem( + RawMessageSet.Item.newBuilder() + .setTypeId(typeId1) + .setMessage( + TestMessageSetExtension1.newBuilder().setI(123).build().toByteString()) + .build()) + .build(); + + // Serialize RawMessageSet unnormally (message value before type id) + ByteString.CodedBuilder out = ByteString.newCodedBuilder(raw.getSerializedSize()); + CodedOutputStream output = out.getCodedOutput(); + List<RawMessageSet.Item> items = raw.getItemList(); + for (RawMessageSet.Item item : items) { + output.writeTag(1, WireFormat.WIRETYPE_START_GROUP); + output.writeBytes(3, item.getMessage()); + output.writeInt32(2, item.getTypeId()); + output.writeTag(1, WireFormat.WIRETYPE_END_GROUP); + } + ByteString data = out.build(); + + // Merge bytes into TestMessageSet and check the contents. + TestMessageSet messageSet = + TestMessageSet.newBuilder().mergeFrom(data, extensionRegistry).build(); + assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); + } + + // ================================================================ + // oneof + public void testOneofWireFormat() throws Exception { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestUtil.setOneof(builder); + TestOneof2 message = builder.build(); + ByteString rawBytes = message.toByteString(); + + assertEquals(rawBytes.size(), message.getSerializedSize()); + + TestOneof2 message2 = TestOneof2.parseFrom(rawBytes); + TestUtil.assertOneofSet(message2); + } + + public void testOneofOnlyLastSet() throws Exception { + TestOneofBackwardsCompatible source = + TestOneofBackwardsCompatible.newBuilder().setFooInt(100).setFooString("101").build(); + + ByteString rawBytes = source.toByteString(); + TestOneof2 message = TestOneof2.parseFrom(rawBytes); + assertFalse(message.hasFooInt()); + assertTrue(message.hasFooString()); + } + + private void assertInvalidWireFormat( + MessageLite defaultInstance, byte[] data, int offset, int length) { + // Test all combinations: (builder vs parser) x (byte[] vs. InputStream). + try { + defaultInstance.newBuilderForType().mergeFrom(data, offset, length); + fail("Expected exception"); + } catch (InvalidProtocolBufferException e) { + // Pass. + } + try { + defaultInstance.getParserForType().parseFrom(data, offset, length); + fail("Expected exception"); + } catch (InvalidProtocolBufferException e) { + // Pass. + } + try { + InputStream input = new ByteArrayInputStream(data, offset, length); + defaultInstance.newBuilderForType().mergeFrom(input); + fail("Expected exception"); + } catch (IOException e) { + // Pass. + } + try { + InputStream input = new ByteArrayInputStream(data, offset, length); + defaultInstance.getParserForType().parseFrom(input); + fail("Expected exception"); + } catch (IOException e) { + // Pass. + } + } + + private void assertInvalidWireFormat(MessageLite defaultInstance, byte[] data) { + assertInvalidWireFormat(defaultInstance, data, 0, data.length); + } + + private void assertInvalidWireFormat(byte[] data) { + assertInvalidWireFormat(TestAllTypes.getDefaultInstance(), data); + assertInvalidWireFormat(UnittestProto3.TestAllTypes.getDefaultInstance(), data); + } + + public void testParserRejectInvalidTag() throws Exception { + byte[] invalidTags = + new byte[] { + // Zero tag is not allowed. + 0, + // Invalid wire types. + (byte) WireFormat.makeTag(1, 6), + (byte) WireFormat.makeTag(1, 7), + // Field number 0 is not allowed. + (byte) WireFormat.makeTag(0, WireFormat.WIRETYPE_VARINT), + }; + for (byte invalidTag : invalidTags) { + // Add a trailing 0 to make sure the parsing actually fails on the tag. + byte[] data = new byte[] {invalidTag, 0}; + assertInvalidWireFormat(data); + + // Invalid tag in an unknown group field. + data = + new byte[] { + (byte) WireFormat.makeTag(1, WireFormat.WIRETYPE_START_GROUP), + invalidTag, + 0, + (byte) WireFormat.makeTag(1, WireFormat.WIRETYPE_END_GROUP), + }; + assertInvalidWireFormat(data); + + // Invalid tag in a MessageSet item. + data = + new byte[] { + (byte) WireFormat.MESSAGE_SET_ITEM_TAG, + (byte) WireFormat.MESSAGE_SET_TYPE_ID_TAG, + 100, // TYPE_ID = 100 + (byte) WireFormat.MESSAGE_SET_MESSAGE_TAG, + 0, // empty payload + invalidTag, + 0, + (byte) WireFormat.MESSAGE_SET_ITEM_END_TAG, + }; + assertInvalidWireFormat(TestMessageSet.getDefaultInstance(), data); + + // Invalid tag inside a MessageSet item's unknown group. + data = + new byte[] { + (byte) WireFormat.MESSAGE_SET_ITEM_TAG, + (byte) WireFormat.MESSAGE_SET_TYPE_ID_TAG, + 100, // TYPE_ID = 100 + (byte) WireFormat.MESSAGE_SET_MESSAGE_TAG, + 0, // empty payload + (byte) WireFormat.makeTag(4, WireFormat.WIRETYPE_START_GROUP), + invalidTag, + 0, + (byte) WireFormat.makeTag(4, WireFormat.WIRETYPE_END_GROUP), + (byte) WireFormat.MESSAGE_SET_ITEM_END_TAG, + }; + assertInvalidWireFormat(TestMessageSet.getDefaultInstance(), data); + + // Invalid tag inside a map field. + data = + new byte[] { + (byte) WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED), 2, invalidTag, 0, + }; + assertInvalidWireFormat(TestMap.getDefaultInstance(), data); + } + } + + public void testUnmatchedGroupTag() throws Exception { + int startTag = WireFormat.makeTag(16, WireFormat.WIRETYPE_START_GROUP); + byte[] data = + new byte[] { + (byte) ((startTag & 0x7F) | 0x80), (byte) ((startTag >>> 7) & 0x7F), + }; + assertInvalidWireFormat(data); + + // Unmatched group tags inside a MessageSet item. + data = + new byte[] { + (byte) WireFormat.MESSAGE_SET_ITEM_TAG, + (byte) WireFormat.MESSAGE_SET_TYPE_ID_TAG, + 100, // TYPE_ID = 100 + (byte) WireFormat.MESSAGE_SET_MESSAGE_TAG, + 0, // empty payload + (byte) WireFormat.makeTag(4, WireFormat.WIRETYPE_START_GROUP), + }; + assertInvalidWireFormat(TestMessageSet.getDefaultInstance(), data); + } + + private void assertAccepted(MessageLite defaultInstance, byte[] data) throws Exception { + MessageLite message1 = defaultInstance.newBuilderForType().mergeFrom(data).build(); + MessageLite message2 = defaultInstance.getParserForType().parseFrom(data); + MessageLite message3 = + defaultInstance.newBuilderForType().mergeFrom(new ByteArrayInputStream(data)).build(); + MessageLite message4 = + defaultInstance.getParserForType().parseFrom(new ByteArrayInputStream(data)); + assertEquals(message1, message2); + assertEquals(message2, message3); + assertEquals(message3, message4); + } + + public void testUnmatchedWireType() throws Exception { + // Build a payload with all fields from 1 to 128 being varints. Parsing it into TestAllTypes + // or other message types should succeed even though the wire type doesn't match for some + // fields. + ByteArrayOutputStream output = new ByteArrayOutputStream(); + CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); + for (int i = 1; i <= 128; i++) { + codedOutput.writeInt32(i, 0); + } + codedOutput.flush(); + byte[] data = output.toByteArray(); + // It can be parsed into any message type that doesn't have required fields. + assertAccepted(TestAllTypes.getDefaultInstance(), data); + assertAccepted(UnittestProto3.TestAllTypes.getDefaultInstance(), data); + assertAccepted(TestMap.getDefaultInstance(), data); + assertAccepted(MapForProto2TestProto.TestMap.getDefaultInstance(), data); + } + + public void testParseTruncatedPackedFields() throws Exception { + TestPackedTypes all = TestUtil.getPackedSet(); + TestPackedTypes[] messages = + new TestPackedTypes[] { + TestPackedTypes.newBuilder().addAllPackedInt32(all.getPackedInt32List()).build(), + TestPackedTypes.newBuilder().addAllPackedInt64(all.getPackedInt64List()).build(), + TestPackedTypes.newBuilder().addAllPackedUint32(all.getPackedUint32List()).build(), + TestPackedTypes.newBuilder().addAllPackedUint64(all.getPackedUint64List()).build(), + TestPackedTypes.newBuilder().addAllPackedSint32(all.getPackedSint32List()).build(), + TestPackedTypes.newBuilder().addAllPackedSint64(all.getPackedSint64List()).build(), + TestPackedTypes.newBuilder().addAllPackedFixed32(all.getPackedFixed32List()).build(), + TestPackedTypes.newBuilder().addAllPackedFixed64(all.getPackedFixed64List()).build(), + TestPackedTypes.newBuilder().addAllPackedSfixed32(all.getPackedSfixed32List()).build(), + TestPackedTypes.newBuilder().addAllPackedSfixed64(all.getPackedSfixed64List()).build(), + TestPackedTypes.newBuilder().addAllPackedFloat(all.getPackedFloatList()).build(), + TestPackedTypes.newBuilder().addAllPackedDouble(all.getPackedDoubleList()).build(), + TestPackedTypes.newBuilder().addAllPackedEnum(all.getPackedEnumList()).build(), + }; + for (TestPackedTypes message : messages) { + byte[] data = message.toByteArray(); + // Parsing truncated payload should fail. + for (int i = 1; i < data.length; i++) { + assertInvalidWireFormat(TestPackedTypes.getDefaultInstance(), data, 0, i); + } + } + } + + public void testParsePackedFieldsWithIncorrectLength() throws Exception { + // Set the length-prefix to 1 with a 4-bytes payload to test what happens when reading a packed + // element moves the reading position past the given length limit. It should result in an + // InvalidProtocolBufferException but an implementation may forget to check it especially for + // packed varint fields. + byte[] data = + new byte[] { + 0, + 0, // first two bytes is reserved for the tag. + 1, // length is 1 + (byte) 0x80, + (byte) 0x80, + (byte) 0x80, + (byte) 0x01, // a 4-bytes varint + }; + // All fields that can read a 4-bytes varint (all varint fields and fixed 32-bit fields). + int[] fieldNumbers = + new int[] { + TestPackedTypes.PACKED_INT32_FIELD_NUMBER, + TestPackedTypes.PACKED_INT64_FIELD_NUMBER, + TestPackedTypes.PACKED_UINT32_FIELD_NUMBER, + TestPackedTypes.PACKED_UINT64_FIELD_NUMBER, + TestPackedTypes.PACKED_SINT32_FIELD_NUMBER, + TestPackedTypes.PACKED_SINT64_FIELD_NUMBER, + TestPackedTypes.PACKED_FIXED32_FIELD_NUMBER, + TestPackedTypes.PACKED_SFIXED32_FIELD_NUMBER, + TestPackedTypes.PACKED_FLOAT_FIELD_NUMBER, + TestPackedTypes.PACKED_BOOL_FIELD_NUMBER, + TestPackedTypes.PACKED_ENUM_FIELD_NUMBER, + }; + for (int number : fieldNumbers) { + // Set the tag. + data[0] = + (byte) ((WireFormat.makeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED) & 0x7F) | 0x80); + data[1] = + (byte) ((WireFormat.makeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED) >>> 7) & 0x7F); + assertInvalidWireFormat(TestPackedTypes.getDefaultInstance(), data); + } + + // Data with 8-bytes payload to test some fixed 64-bit fields. + byte[] data8Bytes = + new byte[] { + 0, + 0, // first two bytes is reserved for the tag. + 1, // length is 1 + (byte) 0x80, + (byte) 0x80, + (byte) 0x80, + (byte) 0x80, + (byte) 0x80, + (byte) 0x80, + (byte) 0x80, + (byte) 0x01, // a 8-bytes varint + }; + // All fields that can only read 8-bytes data. + int[] fieldNumbers8Bytes = + new int[] { + TestPackedTypes.PACKED_FIXED64_FIELD_NUMBER, + TestPackedTypes.PACKED_SFIXED64_FIELD_NUMBER, + TestPackedTypes.PACKED_DOUBLE_FIELD_NUMBER, + }; + for (int number : fieldNumbers8Bytes) { + // Set the tag. + data8Bytes[0] = + (byte) ((WireFormat.makeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED) & 0x7F) | 0x80); + data8Bytes[1] = + (byte) ((WireFormat.makeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED) >>> 7) & 0x7F); + assertInvalidWireFormat(TestPackedTypes.getDefaultInstance(), data8Bytes); + } + } + + public void testParseVarintMinMax() throws Exception { + TestAllTypes message = + TestAllTypes.newBuilder() + .setOptionalInt32(Integer.MIN_VALUE) + .addRepeatedInt32(Integer.MAX_VALUE) + .setOptionalInt64(Long.MIN_VALUE) + .addRepeatedInt64(Long.MAX_VALUE) + .build(); + TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(Integer.MIN_VALUE, parsed.getOptionalInt32()); + assertEquals(Integer.MAX_VALUE, parsed.getRepeatedInt32(0)); + assertEquals(Long.MIN_VALUE, parsed.getOptionalInt64()); + assertEquals(Long.MAX_VALUE, parsed.getRepeatedInt64(0)); + } + + public void testParseAllVarintBits() throws Exception { + for (int i = 0; i < 32; i++) { + final int value = 1 << i; + TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(value).build(); + TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(value, parsed.getOptionalInt32()); + } + for (int i = 0; i < 64; i++) { + final long value = 1L << i; + TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt64(value).build(); + TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(value, parsed.getOptionalInt64()); + } + } + + public void testParseEmptyUnknownLengthDelimitedField() throws Exception { + byte[] data = + new byte[] {(byte) WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED), 0}; + TestAllTypes parsed = TestAllTypes.parseFrom(data); + assertTrue(Arrays.equals(data, parsed.toByteArray())); + } + + public void testParseEmptyString() throws Exception { + TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("").build(); + TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray()); + assertEquals("", parsed.getOptionalString()); + } + + public void testParseEmptyStringProto3() throws Exception { + TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("").build(); + // Note that we are parsing from a proto2 proto to a proto3 proto because empty string field is + // not serialized in proto3. + UnittestProto3.TestAllTypes parsed = + UnittestProto3.TestAllTypes.parseFrom(message.toByteArray()); + assertEquals("", parsed.getOptionalString()); + } + + public void testParseEmptyBytes() throws Exception { + TestAllTypes message = TestAllTypes.newBuilder().setOptionalBytes(ByteString.EMPTY).build(); + TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(ByteString.EMPTY, parsed.getOptionalBytes()); + } + + public void testParseEmptyRepeatedStringField() throws Exception { + TestAllTypes message = + TestAllTypes.newBuilder() + .addRepeatedString("") + .addRepeatedString("") + .addRepeatedString("0") + .build(); + TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(3, parsed.getRepeatedStringCount()); + assertEquals("", parsed.getRepeatedString(0)); + assertEquals("", parsed.getRepeatedString(1)); + assertEquals("0", parsed.getRepeatedString(2)); + } + + public void testParseEmptyRepeatedStringFieldProto3() throws Exception { + TestAllTypes message = + TestAllTypes.newBuilder() + .addRepeatedString("") + .addRepeatedString("") + .addRepeatedString("0") + .addRepeatedBytes(ByteString.EMPTY) + .build(); + UnittestProto3.TestAllTypes parsed = + UnittestProto3.TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(3, parsed.getRepeatedStringCount()); + assertEquals("", parsed.getRepeatedString(0)); + assertEquals("", parsed.getRepeatedString(1)); + assertEquals("0", parsed.getRepeatedString(2)); + } + + public void testParseEmptyRepeatedBytesField() throws Exception { + ByteString oneByte = ByteString.copyFrom(new byte[] {1}); + TestAllTypes message = + TestAllTypes.newBuilder() + .addRepeatedBytes(ByteString.EMPTY) + .addRepeatedBytes(ByteString.EMPTY) + .addRepeatedBytes(oneByte) + .build(); + TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(3, parsed.getRepeatedBytesCount()); + assertEquals(ByteString.EMPTY, parsed.getRepeatedBytes(0)); + assertEquals(ByteString.EMPTY, parsed.getRepeatedBytes(1)); + assertEquals(oneByte, parsed.getRepeatedBytes(2)); + } + + public void testSkipUnknownFieldInMessageSetItem() throws Exception { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + // MessageSet item's start tag. + output.write((byte) WireFormat.MESSAGE_SET_ITEM_TAG); + // Put all field types into the item. + TestUtil.getAllSet().writeTo(output); + // Closing the item with the real payload and closing tag. + output.write( + new byte[] { + (byte) WireFormat.MESSAGE_SET_TYPE_ID_TAG, + 100, // TYPE_ID = 100 + (byte) WireFormat.MESSAGE_SET_MESSAGE_TAG, + 0, // empty payload + (byte) WireFormat.MESSAGE_SET_ITEM_END_TAG, + }); + byte[] data = output.toByteArray(); + TestMessageSet parsed = TestMessageSet.parseFrom(data); + + // Convert to RawMessageSet for inspection. + RawMessageSet raw = RawMessageSet.parseFrom(parsed.toByteArray()); + assertEquals(1, raw.getItemCount()); + assertEquals(100, raw.getItem(0).getTypeId()); + assertEquals(0, raw.getItem(0).getMessage().size()); + } + + public void testProto2UnknownEnumValuesInOptionalField() throws Exception { + // Proto2 doesn't allow setting unknown enum values so we use proto3 to build a message with + // unknown enum values + UnittestProto3.TestAllTypes message = + UnittestProto3.TestAllTypes.newBuilder().setOptionalNestedEnumValue(4321).build(); + TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray()); + assertFalse(parsed.hasOptionalNestedEnum()); + // Make sure unknown enum values are preserved. + UnittestProto3.TestAllTypes actual = + UnittestProto3.TestAllTypes.parseFrom(parsed.toByteArray()); + assertEquals(4321, actual.getOptionalNestedEnumValue()); + } + + public void testProto2UnknownEnumValuesInRepeatedField() throws Exception { + // Proto2 doesn't allow setting unknown enum values so we use proto3 to build a message with + // unknown enum values + UnittestProto3.TestAllTypes message = + UnittestProto3.TestAllTypes.newBuilder().addRepeatedNestedEnumValue(5432).build(); + TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(0, parsed.getRepeatedNestedEnumCount()); + // Make sure unknown enum values are preserved. + UnittestProto3.TestAllTypes actual = + UnittestProto3.TestAllTypes.parseFrom(parsed.toByteArray()); + assertEquals(1, actual.getRepeatedNestedEnumCount()); + assertEquals(5432, actual.getRepeatedNestedEnumValue(0)); + } + + public void testProto2UnknownEnumValuesInMapField() throws Exception { + // Proto2 doesn't allow setting unknown enum values so we use proto3 to build a message with + // unknown enum values + TestMap message = TestMap.newBuilder().putInt32ToEnumFieldValue(1, 4321).build(); + MapForProto2TestProto.TestMap parsed = + MapForProto2TestProto.TestMap.parseFrom(message.toByteArray()); + assertEquals(0, parsed.getInt32ToEnumFieldMap().size()); + // Make sure unknown enum values are preserved. + TestMap actual = TestMap.parseFrom(parsed.toByteArray()); + assertEquals(1, actual.getInt32ToEnumFieldMap().size()); + assertEquals(4321, actual.getInt32ToEnumFieldValueOrThrow(1)); + } + + public void testProto2UnknownEnumValuesInOneof() throws Exception { + // Proto2 doesn't allow setting unknown enum values so we use proto3 to build a message with + // unknown enum values + UnittestProto3.TestOneof2 message = + UnittestProto3.TestOneof2.newBuilder().setFooEnumValue(1234).build(); + TestOneof2 parsed = TestOneof2.parseFrom(message.toByteArray()); + assertFalse(parsed.hasFooEnum()); + // Make sure unknown enum values are preserved. + UnittestProto3.TestOneof2 actual = UnittestProto3.TestOneof2.parseFrom(parsed.toByteArray()); + assertEquals(1234, actual.getFooEnumValue()); + } + + public void testProto2UnknownEnumValuesInExtension() throws Exception { + ExtensionRegistryLite extensionRegistry = TestUtilLite.getExtensionRegistryLite(); + // Raw bytes for "[.optional_foreign_enum_extension_lite]: 10" + final byte[] rawBytes = new byte[]{-80, 1, 10}; + TestAllExtensionsLite testAllExtensionsLite = + TestAllExtensionsLite.parseFrom(rawBytes, extensionRegistry); + assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, + testAllExtensionsLite.getExtension(optionalForeignEnumExtensionLite)); + final byte[] resultRawBytes = testAllExtensionsLite.toByteArray(); + assertEquals(rawBytes.length, resultRawBytes.length); + for (int i = 0; i < rawBytes.length; i++) { + assertEquals(rawBytes[i], resultRawBytes[i]); + } + } + + public void testProto3UnknownEnumValuesInOptionalField() throws Exception { + UnittestProto3.TestAllTypes message = + UnittestProto3.TestAllTypes.newBuilder().setOptionalNestedEnumValue(4321).build(); + UnittestProto3.TestAllTypes parsed = + UnittestProto3.TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(4321, parsed.getOptionalNestedEnumValue()); + } + + public void testProto3UnknownEnumValuesInRepeatedField() throws Exception { + UnittestProto3.TestAllTypes message = + UnittestProto3.TestAllTypes.newBuilder().addRepeatedNestedEnumValue(5432).build(); + UnittestProto3.TestAllTypes parsed = + UnittestProto3.TestAllTypes.parseFrom(message.toByteArray()); + assertEquals(1, parsed.getRepeatedNestedEnumCount()); + assertEquals(5432, parsed.getRepeatedNestedEnumValue(0)); + } + + public void testProto3UnknownEnumValuesInMapField() throws Exception { + TestMap message = TestMap.newBuilder().putInt32ToEnumFieldValue(1, 4321).build(); + TestMap parsed = TestMap.parseFrom(message.toByteArray()); + assertEquals(1, parsed.getInt32ToEnumFieldMap().size()); + assertEquals(4321, parsed.getInt32ToEnumFieldValueOrThrow(1)); + } + + public void testProto3UnknownEnumValuesInOneof() throws Exception { + UnittestProto3.TestOneof2 message = + UnittestProto3.TestOneof2.newBuilder().setFooEnumValue(1234).build(); + UnittestProto3.TestOneof2 parsed = UnittestProto3.TestOneof2.parseFrom(message.toByteArray()); + assertEquals(1234, parsed.getFooEnumValue()); + } + + public void testProto3MessageFieldMergeBehavior() throws Exception { + UnittestProto3.NestedTestAllTypes message1 = + UnittestProto3.NestedTestAllTypes.newBuilder() + .setPayload( + UnittestProto3.TestAllTypes.newBuilder() + .setOptionalInt32(1234) + .setOptionalInt64(5678)) + .build(); + UnittestProto3.NestedTestAllTypes message2 = + UnittestProto3.NestedTestAllTypes.newBuilder() + .setPayload( + UnittestProto3.TestAllTypes.newBuilder() + .setOptionalInt32(4321) + .setOptionalUint32(8765)) + .build(); + + UnittestProto3.NestedTestAllTypes merged = + UnittestProto3.NestedTestAllTypes.newBuilder() + .mergeFrom(message1.toByteArray()) + .mergeFrom(message2.toByteArray()) + .build(); + // Field values coming later in the stream override earlier values. + assertEquals(4321, merged.getPayload().getOptionalInt32()); + // Field values present in either message should be present in the merged result. + assertEquals(5678, merged.getPayload().getOptionalInt64()); + assertEquals(8765, merged.getPayload().getOptionalUint32()); + } + + public void testMergeFromPartialByteArray() throws Exception { + byte[] data = TestUtil.getAllSet().toByteArray(); + byte[] dataWithPaddings = new byte[data.length + 2]; + System.arraycopy(data, 0, dataWithPaddings, 1, data.length); + // Parsing will fail if the builder (or parser) interprets offset or length incorrectly. + TestAllTypes.newBuilder().mergeFrom(dataWithPaddings, 1, data.length); + TestAllTypes.parser().parseFrom(dataWithPaddings, 1, data.length); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/WrappersLiteOfMethodTest.java b/java/core/src/test/java/com/google/protobuf/WrappersLiteOfMethodTest.java new file mode 100755 index 000000000..4a3c7647f --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/WrappersLiteOfMethodTest.java @@ -0,0 +1,61 @@ +// 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.wrapperstest.WrappersTestProto.TopLevelMessage; +import junit.framework.TestCase; + +public class WrappersLiteOfMethodTest extends TestCase { + + public void testOf() throws Exception { + TopLevelMessage.Builder builder = TopLevelMessage.newBuilder(); + builder.setFieldDouble(DoubleValue.of(2.333)); + builder.setFieldFloat(FloatValue.of(2.333f)); + builder.setFieldInt32(Int32Value.of(2333)); + builder.setFieldInt64(Int64Value.of(23333333333333L)); + builder.setFieldUint32(UInt32Value.of(2333)); + builder.setFieldUint64(UInt64Value.of(23333333333333L)); + builder.setFieldBool(BoolValue.of(true)); + builder.setFieldString(StringValue.of("23333")); + builder.setFieldBytes(BytesValue.of(ByteString.wrap("233".getBytes(Internal.UTF_8)))); + + TopLevelMessage message = builder.build(); + assertTrue(2.333 == message.getFieldDouble().getValue()); + assertTrue(2.333f == message.getFieldFloat().getValue()); + assertTrue(2333 == message.getFieldInt32().getValue()); + assertTrue(23333333333333L == message.getFieldInt64().getValue()); + assertTrue(2333 == message.getFieldUint32().getValue()); + assertTrue(23333333333333L == message.getFieldUint64().getValue()); + assertTrue(true == message.getFieldBool().getValue()); + assertTrue(message.getFieldString().getValue().equals("23333")); + assertTrue(message.getFieldBytes().getValue().toStringUtf8().equals("233")); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/WrappersOfMethodTest.java b/java/core/src/test/java/com/google/protobuf/WrappersOfMethodTest.java new file mode 100755 index 000000000..f0d662d0c --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/WrappersOfMethodTest.java @@ -0,0 +1,61 @@ +// 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.wrapperstest.WrappersTestProto.TopLevelMessage; +import junit.framework.TestCase; + +public class WrappersOfMethodTest extends TestCase { + + public void testOf() throws Exception { + TopLevelMessage.Builder builder = TopLevelMessage.newBuilder(); + builder.setFieldDouble(DoubleValue.of(2.333)); + builder.setFieldFloat(FloatValue.of(2.333f)); + builder.setFieldInt32(Int32Value.of(2333)); + builder.setFieldInt64(Int64Value.of(23333333333333L)); + builder.setFieldUint32(UInt32Value.of(2333)); + builder.setFieldUint64(UInt64Value.of(23333333333333L)); + builder.setFieldBool(BoolValue.of(true)); + builder.setFieldString(StringValue.of("23333")); + builder.setFieldBytes(BytesValue.of(ByteString.wrap("233".getBytes(Internal.UTF_8)))); + + TopLevelMessage message = builder.build(); + assertTrue(2.333 == message.getFieldDouble().getValue()); + assertTrue(2.333f == message.getFieldFloat().getValue()); + assertTrue(2333 == message.getFieldInt32().getValue()); + assertTrue(23333333333333L == message.getFieldInt64().getValue()); + assertTrue(2333 == message.getFieldUint32().getValue()); + assertTrue(23333333333333L == message.getFieldUint64().getValue()); + assertTrue(true == message.getFieldBool().getValue()); + assertTrue(message.getFieldString().getValue().equals("23333")); + assertTrue(message.getFieldBytes().getValue().toStringUtf8().equals("233")); + } +} diff --git a/java/core/src/test/proto/com/google/protobuf/cached_field_size_test.proto b/java/core/src/test/proto/com/google/protobuf/cached_field_size_test.proto new file mode 100755 index 000000000..ce78b34c6 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/cached_field_size_test.proto @@ -0,0 +1,45 @@ +// 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. + +// A regression test for b/74087933 +syntax = "proto2"; + +package protobuf_unittest; + +option optimize_for = CODE_SIZE; +option java_multiple_files = true; + +import "google/protobuf/unittest.proto"; +import "google/protobuf/unittest_proto3.proto"; + +message TestCachedFieldSizeMessage { + optional protobuf_unittest.TestPackedTypes proto2_child = 1; + optional proto3_unittest.TestPackedTypes proto3_child = 2; +} diff --git a/java/core/src/test/proto/com/google/protobuf/message_lite_extension_util_test.proto b/java/core/src/test/proto/com/google/protobuf/message_lite_extension_util_test.proto new file mode 100755 index 000000000..f985ab0f5 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/message_lite_extension_util_test.proto @@ -0,0 +1,47 @@ +// 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. + +// Proto definitions used to test MessageLiteExtensionUtil +syntax = "proto2"; + +package protobuf_unittest; + +option java_outer_classname = "MessageLiteExtensionTestProtos"; + +message Car { + optional string make = 1; + extensions 1000 to max; +} + +extend Car { + optional bool turbo = 1001; + optional bool self_driving = 1002; + optional string plate = 9999; +} diff --git a/java/core/src/test/proto/com/google/protobuf/nested_extension.proto b/java/core/src/test/proto/com/google/protobuf/nested_extension.proto index 037040b5b..2da6d08e3 100644 --- a/java/core/src/test/proto/com/google/protobuf/nested_extension.proto +++ b/java/core/src/test/proto/com/google/protobuf/nested_extension.proto @@ -35,10 +35,10 @@ syntax = "proto2"; -import "com/google/protobuf/non_nested_extension.proto"; - package protobuf_unittest; +import "com/google/protobuf/non_nested_extension.proto"; + message MyNestedExtension { extend MessageToBeExtended { diff --git a/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto index 40d0f1905..024097cb5 100644 --- a/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto +++ b/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto @@ -38,10 +38,10 @@ syntax = "proto2"; package protobuf_unittest; -option optimize_for = LITE_RUNTIME; - import "com/google/protobuf/non_nested_extension_lite.proto"; +option optimize_for = LITE_RUNTIME; + message MyNestedExtensionLite { extend MessageLiteToBeExtended { optional MessageLiteToBeExtended recursiveExtensionLite = 3; diff --git a/java/core/src/test/proto/com/google/protobuf/packed_field_test.proto b/java/core/src/test/proto/com/google/protobuf/packed_field_test.proto new file mode 100755 index 000000000..7935322b7 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/packed_field_test.proto @@ -0,0 +1,76 @@ +// 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. + +syntax = "proto3"; + +package packed_field_test; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "PackedFieldTestProto"; + +message TestAllTypes { + enum NestedEnum { + FOO = 0; + BAR = 1; + BAZ = 2; + } + + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated NestedEnum repeated_nested_enum = 51; +} + +message TestUnpackedTypes { + repeated int32 repeated_int32 = 1 [packed = false]; + repeated int64 repeated_int64 = 2 [packed = false]; + repeated uint32 repeated_uint32 = 3 [packed = false]; + repeated uint64 repeated_uint64 = 4 [packed = false]; + repeated sint32 repeated_sint32 = 5 [packed = false]; + repeated sint64 repeated_sint64 = 6 [packed = false]; + repeated fixed32 repeated_fixed32 = 7 [packed = false]; + repeated fixed64 repeated_fixed64 = 8 [packed = false]; + repeated sfixed32 repeated_sfixed32 = 9 [packed = false]; + repeated sfixed64 repeated_sfixed64 = 10 [packed = false]; + repeated float repeated_float = 11 [packed = false]; + repeated double repeated_double = 12 [packed = false]; + repeated bool repeated_bool = 13 [packed = false]; + repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false]; +} diff --git a/java/core/src/test/proto/com/google/protobuf/proto2_message.proto b/java/core/src/test/proto/com/google/protobuf/proto2_message.proto new file mode 100755 index 000000000..005a911d9 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/proto2_message.proto @@ -0,0 +1,429 @@ +// 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. + +// LINT: ALLOW_GROUPS +syntax = "proto2"; + +option java_package = "com.google.protobuf.testing"; +option java_outer_classname = "Proto2Testing"; +package protobuf.experimental; + + +message Proto2SpecialFieldName { + optional double regular_name = 1; + optional int32 cached_size = 2; + optional int64 serialized_size = 3; + optional string class = 4; +} + +message Proto2Message { + + enum TestEnum { + ZERO = 0; + ONE = 1; + TWO = 2; + } + + optional double field_double_1 = 1; + optional float field_float_2 = 2; + optional int64 field_int64_3 = 3; + optional uint64 field_uint64_4 = 4; + optional int32 field_int32_5 = 5; + optional fixed64 field_fixed64_6 = 6; + optional fixed32 field_fixed32_7 = 7; + optional bool field_bool_8 = 8; + optional string field_string_9 = 9; + optional Proto2Message field_message_10 = 10; + optional bytes field_bytes_11 = 11; + optional uint32 field_uint32_12 = 12; + optional TestEnum field_enum_13 = 13; + optional sfixed32 field_sfixed32_14 = 14; + optional sfixed64 field_sfixed64_15 = 15; + optional sint32 field_sint32_16 = 16; + optional sint64 field_sint64_17 = 17; + repeated double field_double_list_18 = 18 [packed = false]; + repeated float field_float_list_19 = 19 [packed = false]; + repeated int64 field_int64_list_20 = 20 [packed = false]; + repeated uint64 field_uint64_list_21 = 21 [packed = false]; + repeated int32 field_int32_list_22 = 22 [packed = false]; + repeated fixed64 field_fixed64_list_23 = 23 [packed = false]; + repeated fixed32 field_fixed32_list_24 = 24 [packed = false]; + repeated bool field_bool_list_25 = 25 [packed = false]; + repeated string field_string_list_26 = 26 [packed = false]; + repeated Proto2Message field_message_list_27 = 27 [packed = false]; + repeated bytes field_bytes_list_28 = 28 [packed = false]; + repeated uint32 field_uint32_list_29 = 29 [packed = false]; + repeated TestEnum field_enum_list_30 = 30 [packed = false]; + repeated sfixed32 field_sfixed32_list_31 = 31 [packed = false]; + repeated sfixed64 field_sfixed64_list_32 = 32 [packed = false]; + repeated sint32 field_sint32_list_33 = 33 [packed = false]; + repeated sint64 field_sint64_list_34 = 34 [packed = false]; + repeated double field_double_list_packed_35 = 35 [packed = true]; + repeated float field_float_list_packed_36 = 36 [packed = true]; + repeated int64 field_int64_list_packed_37 = 37 [packed = true]; + repeated uint64 field_uint64_list_packed_38 = 38 [packed = true]; + repeated int32 field_int32_list_packed_39 = 39 [packed = true]; + repeated fixed64 field_fixed64_list_packed_40 = 40 [packed = true]; + repeated fixed32 field_fixed32_list_packed_41 = 41 [packed = true]; + repeated bool field_bool_list_packed_42 = 42 [packed = true]; + repeated uint32 field_uint32_list_packed_43 = 43 [packed = true]; + repeated TestEnum field_enum_list_packed_44 = 44 [packed = true]; + repeated sfixed32 field_sfixed32_list_packed_45 = 45 [packed = true]; + repeated sfixed64 field_sfixed64_list_packed_46 = 46 [packed = true]; + repeated sint32 field_sint32_list_packed_47 = 47 [packed = true]; + repeated sint64 field_sint64_list_packed_48 = 48 [packed = true]; + optional group FieldGroup49 = 49 { + optional int32 field_int32_50 = 50; + } + repeated group FieldGroupList51 = 51 { + optional int32 field_int32_52 = 52; + } + oneof test_oneof { + double field_double_53 = 53; + float field_float_54 = 54; + int64 field_int64_55 = 55; + uint64 field_uint64_56 = 56; + int32 field_int32_57 = 57; + fixed64 field_fixed64_58 = 58; + fixed32 field_fixed32_59 = 59; + bool field_bool_60 = 60; + string field_string_61 = 61; + Proto2Message field_message_62 = 62; + bytes field_bytes_63 = 63; + uint32 field_uint32_64 = 64; + sfixed32 field_sfixed32_65 = 65; + sfixed64 field_sfixed64_66 = 66; + sint32 field_sint32_67 = 67; + sint64 field_sint64_68 = 68; + group FieldGroup69 = 69 { + optional int32 field_int32_70 = 70; + } + } + + message RequiredNestedMessage { + optional int32 value = 1; + } + + required double field_required_double_71 = 71; + required float field_required_float_72 = 72; + required int64 field_required_int64_73 = 73; + required uint64 field_required_uint64_74 = 74; + required int32 field_required_int32_75 = 75; + required fixed64 field_required_fixed64_76 = 76; + required fixed32 field_required_fixed32_77 = 77; + required bool field_required_bool_78 = 78; + required string field_required_string_79 = 79; + required RequiredNestedMessage field_required_message_80 = 80; + required bytes field_required_bytes_81 = 81; + required uint32 field_required_uint32_82 = 82; + required TestEnum field_required_enum_83 = 83; + required sfixed32 field_required_sfixed32_84 = 84; + required sfixed64 field_required_sfixed64_85 = 85; + required sint32 field_required_sint32_86 = 86; + required sint64 field_required_sint64_87 = 87; + required group FieldRequiredGroup88 = 88 { + optional int32 field_int32_89 = 89; + } +} + +message Proto2Empty {} + +message Proto2MessageWithExtensions { + extensions 1 to 10000; +} + +extend Proto2MessageWithExtensions { + optional double field_double_1 = 1; + optional float field_float_2 = 2; + optional int64 field_int64_3 = 3; + optional uint64 field_uint64_4 = 4; + optional int32 field_int32_5 = 5; + optional fixed64 field_fixed64_6 = 6; + optional fixed32 field_fixed32_7 = 7; + optional bool field_bool_8 = 8; + optional string field_string_9 = 9; + optional Proto2Message field_message_10 = 10; + optional bytes field_bytes_11 = 11; + optional uint32 field_uint32_12 = 12; + optional Proto2Message.TestEnum field_enum_13 = 13; + optional sfixed32 field_sfixed32_14 = 14; + optional sfixed64 field_sfixed64_15 = 15; + optional sint32 field_sint32_16 = 16; + optional sint64 field_sint64_17 = 17; + + repeated double field_double_list_18 = 18 [packed = false]; + repeated float field_float_list_19 = 19 [packed = false]; + repeated int64 field_int64_list_20 = 20 [packed = false]; + repeated uint64 field_uint64_list_21 = 21 [packed = false]; + repeated int32 field_int32_list_22 = 22 [packed = false]; + repeated fixed64 field_fixed64_list_23 = 23 [packed = false]; + repeated fixed32 field_fixed32_list_24 = 24 [packed = false]; + repeated bool field_bool_list_25 = 25 [packed = false]; + repeated string field_string_list_26 = 26 [packed = false]; + repeated Proto2Message field_message_list_27 = 27 [packed = false]; + repeated bytes field_bytes_list_28 = 28 [packed = false]; + repeated uint32 field_uint32_list_29 = 29 [packed = false]; + repeated Proto2Message.TestEnum field_enum_list_30 = 30 [packed = false]; + repeated sfixed32 field_sfixed32_list_31 = 31 [packed = false]; + repeated sfixed64 field_sfixed64_list_32 = 32 [packed = false]; + repeated sint32 field_sint32_list_33 = 33 [packed = false]; + repeated sint64 field_sint64_list_34 = 34 [packed = false]; + + repeated double field_double_list_packed_35 = 35 [packed = true]; + repeated float field_float_list_packed_36 = 36 [packed = true]; + repeated int64 field_int64_list_packed_37 = 37 [packed = true]; + repeated uint64 field_uint64_list_packed_38 = 38 [packed = true]; + repeated int32 field_int32_list_packed_39 = 39 [packed = true]; + repeated fixed64 field_fixed64_list_packed_40 = 40 [packed = true]; + repeated fixed32 field_fixed32_list_packed_41 = 41 [packed = true]; + repeated bool field_bool_list_packed_42 = 42 [packed = true]; + repeated uint32 field_uint32_list_packed_43 = 43 [packed = true]; + repeated Proto2Message.TestEnum field_enum_list_packed_44 = 44 + [packed = true]; + repeated sfixed32 field_sfixed32_list_packed_45 = 45 [packed = true]; + repeated sfixed64 field_sfixed64_list_packed_46 = 46 [packed = true]; + repeated sint32 field_sint32_list_packed_47 = 47 [packed = true]; + repeated sint64 field_sint64_list_packed_48 = 48 [packed = true]; + + optional group FieldGroup49 = 49 { + optional int32 field_int32_50 = 50; + } + + repeated group FieldGroupList51 = 51 { + optional int32 field_int32_52 = 52; + } +} + +message Proto2MessageWithMaps { + map<bool, bool> field_map_bool_bool_1 = 1; + map<bool, bytes> field_map_bool_bytes_2 = 2; + map<bool, double> field_map_bool_double_3 = 3; + map<bool, Proto2Message.TestEnum> field_map_bool_enum_4 = 4; + map<bool, fixed32> field_map_bool_fixed32_5 = 5; + map<bool, fixed64> field_map_bool_fixed64_6 = 6; + map<bool, float> field_map_bool_float_7 = 7; + map<bool, int32> field_map_bool_int32_8 = 8; + map<bool, int64> field_map_bool_int64_9 = 9; + map<bool, Proto2Message> field_map_bool_message_10 = 10; + map<bool, sfixed32> field_map_bool_sfixed32_11 = 11; + map<bool, sfixed64> field_map_bool_sfixed64_12 = 12; + map<bool, sint32> field_map_bool_sint32_13 = 13; + map<bool, sint64> field_map_bool_sint64_14 = 14; + map<bool, string> field_map_bool_string_15 = 15; + map<bool, uint32> field_map_bool_uint32_16 = 16; + map<bool, uint64> field_map_bool_uint64_17 = 17; + map<fixed32, bool> field_map_fixed32_bool_18 = 18; + map<fixed32, bytes> field_map_fixed32_bytes_19 = 19; + map<fixed32, double> field_map_fixed32_double_20 = 20; + map<fixed32, Proto2Message.TestEnum> field_map_fixed32_enum_21 = 21; + map<fixed32, fixed32> field_map_fixed32_fixed32_22 = 22; + map<fixed32, fixed64> field_map_fixed32_fixed64_23 = 23; + map<fixed32, float> field_map_fixed32_float_24 = 24; + map<fixed32, int32> field_map_fixed32_int32_25 = 25; + map<fixed32, int64> field_map_fixed32_int64_26 = 26; + map<fixed32, Proto2Message> field_map_fixed32_message_27 = 27; + map<fixed32, sfixed32> field_map_fixed32_sfixed32_28 = 28; + map<fixed32, sfixed64> field_map_fixed32_sfixed64_29 = 29; + map<fixed32, sint32> field_map_fixed32_sint32_30 = 30; + map<fixed32, sint64> field_map_fixed32_sint64_31 = 31; + map<fixed32, string> field_map_fixed32_string_32 = 32; + map<fixed32, uint32> field_map_fixed32_uint32_33 = 33; + map<fixed32, uint64> field_map_fixed32_uint64_34 = 34; + map<fixed64, bool> field_map_fixed64_bool_35 = 35; + map<fixed64, bytes> field_map_fixed64_bytes_36 = 36; + map<fixed64, double> field_map_fixed64_double_37 = 37; + map<fixed64, Proto2Message.TestEnum> field_map_fixed64_enum_38 = 38; + map<fixed64, fixed32> field_map_fixed64_fixed32_39 = 39; + map<fixed64, fixed64> field_map_fixed64_fixed64_40 = 40; + map<fixed64, float> field_map_fixed64_float_41 = 41; + map<fixed64, int32> field_map_fixed64_int32_42 = 42; + map<fixed64, int64> field_map_fixed64_int64_43 = 43; + map<fixed64, Proto2Message> field_map_fixed64_message_44 = 44; + map<fixed64, sfixed32> field_map_fixed64_sfixed32_45 = 45; + map<fixed64, sfixed64> field_map_fixed64_sfixed64_46 = 46; + map<fixed64, sint32> field_map_fixed64_sint32_47 = 47; + map<fixed64, sint64> field_map_fixed64_sint64_48 = 48; + map<fixed64, string> field_map_fixed64_string_49 = 49; + map<fixed64, uint32> field_map_fixed64_uint32_50 = 50; + map<fixed64, uint64> field_map_fixed64_uint64_51 = 51; + map<int32, bool> field_map_int32_bool_52 = 52; + map<int32, bytes> field_map_int32_bytes_53 = 53; + map<int32, double> field_map_int32_double_54 = 54; + map<int32, Proto2Message.TestEnum> field_map_int32_enum_55 = 55; + map<int32, fixed32> field_map_int32_fixed32_56 = 56; + map<int32, fixed64> field_map_int32_fixed64_57 = 57; + map<int32, float> field_map_int32_float_58 = 58; + map<int32, int32> field_map_int32_int32_59 = 59; + map<int32, int64> field_map_int32_int64_60 = 60; + map<int32, Proto2Message> field_map_int32_message_61 = 61; + map<int32, sfixed32> field_map_int32_sfixed32_62 = 62; + map<int32, sfixed64> field_map_int32_sfixed64_63 = 63; + map<int32, sint32> field_map_int32_sint32_64 = 64; + map<int32, sint64> field_map_int32_sint64_65 = 65; + map<int32, string> field_map_int32_string_66 = 66; + map<int32, uint32> field_map_int32_uint32_67 = 67; + map<int32, uint64> field_map_int32_uint64_68 = 68; + map<int64, bool> field_map_int64_bool_69 = 69; + map<int64, bytes> field_map_int64_bytes_70 = 70; + map<int64, double> field_map_int64_double_71 = 71; + map<int64, Proto2Message.TestEnum> field_map_int64_enum_72 = 72; + map<int64, fixed32> field_map_int64_fixed32_73 = 73; + map<int64, fixed64> field_map_int64_fixed64_74 = 74; + map<int64, float> field_map_int64_float_75 = 75; + map<int64, int32> field_map_int64_int32_76 = 76; + map<int64, int64> field_map_int64_int64_77 = 77; + map<int64, Proto2Message> field_map_int64_message_78 = 78; + map<int64, sfixed32> field_map_int64_sfixed32_79 = 79; + map<int64, sfixed64> field_map_int64_sfixed64_80 = 80; + map<int64, sint32> field_map_int64_sint32_81 = 81; + map<int64, sint64> field_map_int64_sint64_82 = 82; + map<int64, string> field_map_int64_string_83 = 83; + map<int64, uint32> field_map_int64_uint32_84 = 84; + map<int64, uint64> field_map_int64_uint64_85 = 85; + map<sfixed32, bool> field_map_sfixed32_bool_86 = 86; + map<sfixed32, bytes> field_map_sfixed32_bytes_87 = 87; + map<sfixed32, double> field_map_sfixed32_double_88 = 88; + map<sfixed32, Proto2Message.TestEnum> field_map_sfixed32_enum_89 = 89; + map<sfixed32, fixed32> field_map_sfixed32_fixed32_90 = 90; + map<sfixed32, fixed64> field_map_sfixed32_fixed64_91 = 91; + map<sfixed32, float> field_map_sfixed32_float_92 = 92; + map<sfixed32, int32> field_map_sfixed32_int32_93 = 93; + map<sfixed32, int64> field_map_sfixed32_int64_94 = 94; + map<sfixed32, Proto2Message> field_map_sfixed32_message_95 = 95; + map<sfixed32, sfixed32> field_map_sfixed32_sfixed32_96 = 96; + map<sfixed32, sfixed64> field_map_sfixed32_sfixed64_97 = 97; + map<sfixed32, sint32> field_map_sfixed32_sint32_98 = 98; + map<sfixed32, sint64> field_map_sfixed32_sint64_99 = 99; + map<sfixed32, string> field_map_sfixed32_string_100 = 100; + map<sfixed32, uint32> field_map_sfixed32_uint32_101 = 101; + map<sfixed32, uint64> field_map_sfixed32_uint64_102 = 102; + map<sfixed64, bool> field_map_sfixed64_bool_103 = 103; + map<sfixed64, bytes> field_map_sfixed64_bytes_104 = 104; + map<sfixed64, double> field_map_sfixed64_double_105 = 105; + map<sfixed64, Proto2Message.TestEnum> field_map_sfixed64_enum_106 = 106; + map<sfixed64, fixed32> field_map_sfixed64_fixed32_107 = 107; + map<sfixed64, fixed64> field_map_sfixed64_fixed64_108 = 108; + map<sfixed64, float> field_map_sfixed64_float_109 = 109; + map<sfixed64, int32> field_map_sfixed64_int32_110 = 110; + map<sfixed64, int64> field_map_sfixed64_int64_111 = 111; + map<sfixed64, Proto2Message> field_map_sfixed64_message_112 = 112; + map<sfixed64, sfixed32> field_map_sfixed64_sfixed32_113 = 113; + map<sfixed64, sfixed64> field_map_sfixed64_sfixed64_114 = 114; + map<sfixed64, sint32> field_map_sfixed64_sint32_115 = 115; + map<sfixed64, sint64> field_map_sfixed64_sint64_116 = 116; + map<sfixed64, string> field_map_sfixed64_string_117 = 117; + map<sfixed64, uint32> field_map_sfixed64_uint32_118 = 118; + map<sfixed64, uint64> field_map_sfixed64_uint64_119 = 119; + map<sint32, bool> field_map_sint32_bool_120 = 120; + map<sint32, bytes> field_map_sint32_bytes_121 = 121; + map<sint32, double> field_map_sint32_double_122 = 122; + map<sint32, Proto2Message.TestEnum> field_map_sint32_enum_123 = 123; + map<sint32, fixed32> field_map_sint32_fixed32_124 = 124; + map<sint32, fixed64> field_map_sint32_fixed64_125 = 125; + map<sint32, float> field_map_sint32_float_126 = 126; + map<sint32, int32> field_map_sint32_int32_127 = 127; + map<sint32, int64> field_map_sint32_int64_128 = 128; + map<sint32, Proto2Message> field_map_sint32_message_129 = 129; + map<sint32, sfixed32> field_map_sint32_sfixed32_130 = 130; + map<sint32, sfixed64> field_map_sint32_sfixed64_131 = 131; + map<sint32, sint32> field_map_sint32_sint32_132 = 132; + map<sint32, sint64> field_map_sint32_sint64_133 = 133; + map<sint32, string> field_map_sint32_string_134 = 134; + map<sint32, uint32> field_map_sint32_uint32_135 = 135; + map<sint32, uint64> field_map_sint32_uint64_136 = 136; + map<sint64, bool> field_map_sint64_bool_137 = 137; + map<sint64, bytes> field_map_sint64_bytes_138 = 138; + map<sint64, double> field_map_sint64_double_139 = 139; + map<sint64, Proto2Message.TestEnum> field_map_sint64_enum_140 = 140; + map<sint64, fixed32> field_map_sint64_fixed32_141 = 141; + map<sint64, fixed64> field_map_sint64_fixed64_142 = 142; + map<sint64, float> field_map_sint64_float_143 = 143; + map<sint64, int32> field_map_sint64_int32_144 = 144; + map<sint64, int64> field_map_sint64_int64_145 = 145; + map<sint64, Proto2Message> field_map_sint64_message_146 = 146; + map<sint64, sfixed32> field_map_sint64_sfixed32_147 = 147; + map<sint64, sfixed64> field_map_sint64_sfixed64_148 = 148; + map<sint64, sint32> field_map_sint64_sint32_149 = 149; + map<sint64, sint64> field_map_sint64_sint64_150 = 150; + map<sint64, string> field_map_sint64_string_151 = 151; + map<sint64, uint32> field_map_sint64_uint32_152 = 152; + map<sint64, uint64> field_map_sint64_uint64_153 = 153; + map<string, bool> field_map_string_bool_154 = 154; + map<string, bytes> field_map_string_bytes_155 = 155; + map<string, double> field_map_string_double_156 = 156; + map<string, Proto2Message.TestEnum> field_map_string_enum_157 = 157; + map<string, fixed32> field_map_string_fixed32_158 = 158; + map<string, fixed64> field_map_string_fixed64_159 = 159; + map<string, float> field_map_string_float_160 = 160; + map<string, int32> field_map_string_int32_161 = 161; + map<string, int64> field_map_string_int64_162 = 162; + map<string, Proto2Message> field_map_string_message_163 = 163; + map<string, sfixed32> field_map_string_sfixed32_164 = 164; + map<string, sfixed64> field_map_string_sfixed64_165 = 165; + map<string, sint32> field_map_string_sint32_166 = 166; + map<string, sint64> field_map_string_sint64_167 = 167; + map<string, string> field_map_string_string_168 = 168; + map<string, uint32> field_map_string_uint32_169 = 169; + map<string, uint64> field_map_string_uint64_170 = 170; + map<uint32, bool> field_map_uint32_bool_171 = 171; + map<uint32, bytes> field_map_uint32_bytes_172 = 172; + map<uint32, double> field_map_uint32_double_173 = 173; + map<uint32, Proto2Message.TestEnum> field_map_uint32_enum_174 = 174; + map<uint32, fixed32> field_map_uint32_fixed32_175 = 175; + map<uint32, fixed64> field_map_uint32_fixed64_176 = 176; + map<uint32, float> field_map_uint32_float_177 = 177; + map<uint32, int32> field_map_uint32_int32_178 = 178; + map<uint32, int64> field_map_uint32_int64_179 = 179; + map<uint32, Proto2Message> field_map_uint32_message_180 = 180; + map<uint32, sfixed32> field_map_uint32_sfixed32_181 = 181; + map<uint32, sfixed64> field_map_uint32_sfixed64_182 = 182; + map<uint32, sint32> field_map_uint32_sint32_183 = 183; + map<uint32, sint64> field_map_uint32_sint64_184 = 184; + map<uint32, string> field_map_uint32_string_185 = 185; + map<uint32, uint32> field_map_uint32_uint32_186 = 186; + map<uint32, uint64> field_map_uint32_uint64_187 = 187; + map<uint64, bool> field_map_uint64_bool_188 = 188; + map<uint64, bytes> field_map_uint64_bytes_189 = 189; + map<uint64, double> field_map_uint64_double_190 = 190; + map<uint64, Proto2Message.TestEnum> field_map_uint64_enum_191 = 191; + map<uint64, fixed32> field_map_uint64_fixed32_192 = 192; + map<uint64, fixed64> field_map_uint64_fixed64_193 = 193; + map<uint64, float> field_map_uint64_float_194 = 194; + map<uint64, int32> field_map_uint64_int32_195 = 195; + map<uint64, int64> field_map_uint64_int64_196 = 196; + map<uint64, Proto2Message> field_map_uint64_message_197 = 197; + map<uint64, sfixed32> field_map_uint64_sfixed32_198 = 198; + map<uint64, sfixed64> field_map_uint64_sfixed64_199 = 199; + map<uint64, sint32> field_map_uint64_sint32_200 = 200; + map<uint64, sint64> field_map_uint64_sint64_201 = 201; + map<uint64, string> field_map_uint64_string_202 = 202; + map<uint64, uint32> field_map_uint64_uint32_203 = 203; + map<uint64, uint64> field_map_uint64_uint64_204 = 204; +} diff --git a/java/core/src/test/proto/com/google/protobuf/proto2_message_lite.proto b/java/core/src/test/proto/com/google/protobuf/proto2_message_lite.proto new file mode 100755 index 000000000..8385dfdce --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/proto2_message_lite.proto @@ -0,0 +1,422 @@ +// 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. + +// LINT: ALLOW_GROUPS +syntax = "proto2"; + +option java_package = "com.google.protobuf.testing"; +option java_outer_classname = "Proto2TestingLite"; +package protobuf.experimental.lite; + + +message Proto2MessageLite { + + enum TestEnum { + ZERO = 0; + ONE = 1; + TWO = 2; + } + + optional double field_double_1 = 1; + optional float field_float_2 = 2; + optional int64 field_int64_3 = 3; + optional uint64 field_uint64_4 = 4; + optional int32 field_int32_5 = 5; + optional fixed64 field_fixed64_6 = 6; + optional fixed32 field_fixed32_7 = 7; + optional bool field_bool_8 = 8; + optional string field_string_9 = 9; + optional Proto2MessageLite field_message_10 = 10; + optional bytes field_bytes_11 = 11; + optional uint32 field_uint32_12 = 12; + optional TestEnum field_enum_13 = 13; + optional sfixed32 field_sfixed32_14 = 14; + optional sfixed64 field_sfixed64_15 = 15; + optional sint32 field_sint32_16 = 16; + optional sint64 field_sint64_17 = 17; + repeated double field_double_list_18 = 18 [packed = false]; + repeated float field_float_list_19 = 19 [packed = false]; + repeated int64 field_int64_list_20 = 20 [packed = false]; + repeated uint64 field_uint64_list_21 = 21 [packed = false]; + repeated int32 field_int32_list_22 = 22 [packed = false]; + repeated fixed64 field_fixed64_list_23 = 23 [packed = false]; + repeated fixed32 field_fixed32_list_24 = 24 [packed = false]; + repeated bool field_bool_list_25 = 25 [packed = false]; + repeated string field_string_list_26 = 26 [packed = false]; + repeated Proto2MessageLite field_message_list_27 = 27 [packed = false]; + repeated bytes field_bytes_list_28 = 28 [packed = false]; + repeated uint32 field_uint32_list_29 = 29 [packed = false]; + repeated TestEnum field_enum_list_30 = 30 [packed = false]; + repeated sfixed32 field_sfixed32_list_31 = 31 [packed = false]; + repeated sfixed64 field_sfixed64_list_32 = 32 [packed = false]; + repeated sint32 field_sint32_list_33 = 33 [packed = false]; + repeated sint64 field_sint64_list_34 = 34 [packed = false]; + repeated double field_double_list_packed_35 = 35 [packed = true]; + repeated float field_float_list_packed_36 = 36 [packed = true]; + repeated int64 field_int64_list_packed_37 = 37 [packed = true]; + repeated uint64 field_uint64_list_packed_38 = 38 [packed = true]; + repeated int32 field_int32_list_packed_39 = 39 [packed = true]; + repeated fixed64 field_fixed64_list_packed_40 = 40 [packed = true]; + repeated fixed32 field_fixed32_list_packed_41 = 41 [packed = true]; + repeated bool field_bool_list_packed_42 = 42 [packed = true]; + repeated uint32 field_uint32_list_packed_43 = 43 [packed = true]; + repeated TestEnum field_enum_list_packed_44 = 44 [packed = true]; + repeated sfixed32 field_sfixed32_list_packed_45 = 45 [packed = true]; + repeated sfixed64 field_sfixed64_list_packed_46 = 46 [packed = true]; + repeated sint32 field_sint32_list_packed_47 = 47 [packed = true]; + repeated sint64 field_sint64_list_packed_48 = 48 [packed = true]; + optional group FieldGroup49 = 49 { + optional int32 field_int32_50 = 50; + } + repeated group FieldGroupList51 = 51 { + optional int32 field_int32_52 = 52; + } + oneof test_oneof { + double field_double_53 = 53; + float field_float_54 = 54; + int64 field_int64_55 = 55; + uint64 field_uint64_56 = 56; + int32 field_int32_57 = 57; + fixed64 field_fixed64_58 = 58; + fixed32 field_fixed32_59 = 59; + bool field_bool_60 = 60; + string field_string_61 = 61; + Proto2MessageLite field_message_62 = 62; + bytes field_bytes_63 = 63; + uint32 field_uint32_64 = 64; + sfixed32 field_sfixed32_65 = 65; + sfixed64 field_sfixed64_66 = 66; + sint32 field_sint32_67 = 67; + sint64 field_sint64_68 = 68; + group FieldGroup69 = 69 { + optional int32 field_int32_70 = 70; + } + } + + message RequiredNestedMessage { + optional int32 value = 1; + } + + required double field_required_double_71 = 71; + required float field_required_float_72 = 72; + required int64 field_required_int64_73 = 73; + required uint64 field_required_uint64_74 = 74; + required int32 field_required_int32_75 = 75; + required fixed64 field_required_fixed64_76 = 76; + required fixed32 field_required_fixed32_77 = 77; + required bool field_required_bool_78 = 78; + required string field_required_string_79 = 79; + required RequiredNestedMessage field_required_message_80 = 80; + required bytes field_required_bytes_81 = 81; + required uint32 field_required_uint32_82 = 82; + required TestEnum field_required_enum_83 = 83; + required sfixed32 field_required_sfixed32_84 = 84; + required sfixed64 field_required_sfixed64_85 = 85; + required sint32 field_required_sint32_86 = 86; + required sint64 field_required_sint64_87 = 87; + required group FieldRequiredGroup88 = 88 { + optional int32 field_int32_89 = 89; + } +} + +message Proto2EmptyLite {} + +message Proto2MessageLiteWithExtensions { + extensions 1 to max; +} + +extend Proto2MessageLiteWithExtensions { + optional double field_double_1 = 1; + optional float field_float_2 = 2; + optional int64 field_int64_3 = 3; + optional uint64 field_uint64_4 = 4; + optional int32 field_int32_5 = 5; + optional fixed64 field_fixed64_6 = 6; + optional fixed32 field_fixed32_7 = 7; + optional bool field_bool_8 = 8; + optional string field_string_9 = 9; + optional Proto2MessageLite field_message_10 = 10; + optional bytes field_bytes_11 = 11; + optional uint32 field_uint32_12 = 12; + optional Proto2MessageLite.TestEnum field_enum_13 = 13; + optional sfixed32 field_sfixed32_14 = 14; + optional sfixed64 field_sfixed64_15 = 15; + optional sint32 field_sint32_16 = 16; + optional sint64 field_sint64_17 = 17; + + repeated double field_double_list_18 = 18 [packed = false]; + repeated float field_float_list_19 = 19 [packed = false]; + repeated int64 field_int64_list_20 = 20 [packed = false]; + repeated uint64 field_uint64_list_21 = 21 [packed = false]; + repeated int32 field_int32_list_22 = 22 [packed = false]; + repeated fixed64 field_fixed64_list_23 = 23 [packed = false]; + repeated fixed32 field_fixed32_list_24 = 24 [packed = false]; + repeated bool field_bool_list_25 = 25 [packed = false]; + repeated string field_string_list_26 = 26 [packed = false]; + repeated Proto2MessageLite field_message_list_27 = 27 [packed = false]; + repeated bytes field_bytes_list_28 = 28 [packed = false]; + repeated uint32 field_uint32_list_29 = 29 [packed = false]; + repeated Proto2MessageLite.TestEnum field_enum_list_30 = 30 [packed = false]; + repeated sfixed32 field_sfixed32_list_31 = 31 [packed = false]; + repeated sfixed64 field_sfixed64_list_32 = 32 [packed = false]; + repeated sint32 field_sint32_list_33 = 33 [packed = false]; + repeated sint64 field_sint64_list_34 = 34 [packed = false]; + + repeated double field_double_list_packed_35 = 35 [packed = true]; + repeated float field_float_list_packed_36 = 36 [packed = true]; + repeated int64 field_int64_list_packed_37 = 37 [packed = true]; + repeated uint64 field_uint64_list_packed_38 = 38 [packed = true]; + repeated int32 field_int32_list_packed_39 = 39 [packed = true]; + repeated fixed64 field_fixed64_list_packed_40 = 40 [packed = true]; + repeated fixed32 field_fixed32_list_packed_41 = 41 [packed = true]; + repeated bool field_bool_list_packed_42 = 42 [packed = true]; + repeated uint32 field_uint32_list_packed_43 = 43 [packed = true]; + repeated Proto2MessageLite.TestEnum field_enum_list_packed_44 = 44 + [packed = true]; + repeated sfixed32 field_sfixed32_list_packed_45 = 45 [packed = true]; + repeated sfixed64 field_sfixed64_list_packed_46 = 46 [packed = true]; + repeated sint32 field_sint32_list_packed_47 = 47 [packed = true]; + repeated sint64 field_sint64_list_packed_48 = 48 [packed = true]; + + optional group FieldGroup49 = 49 { + optional int32 field_int32_50 = 50; + } + + repeated group FieldGroupList51 = 51 { + optional int32 field_int32_52 = 52; + } +} + +message Proto2MessageLiteWithMaps { + map<bool, bool> field_map_bool_bool_1 = 1; + map<bool, bytes> field_map_bool_bytes_2 = 2; + map<bool, double> field_map_bool_double_3 = 3; + map<bool, Proto2MessageLite.TestEnum> field_map_bool_enum_4 = 4; + map<bool, fixed32> field_map_bool_fixed32_5 = 5; + map<bool, fixed64> field_map_bool_fixed64_6 = 6; + map<bool, float> field_map_bool_float_7 = 7; + map<bool, int32> field_map_bool_int32_8 = 8; + map<bool, int64> field_map_bool_int64_9 = 9; + map<bool, Proto2MessageLite> field_map_bool_message_10 = 10; + map<bool, sfixed32> field_map_bool_sfixed32_11 = 11; + map<bool, sfixed64> field_map_bool_sfixed64_12 = 12; + map<bool, sint32> field_map_bool_sint32_13 = 13; + map<bool, sint64> field_map_bool_sint64_14 = 14; + map<bool, string> field_map_bool_string_15 = 15; + map<bool, uint32> field_map_bool_uint32_16 = 16; + map<bool, uint64> field_map_bool_uint64_17 = 17; + map<fixed32, bool> field_map_fixed32_bool_18 = 18; + map<fixed32, bytes> field_map_fixed32_bytes_19 = 19; + map<fixed32, double> field_map_fixed32_double_20 = 20; + map<fixed32, Proto2MessageLite.TestEnum> field_map_fixed32_enum_21 = 21; + map<fixed32, fixed32> field_map_fixed32_fixed32_22 = 22; + map<fixed32, fixed64> field_map_fixed32_fixed64_23 = 23; + map<fixed32, float> field_map_fixed32_float_24 = 24; + map<fixed32, int32> field_map_fixed32_int32_25 = 25; + map<fixed32, int64> field_map_fixed32_int64_26 = 26; + map<fixed32, Proto2MessageLite> field_map_fixed32_message_27 = 27; + map<fixed32, sfixed32> field_map_fixed32_sfixed32_28 = 28; + map<fixed32, sfixed64> field_map_fixed32_sfixed64_29 = 29; + map<fixed32, sint32> field_map_fixed32_sint32_30 = 30; + map<fixed32, sint64> field_map_fixed32_sint64_31 = 31; + map<fixed32, string> field_map_fixed32_string_32 = 32; + map<fixed32, uint32> field_map_fixed32_uint32_33 = 33; + map<fixed32, uint64> field_map_fixed32_uint64_34 = 34; + map<fixed64, bool> field_map_fixed64_bool_35 = 35; + map<fixed64, bytes> field_map_fixed64_bytes_36 = 36; + map<fixed64, double> field_map_fixed64_double_37 = 37; + map<fixed64, Proto2MessageLite.TestEnum> field_map_fixed64_enum_38 = 38; + map<fixed64, fixed32> field_map_fixed64_fixed32_39 = 39; + map<fixed64, fixed64> field_map_fixed64_fixed64_40 = 40; + map<fixed64, float> field_map_fixed64_float_41 = 41; + map<fixed64, int32> field_map_fixed64_int32_42 = 42; + map<fixed64, int64> field_map_fixed64_int64_43 = 43; + map<fixed64, Proto2MessageLite> field_map_fixed64_message_44 = 44; + map<fixed64, sfixed32> field_map_fixed64_sfixed32_45 = 45; + map<fixed64, sfixed64> field_map_fixed64_sfixed64_46 = 46; + map<fixed64, sint32> field_map_fixed64_sint32_47 = 47; + map<fixed64, sint64> field_map_fixed64_sint64_48 = 48; + map<fixed64, string> field_map_fixed64_string_49 = 49; + map<fixed64, uint32> field_map_fixed64_uint32_50 = 50; + map<fixed64, uint64> field_map_fixed64_uint64_51 = 51; + map<int32, bool> field_map_int32_bool_52 = 52; + map<int32, bytes> field_map_int32_bytes_53 = 53; + map<int32, double> field_map_int32_double_54 = 54; + map<int32, Proto2MessageLite.TestEnum> field_map_int32_enum_55 = 55; + map<int32, fixed32> field_map_int32_fixed32_56 = 56; + map<int32, fixed64> field_map_int32_fixed64_57 = 57; + map<int32, float> field_map_int32_float_58 = 58; + map<int32, int32> field_map_int32_int32_59 = 59; + map<int32, int64> field_map_int32_int64_60 = 60; + map<int32, Proto2MessageLite> field_map_int32_message_61 = 61; + map<int32, sfixed32> field_map_int32_sfixed32_62 = 62; + map<int32, sfixed64> field_map_int32_sfixed64_63 = 63; + map<int32, sint32> field_map_int32_sint32_64 = 64; + map<int32, sint64> field_map_int32_sint64_65 = 65; + map<int32, string> field_map_int32_string_66 = 66; + map<int32, uint32> field_map_int32_uint32_67 = 67; + map<int32, uint64> field_map_int32_uint64_68 = 68; + map<int64, bool> field_map_int64_bool_69 = 69; + map<int64, bytes> field_map_int64_bytes_70 = 70; + map<int64, double> field_map_int64_double_71 = 71; + map<int64, Proto2MessageLite.TestEnum> field_map_int64_enum_72 = 72; + map<int64, fixed32> field_map_int64_fixed32_73 = 73; + map<int64, fixed64> field_map_int64_fixed64_74 = 74; + map<int64, float> field_map_int64_float_75 = 75; + map<int64, int32> field_map_int64_int32_76 = 76; + map<int64, int64> field_map_int64_int64_77 = 77; + map<int64, Proto2MessageLite> field_map_int64_message_78 = 78; + map<int64, sfixed32> field_map_int64_sfixed32_79 = 79; + map<int64, sfixed64> field_map_int64_sfixed64_80 = 80; + map<int64, sint32> field_map_int64_sint32_81 = 81; + map<int64, sint64> field_map_int64_sint64_82 = 82; + map<int64, string> field_map_int64_string_83 = 83; + map<int64, uint32> field_map_int64_uint32_84 = 84; + map<int64, uint64> field_map_int64_uint64_85 = 85; + map<sfixed32, bool> field_map_sfixed32_bool_86 = 86; + map<sfixed32, bytes> field_map_sfixed32_bytes_87 = 87; + map<sfixed32, double> field_map_sfixed32_double_88 = 88; + map<sfixed32, Proto2MessageLite.TestEnum> field_map_sfixed32_enum_89 = 89; + map<sfixed32, fixed32> field_map_sfixed32_fixed32_90 = 90; + map<sfixed32, fixed64> field_map_sfixed32_fixed64_91 = 91; + map<sfixed32, float> field_map_sfixed32_float_92 = 92; + map<sfixed32, int32> field_map_sfixed32_int32_93 = 93; + map<sfixed32, int64> field_map_sfixed32_int64_94 = 94; + map<sfixed32, Proto2MessageLite> field_map_sfixed32_message_95 = 95; + map<sfixed32, sfixed32> field_map_sfixed32_sfixed32_96 = 96; + map<sfixed32, sfixed64> field_map_sfixed32_sfixed64_97 = 97; + map<sfixed32, sint32> field_map_sfixed32_sint32_98 = 98; + map<sfixed32, sint64> field_map_sfixed32_sint64_99 = 99; + map<sfixed32, string> field_map_sfixed32_string_100 = 100; + map<sfixed32, uint32> field_map_sfixed32_uint32_101 = 101; + map<sfixed32, uint64> field_map_sfixed32_uint64_102 = 102; + map<sfixed64, bool> field_map_sfixed64_bool_103 = 103; + map<sfixed64, bytes> field_map_sfixed64_bytes_104 = 104; + map<sfixed64, double> field_map_sfixed64_double_105 = 105; + map<sfixed64, Proto2MessageLite.TestEnum> field_map_sfixed64_enum_106 = 106; + map<sfixed64, fixed32> field_map_sfixed64_fixed32_107 = 107; + map<sfixed64, fixed64> field_map_sfixed64_fixed64_108 = 108; + map<sfixed64, float> field_map_sfixed64_float_109 = 109; + map<sfixed64, int32> field_map_sfixed64_int32_110 = 110; + map<sfixed64, int64> field_map_sfixed64_int64_111 = 111; + map<sfixed64, Proto2MessageLite> field_map_sfixed64_message_112 = 112; + map<sfixed64, sfixed32> field_map_sfixed64_sfixed32_113 = 113; + map<sfixed64, sfixed64> field_map_sfixed64_sfixed64_114 = 114; + map<sfixed64, sint32> field_map_sfixed64_sint32_115 = 115; + map<sfixed64, sint64> field_map_sfixed64_sint64_116 = 116; + map<sfixed64, string> field_map_sfixed64_string_117 = 117; + map<sfixed64, uint32> field_map_sfixed64_uint32_118 = 118; + map<sfixed64, uint64> field_map_sfixed64_uint64_119 = 119; + map<sint32, bool> field_map_sint32_bool_120 = 120; + map<sint32, bytes> field_map_sint32_bytes_121 = 121; + map<sint32, double> field_map_sint32_double_122 = 122; + map<sint32, Proto2MessageLite.TestEnum> field_map_sint32_enum_123 = 123; + map<sint32, fixed32> field_map_sint32_fixed32_124 = 124; + map<sint32, fixed64> field_map_sint32_fixed64_125 = 125; + map<sint32, float> field_map_sint32_float_126 = 126; + map<sint32, int32> field_map_sint32_int32_127 = 127; + map<sint32, int64> field_map_sint32_int64_128 = 128; + map<sint32, Proto2MessageLite> field_map_sint32_message_129 = 129; + map<sint32, sfixed32> field_map_sint32_sfixed32_130 = 130; + map<sint32, sfixed64> field_map_sint32_sfixed64_131 = 131; + map<sint32, sint32> field_map_sint32_sint32_132 = 132; + map<sint32, sint64> field_map_sint32_sint64_133 = 133; + map<sint32, string> field_map_sint32_string_134 = 134; + map<sint32, uint32> field_map_sint32_uint32_135 = 135; + map<sint32, uint64> field_map_sint32_uint64_136 = 136; + map<sint64, bool> field_map_sint64_bool_137 = 137; + map<sint64, bytes> field_map_sint64_bytes_138 = 138; + map<sint64, double> field_map_sint64_double_139 = 139; + map<sint64, Proto2MessageLite.TestEnum> field_map_sint64_enum_140 = 140; + map<sint64, fixed32> field_map_sint64_fixed32_141 = 141; + map<sint64, fixed64> field_map_sint64_fixed64_142 = 142; + map<sint64, float> field_map_sint64_float_143 = 143; + map<sint64, int32> field_map_sint64_int32_144 = 144; + map<sint64, int64> field_map_sint64_int64_145 = 145; + map<sint64, Proto2MessageLite> field_map_sint64_message_146 = 146; + map<sint64, sfixed32> field_map_sint64_sfixed32_147 = 147; + map<sint64, sfixed64> field_map_sint64_sfixed64_148 = 148; + map<sint64, sint32> field_map_sint64_sint32_149 = 149; + map<sint64, sint64> field_map_sint64_sint64_150 = 150; + map<sint64, string> field_map_sint64_string_151 = 151; + map<sint64, uint32> field_map_sint64_uint32_152 = 152; + map<sint64, uint64> field_map_sint64_uint64_153 = 153; + map<string, bool> field_map_string_bool_154 = 154; + map<string, bytes> field_map_string_bytes_155 = 155; + map<string, double> field_map_string_double_156 = 156; + map<string, Proto2MessageLite.TestEnum> field_map_string_enum_157 = 157; + map<string, fixed32> field_map_string_fixed32_158 = 158; + map<string, fixed64> field_map_string_fixed64_159 = 159; + map<string, float> field_map_string_float_160 = 160; + map<string, int32> field_map_string_int32_161 = 161; + map<string, int64> field_map_string_int64_162 = 162; + map<string, Proto2MessageLite> field_map_string_message_163 = 163; + map<string, sfixed32> field_map_string_sfixed32_164 = 164; + map<string, sfixed64> field_map_string_sfixed64_165 = 165; + map<string, sint32> field_map_string_sint32_166 = 166; + map<string, sint64> field_map_string_sint64_167 = 167; + map<string, string> field_map_string_string_168 = 168; + map<string, uint32> field_map_string_uint32_169 = 169; + map<string, uint64> field_map_string_uint64_170 = 170; + map<uint32, bool> field_map_uint32_bool_171 = 171; + map<uint32, bytes> field_map_uint32_bytes_172 = 172; + map<uint32, double> field_map_uint32_double_173 = 173; + map<uint32, Proto2MessageLite.TestEnum> field_map_uint32_enum_174 = 174; + map<uint32, fixed32> field_map_uint32_fixed32_175 = 175; + map<uint32, fixed64> field_map_uint32_fixed64_176 = 176; + map<uint32, float> field_map_uint32_float_177 = 177; + map<uint32, int32> field_map_uint32_int32_178 = 178; + map<uint32, int64> field_map_uint32_int64_179 = 179; + map<uint32, Proto2MessageLite> field_map_uint32_message_180 = 180; + map<uint32, sfixed32> field_map_uint32_sfixed32_181 = 181; + map<uint32, sfixed64> field_map_uint32_sfixed64_182 = 182; + map<uint32, sint32> field_map_uint32_sint32_183 = 183; + map<uint32, sint64> field_map_uint32_sint64_184 = 184; + map<uint32, string> field_map_uint32_string_185 = 185; + map<uint32, uint32> field_map_uint32_uint32_186 = 186; + map<uint32, uint64> field_map_uint32_uint64_187 = 187; + map<uint64, bool> field_map_uint64_bool_188 = 188; + map<uint64, bytes> field_map_uint64_bytes_189 = 189; + map<uint64, double> field_map_uint64_double_190 = 190; + map<uint64, Proto2MessageLite.TestEnum> field_map_uint64_enum_191 = 191; + map<uint64, fixed32> field_map_uint64_fixed32_192 = 192; + map<uint64, fixed64> field_map_uint64_fixed64_193 = 193; + map<uint64, float> field_map_uint64_float_194 = 194; + map<uint64, int32> field_map_uint64_int32_195 = 195; + map<uint64, int64> field_map_uint64_int64_196 = 196; + map<uint64, Proto2MessageLite> field_map_uint64_message_197 = 197; + map<uint64, sfixed32> field_map_uint64_sfixed32_198 = 198; + map<uint64, sfixed64> field_map_uint64_sfixed64_199 = 199; + map<uint64, sint32> field_map_uint64_sint32_200 = 200; + map<uint64, sint64> field_map_uint64_sint64_201 = 201; + map<uint64, string> field_map_uint64_string_202 = 202; + map<uint64, uint32> field_map_uint64_uint32_203 = 203; + map<uint64, uint64> field_map_uint64_uint64_204 = 204; +} diff --git a/java/core/src/test/proto/com/google/protobuf/proto3_message.proto b/java/core/src/test/proto/com/google/protobuf/proto3_message.proto new file mode 100755 index 000000000..01c7deb7c --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/proto3_message.proto @@ -0,0 +1,326 @@ +// 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. + +syntax = "proto3"; + +option java_package = "com.google.protobuf.testing"; +option java_outer_classname = "Proto3Testing"; +package protobuf.experimental; + +message Proto3SpecialFieldName { + double regular_name = 1; + int32 cached_size = 2; + int64 serialized_size = 3; + string class = 4; +} + +message Proto3Message { + enum TestEnum { + ZERO = 0; + ONE = 1; + TWO = 2; + } + + double field_double_1 = 1; + float field_float_2 = 2; + int64 field_int64_3 = 3; + uint64 field_uint64_4 = 4; + int32 field_int32_5 = 5; + fixed64 field_fixed64_6 = 6; + fixed32 field_fixed32_7 = 7; + bool field_bool_8 = 8; + string field_string_9 = 9; + Proto3Message field_message_10 = 10; + bytes field_bytes_11 = 11; + uint32 field_uint32_12 = 12; + TestEnum field_enum_13 = 13; + sfixed32 field_sfixed32_14 = 14; + sfixed64 field_sfixed64_15 = 15; + sint32 field_sint32_16 = 16; + sint64 field_sint64_17 = 17; + repeated double field_double_list_18 = 18 [packed = false]; + repeated float field_float_list_19 = 19 [packed = false]; + repeated int64 field_int64_list_20 = 20 [packed = false]; + repeated uint64 field_uint64_list_21 = 21 [packed = false]; + repeated int32 field_int32_list_22 = 22 [packed = false]; + repeated fixed64 field_fixed64_list_23 = 23 [packed = false]; + repeated fixed32 field_fixed32_list_24 = 24 [packed = false]; + repeated bool field_bool_list_25 = 25 [packed = false]; + repeated string field_string_list_26 = 26 [packed = false]; + repeated Proto3Message field_message_list_27 = 27 [packed = false]; + repeated bytes field_bytes_list_28 = 28 [packed = false]; + repeated uint32 field_uint32_list_29 = 29 [packed = false]; + repeated TestEnum field_enum_list_30 = 30 [packed = false]; + repeated sfixed32 field_sfixed32_list_31 = 31 [packed = false]; + repeated sfixed64 field_sfixed64_list_32 = 32 [packed = false]; + repeated sint32 field_sint32_list_33 = 33 [packed = false]; + repeated sint64 field_sint64_list_34 = 34 [packed = false]; + repeated double field_double_list_packed_35 = 35 [packed = true]; + repeated float field_float_list_packed_36 = 36 [packed = true]; + repeated int64 field_int64_list_packed_37 = 37 [packed = true]; + repeated uint64 field_uint64_list_packed_38 = 38 [packed = true]; + repeated int32 field_int32_list_packed_39 = 39 [packed = true]; + repeated fixed64 field_fixed64_list_packed_40 = 40 [packed = true]; + repeated fixed32 field_fixed32_list_packed_41 = 41 [packed = true]; + repeated bool field_bool_list_packed_42 = 42 [packed = true]; + repeated uint32 field_uint32_list_packed_43 = 43 [packed = true]; + repeated TestEnum field_enum_list_packed_44 = 44 [packed = true]; + repeated sfixed32 field_sfixed32_list_packed_45 = 45 [packed = true]; + repeated sfixed64 field_sfixed64_list_packed_46 = 46 [packed = true]; + repeated sint32 field_sint32_list_packed_47 = 47 [packed = true]; + repeated sint64 field_sint64_list_packed_48 = 48 [packed = true]; + oneof test_oneof { + double field_double_53 = 53; + float field_float_54 = 54; + int64 field_int64_55 = 55; + uint64 field_uint64_56 = 56; + int32 field_int32_57 = 57; + fixed64 field_fixed64_58 = 58; + fixed32 field_fixed32_59 = 59; + bool field_bool_60 = 60; + string field_string_61 = 61; + Proto3Message field_message_62 = 62; + bytes field_bytes_63 = 63; + uint32 field_uint32_64 = 64; + sfixed32 field_sfixed32_65 = 65; + sfixed64 field_sfixed64_66 = 66; + sint32 field_sint32_67 = 67; + sint64 field_sint64_68 = 68; + } +} + +message Proto3Empty {} + +message Proto3MessageWithMaps { + map<bool, bool> field_map_bool_bool_1 = 1; + map<bool, bytes> field_map_bool_bytes_2 = 2; + map<bool, double> field_map_bool_double_3 = 3; + map<bool, Proto3Message.TestEnum> field_map_bool_enum_4 = 4; + map<bool, fixed32> field_map_bool_fixed32_5 = 5; + map<bool, fixed64> field_map_bool_fixed64_6 = 6; + map<bool, float> field_map_bool_float_7 = 7; + map<bool, int32> field_map_bool_int32_8 = 8; + map<bool, int64> field_map_bool_int64_9 = 9; + map<bool, Proto3Message> field_map_bool_message_10 = 10; + map<bool, sfixed32> field_map_bool_sfixed32_11 = 11; + map<bool, sfixed64> field_map_bool_sfixed64_12 = 12; + map<bool, sint32> field_map_bool_sint32_13 = 13; + map<bool, sint64> field_map_bool_sint64_14 = 14; + map<bool, string> field_map_bool_string_15 = 15; + map<bool, uint32> field_map_bool_uint32_16 = 16; + map<bool, uint64> field_map_bool_uint64_17 = 17; + map<fixed32, bool> field_map_fixed32_bool_18 = 18; + map<fixed32, bytes> field_map_fixed32_bytes_19 = 19; + map<fixed32, double> field_map_fixed32_double_20 = 20; + map<fixed32, Proto3Message.TestEnum> field_map_fixed32_enum_21 = 21; + map<fixed32, fixed32> field_map_fixed32_fixed32_22 = 22; + map<fixed32, fixed64> field_map_fixed32_fixed64_23 = 23; + map<fixed32, float> field_map_fixed32_float_24 = 24; + map<fixed32, int32> field_map_fixed32_int32_25 = 25; + map<fixed32, int64> field_map_fixed32_int64_26 = 26; + map<fixed32, Proto3Message> field_map_fixed32_message_27 = 27; + map<fixed32, sfixed32> field_map_fixed32_sfixed32_28 = 28; + map<fixed32, sfixed64> field_map_fixed32_sfixed64_29 = 29; + map<fixed32, sint32> field_map_fixed32_sint32_30 = 30; + map<fixed32, sint64> field_map_fixed32_sint64_31 = 31; + map<fixed32, string> field_map_fixed32_string_32 = 32; + map<fixed32, uint32> field_map_fixed32_uint32_33 = 33; + map<fixed32, uint64> field_map_fixed32_uint64_34 = 34; + map<fixed64, bool> field_map_fixed64_bool_35 = 35; + map<fixed64, bytes> field_map_fixed64_bytes_36 = 36; + map<fixed64, double> field_map_fixed64_double_37 = 37; + map<fixed64, Proto3Message.TestEnum> field_map_fixed64_enum_38 = 38; + map<fixed64, fixed32> field_map_fixed64_fixed32_39 = 39; + map<fixed64, fixed64> field_map_fixed64_fixed64_40 = 40; + map<fixed64, float> field_map_fixed64_float_41 = 41; + map<fixed64, int32> field_map_fixed64_int32_42 = 42; + map<fixed64, int64> field_map_fixed64_int64_43 = 43; + map<fixed64, Proto3Message> field_map_fixed64_message_44 = 44; + map<fixed64, sfixed32> field_map_fixed64_sfixed32_45 = 45; + map<fixed64, sfixed64> field_map_fixed64_sfixed64_46 = 46; + map<fixed64, sint32> field_map_fixed64_sint32_47 = 47; + map<fixed64, sint64> field_map_fixed64_sint64_48 = 48; + map<fixed64, string> field_map_fixed64_string_49 = 49; + map<fixed64, uint32> field_map_fixed64_uint32_50 = 50; + map<fixed64, uint64> field_map_fixed64_uint64_51 = 51; + map<int32, bool> field_map_int32_bool_52 = 52; + map<int32, bytes> field_map_int32_bytes_53 = 53; + map<int32, double> field_map_int32_double_54 = 54; + map<int32, Proto3Message.TestEnum> field_map_int32_enum_55 = 55; + map<int32, fixed32> field_map_int32_fixed32_56 = 56; + map<int32, fixed64> field_map_int32_fixed64_57 = 57; + map<int32, float> field_map_int32_float_58 = 58; + map<int32, int32> field_map_int32_int32_59 = 59; + map<int32, int64> field_map_int32_int64_60 = 60; + map<int32, Proto3Message> field_map_int32_message_61 = 61; + map<int32, sfixed32> field_map_int32_sfixed32_62 = 62; + map<int32, sfixed64> field_map_int32_sfixed64_63 = 63; + map<int32, sint32> field_map_int32_sint32_64 = 64; + map<int32, sint64> field_map_int32_sint64_65 = 65; + map<int32, string> field_map_int32_string_66 = 66; + map<int32, uint32> field_map_int32_uint32_67 = 67; + map<int32, uint64> field_map_int32_uint64_68 = 68; + map<int64, bool> field_map_int64_bool_69 = 69; + map<int64, bytes> field_map_int64_bytes_70 = 70; + map<int64, double> field_map_int64_double_71 = 71; + map<int64, Proto3Message.TestEnum> field_map_int64_enum_72 = 72; + map<int64, fixed32> field_map_int64_fixed32_73 = 73; + map<int64, fixed64> field_map_int64_fixed64_74 = 74; + map<int64, float> field_map_int64_float_75 = 75; + map<int64, int32> field_map_int64_int32_76 = 76; + map<int64, int64> field_map_int64_int64_77 = 77; + map<int64, Proto3Message> field_map_int64_message_78 = 78; + map<int64, sfixed32> field_map_int64_sfixed32_79 = 79; + map<int64, sfixed64> field_map_int64_sfixed64_80 = 80; + map<int64, sint32> field_map_int64_sint32_81 = 81; + map<int64, sint64> field_map_int64_sint64_82 = 82; + map<int64, string> field_map_int64_string_83 = 83; + map<int64, uint32> field_map_int64_uint32_84 = 84; + map<int64, uint64> field_map_int64_uint64_85 = 85; + map<sfixed32, bool> field_map_sfixed32_bool_86 = 86; + map<sfixed32, bytes> field_map_sfixed32_bytes_87 = 87; + map<sfixed32, double> field_map_sfixed32_double_88 = 88; + map<sfixed32, Proto3Message.TestEnum> field_map_sfixed32_enum_89 = 89; + map<sfixed32, fixed32> field_map_sfixed32_fixed32_90 = 90; + map<sfixed32, fixed64> field_map_sfixed32_fixed64_91 = 91; + map<sfixed32, float> field_map_sfixed32_float_92 = 92; + map<sfixed32, int32> field_map_sfixed32_int32_93 = 93; + map<sfixed32, int64> field_map_sfixed32_int64_94 = 94; + map<sfixed32, Proto3Message> field_map_sfixed32_message_95 = 95; + map<sfixed32, sfixed32> field_map_sfixed32_sfixed32_96 = 96; + map<sfixed32, sfixed64> field_map_sfixed32_sfixed64_97 = 97; + map<sfixed32, sint32> field_map_sfixed32_sint32_98 = 98; + map<sfixed32, sint64> field_map_sfixed32_sint64_99 = 99; + map<sfixed32, string> field_map_sfixed32_string_100 = 100; + map<sfixed32, uint32> field_map_sfixed32_uint32_101 = 101; + map<sfixed32, uint64> field_map_sfixed32_uint64_102 = 102; + map<sfixed64, bool> field_map_sfixed64_bool_103 = 103; + map<sfixed64, bytes> field_map_sfixed64_bytes_104 = 104; + map<sfixed64, double> field_map_sfixed64_double_105 = 105; + map<sfixed64, Proto3Message.TestEnum> field_map_sfixed64_enum_106 = 106; + map<sfixed64, fixed32> field_map_sfixed64_fixed32_107 = 107; + map<sfixed64, fixed64> field_map_sfixed64_fixed64_108 = 108; + map<sfixed64, float> field_map_sfixed64_float_109 = 109; + map<sfixed64, int32> field_map_sfixed64_int32_110 = 110; + map<sfixed64, int64> field_map_sfixed64_int64_111 = 111; + map<sfixed64, Proto3Message> field_map_sfixed64_message_112 = 112; + map<sfixed64, sfixed32> field_map_sfixed64_sfixed32_113 = 113; + map<sfixed64, sfixed64> field_map_sfixed64_sfixed64_114 = 114; + map<sfixed64, sint32> field_map_sfixed64_sint32_115 = 115; + map<sfixed64, sint64> field_map_sfixed64_sint64_116 = 116; + map<sfixed64, string> field_map_sfixed64_string_117 = 117; + map<sfixed64, uint32> field_map_sfixed64_uint32_118 = 118; + map<sfixed64, uint64> field_map_sfixed64_uint64_119 = 119; + map<sint32, bool> field_map_sint32_bool_120 = 120; + map<sint32, bytes> field_map_sint32_bytes_121 = 121; + map<sint32, double> field_map_sint32_double_122 = 122; + map<sint32, Proto3Message.TestEnum> field_map_sint32_enum_123 = 123; + map<sint32, fixed32> field_map_sint32_fixed32_124 = 124; + map<sint32, fixed64> field_map_sint32_fixed64_125 = 125; + map<sint32, float> field_map_sint32_float_126 = 126; + map<sint32, int32> field_map_sint32_int32_127 = 127; + map<sint32, int64> field_map_sint32_int64_128 = 128; + map<sint32, Proto3Message> field_map_sint32_message_129 = 129; + map<sint32, sfixed32> field_map_sint32_sfixed32_130 = 130; + map<sint32, sfixed64> field_map_sint32_sfixed64_131 = 131; + map<sint32, sint32> field_map_sint32_sint32_132 = 132; + map<sint32, sint64> field_map_sint32_sint64_133 = 133; + map<sint32, string> field_map_sint32_string_134 = 134; + map<sint32, uint32> field_map_sint32_uint32_135 = 135; + map<sint32, uint64> field_map_sint32_uint64_136 = 136; + map<sint64, bool> field_map_sint64_bool_137 = 137; + map<sint64, bytes> field_map_sint64_bytes_138 = 138; + map<sint64, double> field_map_sint64_double_139 = 139; + map<sint64, Proto3Message.TestEnum> field_map_sint64_enum_140 = 140; + map<sint64, fixed32> field_map_sint64_fixed32_141 = 141; + map<sint64, fixed64> field_map_sint64_fixed64_142 = 142; + map<sint64, float> field_map_sint64_float_143 = 143; + map<sint64, int32> field_map_sint64_int32_144 = 144; + map<sint64, int64> field_map_sint64_int64_145 = 145; + map<sint64, Proto3Message> field_map_sint64_message_146 = 146; + map<sint64, sfixed32> field_map_sint64_sfixed32_147 = 147; + map<sint64, sfixed64> field_map_sint64_sfixed64_148 = 148; + map<sint64, sint32> field_map_sint64_sint32_149 = 149; + map<sint64, sint64> field_map_sint64_sint64_150 = 150; + map<sint64, string> field_map_sint64_string_151 = 151; + map<sint64, uint32> field_map_sint64_uint32_152 = 152; + map<sint64, uint64> field_map_sint64_uint64_153 = 153; + map<string, bool> field_map_string_bool_154 = 154; + map<string, bytes> field_map_string_bytes_155 = 155; + map<string, double> field_map_string_double_156 = 156; + map<string, Proto3Message.TestEnum> field_map_string_enum_157 = 157; + map<string, fixed32> field_map_string_fixed32_158 = 158; + map<string, fixed64> field_map_string_fixed64_159 = 159; + map<string, float> field_map_string_float_160 = 160; + map<string, int32> field_map_string_int32_161 = 161; + map<string, int64> field_map_string_int64_162 = 162; + map<string, Proto3Message> field_map_string_message_163 = 163; + map<string, sfixed32> field_map_string_sfixed32_164 = 164; + map<string, sfixed64> field_map_string_sfixed64_165 = 165; + map<string, sint32> field_map_string_sint32_166 = 166; + map<string, sint64> field_map_string_sint64_167 = 167; + map<string, string> field_map_string_string_168 = 168; + map<string, uint32> field_map_string_uint32_169 = 169; + map<string, uint64> field_map_string_uint64_170 = 170; + map<uint32, bool> field_map_uint32_bool_171 = 171; + map<uint32, bytes> field_map_uint32_bytes_172 = 172; + map<uint32, double> field_map_uint32_double_173 = 173; + map<uint32, Proto3Message.TestEnum> field_map_uint32_enum_174 = 174; + map<uint32, fixed32> field_map_uint32_fixed32_175 = 175; + map<uint32, fixed64> field_map_uint32_fixed64_176 = 176; + map<uint32, float> field_map_uint32_float_177 = 177; + map<uint32, int32> field_map_uint32_int32_178 = 178; + map<uint32, int64> field_map_uint32_int64_179 = 179; + map<uint32, Proto3Message> field_map_uint32_message_180 = 180; + map<uint32, sfixed32> field_map_uint32_sfixed32_181 = 181; + map<uint32, sfixed64> field_map_uint32_sfixed64_182 = 182; + map<uint32, sint32> field_map_uint32_sint32_183 = 183; + map<uint32, sint64> field_map_uint32_sint64_184 = 184; + map<uint32, string> field_map_uint32_string_185 = 185; + map<uint32, uint32> field_map_uint32_uint32_186 = 186; + map<uint32, uint64> field_map_uint32_uint64_187 = 187; + map<uint64, bool> field_map_uint64_bool_188 = 188; + map<uint64, bytes> field_map_uint64_bytes_189 = 189; + map<uint64, double> field_map_uint64_double_190 = 190; + map<uint64, Proto3Message.TestEnum> field_map_uint64_enum_191 = 191; + map<uint64, fixed32> field_map_uint64_fixed32_192 = 192; + map<uint64, fixed64> field_map_uint64_fixed64_193 = 193; + map<uint64, float> field_map_uint64_float_194 = 194; + map<uint64, int32> field_map_uint64_int32_195 = 195; + map<uint64, int64> field_map_uint64_int64_196 = 196; + map<uint64, Proto3Message> field_map_uint64_message_197 = 197; + map<uint64, sfixed32> field_map_uint64_sfixed32_198 = 198; + map<uint64, sfixed64> field_map_uint64_sfixed64_199 = 199; + map<uint64, sint32> field_map_uint64_sint32_200 = 200; + map<uint64, sint64> field_map_uint64_sint64_201 = 201; + map<uint64, string> field_map_uint64_string_202 = 202; + map<uint64, uint32> field_map_uint64_uint32_203 = 203; + map<uint64, uint64> field_map_uint64_uint64_204 = 204; +} diff --git a/java/core/src/test/proto/com/google/protobuf/proto3_message_lite.proto b/java/core/src/test/proto/com/google/protobuf/proto3_message_lite.proto new file mode 100755 index 000000000..ed364ec9f --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/proto3_message_lite.proto @@ -0,0 +1,319 @@ +// 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. + +syntax = "proto3"; + +option java_package = "com.google.protobuf.testing"; +option java_outer_classname = "Proto3TestingLite"; +package protobuf.experimental; + +message Proto3MessageLite { + enum TestEnum { + ZERO = 0; + ONE = 1; + TWO = 2; + } + + double field_double_1 = 1; + float field_float_2 = 2; + int64 field_int64_3 = 3; + uint64 field_uint64_4 = 4; + int32 field_int32_5 = 5; + fixed64 field_fixed64_6 = 6; + fixed32 field_fixed32_7 = 7; + bool field_bool_8 = 8; + string field_string_9 = 9; + Proto3MessageLite field_message_10 = 10; + bytes field_bytes_11 = 11; + uint32 field_uint32_12 = 12; + TestEnum field_enum_13 = 13; + sfixed32 field_sfixed32_14 = 14; + sfixed64 field_sfixed64_15 = 15; + sint32 field_sint32_16 = 16; + sint64 field_sint64_17 = 17; + repeated double field_double_list_18 = 18 [packed = false]; + repeated float field_float_list_19 = 19 [packed = false]; + repeated int64 field_int64_list_20 = 20 [packed = false]; + repeated uint64 field_uint64_list_21 = 21 [packed = false]; + repeated int32 field_int32_list_22 = 22 [packed = false]; + repeated fixed64 field_fixed64_list_23 = 23 [packed = false]; + repeated fixed32 field_fixed32_list_24 = 24 [packed = false]; + repeated bool field_bool_list_25 = 25 [packed = false]; + repeated string field_string_list_26 = 26 [packed = false]; + repeated Proto3MessageLite field_message_list_27 = 27 [packed = false]; + repeated bytes field_bytes_list_28 = 28 [packed = false]; + repeated uint32 field_uint32_list_29 = 29 [packed = false]; + repeated TestEnum field_enum_list_30 = 30 [packed = false]; + repeated sfixed32 field_sfixed32_list_31 = 31 [packed = false]; + repeated sfixed64 field_sfixed64_list_32 = 32 [packed = false]; + repeated sint32 field_sint32_list_33 = 33 [packed = false]; + repeated sint64 field_sint64_list_34 = 34 [packed = false]; + repeated double field_double_list_packed_35 = 35 [packed = true]; + repeated float field_float_list_packed_36 = 36 [packed = true]; + repeated int64 field_int64_list_packed_37 = 37 [packed = true]; + repeated uint64 field_uint64_list_packed_38 = 38 [packed = true]; + repeated int32 field_int32_list_packed_39 = 39 [packed = true]; + repeated fixed64 field_fixed64_list_packed_40 = 40 [packed = true]; + repeated fixed32 field_fixed32_list_packed_41 = 41 [packed = true]; + repeated bool field_bool_list_packed_42 = 42 [packed = true]; + repeated uint32 field_uint32_list_packed_43 = 43 [packed = true]; + repeated TestEnum field_enum_list_packed_44 = 44 [packed = true]; + repeated sfixed32 field_sfixed32_list_packed_45 = 45 [packed = true]; + repeated sfixed64 field_sfixed64_list_packed_46 = 46 [packed = true]; + repeated sint32 field_sint32_list_packed_47 = 47 [packed = true]; + repeated sint64 field_sint64_list_packed_48 = 48 [packed = true]; + oneof test_oneof { + double field_double_53 = 53; + float field_float_54 = 54; + int64 field_int64_55 = 55; + uint64 field_uint64_56 = 56; + int32 field_int32_57 = 57; + fixed64 field_fixed64_58 = 58; + fixed32 field_fixed32_59 = 59; + bool field_bool_60 = 60; + string field_string_61 = 61; + Proto3MessageLite field_message_62 = 62; + bytes field_bytes_63 = 63; + uint32 field_uint32_64 = 64; + sfixed32 field_sfixed32_65 = 65; + sfixed64 field_sfixed64_66 = 66; + sint32 field_sint32_67 = 67; + sint64 field_sint64_68 = 68; + } +} + +message Proto3EmptyLite {} + +message Proto3MessageLiteWithMaps { + map<bool, bool> field_map_bool_bool_1 = 1; + map<bool, bytes> field_map_bool_bytes_2 = 2; + map<bool, double> field_map_bool_double_3 = 3; + map<bool, Proto3MessageLite.TestEnum> field_map_bool_enum_4 = 4; + map<bool, fixed32> field_map_bool_fixed32_5 = 5; + map<bool, fixed64> field_map_bool_fixed64_6 = 6; + map<bool, float> field_map_bool_float_7 = 7; + map<bool, int32> field_map_bool_int32_8 = 8; + map<bool, int64> field_map_bool_int64_9 = 9; + map<bool, Proto3MessageLite> field_map_bool_message_10 = 10; + map<bool, sfixed32> field_map_bool_sfixed32_11 = 11; + map<bool, sfixed64> field_map_bool_sfixed64_12 = 12; + map<bool, sint32> field_map_bool_sint32_13 = 13; + map<bool, sint64> field_map_bool_sint64_14 = 14; + map<bool, string> field_map_bool_string_15 = 15; + map<bool, uint32> field_map_bool_uint32_16 = 16; + map<bool, uint64> field_map_bool_uint64_17 = 17; + map<fixed32, bool> field_map_fixed32_bool_18 = 18; + map<fixed32, bytes> field_map_fixed32_bytes_19 = 19; + map<fixed32, double> field_map_fixed32_double_20 = 20; + map<fixed32, Proto3MessageLite.TestEnum> field_map_fixed32_enum_21 = 21; + map<fixed32, fixed32> field_map_fixed32_fixed32_22 = 22; + map<fixed32, fixed64> field_map_fixed32_fixed64_23 = 23; + map<fixed32, float> field_map_fixed32_float_24 = 24; + map<fixed32, int32> field_map_fixed32_int32_25 = 25; + map<fixed32, int64> field_map_fixed32_int64_26 = 26; + map<fixed32, Proto3MessageLite> field_map_fixed32_message_27 = 27; + map<fixed32, sfixed32> field_map_fixed32_sfixed32_28 = 28; + map<fixed32, sfixed64> field_map_fixed32_sfixed64_29 = 29; + map<fixed32, sint32> field_map_fixed32_sint32_30 = 30; + map<fixed32, sint64> field_map_fixed32_sint64_31 = 31; + map<fixed32, string> field_map_fixed32_string_32 = 32; + map<fixed32, uint32> field_map_fixed32_uint32_33 = 33; + map<fixed32, uint64> field_map_fixed32_uint64_34 = 34; + map<fixed64, bool> field_map_fixed64_bool_35 = 35; + map<fixed64, bytes> field_map_fixed64_bytes_36 = 36; + map<fixed64, double> field_map_fixed64_double_37 = 37; + map<fixed64, Proto3MessageLite.TestEnum> field_map_fixed64_enum_38 = 38; + map<fixed64, fixed32> field_map_fixed64_fixed32_39 = 39; + map<fixed64, fixed64> field_map_fixed64_fixed64_40 = 40; + map<fixed64, float> field_map_fixed64_float_41 = 41; + map<fixed64, int32> field_map_fixed64_int32_42 = 42; + map<fixed64, int64> field_map_fixed64_int64_43 = 43; + map<fixed64, Proto3MessageLite> field_map_fixed64_message_44 = 44; + map<fixed64, sfixed32> field_map_fixed64_sfixed32_45 = 45; + map<fixed64, sfixed64> field_map_fixed64_sfixed64_46 = 46; + map<fixed64, sint32> field_map_fixed64_sint32_47 = 47; + map<fixed64, sint64> field_map_fixed64_sint64_48 = 48; + map<fixed64, string> field_map_fixed64_string_49 = 49; + map<fixed64, uint32> field_map_fixed64_uint32_50 = 50; + map<fixed64, uint64> field_map_fixed64_uint64_51 = 51; + map<int32, bool> field_map_int32_bool_52 = 52; + map<int32, bytes> field_map_int32_bytes_53 = 53; + map<int32, double> field_map_int32_double_54 = 54; + map<int32, Proto3MessageLite.TestEnum> field_map_int32_enum_55 = 55; + map<int32, fixed32> field_map_int32_fixed32_56 = 56; + map<int32, fixed64> field_map_int32_fixed64_57 = 57; + map<int32, float> field_map_int32_float_58 = 58; + map<int32, int32> field_map_int32_int32_59 = 59; + map<int32, int64> field_map_int32_int64_60 = 60; + map<int32, Proto3MessageLite> field_map_int32_message_61 = 61; + map<int32, sfixed32> field_map_int32_sfixed32_62 = 62; + map<int32, sfixed64> field_map_int32_sfixed64_63 = 63; + map<int32, sint32> field_map_int32_sint32_64 = 64; + map<int32, sint64> field_map_int32_sint64_65 = 65; + map<int32, string> field_map_int32_string_66 = 66; + map<int32, uint32> field_map_int32_uint32_67 = 67; + map<int32, uint64> field_map_int32_uint64_68 = 68; + map<int64, bool> field_map_int64_bool_69 = 69; + map<int64, bytes> field_map_int64_bytes_70 = 70; + map<int64, double> field_map_int64_double_71 = 71; + map<int64, Proto3MessageLite.TestEnum> field_map_int64_enum_72 = 72; + map<int64, fixed32> field_map_int64_fixed32_73 = 73; + map<int64, fixed64> field_map_int64_fixed64_74 = 74; + map<int64, float> field_map_int64_float_75 = 75; + map<int64, int32> field_map_int64_int32_76 = 76; + map<int64, int64> field_map_int64_int64_77 = 77; + map<int64, Proto3MessageLite> field_map_int64_message_78 = 78; + map<int64, sfixed32> field_map_int64_sfixed32_79 = 79; + map<int64, sfixed64> field_map_int64_sfixed64_80 = 80; + map<int64, sint32> field_map_int64_sint32_81 = 81; + map<int64, sint64> field_map_int64_sint64_82 = 82; + map<int64, string> field_map_int64_string_83 = 83; + map<int64, uint32> field_map_int64_uint32_84 = 84; + map<int64, uint64> field_map_int64_uint64_85 = 85; + map<sfixed32, bool> field_map_sfixed32_bool_86 = 86; + map<sfixed32, bytes> field_map_sfixed32_bytes_87 = 87; + map<sfixed32, double> field_map_sfixed32_double_88 = 88; + map<sfixed32, Proto3MessageLite.TestEnum> field_map_sfixed32_enum_89 = 89; + map<sfixed32, fixed32> field_map_sfixed32_fixed32_90 = 90; + map<sfixed32, fixed64> field_map_sfixed32_fixed64_91 = 91; + map<sfixed32, float> field_map_sfixed32_float_92 = 92; + map<sfixed32, int32> field_map_sfixed32_int32_93 = 93; + map<sfixed32, int64> field_map_sfixed32_int64_94 = 94; + map<sfixed32, Proto3MessageLite> field_map_sfixed32_message_95 = 95; + map<sfixed32, sfixed32> field_map_sfixed32_sfixed32_96 = 96; + map<sfixed32, sfixed64> field_map_sfixed32_sfixed64_97 = 97; + map<sfixed32, sint32> field_map_sfixed32_sint32_98 = 98; + map<sfixed32, sint64> field_map_sfixed32_sint64_99 = 99; + map<sfixed32, string> field_map_sfixed32_string_100 = 100; + map<sfixed32, uint32> field_map_sfixed32_uint32_101 = 101; + map<sfixed32, uint64> field_map_sfixed32_uint64_102 = 102; + map<sfixed64, bool> field_map_sfixed64_bool_103 = 103; + map<sfixed64, bytes> field_map_sfixed64_bytes_104 = 104; + map<sfixed64, double> field_map_sfixed64_double_105 = 105; + map<sfixed64, Proto3MessageLite.TestEnum> field_map_sfixed64_enum_106 = 106; + map<sfixed64, fixed32> field_map_sfixed64_fixed32_107 = 107; + map<sfixed64, fixed64> field_map_sfixed64_fixed64_108 = 108; + map<sfixed64, float> field_map_sfixed64_float_109 = 109; + map<sfixed64, int32> field_map_sfixed64_int32_110 = 110; + map<sfixed64, int64> field_map_sfixed64_int64_111 = 111; + map<sfixed64, Proto3MessageLite> field_map_sfixed64_message_112 = 112; + map<sfixed64, sfixed32> field_map_sfixed64_sfixed32_113 = 113; + map<sfixed64, sfixed64> field_map_sfixed64_sfixed64_114 = 114; + map<sfixed64, sint32> field_map_sfixed64_sint32_115 = 115; + map<sfixed64, sint64> field_map_sfixed64_sint64_116 = 116; + map<sfixed64, string> field_map_sfixed64_string_117 = 117; + map<sfixed64, uint32> field_map_sfixed64_uint32_118 = 118; + map<sfixed64, uint64> field_map_sfixed64_uint64_119 = 119; + map<sint32, bool> field_map_sint32_bool_120 = 120; + map<sint32, bytes> field_map_sint32_bytes_121 = 121; + map<sint32, double> field_map_sint32_double_122 = 122; + map<sint32, Proto3MessageLite.TestEnum> field_map_sint32_enum_123 = 123; + map<sint32, fixed32> field_map_sint32_fixed32_124 = 124; + map<sint32, fixed64> field_map_sint32_fixed64_125 = 125; + map<sint32, float> field_map_sint32_float_126 = 126; + map<sint32, int32> field_map_sint32_int32_127 = 127; + map<sint32, int64> field_map_sint32_int64_128 = 128; + map<sint32, Proto3MessageLite> field_map_sint32_message_129 = 129; + map<sint32, sfixed32> field_map_sint32_sfixed32_130 = 130; + map<sint32, sfixed64> field_map_sint32_sfixed64_131 = 131; + map<sint32, sint32> field_map_sint32_sint32_132 = 132; + map<sint32, sint64> field_map_sint32_sint64_133 = 133; + map<sint32, string> field_map_sint32_string_134 = 134; + map<sint32, uint32> field_map_sint32_uint32_135 = 135; + map<sint32, uint64> field_map_sint32_uint64_136 = 136; + map<sint64, bool> field_map_sint64_bool_137 = 137; + map<sint64, bytes> field_map_sint64_bytes_138 = 138; + map<sint64, double> field_map_sint64_double_139 = 139; + map<sint64, Proto3MessageLite.TestEnum> field_map_sint64_enum_140 = 140; + map<sint64, fixed32> field_map_sint64_fixed32_141 = 141; + map<sint64, fixed64> field_map_sint64_fixed64_142 = 142; + map<sint64, float> field_map_sint64_float_143 = 143; + map<sint64, int32> field_map_sint64_int32_144 = 144; + map<sint64, int64> field_map_sint64_int64_145 = 145; + map<sint64, Proto3MessageLite> field_map_sint64_message_146 = 146; + map<sint64, sfixed32> field_map_sint64_sfixed32_147 = 147; + map<sint64, sfixed64> field_map_sint64_sfixed64_148 = 148; + map<sint64, sint32> field_map_sint64_sint32_149 = 149; + map<sint64, sint64> field_map_sint64_sint64_150 = 150; + map<sint64, string> field_map_sint64_string_151 = 151; + map<sint64, uint32> field_map_sint64_uint32_152 = 152; + map<sint64, uint64> field_map_sint64_uint64_153 = 153; + map<string, bool> field_map_string_bool_154 = 154; + map<string, bytes> field_map_string_bytes_155 = 155; + map<string, double> field_map_string_double_156 = 156; + map<string, Proto3MessageLite.TestEnum> field_map_string_enum_157 = 157; + map<string, fixed32> field_map_string_fixed32_158 = 158; + map<string, fixed64> field_map_string_fixed64_159 = 159; + map<string, float> field_map_string_float_160 = 160; + map<string, int32> field_map_string_int32_161 = 161; + map<string, int64> field_map_string_int64_162 = 162; + map<string, Proto3MessageLite> field_map_string_message_163 = 163; + map<string, sfixed32> field_map_string_sfixed32_164 = 164; + map<string, sfixed64> field_map_string_sfixed64_165 = 165; + map<string, sint32> field_map_string_sint32_166 = 166; + map<string, sint64> field_map_string_sint64_167 = 167; + map<string, string> field_map_string_string_168 = 168; + map<string, uint32> field_map_string_uint32_169 = 169; + map<string, uint64> field_map_string_uint64_170 = 170; + map<uint32, bool> field_map_uint32_bool_171 = 171; + map<uint32, bytes> field_map_uint32_bytes_172 = 172; + map<uint32, double> field_map_uint32_double_173 = 173; + map<uint32, Proto3MessageLite.TestEnum> field_map_uint32_enum_174 = 174; + map<uint32, fixed32> field_map_uint32_fixed32_175 = 175; + map<uint32, fixed64> field_map_uint32_fixed64_176 = 176; + map<uint32, float> field_map_uint32_float_177 = 177; + map<uint32, int32> field_map_uint32_int32_178 = 178; + map<uint32, int64> field_map_uint32_int64_179 = 179; + map<uint32, Proto3MessageLite> field_map_uint32_message_180 = 180; + map<uint32, sfixed32> field_map_uint32_sfixed32_181 = 181; + map<uint32, sfixed64> field_map_uint32_sfixed64_182 = 182; + map<uint32, sint32> field_map_uint32_sint32_183 = 183; + map<uint32, sint64> field_map_uint32_sint64_184 = 184; + map<uint32, string> field_map_uint32_string_185 = 185; + map<uint32, uint32> field_map_uint32_uint32_186 = 186; + map<uint32, uint64> field_map_uint32_uint64_187 = 187; + map<uint64, bool> field_map_uint64_bool_188 = 188; + map<uint64, bytes> field_map_uint64_bytes_189 = 189; + map<uint64, double> field_map_uint64_double_190 = 190; + map<uint64, Proto3MessageLite.TestEnum> field_map_uint64_enum_191 = 191; + map<uint64, fixed32> field_map_uint64_fixed32_192 = 192; + map<uint64, fixed64> field_map_uint64_fixed64_193 = 193; + map<uint64, float> field_map_uint64_float_194 = 194; + map<uint64, int32> field_map_uint64_int32_195 = 195; + map<uint64, int64> field_map_uint64_int64_196 = 196; + map<uint64, Proto3MessageLite> field_map_uint64_message_197 = 197; + map<uint64, sfixed32> field_map_uint64_sfixed32_198 = 198; + map<uint64, sfixed64> field_map_uint64_sfixed64_199 = 199; + map<uint64, sint32> field_map_uint64_sint32_200 = 200; + map<uint64, sint64> field_map_uint64_sint64_201 = 201; + map<uint64, string> field_map_uint64_string_202 = 202; + map<uint64, uint32> field_map_uint64_uint32_203 = 203; + map<uint64, uint64> field_map_uint64_uint64_204 = 204; +} diff --git a/java/core/src/test/proto/com/google/protobuf/wrappers_test.proto b/java/core/src/test/proto/com/google/protobuf/wrappers_test.proto new file mode 100755 index 000000000..f151edf8e --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/wrappers_test.proto @@ -0,0 +1,49 @@ +// 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. + +syntax = "proto3"; + +package wrappers_test; +option java_package = "com.google.protobuf.wrapperstest"; +option java_outer_classname = "WrappersTestProto"; +import "google/protobuf/wrappers.proto"; + +message TopLevelMessage { + int32 field1 = 1; + .google.protobuf.DoubleValue field_double = 2; + .google.protobuf.FloatValue field_float = 3; + .google.protobuf.Int64Value field_int64 = 4; + .google.protobuf.UInt64Value field_uint64 = 5; + .google.protobuf.Int32Value field_int32 = 6; + .google.protobuf.UInt32Value field_uint32 = 7; + .google.protobuf.BoolValue field_bool = 8; + .google.protobuf.StringValue field_string = 9; + .google.protobuf.BytesValue field_bytes = 10; +} diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/lite/src/test/java/com/google/protobuf/LiteTest.java index 89213a76c..960b2037c 100644..100755 --- a/java/core/src/test/java/com/google/protobuf/LiteTest.java +++ b/java/lite/src/test/java/com/google/protobuf/LiteTest.java @@ -50,6 +50,8 @@ import com.google.protobuf.UnittestLite.TestHugeFieldNumbersLite; import com.google.protobuf.UnittestLite.TestNestedExtensionLite; import map_lite_test.MapTestProto.TestMap; import map_lite_test.MapTestProto.TestMap.MessageValue; +import protobuf_unittest.NestedExtensionLite; +import protobuf_unittest.NonNestedExtensionLite; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; @@ -2338,6 +2340,26 @@ public class LiteTest extends TestCase { } } + public void testExtensionRenamesKeywords() { + assertTrue(NonNestedExtensionLite.package_ instanceof GeneratedMessageLite.GeneratedExtension); + assertTrue( + NestedExtensionLite.MyNestedExtensionLite.private_ + instanceof GeneratedMessageLite.GeneratedExtension); + + NonNestedExtensionLite.MessageLiteToBeExtended msg = + NonNestedExtensionLite.MessageLiteToBeExtended.newBuilder() + .setExtension(NonNestedExtensionLite.package_, true) + .build(); + assertTrue(msg.getExtension(NonNestedExtensionLite.package_)); + + msg = + NonNestedExtensionLite.MessageLiteToBeExtended.newBuilder() + .setExtension(NestedExtensionLite.MyNestedExtensionLite.private_, 2.4) + .build(); + assertEquals( + 2.4, msg.getExtension(NestedExtensionLite.MyNestedExtensionLite.private_), 0.001); + } + private static final class OneTimeIterableList<T> extends ArrayList<T> { private boolean wasIterated = false; diff --git a/java/lite/src/test/java/com/google/protobuf/Proto2MessageLiteInfoFactory.java b/java/lite/src/test/java/com/google/protobuf/Proto2MessageLiteInfoFactory.java new file mode 100755 index 000000000..4a1d89b93 --- /dev/null +++ b/java/lite/src/test/java/com/google/protobuf/Proto2MessageLiteInfoFactory.java @@ -0,0 +1,1327 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.FieldInfo.forField; +import static com.google.protobuf.FieldInfo.forFieldWithEnumVerifier; +import static com.google.protobuf.FieldInfo.forMapField; +import static com.google.protobuf.FieldInfo.forOneofMemberField; +import static com.google.protobuf.FieldInfo.forProto2OptionalField; +import static com.google.protobuf.FieldInfo.forProto2RequiredField; +import static com.google.protobuf.FieldInfo.forRepeatedMessageField; + +import com.google.protobuf.testing.Proto2TestingLite; +import com.google.protobuf.testing.Proto2TestingLite.Proto2EmptyLite; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.FieldGroup49; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.FieldGroup69; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.FieldGroupList51; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.FieldRequiredGroup88; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.RequiredNestedMessage; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.TestEnum; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLiteWithExtensions; +import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLiteWithMaps; +import java.lang.reflect.Field; + +/** A factory that generates a hard-coded info for {@link Proto2MessageLite}. */ +public final class Proto2MessageLiteInfoFactory implements MessageInfoFactory { + private static final Proto2MessageLiteInfoFactory instanceForRawMessageInfo = + new Proto2MessageLiteInfoFactory(true); + private static final Proto2MessageLiteInfoFactory instanceForStructuralMessageInfo = + new Proto2MessageLiteInfoFactory(false); + + public static Proto2MessageLiteInfoFactory getInstanceForRawMessageInfo() { + return instanceForRawMessageInfo; + } + + public static Proto2MessageLiteInfoFactory getInstanceForStructuralMessageInfo() { + return instanceForStructuralMessageInfo; + } + + private final boolean produceRawMessageInfo; + + private Proto2MessageLiteInfoFactory(boolean produceRawMessageInfo) { + this.produceRawMessageInfo = produceRawMessageInfo; + } + + @Override + public boolean isSupported(Class<?> clazz) { + return true; + } + + @Override + public MessageInfo messageInfoFor(Class<?> clazz) { + return produceRawMessageInfo ? rawMessageInfoFor(clazz) : structuralMessageInfoFor(clazz); + } + + private MessageInfo rawMessageInfoFor(Class<?> clazz) { + if (Proto2MessageLite.class.isAssignableFrom(clazz)) { + return newRawMessageInfoForProto2MessageLite(); + } else { + throw new IllegalArgumentException("Unsupported class: " + clazz.getName()); + } + } + + private MessageInfo newRawMessageInfoForProto2MessageLite() { + java.lang.Object[] objects = + new java.lang.Object[] { + "testOneof_", + "testOneofCase_", + "bitField0_", + "bitField1_", + "fieldDouble1_", + "fieldFloat2_", + "fieldInt643_", + "fieldUint644_", + "fieldInt325_", + "fieldFixed646_", + "fieldFixed327_", + "fieldBool8_", + "fieldString9_", + "fieldMessage10_", + "fieldBytes11_", + "fieldUint3212_", + "fieldEnum13_", + Proto2MessageLite.TestEnum.internalGetVerifier(), + "fieldSfixed3214_", + "fieldSfixed6415_", + "fieldSint3216_", + "fieldSint6417_", + "fieldDoubleList18_", + "fieldFloatList19_", + "fieldInt64List20_", + "fieldUint64List21_", + "fieldInt32List22_", + "fieldFixed64List23_", + "fieldFixed32List24_", + "fieldBoolList25_", + "fieldStringList26_", + "fieldMessageList27_", + Proto2MessageLite.class, + "fieldBytesList28_", + "fieldUint32List29_", + "fieldEnumList30_", + Proto2MessageLite.TestEnum.internalGetVerifier(), + "fieldSfixed32List31_", + "fieldSfixed64List32_", + "fieldSint32List33_", + "fieldSint64List34_", + "fieldDoubleListPacked35_", + "fieldFloatListPacked36_", + "fieldInt64ListPacked37_", + "fieldUint64ListPacked38_", + "fieldInt32ListPacked39_", + "fieldFixed64ListPacked40_", + "fieldFixed32ListPacked41_", + "fieldBoolListPacked42_", + "fieldUint32ListPacked43_", + "fieldEnumListPacked44_", + Proto2MessageLite.TestEnum.internalGetVerifier(), + "fieldSfixed32ListPacked45_", + "fieldSfixed64ListPacked46_", + "fieldSint32ListPacked47_", + "fieldSint64ListPacked48_", + "fieldGroup49_", + "fieldGroupList51_", + Proto2MessageLite.FieldGroupList51.class, + Proto2MessageLite.class, + Proto2MessageLite.FieldGroup69.class, + "fieldRequiredDouble71_", + "fieldRequiredFloat72_", + "fieldRequiredInt6473_", + "fieldRequiredUint6474_", + "fieldRequiredInt3275_", + "fieldRequiredFixed6476_", + "fieldRequiredFixed3277_", + "fieldRequiredBool78_", + "fieldRequiredString79_", + "fieldRequiredMessage80_", + "fieldRequiredBytes81_", + "fieldRequiredUint3282_", + "fieldRequiredEnum83_", + Proto2MessageLite.TestEnum.internalGetVerifier(), + "fieldRequiredSfixed3284_", + "fieldRequiredSfixed6485_", + "fieldRequiredSint3286_", + "fieldRequiredSint6487_", + "fieldRequiredGroup88_", + }; + // To update this after a proto change, run protoc on proto2_message_lite.proto and copy over + // the content of the generated buildMessageInfo() method here. + java.lang.String info = + "\u0001U\u0001\u0002\u0001XU\u0000 \u0015\u0001\u0000\u0000\u0002\u0001\u0001\u0003" + + "\u0002\u0002\u0004\u0003\u0003\u0005\u0004\u0004\u0006\u0005\u0005\u0007\u0006\u0006" + + "\b\u0007\u0007\t\b\b\n\u0409\t\u000b\n\n\f\u000b\u000b\r\f\f\u000e\r\r\u000f\u000e" + + "\u000e\u0010\u000f\u000f\u0011\u0010\u0010\u0012\u0012\u0013\u0013\u0014\u0014\u0015" + + "\u0015\u0016\u0016\u0017\u0017\u0018\u0018\u0019\u0019\u001a\u001a\u001b\u041b\u001c" + + "\u001c\u001d\u001d\u001e\u001e\u001f\u001f !!\"\"##$$%%&&\'\'(())**++,,--..//00" + + "1\u0011\u00113153\u000064\u000075\u000086\u000097\u0000:8\u0000;9\u0000<:\u0000=" + + ";\u0000>\u043c\u0000?=\u0000@>\u0000A@\u0000BA\u0000CB\u0000DC\u0000ED\u0000G\u0500" + + "#H\u0501$I\u0502%J\u0503&K\u0504\'L\u0505(M\u0506)N\u0507*O\u0508+P\u0509,Q\u050a" + + "-R\u050b.S\u050c/T\u050d0U\u050e1V\u050f2W\u05103X\u05114"; + return new RawMessageInfo(Proto2MessageLite.getDefaultInstance(), info, objects); + } + + private MessageInfo structuralMessageInfoFor(Class<?> clazz) { + if (Proto2MessageLite.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto2MessageLite(); + } else if (FieldGroup49.class.isAssignableFrom(clazz)) { + return newMessageInfoForFieldGroup49(); + } else if (FieldGroupList51.class.isAssignableFrom(clazz)) { + return newMessageInfoForFieldGroupList51(); + } else if (FieldGroup69.class.isAssignableFrom(clazz)) { + return newMessageInfoForFieldGroup69(); + } else if (FieldRequiredGroup88.class.isAssignableFrom(clazz)) { + return newMessageInfoForFieldRequiredGroup88(); + } else if (RequiredNestedMessage.class.isAssignableFrom(clazz)) { + return newMessageInfoForRequiredNestedMessage(); + } else if (Proto2EmptyLite.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto2EmptyLite(); + } else if (Proto2MessageLiteWithExtensions.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto2MessageLiteWithExtensions(); + } else if (Proto2TestingLite.FieldGroup49.class.isAssignableFrom(clazz)) { + return newMessageInfoForExtensionFieldGroup49(); + } else if (Proto2TestingLite.FieldGroupList51.class.isAssignableFrom(clazz)) { + return newMessageInfoForExtensionFieldGroupList51(); + } else if (Proto2TestingLite.Proto2MessageLiteWithMaps.class.isAssignableFrom(clazz)) { + return newMessageInfoForProto2MessageLiteWithMaps(); + } else { + throw new IllegalArgumentException("Unsupported class: " + clazz.getName()); + } + } + + /** + * Creates a new hard-coded info for {@link Proto2MessageLite}. Each time this is called, we + * manually go through the entire process of what a message would do if it self-registered its own + * info, including looking up each field by name. This is done for benchmarking purposes, so that + * we get a more accurate representation of the time it takes to perform this process. + */ + private static StructuralMessageInfo newMessageInfoForProto2MessageLite() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(48); + builder.withCheckInitialized( + new int[] { + 10, 27, 62, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + }); + lookupFieldsByName(builder); + return builder.build(); + } + + private static void lookupFieldsByName(StructuralMessageInfo.Builder builder) { + Field bitField0 = field(Proto2MessageLite.class, "bitField0_"); + + builder.withDefaultInstance(Proto2MessageLite.getDefaultInstance()); + builder.withSyntax(ProtoSyntax.PROTO2); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldDouble1_"), + 1, + FieldType.DOUBLE, + bitField0, + 0x00000001, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldFloat2_"), + 2, + FieldType.FLOAT, + bitField0, + 0x00000002, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldInt643_"), + 3, + FieldType.INT64, + bitField0, + 0x00000004, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldUint644_"), + 4, + FieldType.UINT64, + bitField0, + 0x00000008, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldInt325_"), + 5, + FieldType.INT32, + bitField0, + 0x00000010, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldFixed646_"), + 6, + FieldType.FIXED64, + bitField0, + 0x00000020, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldFixed327_"), + 7, + FieldType.FIXED32, + bitField0, + 0x00000040, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldBool8_"), + 8, + FieldType.BOOL, + bitField0, + 0x00000080, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldString9_"), + 9, + FieldType.STRING, + bitField0, + 0x00000100, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldMessage10_"), + 10, + FieldType.MESSAGE, + bitField0, + 0x00000200, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldBytes11_"), + 11, + FieldType.BYTES, + bitField0, + 0x00000400, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldUint3212_"), + 12, + FieldType.UINT32, + bitField0, + 0x00000800, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldEnum13_"), + 13, + FieldType.ENUM, + bitField0, + 0x00001000, + false, + TestEnum.internalGetVerifier())); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldSfixed3214_"), + 14, + FieldType.SFIXED32, + bitField0, + 0x00002000, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldSfixed6415_"), + 15, + FieldType.SFIXED64, + bitField0, + 0x00004000, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldSint3216_"), + 16, + FieldType.SINT32, + bitField0, + 0x00008000, + false, + null)); + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldSint6417_"), + 17, + FieldType.SINT64, + bitField0, + 0x00010000, + false, + null)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldDoubleList18_"), + 18, + FieldType.DOUBLE_LIST, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldFloatList19_"), 19, FieldType.FLOAT_LIST, false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldInt64List20_"), 20, FieldType.INT64_LIST, false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldUint64List21_"), + 21, + FieldType.UINT64_LIST, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldInt32List22_"), 22, FieldType.INT32_LIST, false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldFixed64List23_"), + 23, + FieldType.FIXED64_LIST, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldFixed32List24_"), + 24, + FieldType.FIXED32_LIST, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldBoolList25_"), 25, FieldType.BOOL_LIST, false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldStringList26_"), + 26, + FieldType.STRING_LIST, + false)); + builder.withField( + forRepeatedMessageField( + field(Proto2MessageLite.class, "fieldMessageList27_"), + 27, + FieldType.MESSAGE_LIST, + Proto2MessageLite.class)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldBytesList28_"), 28, FieldType.BYTES_LIST, false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldUint32List29_"), + 29, + FieldType.UINT32_LIST, + false)); + builder.withField( + forFieldWithEnumVerifier( + field(Proto2MessageLite.class, "fieldEnumList30_"), + 30, + FieldType.ENUM_LIST, + TestEnum.internalGetVerifier())); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldSfixed32List31_"), + 31, + FieldType.SFIXED32_LIST, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldSfixed64List32_"), + 32, + FieldType.SFIXED64_LIST, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldSint32List33_"), + 33, + FieldType.SINT32_LIST, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldSint64List34_"), + 34, + FieldType.SINT64_LIST, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldDoubleListPacked35_"), + 35, + FieldType.DOUBLE_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldFloatListPacked36_"), + 36, + FieldType.FLOAT_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldInt64ListPacked37_"), + 37, + FieldType.INT64_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldUint64ListPacked38_"), + 38, + FieldType.UINT64_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldInt32ListPacked39_"), + 39, + FieldType.INT32_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldFixed64ListPacked40_"), + 40, + FieldType.FIXED64_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldFixed32ListPacked41_"), + 41, + FieldType.FIXED32_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldBoolListPacked42_"), + 42, + FieldType.BOOL_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldUint32ListPacked43_"), + 43, + FieldType.UINT32_LIST_PACKED, + false)); + builder.withField( + forFieldWithEnumVerifier( + field(Proto2MessageLite.class, "fieldEnumListPacked44_"), + 44, + FieldType.ENUM_LIST_PACKED, + TestEnum.internalGetVerifier())); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldSfixed32ListPacked45_"), + 45, + FieldType.SFIXED32_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldSfixed64ListPacked46_"), + 46, + FieldType.SFIXED64_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldSint32ListPacked47_"), + 47, + FieldType.SINT32_LIST_PACKED, + false)); + builder.withField( + forField( + field(Proto2MessageLite.class, "fieldSint64ListPacked48_"), + 48, + FieldType.SINT64_LIST_PACKED, + false)); + + builder.withField( + forProto2OptionalField( + field(Proto2MessageLite.class, "fieldGroup49_"), + 49, + FieldType.GROUP, + bitField0, + 0x00020000, + false, + null)); + builder.withField( + forRepeatedMessageField( + field(Proto2MessageLite.class, "fieldGroupList51_"), + 51, + FieldType.GROUP_LIST, + Proto2MessageLite.FieldGroupList51.class)); + + OneofInfo oneof = + new OneofInfo( + 0, + field(Proto2MessageLite.class, "testOneofCase_"), + field(Proto2MessageLite.class, "testOneof_")); + builder.withField(forOneofMemberField(53, FieldType.DOUBLE, oneof, Double.class, false, null)); + builder.withField(forOneofMemberField(54, FieldType.FLOAT, oneof, Float.class, false, null)); + builder.withField(forOneofMemberField(55, FieldType.INT64, oneof, Long.class, false, null)); + builder.withField(forOneofMemberField(56, FieldType.UINT64, oneof, Long.class, false, null)); + builder.withField(forOneofMemberField(57, FieldType.INT32, oneof, Integer.class, false, null)); + builder.withField(forOneofMemberField(58, FieldType.FIXED64, oneof, Long.class, false, null)); + builder.withField( + forOneofMemberField(59, FieldType.FIXED32, oneof, Integer.class, false, null)); + builder.withField(forOneofMemberField(60, FieldType.BOOL, oneof, Boolean.class, false, null)); + builder.withField(forOneofMemberField(61, FieldType.STRING, oneof, String.class, false, null)); + builder.withField( + forOneofMemberField(62, FieldType.MESSAGE, oneof, Proto2MessageLite.class, false, null)); + builder.withField( + forOneofMemberField(63, FieldType.BYTES, oneof, ByteString.class, false, null)); + builder.withField(forOneofMemberField(64, FieldType.UINT32, oneof, Integer.class, false, null)); + builder.withField( + forOneofMemberField(65, FieldType.SFIXED32, oneof, Integer.class, false, null)); + builder.withField(forOneofMemberField(66, FieldType.SFIXED64, oneof, Long.class, false, null)); + builder.withField(forOneofMemberField(67, FieldType.SINT32, oneof, Integer.class, false, null)); + builder.withField(forOneofMemberField(68, FieldType.SINT64, oneof, Long.class, false, null)); + builder.withField( + forOneofMemberField( + 69, FieldType.GROUP, oneof, Proto2MessageLite.FieldGroup69.class, false, null)); + + Field bitField1 = field(Proto2MessageLite.class, "bitField1_"); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredDouble71_"), + 71, + FieldType.DOUBLE, + bitField1, + 0x00000008, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredFloat72_"), + 72, + FieldType.FLOAT, + bitField1, + 0x00000010, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredInt6473_"), + 73, + FieldType.INT64, + bitField1, + 0x00000020, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredUint6474_"), + 74, + FieldType.UINT64, + bitField1, + 0x00000040, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredInt3275_"), + 75, + FieldType.INT32, + bitField1, + 0x00000080, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredFixed6476_"), + 76, + FieldType.FIXED64, + bitField1, + 0x00000100, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredFixed3277_"), + 77, + FieldType.FIXED32, + bitField1, + 0x00000200, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredBool78_"), + 78, + FieldType.BOOL, + bitField1, + 0x00000400, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredString79_"), + 79, + FieldType.STRING, + bitField1, + 0x00000800, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredMessage80_"), + 80, + FieldType.MESSAGE, + bitField1, + 0x00001000, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredBytes81_"), + 81, + FieldType.BYTES, + bitField1, + 0x00002000, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredUint3282_"), + 82, + FieldType.UINT32, + bitField1, + 0x00004000, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredEnum83_"), + 83, + FieldType.ENUM, + bitField1, + 0x00008000, + false, + TestEnum.internalGetVerifier())); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredSfixed3284_"), + 84, + FieldType.SFIXED32, + bitField1, + 0x00010000, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredSfixed6485_"), + 85, + FieldType.SFIXED64, + bitField1, + 0x00020000, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredSint3286_"), + 86, + FieldType.SINT32, + bitField1, + 0x00040000, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredSint6487_"), + 87, + FieldType.SINT64, + bitField1, + 0x00080000, + false, + null)); + builder.withField( + forProto2RequiredField( + field(Proto2MessageLite.class, "fieldRequiredGroup88_"), + 88, + FieldType.GROUP, + bitField1, + 0x00100000, + false, + null)); + } + + private static StructuralMessageInfo newMessageInfoForFieldGroup49() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(FieldGroup49.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(FieldGroup49.class, "fieldInt3250_"), + 50, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForFieldGroupList51() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(FieldGroup49.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(FieldGroupList51.class, "fieldInt3252_"), + 52, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForFieldGroup69() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(FieldGroup69.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(FieldGroup69.class, "fieldInt3270_"), + 70, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForRequiredNestedMessage() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(RequiredNestedMessage.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(RequiredNestedMessage.class, "value_"), + 1, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForFieldRequiredGroup88() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(FieldRequiredGroup88.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(FieldRequiredGroup88.class, "fieldInt3289_"), + 89, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForProto2EmptyLite() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForProto2MessageLiteWithExtensions() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(0); + builder.withSyntax(ProtoSyntax.PROTO2); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForExtensionFieldGroup49() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(Proto2TestingLite.FieldGroup49.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(Proto2TestingLite.FieldGroup49.class, "fieldInt3250_"), + 50, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + private static StructuralMessageInfo newMessageInfoForExtensionFieldGroupList51() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1); + builder.withSyntax(ProtoSyntax.PROTO2); + Field bitField0 = field(Proto2TestingLite.FieldGroup49.class, "bitField0_"); + builder.withField( + forProto2OptionalField( + field(Proto2TestingLite.FieldGroupList51.class, "fieldInt3252_"), + 52, + FieldType.INT32, + bitField0, + 0x00000001, + false, + null)); + return builder.build(); + } + + + private static StructuralMessageInfo newMessageInfoForProto2MessageLiteWithMaps() { + StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(); + builder.withCheckInitialized( + new int[] { + 10, 27, 44, 61, 78, 95, 112, 129, 146, 163, 180, 197, + }); + builder.withSyntax(ProtoSyntax.PROTO2); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_bool_1", 1)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_bytes_2", 2)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_double_3", 3)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_enum_4", 4)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_fixed32_5", 5)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_fixed64_6", 6)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_float_7", 7)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_int32_8", 8)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_int64_9", 9)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_message_10", 10)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_sfixed32_11", 11)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_sfixed64_12", 12)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_sint32_13", 13)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_sint64_14", 14)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_string_15", 15)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_uint32_16", 16)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_uint64_17", 17)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_bool_18", 18)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_bytes_19", 19)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_double_20", 20)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_enum_21", 21)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_fixed32_22", 22)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_fixed64_23", 23)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_float_24", 24)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_int32_25", 25)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_int64_26", 26)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_message_27", 27)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_sfixed32_28", 28)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_sfixed64_29", 29)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_sint32_30", 30)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_sint64_31", 31)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_string_32", 32)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_uint32_33", 33)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_uint64_34", 34)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_bool_35", 35)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_bytes_36", 36)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_double_37", 37)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_enum_38", 38)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_fixed32_39", 39)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_fixed64_40", 40)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_float_41", 41)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_int32_42", 42)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_int64_43", 43)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_message_44", 44)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_sfixed32_45", 45)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_sfixed64_46", 46)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_sint32_47", 47)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_sint64_48", 48)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_string_49", 49)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_uint32_50", 50)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_uint64_51", 51)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_bool_52", 52)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_bytes_53", 53)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_double_54", 54)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_enum_55", 55)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_fixed32_56", 56)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_fixed64_57", 57)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_float_58", 58)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_int32_59", 59)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_int64_60", 60)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_message_61", 61)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_sfixed32_62", 62)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_sfixed64_63", 63)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_sint32_64", 64)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_sint64_65", 65)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_string_66", 66)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_uint32_67", 67)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_uint64_68", 68)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_bool_69", 69)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_bytes_70", 70)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_double_71", 71)); + builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_enum_72", 72)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_fixed32_73", 73)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_fixed64_74", 74)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_float_75", 75)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_int32_76", 76)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_int64_77", 77)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_message_78", 78)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_sfixed32_79", 79)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_sfixed64_80", 80)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_sint32_81", 81)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_sint64_82", 82)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_string_83", 83)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_uint32_84", 84)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_uint64_85", 85)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_bool_86", 86)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_bytes_87", 87)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_double_88", 88)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_enum_89", 89)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_fixed32_90", 90)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_fixed64_91", 91)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_float_92", 92)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_int32_93", 93)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_int64_94", 94)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_message_95", 95)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_sfixed32_96", 96)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_sfixed64_97", 97)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_sint32_98", 98)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_sint64_99", 99)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_string_100", 100)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_uint32_101", 101)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_uint64_102", 102)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_bool_103", 103)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_bytes_104", 104)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_double_105", 105)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_enum_106", 106)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_fixed32_107", 107)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_fixed64_108", 108)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_float_109", 109)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_int32_110", 110)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_int64_111", 111)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_message_112", 112)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_sfixed32_113", 113)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_sfixed64_114", 114)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_sint32_115", 115)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_sint64_116", 116)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_string_117", 117)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_uint32_118", 118)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_uint64_119", 119)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_bool_120", 120)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_bytes_121", 121)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_double_122", 122)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_enum_123", 123)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_fixed32_124", 124)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_fixed64_125", 125)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_float_126", 126)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_int32_127", 127)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_int64_128", 128)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_message_129", 129)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_sfixed32_130", 130)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_sfixed64_131", 131)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_sint32_132", 132)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_sint64_133", 133)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_string_134", 134)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_uint32_135", 135)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_uint64_136", 136)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_bool_137", 137)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_bytes_138", 138)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_double_139", 139)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_enum_140", 140)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_fixed32_141", 141)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_fixed64_142", 142)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_float_143", 143)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_int32_144", 144)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_int64_145", 145)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_message_146", 146)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_sfixed32_147", 147)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_sfixed64_148", 148)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_sint32_149", 149)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_sint64_150", 150)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_string_151", 151)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_uint32_152", 152)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_uint64_153", 153)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_bool_154", 154)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_bytes_155", 155)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_double_156", 156)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_enum_157", 157)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_fixed32_158", 158)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_fixed64_159", 159)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_float_160", 160)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_int32_161", 161)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_int64_162", 162)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_message_163", 163)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_sfixed32_164", 164)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_sfixed64_165", 165)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_sint32_166", 166)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_sint64_167", 167)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_string_168", 168)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_uint32_169", 169)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_uint64_170", 170)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_bool_171", 171)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_bytes_172", 172)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_double_173", 173)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_enum_174", 174)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_fixed32_175", 175)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_fixed64_176", 176)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_float_177", 177)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_int32_178", 178)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_int64_179", 179)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_message_180", 180)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_sfixed32_181", 181)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_sfixed64_182", 182)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_sint32_183", 183)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_sint64_184", 184)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_string_185", 185)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_uint32_186", 186)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_uint64_187", 187)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_bool_188", 188)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_bytes_189", 189)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_double_190", 190)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_enum_191", 191)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_fixed32_192", 192)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_fixed64_193", 193)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_float_194", 194)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_int32_195", 195)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_int64_196", 196)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_message_197", 197)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_sfixed32_198", 198)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_sfixed64_199", 199)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_sint32_200", 200)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_sint64_201", 201)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_string_202", 202)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_uint32_203", 203)); + builder.withField( + mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_uint64_204", 204)); + + return builder.build(); + } + + private static Field field(Class<?> clazz, String name) { + try { + return clazz.getDeclaredField(name); + } catch (NoSuchFieldException | SecurityException e) { + throw new RuntimeException(e); + } + } + + private static FieldInfo mapFieldInfo(Class<?> clazz, String fieldName, int fieldNumber) { + try { + return forMapField( + field(clazz, SchemaUtil.toCamelCase(fieldName, false) + "_"), + fieldNumber, + SchemaUtil.getMapDefaultEntry(clazz, fieldName), + fieldName.contains("_enum_") ? TestEnum.internalGetVerifier() : null); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } +} diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java index b7b437cea..75e2ae8a8 100644 --- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java @@ -464,6 +464,20 @@ public class JsonFormatTest extends TestCase { assertEquals(NullValue.NULL_VALUE, message.getOneofNullValue()); } + public void testNullMessageInDuplicateOneof() throws Exception { + // Succeeds if null is first. + TestOneof.Builder successBuilder = TestOneof.newBuilder(); + mergeFromJson("{\"oneofNestedMessage\": null, \"oneofInt32\": 1}", successBuilder); + + // Fails if null is last. + try { + TestOneof.Builder builder = TestOneof.newBuilder(); + mergeFromJson("{\"oneofInt32\": 1, \"oneofNestedMessage\": null}", builder); + fail(); + } catch (InvalidProtocolBufferException expected) { + } + } + public void testParserRejectDuplicatedFields() throws Exception { // TODO(xiaofeng): The parser we are currently using (GSON) will accept and keep the last // one if multiple entries have the same name. This is not the desired behavior but it can |
