diff options
Diffstat (limited to 'src/google/protobuf/wire_format.cc')
-rw-r--r-- | src/google/protobuf/wire_format.cc | 74 |
1 files changed, 56 insertions, 18 deletions
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index ead763b1..91892897 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -39,6 +39,7 @@ #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/wire_format_lite_inl.h> #include <google/protobuf/descriptor.pb.h> @@ -182,7 +183,8 @@ void WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields, output->WriteVarint32(WireFormatLite::MakeTag(field.number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); output->WriteVarint32(field.length_delimited().size()); - output->WriteString(field.length_delimited()); + output->WriteRawMaybeAliased(field.length_delimited().data(), + field.length_delimited().size()); break; case UnknownField::TYPE_GROUP: output->WriteVarint32(WireFormatLite::MakeTag(field.number(), @@ -411,6 +413,37 @@ bool WireFormat::ParseAndMergePartial(io::CodedInputStream* input, } } +bool WireFormat::SkipMessageSetField(io::CodedInputStream* input, + uint32 field_number, + UnknownFieldSet* unknown_fields) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + return input->ReadString( + unknown_fields->AddLengthDelimited(field_number), length); +} + +bool WireFormat::ParseAndMergeMessageSetField(uint32 field_number, + const FieldDescriptor* field, + Message* message, + io::CodedInputStream* input) { + const Reflection* message_reflection = message->GetReflection(); + if (field == NULL) { + // We store unknown MessageSet extensions as groups. + return SkipMessageSetField( + input, field_number, message_reflection->MutableUnknownFields(message)); + } else if (field->is_repeated() || + field->type() != FieldDescriptor::TYPE_MESSAGE) { + // This shouldn't happen as we only allow optional message extensions to + // MessageSet. + GOOGLE_LOG(ERROR) << "Extensions of MessageSets must be optional messages."; + return false; + } else { + Message* sub_message = message_reflection->MutableMessage( + message, field, input->GetExtensionFactory()); + return WireFormatLite::ReadMessage(input, sub_message); + } +} + bool WireFormat::ParseAndMergeField( uint32 tag, const FieldDescriptor* field, // May be NULL for unknown @@ -562,7 +595,8 @@ bool WireFormat::ParseAndMergeField( case FieldDescriptor::TYPE_STRING: { string value; if (!WireFormatLite::ReadString(input, &value)) return false; - VerifyUTF8String(value.data(), value.length(), PARSE); + VerifyUTF8StringNamedField(value.data(), value.length(), PARSE, + field->name().c_str()); if (field->is_repeated()) { message_reflection->AddString(message, field, value); } else { @@ -626,10 +660,7 @@ bool WireFormat::ParseAndMergeMessageSetItem( // 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; + uint32 last_type_id = 0; // Once we see a type_id, we'll look up the FieldDescriptor for the // extension. @@ -647,8 +678,7 @@ bool WireFormat::ParseAndMergeMessageSetItem( case WireFormatLite::kMessageSetTypeIdTag: { uint32 type_id; if (!input->ReadVarint32(&type_id)) return false; - fake_tag = WireFormatLite::MakeTag( - type_id, WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + last_type_id = type_id; field = message_reflection->FindKnownExtensionByNumber(type_id); if (!message_data.empty()) { @@ -657,8 +687,8 @@ bool WireFormat::ParseAndMergeMessageSetItem( io::ArrayInputStream raw_input(message_data.data(), message_data.size()); io::CodedInputStream sub_input(&raw_input); - if (!ParseAndMergeField(fake_tag, field, message, - &sub_input)) { + if (!ParseAndMergeMessageSetField(last_type_id, field, message, + &sub_input)) { return false; } message_data.clear(); @@ -668,7 +698,7 @@ bool WireFormat::ParseAndMergeMessageSetItem( } case WireFormatLite::kMessageSetMessageTag: { - if (fake_tag == 0) { + if (last_type_id == 0) { // We haven't seen a type_id yet. Append this data to message_data. string temp; uint32 length; @@ -680,7 +710,8 @@ bool WireFormat::ParseAndMergeMessageSetItem( coded_output.WriteString(temp); } else { // Already saw type_id, so we can parse this directly. - if (!ParseAndMergeField(fake_tag, field, message, input)) { + if (!ParseAndMergeMessageSetField(last_type_id, field, message, + input)) { return false; } } @@ -828,7 +859,8 @@ void WireFormat::SerializeFieldWithCachedSizes( message_reflection->GetRepeatedStringReference( message, field, j, &scratch) : message_reflection->GetStringReference(message, field, &scratch); - VerifyUTF8String(value.data(), value.length(), SERIALIZE); + VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE, + field->name().c_str()); WireFormatLite::WriteString(field->number(), value, output); break; } @@ -1038,7 +1070,8 @@ int WireFormat::MessageSetItemByteSize( void WireFormat::VerifyUTF8StringFallback(const char* data, int size, - Operation op) { + Operation op, + const char* field_name) { if (!IsStructurallyValidUTF8(data, size)) { const char* operation_str = NULL; switch (op) { @@ -1050,10 +1083,15 @@ void WireFormat::VerifyUTF8StringFallback(const char* data, break; // no default case: have the compiler warn if a case is not covered. } - GOOGLE_LOG(ERROR) << "String field contains invalid UTF-8 data when " - << operation_str - << " a protocol buffer. Use the 'bytes' type if you intend to " - "send raw bytes."; + string quoted_field_name = ""; + if (field_name != NULL) { + quoted_field_name = StringPrintf(" '%s'", field_name); + } + // no space below to avoid double space when the field name is missing. + GOOGLE_LOG(ERROR) << "String field" << quoted_field_name << " contains invalid " + << "UTF-8 data when " << operation_str << " a protocol " + << "buffer. Use the 'bytes' type if you intend to send raw " + << "bytes. "; } } |