diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index 72e13c4ba7..99db63f76e 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -766,6 +766,44 @@ struct WireFormat::MessageSetParser { const Reflection* reflection; }; +static const char* HandleMessage(Message* msg, const char* ptr, + internal::ParseContext* ctx, uint64_t tag, + const Reflection* reflection, + const FieldDescriptor* field) { + Message* sub_message; + if (field->is_repeated()) { + sub_message = reflection->AddMessage(msg, field, ctx->data().factory); + } else { + sub_message = reflection->MutableMessage(msg, field, ctx->data().factory); + } + + if (WireFormatLite::GetTagWireType(tag) == + WireFormatLite::WIRETYPE_START_GROUP) { + return ctx->ParseGroup(sub_message, ptr, tag); + } else { + ABSL_DCHECK(WireFormatLite::GetTagWireType(tag) == + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + } + + ptr = ctx->ParseMessage(sub_message, ptr); + + // For map entries, if the value is an unknown enum we have to push it + // into the unknown field set and remove it from the list. + if (ptr != nullptr && field->is_map()) { + auto* value_field = field->message_type()->map_value(); + auto* enum_type = value_field->enum_type(); + if (enum_type != nullptr && + !internal::cpp::HasPreservingUnknownEnumSemantics(value_field) && + enum_type->FindValueByNumber(sub_message->GetReflection()->GetEnumValue( + *sub_message, value_field)) == nullptr) { + reflection->MutableUnknownFields(msg)->AddLengthDelimited( + field->number(), sub_message->SerializeAsString()); + reflection->RemoveLast(msg, field); + } + } + return ptr; +} + const char* WireFormat::_InternalParse(Message* msg, const char* ptr, internal::ParseContext* ctx) { const Descriptor* descriptor = msg->GetDescriptor(); @@ -995,46 +1033,9 @@ const char* WireFormat::_InternalParseAndMergeField( return ptr; } - case FieldDescriptor::TYPE_GROUP: { - Message* sub_message; - if (field->is_repeated()) { - sub_message = reflection->AddMessage(msg, field, ctx->data().factory); - } else { - sub_message = - reflection->MutableMessage(msg, field, ctx->data().factory); - } - - return ctx->ParseGroup(sub_message, ptr, tag); - } - - case FieldDescriptor::TYPE_MESSAGE: { - Message* sub_message; - if (field->is_repeated()) { - sub_message = reflection->AddMessage(msg, field, ctx->data().factory); - } else { - sub_message = - reflection->MutableMessage(msg, field, ctx->data().factory); - } - ptr = ctx->ParseMessage(sub_message, ptr); - - // For map entries, if the value is an unknown enum we have to push it - // into the unknown field set and remove it from the list. - if (ptr != nullptr && field->is_map()) { - auto* value_field = field->message_type()->map_value(); - auto* enum_type = value_field->enum_type(); - if (enum_type != nullptr && - !internal::cpp::HasPreservingUnknownEnumSemantics(value_field) && - enum_type->FindValueByNumber( - sub_message->GetReflection()->GetEnumValue( - *sub_message, value_field)) == nullptr) { - reflection->MutableUnknownFields(msg)->AddLengthDelimited( - field->number(), sub_message->SerializeAsString()); - reflection->RemoveLast(msg, field); - } - } - - return ptr; - } + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + return HandleMessage(msg, ptr, ctx, tag, reflection, field); } // GCC 8 complains about control reaching end of non-void function here.