| // 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.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.mergeGroupField; |
| import static com.google.protobuf.ArrayDecoders.mergeMessageField; |
| 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. */ |
| @CheckReturnValue |
| 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 NO_PRESENCE_SENTINEL = -1 & OFFSET_MASK; |
| 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> |
| * |
| * Note that presence field offset can only use 20 bits - 1. All bits set to 1 is the sentinel |
| * value for non-presence. This is not validated at runtime, we simply assume message layouts |
| * will not exceed 1MB (assuming ~10 bytes per field, that implies 100k fields which should hit |
| * other javac limits first). |
| */ |
| 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 unusedFlags = 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 */) { |
| if (!isProto3) { |
| 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 (!isProto3) { |
| 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); |
| boolean hasHasBit = (fieldTypeWithExtraBits & 0x1000) == 0x1000; |
| if (hasHasBit && 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 = NO_PRESENCE_SENTINEL; |
| 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, 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, 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 (!type.isList() && !type.isMap()) { |
| Field presenceField = fi.getPresenceField(); |
| if (presenceField == null) { |
| presenceFieldOffset = NO_PRESENCE_SENTINEL; |
| } else { |
| presenceFieldOffset = (int) UnsafeUtil.objectFieldOffset(presenceField); |
| } |
| 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) { |
| checkMutable(message); |
| 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); |
| } |
| |
| 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 targetParent, T sourceParent, int pos) { |
| if (!isFieldPresent(sourceParent, pos)) { |
| return; |
| } |
| |
| final int typeAndOffset = typeAndOffsetAt(pos); |
| final long offset = offset(typeAndOffset); |
| |
| final Object source = UNSAFE.getObject(sourceParent, offset); |
| if (source == null) { |
| throw new IllegalStateException( |
| "Source subfield " + numberAt(pos) + " is present but null: " + sourceParent); |
| } |
| |
| final Schema fieldSchema = getMessageFieldSchema(pos); |
| if (!isFieldPresent(targetParent, pos)) { |
| if (!isMutable(source)) { |
| // Can safely share source if it is immutable |
| UNSAFE.putObject(targetParent, offset, source); |
| } else { |
| // Make a safetey copy of source |
| final Object copyOfSource = fieldSchema.newInstance(); |
| fieldSchema.mergeFrom(copyOfSource, source); |
| UNSAFE.putObject(targetParent, offset, copyOfSource); |
| } |
| setFieldPresent(targetParent, pos); |
| return; |
| } |
| |
| // Sub-message is present, merge from source |
| Object target = UNSAFE.getObject(targetParent, offset); |
| if (!isMutable(target)) { |
| Object newInstance = fieldSchema.newInstance(); |
| fieldSchema.mergeFrom(newInstance, target); |
| UNSAFE.putObject(targetParent, offset, newInstance); |
| target = newInstance; |
| } |
| fieldSchema.mergeFrom(target, source); |
| } |
| |
| private void mergeOneofMessage(T targetParent, T sourceParent, int pos) { |
| int number = numberAt(pos); |
| if (!isOneofPresent(sourceParent, number, pos)) { |
| return; |
| } |
| |
| long offset = offset(typeAndOffsetAt(pos)); |
| final Object source = UNSAFE.getObject(sourceParent, offset); |
| if (source == null) { |
| throw new IllegalStateException( |
| "Source subfield " + numberAt(pos) + " is present but null: " + sourceParent); |
| } |
| |
| final Schema fieldSchema = getMessageFieldSchema(pos); |
| if (!isOneofPresent(targetParent, number, pos)) { |
| if (!isMutable(source)) { |
| // Can safely share source if it is immutable |
| UNSAFE.putObject(targetParent, offset, source); |
| } else { |
| // Make a safety copy of theirs |
| final Object copyOfSource = fieldSchema.newInstance(); |
| fieldSchema.mergeFrom(copyOfSource, source); |
| UNSAFE.putObject(targetParent, offset, copyOfSource); |
| } |
| setOneofPresent(targetParent, number, pos); |
| return; |
| } |
| |
| // Sub-message is present, merge from source |
| Object target = UNSAFE.getObject(targetParent, offset); |
| if (!isMutable(target)) { |
| Object newInstance = fieldSchema.newInstance(); |
| fieldSchema.mergeFrom(newInstance, target); |
| UNSAFE.putObject(targetParent, offset, newInstance); |
| target = newInstance; |
| } |
| fieldSchema.mergeFrom(target, source); |
| } |
| |
| @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 = NO_PRESENCE_SENTINEL; |
| 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); |
| } |
| |
| @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 = NO_PRESENCE_SENTINEL; |
| 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 (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(); |
| } |
| checkMutable(message); |
| 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( |
| message, |
| 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: |
| final MessageLite current = (MessageLite) mutableMessageFieldForMerge(message, pos); |
| reader.mergeMessageField( |
| current, (Schema<MessageLite>) getMessageFieldSchema(pos), extensionRegistry); |
| storeMessageField(message, pos, current); |
| 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( |
| message, 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: |
| final MessageLite current = (MessageLite) mutableMessageFieldForMerge(message, pos); |
| reader.mergeGroupField( |
| current, (Schema<MessageLite>) getMessageFieldSchema(pos), extensionRegistry); |
| storeMessageField(message, pos, current); |
| 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( |
| message, |
| 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( |
| message, |
| 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: |
| final MessageLite current = |
| (MessageLite) mutableOneofMessageFieldForMerge(message, number, pos); |
| reader.mergeMessageField( |
| current, (Schema<MessageLite>) getMessageFieldSchema(pos), extensionRegistry); |
| storeOneofMessageField(message, number, pos, current); |
| 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( |
| message, 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: |
| final MessageLite current = |
| (MessageLite) mutableOneofMessageFieldForMerge(message, number, pos); |
| reader.mergeGroupField( |
| current, (Schema<MessageLite>) getMessageFieldSchema(pos), extensionRegistry); |
| storeOneofMessageField(message, number, pos, current); |
| break; |
| } |
| default: |
| // Assume we've landed on an empty entry. Treat it as an unknown field. |
| if (unknownFields == null) { |
| unknownFields = unknownFieldSchema.getBuilderFromMessage(message); |
| } |
| 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, message); |
| } |
| if (unknownFields != null) { |
| unknownFieldSchema.setBuilderToMessage(message, unknownFields); |
| } |
| } |
| } |
| |
| @SuppressWarnings("ReferenceEquality") |
| static UnknownFieldSetLite getMutableUnknownFields(Object message) { |
| // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this |
| // better. |
| 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; |
| } |
| SchemaUtil.filterUnknownEnumList( |
| message, |
| number, |
| (ProtobufList<Integer>) list, |
| getEnumFieldVerifier(bufferPosition), |
| null, |
| (UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema); |
| 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) { |
| final Object current = mutableOneofMessageFieldForMerge(message, number, bufferPosition); |
| position = |
| mergeMessageField( |
| current, getMessageFieldSchema(bufferPosition), data, position, limit, registers); |
| storeOneofMessageField(message, number, bufferPosition, current); |
| } |
| 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. |
| 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 Object current = mutableOneofMessageFieldForMerge(message, number, bufferPosition); |
| final int endTag = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP; |
| position = |
| mergeGroupField( |
| current, |
| getMessageFieldSchema(bufferPosition), |
| data, |
| position, |
| limit, |
| endTag, |
| registers); |
| storeOneofMessageField(message, number, bufferPosition, current); |
| } |
| 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. |
| */ |
| @CanIgnoreReturnValue |
| int parseProto2Message( |
| T message, byte[] data, int position, int limit, int endGroup, Registers registers) |
| throws IOException { |
| checkMutable(message); |
| final sun.misc.Unsafe unsafe = UNSAFE; |
| int currentPresenceFieldOffset = NO_PRESENCE_SENTINEL; |
| 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 != NO_PRESENCE_SENTINEL) { |
| 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) { |
| final Object current = mutableMessageFieldForMerge(message, pos); |
| position = |
| mergeMessageField( |
| current, getMessageFieldSchema(pos), data, position, limit, registers); |
| storeMessageField(message, pos, current); |
| 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. |
| 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 Object current = mutableMessageFieldForMerge(message, pos); |
| final int endTag = (number << 3) | WireFormat.WIRETYPE_END_GROUP; |
| position = |
| mergeGroupField( |
| current, |
| getMessageFieldSchema(pos), |
| data, |
| position, |
| limit, |
| endTag, |
| registers); |
| storeMessageField(message, pos, current); |
| 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 != NO_PRESENCE_SENTINEL) { |
| 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, |
| message); |
| } |
| 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; |
| } |
| |
| private Object mutableMessageFieldForMerge(T message, int pos) { |
| final Schema fieldSchema = getMessageFieldSchema(pos); |
| final long offset = offset(typeAndOffsetAt(pos)); |
| |
| // Field not present, create a new one |
| if (!isFieldPresent(message, pos)) { |
| return fieldSchema.newInstance(); |
| } |
| |
| // Field present, if mutable, ready to merge |
| final Object current = UNSAFE.getObject(message, offset); |
| if (isMutable(current)) { |
| return current; |
| } |
| |
| // Field present but immutable, make a new mutable copy |
| final Object newMessage = fieldSchema.newInstance(); |
| if (current != null) { |
| fieldSchema.mergeFrom(newMessage, current); |
| } |
| return newMessage; |
| } |
| |
| private void storeMessageField(T message, int pos, Object field) { |
| UNSAFE.putObject(message, offset(typeAndOffsetAt(pos)), field); |
| setFieldPresent(message, pos); |
| } |
| |
| private Object mutableOneofMessageFieldForMerge(T message, int fieldNumber, int pos) { |
| final Schema fieldSchema = getMessageFieldSchema(pos); |
| |
| // Field not present, create it and mark it present |
| if (!isOneofPresent(message, fieldNumber, pos)) { |
| return fieldSchema.newInstance(); |
| } |
| |
| // Field present, if mutable, ready to merge |
| final Object current = UNSAFE.getObject(message, offset(typeAndOffsetAt(pos))); |
| if (isMutable(current)) { |
| return current; |
| } |
| |
| // Field present but immutable, make a new mutable copy |
| final Object newMessage = fieldSchema.newInstance(); |
| if (current != null) { |
| fieldSchema.mergeFrom(newMessage, current); |
| } |
| return newMessage; |
| } |
| |
| private void storeOneofMessageField(T message, int fieldNumber, int pos, Object field) { |
| UNSAFE.putObject(message, offset(typeAndOffsetAt(pos)), field); |
| setOneofPresent(message, fieldNumber, pos); |
| } |
| |
| /** Parses a proto3 message and returns the limit if parsing is successful. */ |
| @CanIgnoreReturnValue |
| private int parseProto3Message( |
| T message, byte[] data, int position, int limit, Registers registers) throws IOException { |
| checkMutable(message); |
| final sun.misc.Unsafe unsafe = UNSAFE; |
| int currentPresenceFieldOffset = NO_PRESENCE_SENTINEL; |
| 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) { |
| // Proto3 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. |
| // |
| // Note that for fields that do not have hasbits, we unconditionally write and discard |
| // the data. |
| if (presenceFieldOffset != currentPresenceFieldOffset) { |
| if (currentPresenceFieldOffset != NO_PRESENCE_SENTINEL) { |
| unsafe.putInt(message, (long) currentPresenceFieldOffset, currentPresenceField); |
| } |
| if (presenceFieldOffset != NO_PRESENCE_SENTINEL) { |
| currentPresenceField = unsafe.getInt(message, (long) presenceFieldOffset); |
| } |
| currentPresenceFieldOffset = 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) { |
| final Object current = mutableMessageFieldForMerge(message, pos); |
| position = |
| mergeMessageField( |
| current, getMessageFieldSchema(pos), data, position, limit, registers); |
| storeMessageField(message, pos, current); |
| 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); |
| unsafe.putInt(message, fieldOffset, registers.int1); |
| currentPresenceField |= presenceMask; |
| 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; |
| 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 (currentPresenceFieldOffset != NO_PRESENCE_SENTINEL) { |
| unsafe.putInt(message, (long) currentPresenceFieldOffset, currentPresenceField); |
| } |
| 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) { |
| if (!isMutable(message)) { |
| return; |
| } |
| |
| // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this |
| // better. |
| if (message instanceof GeneratedMessageLite) { |
| GeneratedMessageLite<?, ?> generatedMessage = ((GeneratedMessageLite<?, ?>) message); |
| generatedMessage.clearMemoizedSerializedSize(); |
| generatedMessage.clearMemoizedHashCode(); |
| generatedMessage.markImmutable(); |
| } |
| |
| final int bufferLength = buffer.length; |
| for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) { |
| final int typeAndOffset = typeAndOffsetAt(pos); |
| final long offset = offset(typeAndOffset); |
| switch (type(typeAndOffset)) { |
| case 17: // GROUP |
| case 9: // MESSAGE |
| if (isFieldPresent(message, pos)) { |
| getMessageFieldSchema(pos).makeImmutable(UNSAFE.getObject(message, offset)); |
| } |
| 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.makeImmutableListAt(message, offset); |
| break; |
| case 50: // MAP: |
| { |
| Object mapField = UNSAFE.getObject(message, offset); |
| if (mapField != null) { |
| UNSAFE.putObject(message, offset, mapFieldSchema.toImmutable(mapField)); |
| } |
| } |
| break; |
| } |
| } |
| 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 <UT, UB> UB filterMapUnknownEnumValues( |
| Object message, |
| int pos, |
| UB unknownFields, |
| UnknownFieldSchema<UT, UB> unknownFieldSchema, |
| Object containerMessage) { |
| 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, |
| containerMessage); |
| return unknownFields; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <K, V, UT, UB> UB filterUnknownEnumMap( |
| int pos, |
| int number, |
| Map<K, V> mapData, |
| EnumVerifier enumVerifier, |
| UB unknownFields, |
| UnknownFieldSchema<UT, UB> unknownFieldSchema, |
| Object containerMessage) { |
| 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.getBuilderFromMessage(containerMessage); |
| } |
| 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 = NO_PRESENCE_SENTINEL; |
| 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 = buffer[pos + 2]; |
| final int presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK; |
| int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS); |
| if (presenceFieldOffset != currentPresenceFieldOffset) { |
| currentPresenceFieldOffset = presenceFieldOffset; |
| if (currentPresenceFieldOffset != NO_PRESENCE_SENTINEL) { |
| currentPresenceField = UNSAFE.getInt(message, (long) presenceFieldOffset); |
| } |
| } |
| |
| if (isRequired(typeAndOffset)) { |
| if (!isFieldPresent( |
| message, pos, currentPresenceFieldOffset, 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, currentPresenceFieldOffset, 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 boolean isMutable(Object message) { |
| if (message == null) { |
| return false; |
| } |
| |
| // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this |
| // better. |
| if (message instanceof GeneratedMessageLite<?, ?>) { |
| return ((GeneratedMessageLite<?, ?>) message).isMutable(); |
| } |
| |
| // For other types, we'll assume this is true because that's what was |
| // happening before we started checking. |
| return true; |
| } |
| |
| private static void checkMutable(Object message) { |
| if (!isMutable(message)) { |
| throw new IllegalArgumentException("Mutating immutable message: " + message); |
| } |
| } |
| |
| 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 presenceFieldOffset, int presenceField, int presenceMask) { |
| if (presenceFieldOffset == NO_PRESENCE_SENTINEL) { |
| return isFieldPresent(message, pos); |
| } else { |
| return (presenceField & presenceMask) != 0; |
| } |
| } |
| |
| private boolean isFieldPresent(T message, int pos) { |
| final int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos); |
| final long presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK; |
| if (presenceFieldOffset == NO_PRESENCE_SENTINEL) { |
| final int typeAndOffset = typeAndOffsetAt(pos); |
| final long offset = offset(typeAndOffset); |
| switch (type(typeAndOffset)) { |
| case 0: // DOUBLE: |
| return Double.doubleToRawLongBits(UnsafeUtil.getDouble(message, offset)) != 0L; |
| case 1: // FLOAT: |
| return Float.floatToRawIntBits(UnsafeUtil.getFloat(message, offset)) != 0; |
| 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 { |
| final int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS); |
| return (UnsafeUtil.getInt(message, presenceMaskAndOffset & OFFSET_MASK) & presenceMask) != 0; |
| } |
| } |
| |
| private void setFieldPresent(T message, int pos) { |
| int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos); |
| final long presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK; |
| if (presenceFieldOffset == NO_PRESENCE_SENTINEL) { |
| return; |
| } |
| final int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS); |
| 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; |
| } |
| } |