diff options
Diffstat (limited to 'src/google/protobuf/text_format.cc')
-rw-r--r-- | src/google/protobuf/text_format.cc | 354 |
1 files changed, 292 insertions, 62 deletions
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index 0965fd7a..c8de875d 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <algorithm> +#include <climits> #include <float.h> #include <math.h> #include <stdio.h> @@ -44,23 +45,27 @@ #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/any.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/strtod.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/tokenizer.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/dynamic_message.h> +#include <google/protobuf/map_field.h> #include <google/protobuf/repeated_field.h> #include <google/protobuf/unknown_field_set.h> #include <google/protobuf/wire_format_lite.h> #include <google/protobuf/stubs/strutil.h> + + #include <google/protobuf/stubs/map_util.h> #include <google/protobuf/stubs/stl_util.h> + namespace google { namespace protobuf { @@ -212,7 +217,7 @@ const Descriptor* DefaultFinderFindAnyType(const Message& message, // =========================================================================== // Internal class for parsing an ASCII representation of a Protocol Message. // This class makes use of the Protocol Message compiler's tokenizer found -// in //google/protobuf/io/tokenizer.h. Note that class's Parse +// in //net/proto2/io/public/tokenizer.h. Note that class's Parse // method is *not* thread-safe and should only be used in a single thread at // a time. @@ -241,6 +246,7 @@ class TextFormat::Parser::ParserImpl { SingularOverwritePolicy singular_overwrite_policy, bool allow_case_insensitive_field, bool allow_unknown_field, + bool allow_unknown_extension, bool allow_unknown_enum, bool allow_field_number, bool allow_relaxed_whitespace, @@ -254,6 +260,7 @@ class TextFormat::Parser::ParserImpl { singular_overwrite_policy_(singular_overwrite_policy), allow_case_insensitive_field_(allow_case_insensitive_field), allow_unknown_field_(allow_unknown_field), + allow_unknown_extension_(allow_unknown_extension), allow_unknown_enum_(allow_unknown_enum), allow_field_number_(allow_field_number), allow_partial_(allow_partial), @@ -433,7 +440,7 @@ class TextFormat::Parser::ParserImpl { : DefaultFinderFindExtension(message, field_name); if (field == NULL) { - if (!allow_unknown_field_) { + if (!allow_unknown_field_ && !allow_unknown_extension_) { ReportError("Extension \"" + field_name + "\" is not defined or " "is not an extension of \"" + descriptor->full_name() + "\"."); @@ -448,7 +455,8 @@ class TextFormat::Parser::ParserImpl { DO(ConsumeIdentifier(&field_name)); int32 field_number; - if (allow_field_number_ && safe_strto32(field_name, &field_number)) { + if (allow_field_number_ && + safe_strto32(field_name, &field_number)) { if (descriptor->IsExtensionNumber(field_number)) { field = reflection->FindKnownExtensionByNumber(field_number); } else if (descriptor->IsReservedNumber(field_number)) { @@ -501,7 +509,7 @@ class TextFormat::Parser::ParserImpl { // Skips unknown or reserved fields. if (field == NULL) { - GOOGLE_CHECK(allow_unknown_field_ || reserved_field); + GOOGLE_CHECK(allow_unknown_field_ || allow_unknown_extension_ || reserved_field); // Try to guess the type of this field. // If this field is not a message, there should be a ":" between the @@ -758,7 +766,7 @@ label_skip_parsing: LookingAtType(io::Tokenizer::TYPE_INTEGER)) { int64 int_value; DO(ConsumeSignedInteger(&int_value, kint32max)); - value = SimpleItoa(int_value); // for error reporting + value = SimpleItoa(int_value); // for error reporting enum_value = enum_type->FindValueByNumber(int_value); } else { ReportError("Expected integer or identifier, got: " + @@ -882,8 +890,9 @@ label_skip_parsing: // If allow_field_numer_ or allow_unknown_field_ is true, we should able // to parse integer identifiers. - if ((allow_field_number_ || allow_unknown_field_) - && LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + if ((allow_field_number_ || allow_unknown_field_ || + allow_unknown_extension_) && + LookingAtType(io::Tokenizer::TYPE_INTEGER)) { *identifier = tokenizer_.current().text; tokenizer_.Next(); return true; @@ -1138,13 +1147,13 @@ label_skip_parsing: explicit ParserErrorCollector(TextFormat::Parser::ParserImpl* parser) : parser_(parser) { } - virtual ~ParserErrorCollector() { } + ~ParserErrorCollector() override {} - virtual void AddError(int line, int column, const string& message) { + void AddError(int line, int column, const string& message) override { parser_->ReportError(line, column, message); } - virtual void AddWarning(int line, int column, const string& message) { + void AddWarning(int line, int column, const string& message) override { parser_->ReportWarning(line, column, message); } @@ -1162,17 +1171,16 @@ label_skip_parsing: SingularOverwritePolicy singular_overwrite_policy_; const bool allow_case_insensitive_field_; const bool allow_unknown_field_; + const bool allow_unknown_extension_; const bool allow_unknown_enum_; const bool allow_field_number_; const bool allow_partial_; bool had_errors_; }; -#undef DO - // =========================================================================== // Internal class for writing text to the io::ZeroCopyOutputStream. Adapted -// from the Printer found in //google/protobuf/io/printer.h +// from the Printer found in //net/proto2/io/public/printer.h class TextFormat::Printer::TextGenerator : public TextFormat::BaseTextGenerator { public: @@ -1334,6 +1342,7 @@ TextFormat::Parser::Parser() allow_partial_(false), allow_case_insensitive_field_(false), allow_unknown_field_(false), + allow_unknown_extension_(false), allow_unknown_enum_(false), allow_field_number_(false), allow_relaxed_whitespace_(false), @@ -1342,6 +1351,22 @@ TextFormat::Parser::Parser() TextFormat::Parser::~Parser() {} +namespace { + +bool CheckParseInputSize(StringPiece input, + io::ErrorCollector* error_collector) { + if (input.size() > INT_MAX) { + error_collector->AddError( + -1, 0, + StrCat("Input size too large: ", static_cast<int64>(input.size()), + " bytes", " > ", INT_MAX, " bytes.")); + return false; + } + return true; +} + +} // namespace + bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input, Message* output) { output->Clear(); @@ -1351,17 +1376,17 @@ bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input, ? ParserImpl::ALLOW_SINGULAR_OVERWRITES : ParserImpl::FORBID_SINGULAR_OVERWRITES; - ParserImpl parser(output->GetDescriptor(), input, error_collector_, - finder_, parse_info_tree_, - overwrites_policy, - allow_case_insensitive_field_, allow_unknown_field_, - allow_unknown_enum_, allow_field_number_, - allow_relaxed_whitespace_, allow_partial_); + ParserImpl parser( + output->GetDescriptor(), input, error_collector_, finder_, + parse_info_tree_, overwrites_policy, allow_case_insensitive_field_, + allow_unknown_field_, allow_unknown_extension_, allow_unknown_enum_, + allow_field_number_, allow_relaxed_whitespace_, allow_partial_); return MergeUsingImpl(input, output, &parser); } bool TextFormat::Parser::ParseFromString(const string& input, Message* output) { + DO(CheckParseInputSize(input, error_collector_)); io::ArrayInputStream input_stream(input.data(), input.size()); return Parse(&input_stream, output); } @@ -1369,17 +1394,18 @@ bool TextFormat::Parser::ParseFromString(const string& input, bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input, Message* output) { - ParserImpl parser(output->GetDescriptor(), input, error_collector_, - finder_, parse_info_tree_, - ParserImpl::ALLOW_SINGULAR_OVERWRITES, + ParserImpl parser(output->GetDescriptor(), input, error_collector_, finder_, + parse_info_tree_, ParserImpl::ALLOW_SINGULAR_OVERWRITES, allow_case_insensitive_field_, allow_unknown_field_, - allow_unknown_enum_, allow_field_number_, - allow_relaxed_whitespace_, allow_partial_); + allow_unknown_extension_, allow_unknown_enum_, + allow_field_number_, allow_relaxed_whitespace_, + allow_partial_); return MergeUsingImpl(input, output, &parser); } bool TextFormat::Parser::MergeFromString(const string& input, Message* output) { + DO(CheckParseInputSize(input, error_collector_)); io::ArrayInputStream input_stream(input.data(), input.size()); return Merge(&input_stream, output); } @@ -1405,12 +1431,12 @@ bool TextFormat::Parser::ParseFieldValueFromString( const FieldDescriptor* field, Message* output) { io::ArrayInputStream input_stream(input.data(), input.size()); - ParserImpl parser(output->GetDescriptor(), &input_stream, error_collector_, - finder_, parse_info_tree_, - ParserImpl::ALLOW_SINGULAR_OVERWRITES, - allow_case_insensitive_field_, allow_unknown_field_, - allow_unknown_enum_, allow_field_number_, - allow_relaxed_whitespace_, allow_partial_); + ParserImpl parser( + output->GetDescriptor(), &input_stream, error_collector_, finder_, + parse_info_tree_, ParserImpl::ALLOW_SINGULAR_OVERWRITES, + allow_case_insensitive_field_, allow_unknown_field_, + allow_unknown_extension_, allow_unknown_enum_, allow_field_number_, + allow_relaxed_whitespace_, allow_partial_); return parser.ParseField(field, output); } @@ -1435,6 +1461,8 @@ bool TextFormat::Parser::ParseFieldValueFromString( } +#undef DO + // =========================================================================== TextFormat::BaseTextGenerator::~BaseTextGenerator() {} @@ -1444,7 +1472,9 @@ namespace { // A BaseTextGenerator that writes to a string. class StringBaseTextGenerator : public TextFormat::BaseTextGenerator { public: - void Print(const char* text, size_t size) { output_.append(text, size); } + void Print(const char* text, size_t size) override { + output_.append(text, size); + } // Some compilers do not support ref-qualifiers even in C++11 mode. // Disable the optimization for now and revisit it later. @@ -1642,61 +1672,70 @@ class FieldValuePrinterWrapper : public TextFormat::FastFieldValuePrinter { delegate_.reset(delegate); } - void PrintBool(bool val, TextFormat::BaseTextGenerator* generator) const { + void PrintBool(bool val, + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintBool(val)); } - void PrintInt32(int32 val, TextFormat::BaseTextGenerator* generator) const { + void PrintInt32(int32 val, + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintInt32(val)); } - void PrintUInt32(uint32 val, TextFormat::BaseTextGenerator* generator) const { + void PrintUInt32(uint32 val, + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintUInt32(val)); } - void PrintInt64(int64 val, TextFormat::BaseTextGenerator* generator) const { + void PrintInt64(int64 val, + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintInt64(val)); } - void PrintUInt64(uint64 val, TextFormat::BaseTextGenerator* generator) const { + void PrintUInt64(uint64 val, + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintUInt64(val)); } - void PrintFloat(float val, TextFormat::BaseTextGenerator* generator) const { + void PrintFloat(float val, + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintFloat(val)); } - void PrintDouble(double val, TextFormat::BaseTextGenerator* generator) const { + void PrintDouble(double val, + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintDouble(val)); } void PrintString(const string& val, - TextFormat::BaseTextGenerator* generator) const { + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintString(val)); } void PrintBytes(const string& val, - TextFormat::BaseTextGenerator* generator) const { + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintBytes(val)); } void PrintEnum(int32 val, const string& name, - TextFormat::BaseTextGenerator* generator) const { + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintEnum(val, name)); } void PrintFieldName(const Message& message, int field_index, int field_count, const Reflection* reflection, const FieldDescriptor* field, - TextFormat::BaseTextGenerator* generator) const { - generator->PrintString(delegate_->PrintFieldName( - message, reflection, field)); + TextFormat::BaseTextGenerator* generator) const override { + generator->PrintString( + delegate_->PrintFieldName(message, reflection, field)); } void PrintFieldName(const Message& message, const Reflection* reflection, const FieldDescriptor* field, - TextFormat::BaseTextGenerator* generator) const { + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString( delegate_->PrintFieldName(message, reflection, field)); } - void PrintMessageStart(const Message& message, int field_index, - int field_count, bool single_line_mode, - TextFormat::BaseTextGenerator* generator) const { + void PrintMessageStart( + const Message& message, int field_index, int field_count, + bool single_line_mode, + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintMessageStart( message, field_index, field_count, single_line_mode)); } - void PrintMessageEnd(const Message& message, int field_index, int field_count, - bool single_line_mode, - TextFormat::BaseTextGenerator* generator) const { + void PrintMessageEnd( + const Message& message, int field_index, int field_count, + bool single_line_mode, + TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintMessageEnd( message, field_index, field_count, single_line_mode)); } @@ -1710,13 +1749,13 @@ class FastFieldValuePrinterUtf8Escaping : public TextFormat::FastFieldValuePrinter { public: void PrintString(const string& val, - TextFormat::BaseTextGenerator* generator) const { + TextFormat::BaseTextGenerator* generator) const override { generator->PrintLiteral("\""); generator->PrintString(strings::Utf8SafeCEscape(val)); generator->PrintLiteral("\""); } void PrintBytes(const string& val, - TextFormat::BaseTextGenerator* generator) const { + TextFormat::BaseTextGenerator* generator) const override { return FastFieldValuePrinter::PrintString(val, generator); } }; @@ -1867,7 +1906,7 @@ bool TextFormat::Printer::PrintAny(const Message& message, } // Print the "value" in text. - const google::protobuf::Descriptor* value_descriptor = + const Descriptor* value_descriptor = finder_ ? finder_->FindAnyType(message, url_prefix, full_type_name) : DefaultFinderFindAnyType(message, url_prefix, full_type_name); if (value_descriptor == NULL) { @@ -1875,7 +1914,7 @@ bool TextFormat::Printer::PrintAny(const Message& message, return false; } DynamicMessageFactory factory; - std::unique_ptr<google::protobuf::Message> value_message( + std::unique_ptr<Message> value_message( factory.GetPrototype(value_descriptor)->New()); string serialized_value = reflection->GetString(message, value_field); if (!value_message->ParseFromString(serialized_value)) { @@ -1909,7 +1948,13 @@ void TextFormat::Printer::Print(const Message& message, return; } std::vector<const FieldDescriptor*> fields; - reflection->ListFields(message, &fields); + if (descriptor->options().map_entry()) { + fields.push_back(descriptor->field(0)); + fields.push_back(descriptor->field(1)); + } else { + reflection->ListFields(message, &fields); + } + if (print_message_fields_in_index_order_) { std::sort(fields.begin(), fields.end(), FieldIndexSorter()); } @@ -1935,6 +1980,181 @@ void TextFormat::Printer::PrintFieldValueToString( PrintFieldValue(message, message.GetReflection(), field, index, &generator); } +class MapEntryMessageComparator { + public: + explicit MapEntryMessageComparator(const Descriptor* descriptor) + : field_(descriptor->field(0)) {} + + bool operator()(const Message* a, const Message* b) { + const Reflection* reflection = a->GetReflection(); + switch (field_->cpp_type()) { + case FieldDescriptor::CPPTYPE_BOOL: { + bool first = reflection->GetBool(*a, field_); + bool second = reflection->GetBool(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_INT32: { + int32 first = reflection->GetInt32(*a, field_); + int32 second = reflection->GetInt32(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_INT64: { + int64 first = reflection->GetInt64(*a, field_); + int64 second = reflection->GetInt64(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_UINT32: { + uint32 first = reflection->GetUInt32(*a, field_); + uint32 second = reflection->GetUInt32(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_UINT64: { + uint64 first = reflection->GetUInt64(*a, field_); + uint64 second = reflection->GetUInt64(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_STRING: { + string first = reflection->GetString(*a, field_); + string second = reflection->GetString(*b, field_); + return first < second; + } + default: + GOOGLE_LOG(DFATAL) << "Invalid key for map field."; + return true; + } + } + + private: + const FieldDescriptor* field_; +}; + +namespace internal { +class MapFieldPrinterHelper { + public: + // DynamicMapSorter::Sort cannot be used because it enfores syncing with + // repeated field. + static bool SortMap(const Message& message, const Reflection* reflection, + const FieldDescriptor* field, MessageFactory* factory, + std::vector<const Message*>* sorted_map_field); + static void CopyKey(const MapKey& key, Message* message, + const FieldDescriptor* field_desc); + static void CopyValue(const MapValueRef& value, Message* message, + const FieldDescriptor* field_desc); +}; + +// Returns true if elements contained in sorted_map_field need to be released. +bool MapFieldPrinterHelper::SortMap( + const Message& message, const Reflection* reflection, + const FieldDescriptor* field, MessageFactory* factory, + std::vector<const Message*>* sorted_map_field) { + bool need_release = false; + const MapFieldBase& base = + *reflection->MapData(const_cast<Message*>(&message), field); + + if (base.IsRepeatedFieldValid()) { + const RepeatedPtrField<Message>& map_field = + reflection->GetRepeatedPtrField<Message>(message, field); + for (int i = 0; i < map_field.size(); ++i) { + sorted_map_field->push_back( + const_cast<RepeatedPtrField<Message>*>(&map_field)->Mutable(i)); + } + } else { + // TODO(teboring): For performance, instead of creating map entry message + // for each element, just store map keys and sort them. + const Descriptor* map_entry_desc = field->message_type(); + const Message* prototype = factory->GetPrototype(map_entry_desc); + for (MapIterator iter = + reflection->MapBegin(const_cast<Message*>(&message), field); + iter != reflection->MapEnd(const_cast<Message*>(&message), field); + ++iter) { + Message* map_entry_message = prototype->New(); + CopyKey(iter.GetKey(), map_entry_message, map_entry_desc->field(0)); + CopyValue(iter.GetValueRef(), map_entry_message, + map_entry_desc->field(1)); + sorted_map_field->push_back(map_entry_message); + } + need_release = true; + } + + MapEntryMessageComparator comparator(field->message_type()); + std::stable_sort(sorted_map_field->begin(), sorted_map_field->end(), + comparator); + return need_release; +} + +void MapFieldPrinterHelper::CopyKey(const MapKey& key, Message* message, + const FieldDescriptor* field_desc) { + const Reflection* reflection = message->GetReflection(); + switch (field_desc->cpp_type()) { + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(ERROR) << "Not supported."; + break; + case FieldDescriptor::CPPTYPE_STRING: + reflection->SetString(message, field_desc, key.GetStringValue()); + return; + case FieldDescriptor::CPPTYPE_INT64: + reflection->SetInt64(message, field_desc, key.GetInt64Value()); + return; + case FieldDescriptor::CPPTYPE_INT32: + reflection->SetInt32(message, field_desc, key.GetInt32Value()); + return; + case FieldDescriptor::CPPTYPE_UINT64: + reflection->SetUInt64(message, field_desc, key.GetUInt64Value()); + return; + case FieldDescriptor::CPPTYPE_UINT32: + reflection->SetUInt32(message, field_desc, key.GetUInt32Value()); + return; + case FieldDescriptor::CPPTYPE_BOOL: + reflection->SetBool(message, field_desc, key.GetBoolValue()); + return; + } +} + +void MapFieldPrinterHelper::CopyValue(const MapValueRef& value, + Message* message, + const FieldDescriptor* field_desc) { + const Reflection* reflection = message->GetReflection(); + switch (field_desc->cpp_type()) { + case FieldDescriptor::CPPTYPE_DOUBLE: + reflection->SetDouble(message, field_desc, value.GetDoubleValue()); + return; + case FieldDescriptor::CPPTYPE_FLOAT: + reflection->SetFloat(message, field_desc, value.GetFloatValue()); + return; + case FieldDescriptor::CPPTYPE_ENUM: + reflection->SetEnumValue(message, field_desc, value.GetEnumValue()); + return; + case FieldDescriptor::CPPTYPE_MESSAGE: { + Message* sub_message = value.GetMessageValue().New(); + sub_message->CopyFrom(value.GetMessageValue()); + reflection->SetAllocatedMessage(message, sub_message, field_desc); + return; + } + case FieldDescriptor::CPPTYPE_STRING: + reflection->SetString(message, field_desc, value.GetStringValue()); + return; + case FieldDescriptor::CPPTYPE_INT64: + reflection->SetInt64(message, field_desc, value.GetInt64Value()); + return; + case FieldDescriptor::CPPTYPE_INT32: + reflection->SetInt32(message, field_desc, value.GetInt32Value()); + return; + case FieldDescriptor::CPPTYPE_UINT64: + reflection->SetUInt64(message, field_desc, value.GetUInt64Value()); + return; + case FieldDescriptor::CPPTYPE_UINT32: + reflection->SetUInt32(message, field_desc, value.GetUInt32Value()); + return; + case FieldDescriptor::CPPTYPE_BOOL: + reflection->SetBool(message, field_desc, value.GetBoolValue()); + return; + } +} +} // namespace internal + void TextFormat::Printer::PrintField(const Message& message, const Reflection* reflection, const FieldDescriptor* field, @@ -1951,14 +2171,18 @@ void TextFormat::Printer::PrintField(const Message& message, if (field->is_repeated()) { count = reflection->FieldSize(message, field); - } else if (reflection->HasField(message, field)) { + } else if (reflection->HasField(message, field) || + field->containing_type()->options().map_entry()) { count = 1; } - std::vector<const Message*> map_entries; - const bool is_map = field->is_map(); + DynamicMessageFactory factory; + std::vector<const Message*> sorted_map_field; + bool need_release = false; + bool is_map = field->is_map(); if (is_map) { - map_entries = DynamicMapSorter::Sort(message, count, reflection, field); + need_release = internal::MapFieldPrinterHelper::SortMap( + message, reflection, field, &factory, &sorted_map_field); } for (int j = 0; j < count; ++j) { @@ -1971,7 +2195,7 @@ void TextFormat::Printer::PrintField(const Message& message, custom_printers_, field, default_field_value_printer_.get()); const Message& sub_message = field->is_repeated() - ? (is_map ? *map_entries[j] + ? (is_map ? *sorted_map_field[j] : reflection->GetRepeatedMessage(message, field, j)) : reflection->GetMessage(message, field); printer->PrintMessageStart(sub_message, field_index, count, @@ -1992,6 +2216,12 @@ void TextFormat::Printer::PrintField(const Message& message, } } } + + if (need_release) { + for (int j = 0; j < sorted_map_field.size(); ++j) { + delete sorted_map_field[j]; + } + } } void TextFormat::Printer::PrintShortRepeatedField( |