blob: 0d90fe33a6241a4f2eb04cb5728eac75009f1c81 [file] [log] [blame]
// 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/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/implicit_weak_message.h>
#include <google/protobuf/inlined_string_field.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>
#include <type_traits>
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 <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) {
static_assert(std::is_pod<Type>::value ||
std::is_same<Type, InlinedStringField>::value,
"Do not assign");
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) {
static_assert(std::is_pod<Type>::value,
"Do not assign");
*AddField<Type>(msg, offset) = value;
}
inline void SetBit(uint32* has_bits, uint32 has_bit_index) {
GOOGLE_DCHECK(has_bits != nullptr);
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) {
static_assert(std::is_pod<Type>::value,
"Do not assign");
*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;
case TYPE_STRING_INLINED:
case TYPE_BYTES_INLINED:
Raw<InlinedStringField>(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 <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_INLINED:
new (Raw<InlinedStringField>(msg, offset))
InlinedStringField(*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
switch (ctype) {
case StringType_INLINED: {
InlinedStringField* s;
switch (cardinality) {
case Cardinality_SINGULAR:
// TODO(ckennelly): Is this optimal?
s = MutableField<InlinedStringField>(
msg, has_bits, has_bit_index, offset);
break;
case Cardinality_REPEATED:
s = AddField<InlinedStringField>(msg, offset);
break;
case Cardinality_ONEOF:
s = Raw<InlinedStringField>(msg, offset);
break;
}
GOOGLE_DCHECK(s != nullptr);
::std::string* value = s->MutableNoArena(NULL);
if (GOOGLE_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: {
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 != nullptr);
if (GOOGLE_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 <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;
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<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 TYPE_BYTES_INLINED:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case TYPE_STRING_INLINED:
#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_INLINED>(
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:
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<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 TYPE_STRING_INLINED | kRepeatedMask:
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();
if (prototype == NULL) {
prototype =
::google::protobuf::internal::ImplicitWeakMessage::default_instance();
}
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();
if (prototype == NULL) {
prototype =
::google::protobuf::internal::ImplicitWeakMessage::default_instance();
}
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;
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case TYPE_STRING_INLINED: {
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_INLINED>(
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 (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);
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<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__