// 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 #include #include #include #include #include #include #include #include #include #include namespace google { namespace protobuf { namespace internal { enum StringType { StringType_STRING = 0, StringType_INLINED = 3 }; // 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_INLINED = 3, ProcessingType_MESSAGE = 4, }; enum Cardinality { Cardinality_SINGULAR = 0, Cardinality_REPEATED = 1, Cardinality_ONEOF = 3 }; template inline Type* Raw(MessageLite* msg, int64 offset) { return reinterpret_cast(reinterpret_cast(msg) + offset); } template inline const Type* Raw(const MessageLite* msg, int64 offset) { return reinterpret_cast(reinterpret_cast(msg) + offset); } template inline Arena* GetArena(MessageLite* msg, int64 arena_offset) { if (PROTOBUF_PREDICT_FALSE(arena_offset == -1)) { return NULL; } return Raw(msg, arena_offset)->arena(); } inline ExtensionSet* GetExtensionSet(MessageLite* msg, int64 extension_offset) { if (extension_offset == -1) { return NULL; } return Raw(msg, extension_offset); } template inline Type* AddField(MessageLite* msg, int64 offset) { static_assert(std::is_pod::value || std::is_same::value, "Do not assign"); RepeatedField* repeated = Raw>(msg, offset); return repeated->Add(); } template <> inline std::string* AddField(MessageLite* msg, int64 offset) { RepeatedPtrField* repeated = Raw>(msg, offset); return repeated->Add(); } template inline void AddField(MessageLite* msg, int64 offset, Type value) { static_assert(std::is_pod::value, "Do not assign"); *AddField(msg, offset) = value; } inline void SetBit(uint32* has_bits, uint32 has_bit_index) { GOOGLE_DCHECK(has_bits != nullptr); uint32 mask = static_cast(1u) << (has_bit_index % 32); has_bits[has_bit_index / 32u] |= mask; } template inline Type* MutableField(MessageLite* msg, uint32* has_bits, uint32 has_bit_index, int64 offset) { SetBit(has_bits, has_bit_index); return Raw(msg, offset); } template inline void SetField(MessageLite* msg, uint32* has_bits, uint32 has_bit_index, int64 offset, Type value) { static_assert(std::is_pod::value, "Do not assign"); *MutableField(msg, has_bits, has_bit_index, offset) = value; } template 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(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(msg, field.offset); } break; case WireFormatLite::TYPE_STRING: case WireFormatLite::TYPE_BYTES: Raw(msg, field.offset) ->Destroy(&GetEmptyStringAlreadyInited(), arena); break; case TYPE_STRING_INLINED: case TYPE_BYTES_INLINED: Raw(msg, field.offset)->DestroyNoArena(NULL); 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 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(msg, offset) ->UnsafeSetDefault(static_cast(default_ptr)); break; case ProcessingType_INLINED: new (Raw(msg, offset)) InlinedStringField(*static_cast(default_ptr)); break; case ProcessingType_MESSAGE: MessageLite** submessage = Raw(msg, offset); const MessageLite* prototype = table.aux[field_number].messages.default_message(); *submessage = prototype->New(arena); break; } } template 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 switch (ctype) { case StringType_INLINED: { InlinedStringField* s; switch (cardinality) { case Cardinality_SINGULAR: // TODO(ckennelly): Is this optimal? s = MutableField( msg, has_bits, has_bit_index, offset); break; case Cardinality_REPEATED: s = AddField(msg, offset); break; case Cardinality_ONEOF: s = Raw(msg, offset); break; } GOOGLE_DCHECK(s != nullptr); ::std::string* value = s->MutableNoArena(NULL); if (PROTOBUF_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) { return false; } #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED sdata = value->data(); size = value->size(); #endif break; } case StringType_STRING: { std::string* value; switch (cardinality) { case Cardinality_SINGULAR: // TODO(ckennelly): Is this optimal? value = MutableField(msg, has_bits, has_bit_index, offset) ->Mutable(static_cast(default_ptr), arena); break; case Cardinality_REPEATED: value = AddField(msg, offset); break; case Cardinality_ONEOF: value = Raw(msg, offset) ->Mutable(static_cast(default_ptr), arena); break; } GOOGLE_DCHECK(value != nullptr); if (PROTOBUF_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) { return false; } #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED sdata = value->data(); size = value->size(); #endif break; } } #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED if (validate) { WireFormatLite::VerifyUtf8String(sdata, size, WireFormatLite::PARSE, field_name); } #endif return true; } template 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 (PROTOBUF_PREDICT_FALSE( (!WireFormatLite::ReadPrimitive( 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(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; typedef MessageLite WeakType; 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; } } }; class MergePartialFromCodedStreamHelper { public: static MessageLite* Add(RepeatedPtrFieldBase* field, const MessageLite* prototype) { return field->Add( const_cast(prototype)); } }; template 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(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 (PROTOBUF_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(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 (PROTOBUF_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: { \ RepeatedField* values = Raw>(msg, offset); \ if (PROTOBUF_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(msg, table.oneof_case_offset); \ CPPTYPE value; \ if (PROTOBUF_PREDICT_FALSE( \ (!WireFormatLite::ReadPrimitive< \ CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)))) { \ return false; \ } \ ClearOneofField(table.fields[oneof_case[presence_index]], \ GetArena(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(msg, table.arena_offset); const void* default_ptr = table.aux[field_number].strings.default_ptr; if (PROTOBUF_PREDICT_FALSE(( !HandleString( input, msg, arena, has_bits, presence_index, offset, default_ptr, NULL)))) { return false; } break; } case TYPE_BYTES_INLINED: #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED case TYPE_STRING_INLINED: #endif { Arena* const arena = GetArena(msg, table.arena_offset); const void* default_ptr = table.aux[field_number].strings.default_ptr; if (PROTOBUF_PREDICT_FALSE((!HandleString( 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(msg, table.arena_offset); uint32* oneof_case = Raw(msg, table.oneof_case_offset); const void* default_ptr = table.aux[field_number].strings.default_ptr; ResetOneofField( table, field_number, arena, msg, oneof_case + presence_index, offset, default_ptr); if (PROTOBUF_PREDICT_FALSE( (!HandleString( input, msg, arena, has_bits, presence_index, offset, default_ptr, NULL)))) { return false; } break; } case (WireFormatLite::TYPE_BYTES) | kRepeatedMask: case TYPE_BYTES_INLINED | kRepeatedMask: #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED case (WireFormatLite::TYPE_STRING) | kRepeatedMask: case TYPE_STRING_INLINED | kRepeatedMask: #endif { Arena* const arena = GetArena(msg, table.arena_offset); const void* default_ptr = table.aux[field_number].strings.default_ptr; if (PROTOBUF_PREDICT_FALSE(( !HandleString( 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(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 (PROTOBUF_PREDICT_FALSE( (!HandleString( input, msg, arena, has_bits, presence_index, offset, default_ptr, field_name)))) { return false; } break; } case TYPE_STRING_INLINED | kRepeatedMask: case (WireFormatLite::TYPE_STRING) | kRepeatedMask: { Arena* const arena = GetArena(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 (PROTOBUF_PREDICT_FALSE( (!HandleString( input, msg, arena, has_bits, presence_index, offset, default_ptr, field_name)))) { return false; } break; } case (WireFormatLite::TYPE_STRING) | kOneofMask: { Arena* const arena = GetArena(msg, table.arena_offset); uint32* oneof_case = Raw(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( table, field_number, arena, msg, oneof_case + presence_index, offset, default_ptr); if (PROTOBUF_PREDICT_FALSE( (!HandleString( input, msg, arena, has_bits, presence_index, offset, default_ptr, field_name)))) { return false; } break; } #endif case WireFormatLite::TYPE_ENUM: { if (PROTOBUF_PREDICT_FALSE( (!HandleEnum( table, input, msg, has_bits, presence_index, offset, tag, field_number)))) { return false; } break; } case WireFormatLite::TYPE_ENUM | kRepeatedMask: { if (PROTOBUF_PREDICT_FALSE( (!HandleEnum( table, input, msg, has_bits, presence_index, offset, tag, field_number)))) { return false; } break; } case WireFormatLite::TYPE_ENUM | kOneofMask: { uint32* oneof_case = Raw(msg, table.oneof_case_offset); if (PROTOBUF_PREDICT_FALSE( (!HandleEnum(table, input, msg, oneof_case, presence_index, offset, tag, field_number)))) { return false; } break; } case WireFormatLite::TYPE_GROUP: { MessageLite** submsg_holder = MutableField(msg, has_bits, presence_index, offset); MessageLite* submsg = *submsg_holder; if (submsg == NULL) { Arena* const arena = GetArena(msg, table.arena_offset); const MessageLite* prototype = table.aux[field_number].messages.default_message(); submsg = prototype->New(arena); *submsg_holder = submsg; } if (PROTOBUF_PREDICT_FALSE( !WireFormatLite::ReadGroup(field_number, input, submsg))) { return false; } break; } case WireFormatLite::TYPE_GROUP | kRepeatedMask: { RepeatedPtrFieldBase* field = Raw(msg, offset); const MessageLite* prototype = table.aux[field_number].messages.default_message(); GOOGLE_DCHECK(prototype != NULL); MessageLite* submsg = MergePartialFromCodedStreamHelper::Add(field, prototype); if (PROTOBUF_PREDICT_FALSE( !WireFormatLite::ReadGroup(field_number, input, submsg))) { return false; } break; } case WireFormatLite::TYPE_MESSAGE: { MessageLite** submsg_holder = MutableField(msg, has_bits, presence_index, offset); MessageLite* submsg = *submsg_holder; if (submsg == NULL) { Arena* const arena = GetArena(msg, table.arena_offset); const MessageLite* prototype = table.aux[field_number].messages.default_message(); if (prototype == NULL) { prototype = ImplicitWeakMessage::default_instance(); } submsg = prototype->New(arena); *submsg_holder = submsg; } if (PROTOBUF_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(msg, offset); const MessageLite* prototype = table.aux[field_number].messages.default_message(); if (prototype == NULL) { prototype = ImplicitWeakMessage::default_instance(); } MessageLite* submsg = MergePartialFromCodedStreamHelper::Add(field, prototype); if (PROTOBUF_PREDICT_FALSE( !WireFormatLite::ReadMessage(input, submsg))) { return false; } break; } case WireFormatLite::TYPE_MESSAGE | kOneofMask: { Arena* const arena = GetArena(msg, table.arena_offset); uint32* oneof_case = Raw(msg, table.oneof_case_offset); MessageLite** submsg_holder = Raw(msg, offset); ResetOneofField( table, field_number, arena, msg, oneof_case + presence_index, offset, NULL); MessageLite* submsg = *submsg_holder; if (PROTOBUF_PREDICT_FALSE( !WireFormatLite::ReadMessage(input, submsg))) { return false; } break; } #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED case TYPE_STRING_INLINED: { Arena* const arena = GetArena(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 (PROTOBUF_PREDICT_FALSE(( !HandleString( input, msg, arena, has_bits, presence_index, offset, default_ptr, field_name)))) { return false; } break; } #endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED case TYPE_MAP: { if (PROTOBUF_PREDICT_FALSE(!(*table.aux[field_number].maps.parse_map)( input, Raw(msg, offset)))) { return false; } break; } case 0: { // Done. return true; } default: break; } } else if (data->packed_wiretype == static_cast(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); GOOGLE_DCHECK_NE(TYPE_BYTES_INLINED | kRepeatedMask, processing_type); GOOGLE_DCHECK_NE(TYPE_STRING_INLINED | kRepeatedMask, processing_type); // TODO(ckennelly): Use a computed goto on GCC/LLVM. // // Mask out kRepeatedMask bit, allowing the jump table to be smaller. switch (static_cast( processing_type ^ kRepeatedMask)) { #define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ case WireFormatLite::TYPE_##TYPE: { \ RepeatedField* values = Raw>(msg, offset); \ if (PROTOBUF_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 (PROTOBUF_PREDICT_FALSE(!input->ReadVarint32(&length))) { return false; } AuxillaryParseTableField::EnumValidator validator = table.aux[field_number].enums.validator; RepeatedField* values = Raw>(msg, offset); io::CodedInputStream::Limit limit = input->PushLimit(length); while (input->BytesUntilLimit() > 0) { int value; if (PROTOBUF_PREDICT_FALSE( (!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 (PROTOBUF_PREDICT_FALSE( !UnknownFieldHandler::Skip(msg, table, input, tag))) { return false; } } } } } // namespace internal } // namespace protobuf } // namespace google #include #endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__