| // 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. |
| |
| #ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__ |
| #define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__ |
| |
| #include <google/protobuf/generated_message_table_driven.h> |
| |
| #include <google/protobuf/stubs/type_traits.h> |
| |
| #include <google/protobuf/io/zero_copy_stream_impl_lite.h> |
| #include <google/protobuf/extension_set.h> |
| #include <google/protobuf/metadata_lite.h> |
| #include <google/protobuf/repeated_field.h> |
| #include <google/protobuf/wire_format_lite.h> |
| #include <google/protobuf/wire_format_lite_inl.h> |
| |
| |
| namespace google { |
| namespace protobuf { |
| namespace internal { |
| |
| |
| enum StringType { |
| StringType_STRING = 0, |
| StringType_CORD = 1, |
| StringType_STRING_PIECE = 2 |
| }; |
| |
| // Logically a superset of StringType, consisting of all field types that |
| // require special initialization. |
| enum ProcessingType { |
| ProcessingType_STRING = 0, |
| ProcessingType_CORD = 1, |
| ProcessingType_STRING_PIECE = 2, |
| ProcessingType_MESSAGE = 3 |
| }; |
| |
| enum Cardinality { |
| Cardinality_SINGULAR = 0, |
| Cardinality_REPEATED = 1, |
| Cardinality_ONEOF = 3 |
| }; |
| |
| template <typename Type> |
| inline Type* Raw(MessageLite* msg, int64 offset) { |
| return reinterpret_cast<Type*>(reinterpret_cast<uint8*>(msg) + offset); |
| } |
| |
| template <typename Type> |
| inline const Type* Raw(const MessageLite* msg, int64 offset) { |
| return reinterpret_cast<const Type*>(reinterpret_cast<const uint8*>(msg) + |
| offset); |
| } |
| |
| template <typename InternalMetadata> |
| inline Arena* GetArena(MessageLite* msg, int64 arena_offset) { |
| if (GOOGLE_PREDICT_FALSE(arena_offset == -1)) { |
| return NULL; |
| } |
| |
| return Raw<InternalMetadata>(msg, arena_offset)->arena(); |
| } |
| |
| inline ExtensionSet* GetExtensionSet(MessageLite* msg, int64 extension_offset) { |
| if (extension_offset == -1) { |
| return NULL; |
| } |
| |
| return Raw<ExtensionSet>(msg, extension_offset); |
| } |
| |
| template <typename Type> |
| inline Type* AddField(MessageLite* msg, int64 offset) { |
| #if LANG_CXX11 |
| static_assert(has_trivial_copy<Type>::value, |
| "Do not assign"); |
| #endif |
| |
| google::protobuf::RepeatedField<Type>* repeated = |
| Raw<google::protobuf::RepeatedField<Type> >(msg, offset); |
| return repeated->Add(); |
| } |
| |
| template <> |
| inline string* AddField<string>(MessageLite* msg, int64 offset) { |
| google::protobuf::RepeatedPtrField<string>* repeated = |
| Raw<google::protobuf::RepeatedPtrField<string> >(msg, offset); |
| return repeated->Add(); |
| } |
| |
| |
| template <typename Type> |
| inline void AddField(MessageLite* msg, int64 offset, Type value) { |
| #if LANG_CXX11 |
| static_assert(has_trivial_copy<Type>::value, |
| "Do not assign"); |
| #endif |
| *AddField<Type>(msg, offset) = value; |
| } |
| |
| inline void SetBit(uint32* has_bits, uint32 has_bit_index) { |
| GOOGLE_DCHECK(has_bits != NULL); |
| |
| uint32 mask = static_cast<uint32>(1u) << (has_bit_index % 32); |
| has_bits[has_bit_index / 32u] |= mask; |
| } |
| |
| template <typename Type> |
| inline Type* MutableField(MessageLite* msg, uint32* has_bits, |
| uint32 has_bit_index, int64 offset) { |
| SetBit(has_bits, has_bit_index); |
| return Raw<Type>(msg, offset); |
| } |
| |
| template <typename Type> |
| inline void SetField(MessageLite* msg, uint32* has_bits, uint32 has_bit_index, |
| int64 offset, Type value) { |
| #if LANG_CXX11 |
| static_assert(has_trivial_copy<Type>::value, |
| "Do not assign"); |
| #endif |
| *MutableField<Type>(msg, has_bits, has_bit_index, offset) = value; |
| } |
| |
| template <typename Type> |
| inline void SetOneofField(MessageLite* msg, uint32* oneof_case, |
| uint32 oneof_case_index, int64 offset, |
| int field_number, Type value) { |
| oneof_case[oneof_case_index] = field_number; |
| *Raw<Type>(msg, offset) = value; |
| } |
| |
| // Clears a oneof field. The field argument should correspond to the particular |
| // field that is currently set in the oneof. |
| inline void ClearOneofField(const ParseTableField& field, Arena* arena, |
| MessageLite* msg) { |
| switch (field.processing_type & kTypeMask) { |
| case WireFormatLite::TYPE_MESSAGE: |
| if (arena == NULL) { |
| delete *Raw<MessageLite*>(msg, field.offset); |
| } |
| break; |
| |
| case WireFormatLite::TYPE_STRING: |
| case WireFormatLite::TYPE_BYTES: |
| Raw<ArenaStringPtr>(msg, field.offset) |
| ->Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena); |
| break; |
| |
| default: |
| // No cleanup needed. |
| break; |
| } |
| } |
| |
| // Clears and reinitializes a oneof field as necessary, in preparation for |
| // parsing a new value with type field_type and field number field_number. |
| // |
| // Note: the oneof_case argument should point directly to the _oneof_case_ |
| // element corresponding to this particular oneof, not to the beginning of the |
| // _oneof_case_ array. |
| template <ProcessingType field_type> |
| inline void ResetOneofField(const ParseTable& table, int field_number, |
| Arena* arena, MessageLite* msg, uint32* oneof_case, |
| int64 offset, const void* default_ptr) { |
| if (*oneof_case == field_number) { |
| // The oneof is already set to the right type, so there is no need to clear |
| // it. |
| return; |
| } |
| |
| if (*oneof_case != 0) { |
| ClearOneofField(table.fields[*oneof_case], arena, msg); |
| } |
| *oneof_case = field_number; |
| |
| switch (field_type) { |
| case ProcessingType_STRING: |
| Raw<ArenaStringPtr>(msg, offset) |
| ->UnsafeSetDefault(static_cast<const string*>(default_ptr)); |
| break; |
| case ProcessingType_MESSAGE: |
| MessageLite** submessage = Raw<MessageLite*>(msg, offset); |
| const MessageLite* prototype = |
| table.aux[field_number].messages.default_message(); |
| *submessage = prototype->New(arena); |
| break; |
| } |
| } |
| |
| template <Cardinality cardinality, bool validate, StringType ctype> |
| static inline bool HandleString(io::CodedInputStream* input, MessageLite* msg, |
| Arena* arena, uint32* has_bits, |
| uint32 has_bit_index, int64 offset, |
| const void* default_ptr, |
| const char* field_name) { |
| #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED |
| const char* sdata; |
| size_t size; |
| #endif |
| |
| string* value; |
| switch (cardinality) { |
| case Cardinality_SINGULAR: |
| // TODO(ckennelly): Is this optimal? |
| value = |
| MutableField<ArenaStringPtr>(msg, has_bits, has_bit_index, offset) |
| ->Mutable(static_cast<const string*>(default_ptr), arena); |
| break; |
| case Cardinality_REPEATED: |
| value = AddField<string>(msg, offset); |
| break; |
| case Cardinality_ONEOF: |
| value = Raw<ArenaStringPtr>(msg, offset) |
| ->Mutable(static_cast<const string*>(default_ptr), arena); |
| break; |
| } |
| GOOGLE_DCHECK(value != NULL); |
| |
| if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) { |
| return false; |
| } |
| |
| #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED |
| sdata = value->data(); |
| size = value->size(); |
| #endif |
| |
| #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED |
| if (validate) { |
| WireFormatLite::VerifyUtf8String(sdata, size, WireFormatLite::PARSE, |
| field_name); |
| } |
| #endif |
| |
| return true; |
| } |
| |
| template <typename UnknownFieldHandler, typename InternalMetadata, |
| Cardinality cardinality> |
| inline bool HandleEnum(const ParseTable& table, io::CodedInputStream* input, |
| MessageLite* msg, uint32* presence, |
| uint32 presence_index, int64 offset, uint32 tag, |
| int field_number) { |
| int value; |
| if (GOOGLE_PREDICT_FALSE( |
| (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( |
| input, &value)))) { |
| return false; |
| } |
| |
| AuxillaryParseTableField::EnumValidator validator = |
| table.aux[field_number].enums.validator; |
| if (validator(value)) { |
| switch (cardinality) { |
| case Cardinality_SINGULAR: |
| SetField(msg, presence, presence_index, offset, value); |
| break; |
| case Cardinality_REPEATED: |
| AddField(msg, offset, value); |
| break; |
| case Cardinality_ONEOF: |
| ClearOneofField(table.fields[presence[presence_index]], |
| GetArena<InternalMetadata>(msg, table.arena_offset), |
| msg); |
| SetOneofField(msg, presence, presence_index, offset, field_number, |
| value); |
| break; |
| } |
| } else { |
| UnknownFieldHandler::Varint(msg, table, tag, value); |
| } |
| |
| return true; |
| } |
| |
| // RepeatedMessageTypeHandler allows us to operate on RepeatedPtrField fields |
| // without instantiating the specific template. |
| class RepeatedMessageTypeHandler { |
| public: |
| typedef MessageLite Type; |
| static Arena* GetArena(Type* t) { return t->GetArena(); } |
| static void* GetMaybeArenaPointer(Type* t) { |
| return t->GetMaybeArenaPointer(); |
| } |
| static inline Type* NewFromPrototype(const Type* prototype, |
| Arena* arena = NULL) { |
| return prototype->New(arena); |
| } |
| static void Delete(Type* t, Arena* arena = NULL) { |
| if (arena == NULL) { |
| delete t; |
| } |
| } |
| }; |
| |
| inline bool ReadGroup(int field_number, io::CodedInputStream* input, |
| MessageLite* value) { |
| if (GOOGLE_PREDICT_FALSE(!input->IncrementRecursionDepth())) { |
| return false; |
| } |
| |
| if (GOOGLE_PREDICT_FALSE(!value->MergePartialFromCodedStream(input))) { |
| return false; |
| } |
| |
| input->DecrementRecursionDepth(); |
| // Make sure the last thing read was an end tag for this group. |
| if (GOOGLE_PREDICT_FALSE(!input->LastTagWas(WireFormatLite::MakeTag( |
| field_number, WireFormatLite::WIRETYPE_END_GROUP)))) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| inline bool ReadMessage(io::CodedInputStream* input, MessageLite* value) { |
| int length; |
| if (GOOGLE_PREDICT_FALSE(!input->ReadVarintSizeAsInt(&length))) { |
| return false; |
| } |
| |
| std::pair<io::CodedInputStream::Limit, int> p = |
| input->IncrementRecursionDepthAndPushLimit(length); |
| if (GOOGLE_PREDICT_FALSE(p.second < 0 || |
| !value->MergePartialFromCodedStream(input))) { |
| return false; |
| } |
| |
| // Make sure that parsing stopped when the limit was hit, not at an endgroup |
| // tag. |
| return input->DecrementRecursionDepthAndPopLimit(p.first); |
| } |
| |
| class MergePartialFromCodedStreamHelper { |
| public: |
| static MessageLite* Add(RepeatedPtrFieldBase* field, |
| const MessageLite* prototype) { |
| return field->Add<RepeatedMessageTypeHandler>( |
| const_cast<MessageLite*>(prototype)); |
| } |
| }; |
| |
| template <typename UnknownFieldHandler, typename InternalMetadata> |
| bool MergePartialFromCodedStreamImpl(MessageLite* msg, const ParseTable& table, |
| io::CodedInputStream* input) { |
| // We require that has_bits are present, as to avoid having to check for them |
| // for every field. |
| // |
| // TODO(ckennelly): Make this a compile-time parameter with templates. |
| GOOGLE_DCHECK_GE(table.has_bits_offset, 0); |
| uint32* has_bits = Raw<uint32>(msg, table.has_bits_offset); |
| GOOGLE_DCHECK(has_bits != NULL); |
| |
| while (true) { |
| uint32 tag = input->ReadTag(); |
| |
| const WireFormatLite::WireType wire_type = |
| WireFormatLite::GetTagWireType(tag); |
| const int field_number = WireFormatLite::GetTagFieldNumber(tag); |
| |
| if (field_number > table.max_field_number) { |
| // check for possible extensions |
| if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) { |
| // successfully parsed |
| continue; |
| } |
| |
| if (GOOGLE_PREDICT_FALSE(!UnknownFieldHandler::Skip(msg, table, input, tag))) { |
| return false; |
| } |
| |
| continue; |
| } |
| |
| // We implicitly verify that data points to a valid field as we check the |
| // wire types. Entries in table.fields[i] that do not correspond to valid |
| // field numbers have their normal_wiretype and packed_wiretype fields set |
| // with the kInvalidMask value. As wire_type cannot take on that value, we |
| // will never match. |
| const ParseTableField* data = table.fields + field_number; |
| |
| // TODO(ckennelly): Avoid sign extension |
| const int64 presence_index = data->presence_index; |
| const int64 offset = data->offset; |
| const unsigned char processing_type = data->processing_type; |
| |
| if (data->normal_wiretype == static_cast<unsigned char>(wire_type)) { |
| // TODO(ckennelly): Use a computed goto on GCC/LLVM or otherwise eliminate |
| // the bounds check on processing_type. |
| |
| switch (processing_type) { |
| #define HANDLE_TYPE(TYPE, CPPTYPE) \ |
| case (WireFormatLite::TYPE_##TYPE): { \ |
| CPPTYPE value; \ |
| if (GOOGLE_PREDICT_FALSE( \ |
| (!WireFormatLite::ReadPrimitive< \ |
| CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)))) { \ |
| return false; \ |
| } \ |
| SetField(msg, has_bits, presence_index, offset, value); \ |
| break; \ |
| } \ |
| case (WireFormatLite::TYPE_##TYPE) | kRepeatedMask: { \ |
| google::protobuf::RepeatedField<CPPTYPE>* values = \ |
| Raw<google::protobuf::RepeatedField<CPPTYPE> >(msg, offset); \ |
| if (GOOGLE_PREDICT_FALSE((!WireFormatLite::ReadRepeatedPrimitive< \ |
| CPPTYPE, WireFormatLite::TYPE_##TYPE>( \ |
| data->tag_size, tag, input, values)))) { \ |
| return false; \ |
| } \ |
| break; \ |
| } \ |
| case (WireFormatLite::TYPE_##TYPE) | kOneofMask: { \ |
| uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset); \ |
| CPPTYPE value; \ |
| if (GOOGLE_PREDICT_FALSE( \ |
| (!WireFormatLite::ReadPrimitive< \ |
| CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)))) { \ |
| return false; \ |
| } \ |
| ClearOneofField(table.fields[oneof_case[presence_index]], \ |
| GetArena<InternalMetadata>(msg, table.arena_offset), msg); \ |
| SetOneofField(msg, oneof_case, presence_index, offset, field_number, \ |
| value); \ |
| break; \ |
| } |
| |
| HANDLE_TYPE(INT32, int32) |
| HANDLE_TYPE(INT64, int64) |
| HANDLE_TYPE(SINT32, int32) |
| HANDLE_TYPE(SINT64, int64) |
| HANDLE_TYPE(UINT32, uint32) |
| HANDLE_TYPE(UINT64, uint64) |
| |
| HANDLE_TYPE(FIXED32, uint32) |
| HANDLE_TYPE(FIXED64, uint64) |
| HANDLE_TYPE(SFIXED32, int32) |
| HANDLE_TYPE(SFIXED64, int64) |
| |
| HANDLE_TYPE(FLOAT, float) |
| HANDLE_TYPE(DOUBLE, double) |
| |
| HANDLE_TYPE(BOOL, bool) |
| #undef HANDLE_TYPE |
| case WireFormatLite::TYPE_BYTES: |
| #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED |
| case WireFormatLite::TYPE_STRING: |
| #endif |
| { |
| Arena* const arena = |
| GetArena<InternalMetadata>(msg, table.arena_offset); |
| const void* default_ptr = table.aux[field_number].strings.default_ptr; |
| |
| if (GOOGLE_PREDICT_FALSE(( |
| !HandleString<Cardinality_SINGULAR, false, StringType_STRING>( |
| input, msg, arena, has_bits, presence_index, offset, |
| default_ptr, NULL)))) { |
| return false; |
| } |
| break; |
| } |
| case WireFormatLite::TYPE_BYTES | kOneofMask: |
| #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED |
| case WireFormatLite::TYPE_STRING | kOneofMask: |
| #endif |
| { |
| Arena* const arena = |
| GetArena<InternalMetadata>(msg, table.arena_offset); |
| uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset); |
| const void* default_ptr = table.aux[field_number].strings.default_ptr; |
| |
| ResetOneofField<ProcessingType_STRING>( |
| table, field_number, arena, msg, oneof_case + presence_index, |
| offset, default_ptr); |
| |
| if (GOOGLE_PREDICT_FALSE( |
| (!HandleString<Cardinality_ONEOF, false, StringType_STRING>( |
| input, msg, arena, has_bits, presence_index, offset, |
| default_ptr, NULL)))) { |
| return false; |
| } |
| break; |
| } |
| case (WireFormatLite::TYPE_BYTES) | kRepeatedMask: |
| #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED |
| case (WireFormatLite::TYPE_STRING) | kRepeatedMask: |
| #endif |
| { |
| Arena* const arena = |
| GetArena<InternalMetadata>(msg, table.arena_offset); |
| const void* default_ptr = |
| table.aux[field_number].strings.default_ptr; |
| |
| if (GOOGLE_PREDICT_FALSE(( |
| !HandleString<Cardinality_REPEATED, false, StringType_STRING>( |
| input, msg, arena, has_bits, presence_index, offset, |
| default_ptr, NULL)))) { |
| return false; |
| } |
| break; |
| } |
| #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED |
| case (WireFormatLite::TYPE_STRING): { |
| Arena* const arena = |
| GetArena<InternalMetadata>(msg, table.arena_offset); |
| const void* default_ptr = table.aux[field_number].strings.default_ptr; |
| const char* field_name = table.aux[field_number].strings.field_name; |
| |
| if (GOOGLE_PREDICT_FALSE( |
| (!HandleString<Cardinality_SINGULAR, true, StringType_STRING>( |
| input, msg, arena, has_bits, presence_index, offset, |
| default_ptr, field_name)))) { |
| return false; |
| } |
| break; |
| } |
| case (WireFormatLite::TYPE_STRING) | kRepeatedMask: { |
| Arena* const arena = |
| GetArena<InternalMetadata>(msg, table.arena_offset); |
| const void* default_ptr = table.aux[field_number].strings.default_ptr; |
| const char* field_name = table.aux[field_number].strings.field_name; |
| |
| if (GOOGLE_PREDICT_FALSE( |
| (!HandleString<Cardinality_REPEATED, true, StringType_STRING>( |
| input, msg, arena, has_bits, presence_index, offset, |
| default_ptr, field_name)))) { |
| return false; |
| } |
| break; |
| } |
| case (WireFormatLite::TYPE_STRING) | kOneofMask: { |
| Arena* const arena = |
| GetArena<InternalMetadata>(msg, table.arena_offset); |
| uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset); |
| const void* default_ptr = table.aux[field_number].strings.default_ptr; |
| const char* field_name = table.aux[field_number].strings.field_name; |
| |
| ResetOneofField<ProcessingType_STRING>( |
| table, field_number, arena, msg, oneof_case + presence_index, |
| offset, default_ptr); |
| |
| if (GOOGLE_PREDICT_FALSE( |
| (!HandleString<Cardinality_ONEOF, true, StringType_STRING>( |
| input, msg, arena, has_bits, presence_index, offset, |
| default_ptr, field_name)))) { |
| return false; |
| } |
| break; |
| } |
| #endif |
| case WireFormatLite::TYPE_ENUM: { |
| if (GOOGLE_PREDICT_FALSE((!HandleEnum<UnknownFieldHandler, InternalMetadata, |
| Cardinality_SINGULAR>( |
| table, input, msg, has_bits, presence_index, offset, tag, |
| field_number)))) { |
| return false; |
| } |
| break; |
| } |
| case WireFormatLite::TYPE_ENUM | kRepeatedMask: { |
| if (GOOGLE_PREDICT_FALSE((!HandleEnum<UnknownFieldHandler, InternalMetadata, |
| Cardinality_REPEATED>( |
| table, input, msg, has_bits, presence_index, offset, tag, |
| field_number)))) { |
| return false; |
| } |
| break; |
| } |
| case WireFormatLite::TYPE_ENUM | kOneofMask: { |
| uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset); |
| if (GOOGLE_PREDICT_FALSE((!HandleEnum<UnknownFieldHandler, InternalMetadata, |
| Cardinality_ONEOF>( |
| table, input, msg, oneof_case, presence_index, offset, tag, |
| field_number)))) { |
| return false; |
| } |
| break; |
| } |
| case WireFormatLite::TYPE_GROUP: { |
| MessageLite** submsg_holder = |
| MutableField<MessageLite*>(msg, has_bits, presence_index, offset); |
| MessageLite* submsg = *submsg_holder; |
| |
| if (submsg == NULL) { |
| Arena* const arena = |
| GetArena<InternalMetadata>(msg, table.arena_offset); |
| const MessageLite* prototype = |
| table.aux[field_number].messages.default_message(); |
| submsg = prototype->New(arena); |
| *submsg_holder = submsg; |
| } |
| |
| if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadGroup( |
| field_number, input, submsg))) { |
| return false; |
| } |
| |
| break; |
| } |
| case WireFormatLite::TYPE_GROUP | kRepeatedMask: { |
| RepeatedPtrFieldBase* field = Raw<RepeatedPtrFieldBase>(msg, offset); |
| const MessageLite* prototype = |
| table.aux[field_number].messages.default_message(); |
| GOOGLE_DCHECK(prototype != NULL); |
| |
| MessageLite* submsg = |
| MergePartialFromCodedStreamHelper::Add(field, prototype); |
| |
| if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadGroup( |
| field_number, input, submsg))) { |
| return false; |
| } |
| |
| break; |
| } |
| case WireFormatLite::TYPE_MESSAGE: { |
| MessageLite** submsg_holder = |
| MutableField<MessageLite*>(msg, has_bits, presence_index, offset); |
| MessageLite* submsg = *submsg_holder; |
| |
| if (submsg == NULL) { |
| Arena* const arena = |
| GetArena<InternalMetadata>(msg, table.arena_offset); |
| const MessageLite* prototype = |
| table.aux[field_number].messages.default_message(); |
| submsg = prototype->New(arena); |
| *submsg_holder = submsg; |
| } |
| |
| if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadMessage(input, submsg))) { |
| return false; |
| } |
| |
| break; |
| } |
| // TODO(ckennelly): Adapt ReadMessageNoVirtualNoRecursionDepth and |
| // manage input->IncrementRecursionDepth() here. |
| case WireFormatLite::TYPE_MESSAGE | kRepeatedMask: { |
| RepeatedPtrFieldBase* field = Raw<RepeatedPtrFieldBase>(msg, offset); |
| const MessageLite* prototype = |
| table.aux[field_number].messages.default_message(); |
| GOOGLE_DCHECK(prototype != NULL); |
| |
| MessageLite* submsg = |
| MergePartialFromCodedStreamHelper::Add(field, prototype); |
| |
| if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadMessage(input, submsg))) { |
| return false; |
| } |
| |
| break; |
| } |
| case WireFormatLite::TYPE_MESSAGE | kOneofMask: { |
| Arena* const arena = |
| GetArena<InternalMetadata>(msg, table.arena_offset); |
| uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset); |
| MessageLite** submsg_holder = Raw<MessageLite*>(msg, offset); |
| ResetOneofField<ProcessingType_MESSAGE>( |
| table, field_number, arena, msg, oneof_case + presence_index, |
| offset, NULL); |
| MessageLite* submsg = *submsg_holder; |
| |
| if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadMessage(input, submsg))) { |
| return false; |
| } |
| |
| break; |
| } |
| case TYPE_MAP: { |
| if (GOOGLE_PREDICT_FALSE(!(*table.aux[field_number].maps.parse_map)( |
| input, Raw<void>(msg, offset)))) { |
| return false; |
| } |
| break; |
| } |
| case 0: { |
| // Done. |
| return true; |
| } |
| default: |
| break; |
| } |
| } else if (data->packed_wiretype == static_cast<unsigned char>(wire_type)) { |
| // Non-packable fields have their packed_wiretype masked with |
| // kNotPackedMask, which is impossible to match here. |
| GOOGLE_DCHECK(processing_type & kRepeatedMask); |
| GOOGLE_DCHECK_NE(processing_type, kRepeatedMask); |
| GOOGLE_DCHECK_EQ(0, processing_type & kOneofMask); |
| |
| |
| |
| // TODO(ckennelly): Use a computed goto on GCC/LLVM. |
| // |
| // Mask out kRepeatedMask bit, allowing the jump table to be smaller. |
| switch (static_cast<WireFormatLite::FieldType>( |
| processing_type ^ kRepeatedMask)) { |
| #define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ |
| case WireFormatLite::TYPE_##TYPE: { \ |
| google::protobuf::RepeatedField<CPPTYPE>* values = \ |
| Raw<google::protobuf::RepeatedField<CPPTYPE> >(msg, offset); \ |
| if (GOOGLE_PREDICT_FALSE( \ |
| (!WireFormatLite::ReadPackedPrimitive< \ |
| CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, values)))) { \ |
| return false; \ |
| } \ |
| break; \ |
| } |
| |
| HANDLE_PACKED_TYPE(INT32, int32, Int32) |
| HANDLE_PACKED_TYPE(INT64, int64, Int64) |
| HANDLE_PACKED_TYPE(SINT32, int32, Int32) |
| HANDLE_PACKED_TYPE(SINT64, int64, Int64) |
| HANDLE_PACKED_TYPE(UINT32, uint32, UInt32) |
| HANDLE_PACKED_TYPE(UINT64, uint64, UInt64) |
| |
| HANDLE_PACKED_TYPE(FIXED32, uint32, UInt32) |
| HANDLE_PACKED_TYPE(FIXED64, uint64, UInt64) |
| HANDLE_PACKED_TYPE(SFIXED32, int32, Int32) |
| HANDLE_PACKED_TYPE(SFIXED64, int64, Int64) |
| |
| HANDLE_PACKED_TYPE(FLOAT, float, Float) |
| HANDLE_PACKED_TYPE(DOUBLE, double, Double) |
| |
| HANDLE_PACKED_TYPE(BOOL, bool, Bool) |
| #undef HANDLE_PACKED_TYPE |
| case WireFormatLite::TYPE_ENUM: { |
| // To avoid unnecessarily calling MutableUnknownFields (which mutates |
| // InternalMetadataWithArena) when all inputs in the repeated series |
| // are valid, we implement our own parser rather than call |
| // WireFormat::ReadPackedEnumPreserveUnknowns. |
| uint32 length; |
| if (GOOGLE_PREDICT_FALSE(!input->ReadVarint32(&length))) { |
| return false; |
| } |
| |
| AuxillaryParseTableField::EnumValidator validator = |
| table.aux[field_number].enums.validator; |
| google::protobuf::RepeatedField<int>* values = |
| Raw<google::protobuf::RepeatedField<int> >(msg, offset); |
| |
| io::CodedInputStream::Limit limit = input->PushLimit(length); |
| while (input->BytesUntilLimit() > 0) { |
| int value; |
| if (GOOGLE_PREDICT_FALSE( |
| (!google::protobuf::internal::WireFormatLite::ReadPrimitive< |
| int, WireFormatLite::TYPE_ENUM>(input, &value)))) { |
| return false; |
| } |
| |
| if (validator(value)) { |
| values->Add(value); |
| } else { |
| // TODO(ckennelly): Consider caching here. |
| UnknownFieldHandler::Varint(msg, table, tag, value); |
| } |
| } |
| input->PopLimit(limit); |
| |
| break; |
| } |
| case WireFormatLite::TYPE_STRING: |
| case WireFormatLite::TYPE_GROUP: |
| case WireFormatLite::TYPE_MESSAGE: |
| case WireFormatLite::TYPE_BYTES: |
| GOOGLE_DCHECK(false); |
| return false; |
| default: |
| break; |
| } |
| } else { |
| if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) { |
| // Must be the end of the message. |
| return true; |
| } |
| |
| // check for possible extensions |
| if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) { |
| // successfully parsed |
| continue; |
| } |
| |
| // process unknown field. |
| if (GOOGLE_PREDICT_FALSE(!UnknownFieldHandler::Skip(msg, table, input, tag))) { |
| return false; |
| } |
| } |
| } |
| } |
| |
| } // namespace internal |
| } // namespace protobuf |
| |
| } // namespace google |
| #endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__ |