| Index: third_party/protobuf/src/google/protobuf/text_format.cc
|
| diff --git a/third_party/protobuf/src/google/protobuf/text_format.cc b/third_party/protobuf/src/google/protobuf/text_format.cc
|
| index c0dfd53fd7b0c7360f3fada07cc23207f36723e9..e3d908ecddea85e5d51636a41e0147de81825c18 100644
|
| --- a/third_party/protobuf/src/google/protobuf/text_format.cc
|
| +++ b/third_party/protobuf/src/google/protobuf/text_format.cc
|
| @@ -154,7 +154,7 @@ TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::CreateNested(
|
| const FieldDescriptor* field) {
|
| // Owned by us in the map.
|
| TextFormat::ParseInfoTree* instance = new TextFormat::ParseInfoTree();
|
| - vector<TextFormat::ParseInfoTree*>* trees = &nested_[field];
|
| + std::vector<TextFormat::ParseInfoTree*>* trees = &nested_[field];
|
| GOOGLE_CHECK(trees);
|
| trees->push_back(instance);
|
| return instance;
|
| @@ -177,7 +177,7 @@ TextFormat::ParseLocation TextFormat::ParseInfoTree::GetLocation(
|
| CheckFieldIndex(field, index);
|
| if (index == -1) { index = 0; }
|
|
|
| - const vector<TextFormat::ParseLocation>* locations =
|
| + const std::vector<TextFormat::ParseLocation>* locations =
|
| FindOrNull(locations_, field);
|
| if (locations == NULL || index >= locations->size()) {
|
| return TextFormat::ParseLocation();
|
| @@ -191,7 +191,8 @@ TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::GetTreeForNested(
|
| CheckFieldIndex(field, index);
|
| if (index == -1) { index = 0; }
|
|
|
| - const vector<TextFormat::ParseInfoTree*>* trees = FindOrNull(nested_, field);
|
| + const std::vector<TextFormat::ParseInfoTree*>* trees =
|
| + FindOrNull(nested_, field);
|
| if (trees == NULL || index >= trees->size()) {
|
| return NULL;
|
| }
|
| @@ -234,7 +235,8 @@ class TextFormat::Parser::ParserImpl {
|
| bool allow_unknown_field,
|
| bool allow_unknown_enum,
|
| bool allow_field_number,
|
| - bool allow_relaxed_whitespace)
|
| + bool allow_relaxed_whitespace,
|
| + bool allow_partial)
|
| : error_collector_(error_collector),
|
| finder_(finder),
|
| parse_info_tree_(parse_info_tree),
|
| @@ -246,6 +248,7 @@ class TextFormat::Parser::ParserImpl {
|
| allow_unknown_field_(allow_unknown_field),
|
| allow_unknown_enum_(allow_unknown_enum),
|
| allow_field_number_(allow_field_number),
|
| + allow_partial_(allow_partial),
|
| had_errors_(false) {
|
| // For backwards-compatibility with proto1, we need to allow the 'f' suffix
|
| // for floats.
|
| @@ -391,6 +394,16 @@ class TextFormat::Parser::ParserImpl {
|
| DO(ConsumeAnyValue(full_type_name,
|
| message->GetDescriptor()->file()->pool(),
|
| &serialized_value));
|
| + if (singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) {
|
| + // Fail if any_type_url_field has already been specified.
|
| + if ((!any_type_url_field->is_repeated() &&
|
| + reflection->HasField(*message, any_type_url_field)) ||
|
| + (!any_value_field->is_repeated() &&
|
| + reflection->HasField(*message, any_value_field))) {
|
| + ReportError("Non-repeated Any specified multiple times.");
|
| + return false;
|
| + }
|
| + }
|
| reflection->SetString(
|
| message, any_type_url_field,
|
| string(prefix + full_type_name));
|
| @@ -506,32 +519,42 @@ class TextFormat::Parser::ParserImpl {
|
| // Perform special handling for embedded message types.
|
| if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
| // ':' is optional here.
|
| - TryConsume(":");
|
| + bool consumed_semicolon = TryConsume(":");
|
| + if (consumed_semicolon && field->options().weak() && LookingAtType(io::Tokenizer::TYPE_STRING)) {
|
| + // we are getting a bytes string for a weak field.
|
| + string tmp;
|
| + DO(ConsumeString(&tmp));
|
| + reflection->MutableMessage(message, field)->ParseFromString(tmp);
|
| + goto label_skip_parsing;
|
| + }
|
| } else {
|
| // ':' is required here.
|
| DO(Consume(":"));
|
| }
|
|
|
| if (field->is_repeated() && TryConsume("[")) {
|
| - // Short repeated format, e.g. "foo: [1, 2, 3]"
|
| - while (true) {
|
| - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
| - // Perform special handling for embedded message types.
|
| - DO(ConsumeFieldMessage(message, reflection, field));
|
| - } else {
|
| - DO(ConsumeFieldValue(message, reflection, field));
|
| - }
|
| - if (TryConsume("]")) {
|
| - break;
|
| + // Short repeated format, e.g. "foo: [1, 2, 3]".
|
| + if (!TryConsume("]")) {
|
| + // "foo: []" is treated as empty.
|
| + while (true) {
|
| + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
| + // Perform special handling for embedded message types.
|
| + DO(ConsumeFieldMessage(message, reflection, field));
|
| + } else {
|
| + DO(ConsumeFieldValue(message, reflection, field));
|
| + }
|
| + if (TryConsume("]")) {
|
| + break;
|
| + }
|
| + DO(Consume(","));
|
| }
|
| - DO(Consume(","));
|
| }
|
| } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
| DO(ConsumeFieldMessage(message, reflection, field));
|
| } else {
|
| DO(ConsumeFieldValue(message, reflection, field));
|
| }
|
| -
|
| +label_skip_parsing:
|
| // For historical reasons, fields may optionally be separated by commas or
|
| // semicolons.
|
| TryConsume(";") || TryConsume(",");
|
| @@ -718,7 +741,8 @@ class TextFormat::Parser::ParserImpl {
|
| value = SimpleItoa(int_value); // for error reporting
|
| enum_value = enum_type->FindValueByNumber(int_value);
|
| } else {
|
| - ReportError("Expected integer or identifier.");
|
| + ReportError("Expected integer or identifier, got: " +
|
| + tokenizer_.current().text);
|
| return false;
|
| }
|
|
|
| @@ -756,6 +780,20 @@ class TextFormat::Parser::ParserImpl {
|
| }
|
| return true;
|
| }
|
| + if (TryConsume("[")) {
|
| + while (true) {
|
| + if (!LookingAt("{") && !LookingAt("<")) {
|
| + DO(SkipFieldValue());
|
| + } else {
|
| + DO(SkipFieldMessage());
|
| + }
|
| + if (TryConsume("]")) {
|
| + break;
|
| + }
|
| + DO(Consume(","));
|
| + }
|
| + return true;
|
| + }
|
| // Possible field values other than string:
|
| // 12345 => TYPE_INTEGER
|
| // -12345 => TYPE_SYMBOL + TYPE_INTEGER
|
| @@ -831,7 +869,7 @@ class TextFormat::Parser::ParserImpl {
|
| return true;
|
| }
|
|
|
| - ReportError("Expected identifier.");
|
| + ReportError("Expected identifier, got: " + tokenizer_.current().text);
|
| return false;
|
| }
|
|
|
| @@ -851,7 +889,7 @@ class TextFormat::Parser::ParserImpl {
|
| // Returns false if the token is not of type STRING.
|
| bool ConsumeString(string* text) {
|
| if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
|
| - ReportError("Expected string.");
|
| + ReportError("Expected string, got: " + tokenizer_.current().text);
|
| return false;
|
| }
|
|
|
| @@ -869,13 +907,13 @@ class TextFormat::Parser::ParserImpl {
|
| // Returns false if the token is not of type INTEGER.
|
| bool ConsumeUnsignedInteger(uint64* value, uint64 max_value) {
|
| if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
|
| - ReportError("Expected integer.");
|
| + ReportError("Expected integer, got: " + tokenizer_.current().text);
|
| return false;
|
| }
|
|
|
| if (!io::Tokenizer::ParseInteger(tokenizer_.current().text,
|
| max_value, value)) {
|
| - ReportError("Integer out of range.");
|
| + ReportError("Integer out of range (" + tokenizer_.current().text + ")");
|
| return false;
|
| }
|
|
|
| @@ -902,10 +940,14 @@ class TextFormat::Parser::ParserImpl {
|
|
|
| DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
|
|
|
| - *value = static_cast<int64>(unsigned_value);
|
| -
|
| if (negative) {
|
| - *value = -*value;
|
| + if ((static_cast<uint64>(kint64max) + 1) == unsigned_value) {
|
| + *value = kint64min;
|
| + } else {
|
| + *value = -static_cast<int64>(unsigned_value);
|
| + }
|
| + } else {
|
| + *value = static_cast<int64>(unsigned_value);
|
| }
|
|
|
| return true;
|
| @@ -915,18 +957,18 @@ class TextFormat::Parser::ParserImpl {
|
| // Accepts decimal numbers only, rejects hex or oct numbers.
|
| bool ConsumeUnsignedDecimalInteger(uint64* value, uint64 max_value) {
|
| if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
|
| - ReportError("Expected integer.");
|
| + ReportError("Expected integer, got: " + tokenizer_.current().text);
|
| return false;
|
| }
|
|
|
| const string& text = tokenizer_.current().text;
|
| if (IsHexNumber(text) || IsOctNumber(text)) {
|
| - ReportError("Expect a decimal number.");
|
| + ReportError("Expect a decimal number, got: " + text);
|
| return false;
|
| }
|
|
|
| if (!io::Tokenizer::ParseInteger(text, max_value, value)) {
|
| - ReportError("Integer out of range.");
|
| + ReportError("Integer out of range (" + text + ")");
|
| return false;
|
| }
|
|
|
| @@ -971,11 +1013,11 @@ class TextFormat::Parser::ParserImpl {
|
| *value = std::numeric_limits<double>::quiet_NaN();
|
| tokenizer_.Next();
|
| } else {
|
| - ReportError("Expected double.");
|
| + ReportError("Expected double, got: " + text);
|
| return false;
|
| }
|
| } else {
|
| - ReportError("Expected double.");
|
| + ReportError("Expected double, got: " + tokenizer_.current().text);
|
| return false;
|
| }
|
|
|
| @@ -1033,7 +1075,17 @@ class TextFormat::Parser::ParserImpl {
|
| DO(ConsumeMessageDelimiter(&sub_delimiter));
|
| DO(ConsumeMessage(value.get(), sub_delimiter));
|
|
|
| - value->AppendToString(serialized_value);
|
| + if (allow_partial_) {
|
| + value->AppendPartialToString(serialized_value);
|
| + } else {
|
| + if (!value->IsInitialized()) {
|
| + ReportError(
|
| + "Value of type \"" + full_type_name +
|
| + "\" stored in google.protobuf.Any has missing required fields");
|
| + return false;
|
| + }
|
| + value->AppendToString(serialized_value);
|
| + }
|
| return true;
|
| }
|
|
|
| @@ -1098,6 +1150,7 @@ class TextFormat::Parser::ParserImpl {
|
| const bool allow_unknown_field_;
|
| const bool allow_unknown_enum_;
|
| const bool allow_field_number_;
|
| + const bool allow_partial_;
|
| bool had_errors_;
|
| };
|
|
|
| @@ -1259,7 +1312,7 @@ bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
|
| overwrites_policy,
|
| allow_case_insensitive_field_, allow_unknown_field_,
|
| allow_unknown_enum_, allow_field_number_,
|
| - allow_relaxed_whitespace_);
|
| + allow_relaxed_whitespace_, allow_partial_);
|
| return MergeUsingImpl(input, output, &parser);
|
| }
|
|
|
| @@ -1276,7 +1329,7 @@ bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
|
| ParserImpl::ALLOW_SINGULAR_OVERWRITES,
|
| allow_case_insensitive_field_, allow_unknown_field_,
|
| allow_unknown_enum_, allow_field_number_,
|
| - allow_relaxed_whitespace_);
|
| + allow_relaxed_whitespace_, allow_partial_);
|
| return MergeUsingImpl(input, output, &parser);
|
| }
|
|
|
| @@ -1291,7 +1344,7 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* /* input */,
|
| ParserImpl* parser_impl) {
|
| if (!parser_impl->Parse(output)) return false;
|
| if (!allow_partial_ && !output->IsInitialized()) {
|
| - vector<string> missing_fields;
|
| + std::vector<string> missing_fields;
|
| output->FindInitializationErrors(&missing_fields);
|
| parser_impl->ReportError(-1, 0, "Message missing required fields: " +
|
| Join(missing_fields, ", "));
|
| @@ -1310,7 +1363,7 @@ bool TextFormat::Parser::ParseFieldValueFromString(
|
| ParserImpl::ALLOW_SINGULAR_OVERWRITES,
|
| allow_case_insensitive_field_, allow_unknown_field_,
|
| allow_unknown_enum_, allow_field_number_,
|
| - allow_relaxed_whitespace_);
|
| + allow_relaxed_whitespace_, allow_partial_);
|
| return parser.ParseField(field, output);
|
| }
|
|
|
| @@ -1565,7 +1618,7 @@ void TextFormat::Printer::Print(const Message& message,
|
| PrintAny(message, generator)) {
|
| return;
|
| }
|
| - vector<const FieldDescriptor*> fields;
|
| + std::vector<const FieldDescriptor*> fields;
|
| reflection->ListFields(message, &fields);
|
| if (print_message_fields_in_index_order_) {
|
| std::sort(fields.begin(), fields.end(), FieldIndexSorter());
|
|
|