diff options
Diffstat (limited to 'src/google/protobuf/wire_format.cc')
-rw-r--r-- | src/google/protobuf/wire_format.cc | 801 |
1 files changed, 801 insertions, 0 deletions
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc new file mode 100644 index 00000000..77e9c74b --- /dev/null +++ b/src/google/protobuf/wire_format.cc @@ -0,0 +1,801 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. +// http://code.google.com/p/protobuf/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <stack> +#include <string> +#include <vector> + +#include <google/protobuf/wire_format_inl.h> + +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/unknown_field_set.h> + +namespace google { +namespace protobuf { +namespace internal { + +namespace { + +// This function turns out to be convenient when using some macros later. +inline int GetEnumNumber(const EnumValueDescriptor* descriptor) { + return descriptor->number(); +} + +// These are the tags for the old MessageSet format, which was defined as: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// } +// } +const int kMessageSetItemStartTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormat::WIRETYPE_START_GROUP); +const int kMessageSetItemEndTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormat::WIRETYPE_END_GROUP); +const int kMessageSetTypeIdTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(2, WireFormat::WIRETYPE_VARINT); +const int kMessageSetMessageTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(3, WireFormat::WIRETYPE_LENGTH_DELIMITED); + +// Byte size of all tags of a MessageSet::Item combined. +static const int kMessageSetItemTagsSize = + io::CodedOutputStream::VarintSize32(kMessageSetItemStartTag) + + io::CodedOutputStream::VarintSize32(kMessageSetItemEndTag) + + io::CodedOutputStream::VarintSize32(kMessageSetTypeIdTag) + + io::CodedOutputStream::VarintSize32(kMessageSetMessageTag); + +} // anonymous namespace + +const WireFormat::WireType +WireFormat::kWireTypeForFieldType[FieldDescriptor::MAX_TYPE + 1] = { + static_cast<WireFormat::WireType>(-1), // invalid + WIRETYPE_FIXED64, // TYPE_DOUBLE + WIRETYPE_FIXED32, // TYPE_FLOAT + WIRETYPE_VARINT, // TYPE_INT64 + WIRETYPE_VARINT, // TYPE_UINT64 + WIRETYPE_VARINT, // TYPE_INT32 + WIRETYPE_FIXED64, // TYPE_FIXED64 + WIRETYPE_FIXED32, // TYPE_FIXED32 + WIRETYPE_VARINT, // TYPE_BOOL + WIRETYPE_LENGTH_DELIMITED, // TYPE_STRING + WIRETYPE_START_GROUP, // TYPE_GROUP + WIRETYPE_LENGTH_DELIMITED, // TYPE_MESSAGE + WIRETYPE_LENGTH_DELIMITED, // TYPE_BYTES + WIRETYPE_VARINT, // TYPE_UINT32 + WIRETYPE_VARINT, // TYPE_ENUM + WIRETYPE_FIXED32, // TYPE_SFIXED32 + WIRETYPE_FIXED64, // TYPE_SFIXED64 + WIRETYPE_VARINT, // TYPE_SINT32 + WIRETYPE_VARINT, // TYPE_SINT64 +}; + +// =================================================================== + +bool WireFormat::SkipField(io::CodedInputStream* input, uint32 tag, + UnknownFieldSet* unknown_fields) { + UnknownField* field = (unknown_fields == NULL) ? NULL : + unknown_fields->AddField(GetTagFieldNumber(tag)); + + switch (GetTagWireType(tag)) { + case WIRETYPE_VARINT: { + uint64 value; + if (!input->ReadVarint64(&value)) return false; + if (field != NULL) field->add_varint(value); + return true; + } + case WIRETYPE_FIXED64: { + uint64 value; + if (!input->ReadLittleEndian64(&value)) return false; + if (field != NULL) field->add_fixed64(value); + return true; + } + case WIRETYPE_LENGTH_DELIMITED: { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (field == NULL) { + if (!input->Skip(length)) return false; + } else { + input->ReadString(field->add_length_delimited(), length); + } + return true; + } + case WIRETYPE_START_GROUP: { + if (!input->IncrementRecursionDepth()) return false; + if (!SkipMessage(input, (field == NULL) ? NULL : field->add_group())) { + return false; + } + input->DecrementRecursionDepth(); + // Check that the ending tag matched the starting tag. + if (!input->LastTagWas( + MakeTag(GetTagFieldNumber(tag), WIRETYPE_END_GROUP))) { + return false; + } + return true; + } + case WIRETYPE_END_GROUP: { + return false; + } + case WIRETYPE_FIXED32: { + uint32 value; + if (!input->ReadLittleEndian32(&value)) return false; + if (field != NULL) field->add_fixed32(value); + return true; + } + default: { + return false; + } + } +} + +bool WireFormat::SkipMessage(io::CodedInputStream* input, + UnknownFieldSet* unknown_fields) { + while(true) { + uint32 tag = input->ReadTag(); + if (tag == 0) { + // End of input. This is a valid place to end, so return true. + return true; + } + + WireType wire_type = GetTagWireType(tag); + + if (wire_type == WIRETYPE_END_GROUP) { + // Must be the end of the message. + return true; + } + + if (!SkipField(input, tag, unknown_fields)) return false; + } +} + +bool WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields, + io::CodedOutputStream* output) { + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + +#define DO(EXPRESSION) if (!(EXPRESSION)) return false + for (int j = 0; j < field.varint_size(); j++) { + DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_VARINT))); + DO(output->WriteVarint64(field.varint(j))); + } + for (int j = 0; j < field.fixed32_size(); j++) { + DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_FIXED32))); + DO(output->WriteLittleEndian32(field.fixed32(j))); + } + for (int j = 0; j < field.fixed64_size(); j++) { + DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_FIXED64))); + DO(output->WriteLittleEndian64(field.fixed64(j))); + } + for (int j = 0; j < field.length_delimited_size(); j++) { + DO(output->WriteVarint32( + MakeTag(field.number(), WIRETYPE_LENGTH_DELIMITED))); + DO(output->WriteVarint32(field.length_delimited(j).size())); + DO(output->WriteString(field.length_delimited(j))); + } + for (int j = 0; j < field.group_size(); j++) { + DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_START_GROUP))); + DO(SerializeUnknownFields(field.group(j), output)); + DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_END_GROUP))); + } +#undef DO + } + + return true; +} + +bool WireFormat::SerializeUnknownMessageSetItems( + const UnknownFieldSet& unknown_fields, + io::CodedOutputStream* output) { + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + +#define DO(EXPRESSION) if (!(EXPRESSION)) return false + // The only unknown fields that are allowed to exist in a MessageSet are + // messages, which are length-delimited. + for (int j = 0; j < field.length_delimited_size(); j++) { + const string& data = field.length_delimited(j); + + // Start group. + DO(output->WriteVarint32(kMessageSetItemStartTag)); + + // Write type ID. + DO(output->WriteVarint32(kMessageSetTypeIdTag)); + DO(output->WriteVarint32(field.number())); + + // Write message. + DO(output->WriteVarint32(kMessageSetMessageTag)); + DO(output->WriteVarint32(data.size())); + DO(output->WriteString(data)); + + // End group. + DO(output->WriteVarint32(kMessageSetItemEndTag)); + } +#undef DO + } + + return true; +} + +int WireFormat::ComputeUnknownFieldsSize( + const UnknownFieldSet& unknown_fields) { + int size = 0; + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + + for (int j = 0; j < field.varint_size(); j++) { + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_VARINT)); + size += io::CodedOutputStream::VarintSize64(field.varint(j)); + } + for (int j = 0; j < field.fixed32_size(); j++) { + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_FIXED32)); + size += sizeof(int32); + } + for (int j = 0; j < field.fixed64_size(); j++) { + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_FIXED64)); + size += sizeof(int64); + } + for (int j = 0; j < field.length_delimited_size(); j++) { + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_LENGTH_DELIMITED)); + size += io::CodedOutputStream::VarintSize32( + field.length_delimited(j).size()); + size += field.length_delimited(j).size(); + } + for (int j = 0; j < field.group_size(); j++) { + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_START_GROUP)); + size += ComputeUnknownFieldsSize(field.group(j)); + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_END_GROUP)); + } + } + + return size; +} + +int WireFormat::ComputeUnknownMessageSetItemsSize( + const UnknownFieldSet& unknown_fields) { + int size = 0; + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + + // The only unknown fields that are allowed to exist in a MessageSet are + // messages, which are length-delimited. + for (int j = 0; j < field.length_delimited_size(); j++) { + size += kMessageSetItemTagsSize; + size += io::CodedOutputStream::VarintSize32(field.number()); + size += io::CodedOutputStream::VarintSize32( + field.length_delimited(j).size()); + size += field.length_delimited(j).size(); + } + } + + return size; +} + +// =================================================================== + +bool WireFormat::ParseAndMergePartial(const Descriptor* descriptor, + io::CodedInputStream* input, + Message::Reflection* message_reflection) { + while(true) { + uint32 tag = input->ReadTag(); + if (tag == 0) { + // End of input. This is a valid place to end, so return true. + return true; + } + + if (GetTagWireType(tag) == WIRETYPE_END_GROUP) { + // Must be the end of the message. + return true; + } + + const FieldDescriptor* field = NULL; + + if (descriptor != NULL) { + int field_number = GetTagFieldNumber(tag); + field = descriptor->FindFieldByNumber(field_number); + + // If that failed, check if the field is an extension. + if (field == NULL && descriptor->IsExtensionNumber(field_number)) { + field = message_reflection->FindKnownExtensionByNumber(field_number); + } + + // If that failed, but we're a MessageSet, and this is the tag for a + // MessageSet item, then parse that. + if (field == NULL && + descriptor->options().message_set_wire_format() && + tag == kMessageSetItemStartTag) { + if (!ParseAndMergeMessageSetItem(input, message_reflection)) { + return false; + } + continue; // Skip ParseAndMergeField(); already taken care of. + } + } + + if (!ParseAndMergeField(tag, field, message_reflection, input)) { + return false; + } + } +} + +bool WireFormat::ParseAndMergeField( + uint32 tag, + const FieldDescriptor* field, // May be NULL for unknown + Message::Reflection* message_reflection, + io::CodedInputStream* input) { + if (field == NULL || + GetTagWireType(tag) != WireTypeForFieldType(field->type())) { + // We don't recognize this field. Either the field number is unknown + // or the wire type doesn't match. Put it in our unknown field set. + return SkipField(input, tag, message_reflection->MutableUnknownFields()); + } + + switch (field->type()) { +#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: { \ + CPPTYPE value; \ + if (!Read##TYPE_METHOD(input, &value)) return false; \ + if (field->is_repeated()) { \ + message_reflection->Add##CPPTYPE_METHOD(field, value); \ + } else { \ + message_reflection->Set##CPPTYPE_METHOD(field, value); \ + } \ + break; \ + } + + HANDLE_TYPE( INT32, Int32, int32, Int32) + HANDLE_TYPE( INT64, Int64, int64, Int64) + HANDLE_TYPE(SINT32, SInt32, int32, Int32) + HANDLE_TYPE(SINT64, SInt64, int64, Int64) + HANDLE_TYPE(UINT32, UInt32, uint32, UInt32) + HANDLE_TYPE(UINT64, UInt64, uint64, UInt64) + + HANDLE_TYPE( FIXED32, Fixed32, uint32, UInt32) + HANDLE_TYPE( FIXED64, Fixed64, uint64, UInt64) + HANDLE_TYPE(SFIXED32, SFixed32, int32, Int32) + HANDLE_TYPE(SFIXED64, SFixed64, int64, Int64) + + HANDLE_TYPE(FLOAT , Float , float , Float ) + HANDLE_TYPE(DOUBLE, Double, double, Double) + + HANDLE_TYPE(BOOL, Bool, bool, Bool) + + HANDLE_TYPE(STRING, String, string, String) + HANDLE_TYPE(BYTES, Bytes, string, String) + +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_ENUM: { + int value; + if (!ReadEnum(input, &value)) return false; + const EnumValueDescriptor* enum_value = + field->enum_type()->FindValueByNumber(value); + if (enum_value != NULL) { + if (field->is_repeated()) { + message_reflection->AddEnum(field, enum_value); + } else { + message_reflection->SetEnum(field, enum_value); + } + } else { + // The enum value is not one of the known values. Add it to the + // UnknownFieldSet. + int64 sign_extended_value = static_cast<int64>(value); + message_reflection->MutableUnknownFields() + ->AddField(GetTagFieldNumber(tag)) + ->add_varint(sign_extended_value); + } + break; + } + + + case FieldDescriptor::TYPE_GROUP: { + Message* sub_message; + if (field->is_repeated()) { + sub_message = message_reflection->AddMessage(field); + } else { + sub_message = message_reflection->MutableMessage(field); + } + + if (!ReadGroup(GetTagFieldNumber(tag), input, sub_message)) return false; + break; + } + + case FieldDescriptor::TYPE_MESSAGE: { + Message* sub_message; + if (field->is_repeated()) { + sub_message = message_reflection->AddMessage(field); + } else { + sub_message = message_reflection->MutableMessage(field); + } + + if (!ReadMessage(input, sub_message)) return false; + break; + } + } + + return true; +} + +bool WireFormat::ParseAndMergeMessageSetItem( + io::CodedInputStream* input, + Message::Reflection* message_reflection) { + // This method parses a group which should contain two fields: + // required int32 type_id = 2; + // required data message = 3; + + // Once we see a type_id, we'll construct a fake tag for this extension + // which is the tag it would have had under the proto2 extensions wire + // format. + uint32 fake_tag = 0; + + // Once we see a type_id, we'll look up the FieldDescriptor for the + // extension. + const FieldDescriptor* field = NULL; + + // If we see message data before the type_id, we'll append it to this so + // we can parse it later. This will probably never happen in practice, + // as no MessageSet encoder I know of writes the message before the type ID. + // But, it's technically valid so we should allow it. + // TODO(kenton): Use a Cord instead? Do I care? + string message_data; + + while (true) { + uint32 tag = input->ReadTag(); + if (tag == 0) return false; + + switch (tag) { + case kMessageSetTypeIdTag: { + uint32 type_id; + if (!input->ReadVarint32(&type_id)) return false; + fake_tag = MakeTag(type_id, WIRETYPE_LENGTH_DELIMITED); + field = message_reflection->FindKnownExtensionByNumber(type_id); + + if (!message_data.empty()) { + // We saw some message data before the type_id. Have to parse it + // now. + io::ArrayInputStream raw_input(message_data.data(), + message_data.size()); + io::CodedInputStream sub_input(&raw_input); + if (!ParseAndMergeField(fake_tag, field, message_reflection, + &sub_input)) { + return false; + } + message_data.clear(); + } + + break; + } + + case kMessageSetMessageTag: { + if (fake_tag == 0) { + // We haven't seen a type_id yet. Append this data to message_data. + string temp; + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->ReadString(&temp, length)) return false; + message_data.append(temp); + } else { + // Already saw type_id, so we can parse this directly. + if (!ParseAndMergeField(fake_tag, field, message_reflection, input)) { + return false; + } + } + + break; + } + + case kMessageSetItemEndTag: { + return true; + } + + default: { + if (!SkipField(input, tag, NULL)) return false; + } + } + } +} + +// =================================================================== + +bool WireFormat::SerializeWithCachedSizes( + const Descriptor* descriptor, + const Message::Reflection* message_reflection, + int size, io::CodedOutputStream* output) { + int expected_endpoint = output->ByteCount() + size; + + vector<const FieldDescriptor*> fields; + message_reflection->ListFields(&fields); + for (int i = 0; i < fields.size(); i++) { + if (!SerializeFieldWithCachedSizes(fields[i], message_reflection, output)) { + return false; + } + } + + if (descriptor->options().message_set_wire_format()) { + if (!SerializeUnknownMessageSetItems( + message_reflection->GetUnknownFields(), output)) { + return false; + } + } else { + if (!SerializeUnknownFields( + message_reflection->GetUnknownFields(), output)) { + return false; + } + } + + GOOGLE_CHECK_EQ(output->ByteCount(), expected_endpoint) + << ": Protocol message serialized to a size different from what was " + "originally expected. Perhaps it was modified by another thread " + "during serialization?"; + + return true; +} + +bool WireFormat::SerializeFieldWithCachedSizes( + const FieldDescriptor* field, + const Message::Reflection* message_reflection, + io::CodedOutputStream* output) { + if (field->is_extension() && + field->containing_type()->options().message_set_wire_format() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_repeated()) { + return SerializeMessageSetItemWithCachedSizes( + field, message_reflection, output); + } + + int count = 0; + + if (field->is_repeated()) { + count = message_reflection->FieldSize(field); + } else if (message_reflection->HasField(field)) { + count = 1; + } + + for (int j = 0; j < count; j++) { + switch (field->type()) { +#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: \ + if (!Write##TYPE_METHOD( \ + field->number(), \ + field->is_repeated() ? \ + message_reflection->GetRepeated##CPPTYPE_METHOD(field, j) : \ + message_reflection->Get##CPPTYPE_METHOD(field), \ + output)) { \ + return false; \ + } \ + break; + + HANDLE_TYPE( INT32, Int32, Int32) + HANDLE_TYPE( INT64, Int64, Int64) + HANDLE_TYPE(SINT32, SInt32, Int32) + HANDLE_TYPE(SINT64, SInt64, Int64) + HANDLE_TYPE(UINT32, UInt32, UInt32) + HANDLE_TYPE(UINT64, UInt64, UInt64) + + HANDLE_TYPE( FIXED32, Fixed32, UInt32) + HANDLE_TYPE( FIXED64, Fixed64, UInt64) + HANDLE_TYPE(SFIXED32, SFixed32, Int32) + HANDLE_TYPE(SFIXED64, SFixed64, Int64) + + HANDLE_TYPE(FLOAT , Float , Float ) + HANDLE_TYPE(DOUBLE, Double, Double) + + HANDLE_TYPE(BOOL, Bool, Bool) + + HANDLE_TYPE(GROUP , Group , Message) + HANDLE_TYPE(MESSAGE, Message, Message) +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_ENUM: { + const EnumValueDescriptor* value = field->is_repeated() ? + message_reflection->GetRepeatedEnum(field, j) : + message_reflection->GetEnum(field); + if (!WriteEnum(field->number(), value->number(), output)) return false; + break; + } + + // Handle strings separately so that we can get string references + // instead of copying. + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: { + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference(field, j, &scratch) : + message_reflection->GetStringReference(field, &scratch); + if (!WriteString(field->number(), value, output)) return false; + break; + } + } + } + + return true; +} + +bool WireFormat::SerializeMessageSetItemWithCachedSizes( + const FieldDescriptor* field, + const Message::Reflection* message_reflection, + io::CodedOutputStream* output) { + // Start group. + if (!output->WriteVarint32(kMessageSetItemStartTag)) return false; + + // Write type ID. + if (!output->WriteVarint32(kMessageSetTypeIdTag)) return false; + if (!output->WriteVarint32(field->number())) return false; + + // Write message. + if (!output->WriteVarint32(kMessageSetMessageTag)) return false; + + const Message& sub_message = message_reflection->GetMessage(field); + if (!output->WriteVarint32(sub_message.GetCachedSize())) return false; + if (!sub_message.SerializeWithCachedSizes(output)) return false; + + // End group. + if (!output->WriteVarint32(kMessageSetItemEndTag)) return false; + + return true; +} + +// =================================================================== + +int WireFormat::ByteSize( + const Descriptor* descriptor, + const Message::Reflection* message_reflection) { + int our_size = 0; + + vector<const FieldDescriptor*> fields; + message_reflection->ListFields(&fields); + for (int i = 0; i < fields.size(); i++) { + our_size += FieldByteSize(fields[i], message_reflection); + } + + if (descriptor->options().message_set_wire_format()) { + our_size += ComputeUnknownMessageSetItemsSize( + message_reflection->GetUnknownFields()); + } else { + our_size += ComputeUnknownFieldsSize( + message_reflection->GetUnknownFields()); + } + + return our_size; +} + +int WireFormat::FieldByteSize( + const FieldDescriptor* field, + const Message::Reflection* message_reflection) { + if (field->is_extension() && + field->containing_type()->options().message_set_wire_format() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_repeated()) { + return MessageSetItemByteSize(field, message_reflection); + } + + int our_size = 0; + + int count = 0; + + if (field->is_repeated()) { + count = message_reflection->FieldSize(field); + } else if (message_reflection->HasField(field)) { + count = 1; + } + + our_size += count * TagSize(field->number(), field->type()); + + switch (field->type()) { +#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: \ + if (field->is_repeated()) { \ + for (int j = 0; j < count; j++) { \ + our_size += TYPE_METHOD##Size( \ + message_reflection->GetRepeated##CPPTYPE_METHOD(field, j)); \ + } \ + } else { \ + our_size += TYPE_METHOD##Size( \ + message_reflection->Get##CPPTYPE_METHOD(field)); \ + } \ + break; + +#define HANDLE_FIXED_TYPE(TYPE, TYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: \ + our_size += count * k##TYPE_METHOD##Size; \ + break; + + HANDLE_TYPE( INT32, Int32, Int32) + HANDLE_TYPE( INT64, Int64, Int64) + HANDLE_TYPE(SINT32, SInt32, Int32) + HANDLE_TYPE(SINT64, SInt64, Int64) + HANDLE_TYPE(UINT32, UInt32, UInt32) + HANDLE_TYPE(UINT64, UInt64, UInt64) + + HANDLE_FIXED_TYPE( FIXED32, Fixed32) + HANDLE_FIXED_TYPE( FIXED64, Fixed64) + HANDLE_FIXED_TYPE(SFIXED32, SFixed32) + HANDLE_FIXED_TYPE(SFIXED64, SFixed64) + + HANDLE_FIXED_TYPE(FLOAT , Float ) + HANDLE_FIXED_TYPE(DOUBLE, Double) + + HANDLE_FIXED_TYPE(BOOL, Bool) + + HANDLE_TYPE(GROUP , Group , Message) + HANDLE_TYPE(MESSAGE, Message, Message) +#undef HANDLE_TYPE +#undef HANDLE_FIXED_TYPE + + case FieldDescriptor::TYPE_ENUM: { + if (field->is_repeated()) { + for (int j = 0; j < count; j++) { + our_size += EnumSize( + message_reflection->GetRepeatedEnum(field, j)->number()); + } + } else { + our_size += EnumSize( + message_reflection->GetEnum(field)->number()); + } + break; + } + + // Handle strings separately so that we can get string references + // instead of copying. + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: { + for (int j = 0; j < count; j++) { + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference(field, j, &scratch) : + message_reflection->GetStringReference(field, &scratch); + our_size += StringSize(value); + } + break; + } + } + + return our_size; +} + +int WireFormat::MessageSetItemByteSize( + const FieldDescriptor* field, + const Message::Reflection* message_reflection) { + int our_size = kMessageSetItemTagsSize; + + // type_id + our_size += io::CodedOutputStream::VarintSize32(field->number()); + + // message + const Message& sub_message = message_reflection->GetMessage(field); + int message_size = sub_message.ByteSize(); + + our_size += io::CodedOutputStream::VarintSize32(message_size); + our_size += message_size; + + return our_size; +} + +} // namespace internal +} // namespace protobuf +} // namespace google |