| Index: third_party/protobuf/src/google/protobuf/util/internal/protostream_objectwriter.cc
|
| diff --git a/third_party/protobuf/src/google/protobuf/util/internal/protostream_objectwriter.cc b/third_party/protobuf/src/google/protobuf/util/internal/protostream_objectwriter.cc
|
| index c37e671cc22a3ae6124533fe1864aa9350b557f8..97a7909a185df2f61ac721b50109b57b21ef12c8 100644
|
| --- a/third_party/protobuf/src/google/protobuf/util/internal/protostream_objectwriter.cc
|
| +++ b/third_party/protobuf/src/google/protobuf/util/internal/protostream_objectwriter.cc
|
| @@ -63,10 +63,7 @@ ProtoStreamObjectWriter::ProtoStreamObjectWriter(
|
| : ProtoWriter(type_resolver, type, output, listener),
|
| master_type_(type),
|
| current_(NULL),
|
| - options_(options) {
|
| - set_ignore_unknown_fields(options_.ignore_unknown_fields);
|
| - set_use_lower_camel_for_enums(options_.use_lower_camel_for_enums);
|
| -}
|
| + options_(options) {}
|
|
|
| ProtoStreamObjectWriter::ProtoStreamObjectWriter(
|
| const TypeInfo* typeinfo, const google::protobuf::Type& type,
|
| @@ -193,11 +190,17 @@ ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {}
|
| void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) {
|
| ++depth_;
|
| // If an object writer is absent, that means we have not called StartAny()
|
| - // before reaching here, which happens when we have data before the "@type"
|
| - // field.
|
| + // before reaching here. This is an invalid state. StartAny() gets called
|
| + // whenever we see an "@type" being rendered (see AnyWriter::RenderDataPiece).
|
| if (ow_ == NULL) {
|
| - // Save data before the "@type" field for later replay.
|
| - uninterpreted_events_.push_back(Event(Event::START_OBJECT, name));
|
| + // Make sure we are not already in an invalid state. This avoids making
|
| + // multiple unnecessary InvalidValue calls.
|
| + if (!invalid_) {
|
| + parent_->InvalidValue("Any",
|
| + StrCat("Missing or invalid @type for any field in ",
|
| + parent_->master_type_.name()));
|
| + invalid_ = true;
|
| + }
|
| } else if (is_well_known_type_ && depth_ == 1) {
|
| // For well-known types, the only other field besides "@type" should be a
|
| // "value" field.
|
| @@ -217,15 +220,10 @@ void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) {
|
|
|
| bool ProtoStreamObjectWriter::AnyWriter::EndObject() {
|
| --depth_;
|
| - if (ow_ == NULL) {
|
| - if (depth_ >= 0) {
|
| - // Save data before the "@type" field for later replay.
|
| - uninterpreted_events_.push_back(Event(Event::END_OBJECT));
|
| - }
|
| - } else if (depth_ >= 0 || !is_well_known_type_) {
|
| - // As long as depth_ >= 0, we know we haven't reached the end of Any.
|
| - // Propagate these EndObject() calls to the contained ow_. For regular
|
| - // message types, we propagate the end of Any as well.
|
| + // As long as depth_ >= 0, we know we haven't reached the end of Any.
|
| + // Propagate these EndObject() calls to the contained ow_. For regular
|
| + // message types, we propagate the end of Any as well.
|
| + if (ow_ != NULL && (depth_ >= 0 || !is_well_known_type_)) {
|
| ow_->EndObject();
|
| }
|
| // A negative depth_ implies that we have reached the end of Any
|
| @@ -239,9 +237,14 @@ bool ProtoStreamObjectWriter::AnyWriter::EndObject() {
|
|
|
| void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) {
|
| ++depth_;
|
| + // We expect ow_ to be present as this call only makes sense inside an Any.
|
| if (ow_ == NULL) {
|
| - // Save data before the "@type" field for later replay.
|
| - uninterpreted_events_.push_back(Event(Event::START_LIST, name));
|
| + if (!invalid_) {
|
| + parent_->InvalidValue("Any",
|
| + StrCat("Missing or invalid @type for any field in ",
|
| + parent_->master_type_.name()));
|
| + invalid_ = true;
|
| + }
|
| } else if (is_well_known_type_ && depth_ == 1) {
|
| if (name != "value" && !invalid_) {
|
| parent_->InvalidValue("Any",
|
| @@ -260,10 +263,8 @@ void ProtoStreamObjectWriter::AnyWriter::EndList() {
|
| GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible";
|
| depth_ = 0;
|
| }
|
| - if (ow_ == NULL) {
|
| - // Save data before the "@type" field for later replay.
|
| - uninterpreted_events_.push_back(Event(Event::END_LIST));
|
| - } else {
|
| + // We don't write an error on the close, only on the open
|
| + if (ow_ != NULL) {
|
| ow_->EndList();
|
| }
|
| }
|
| @@ -275,8 +276,12 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
|
| if (depth_ == 0 && ow_ == NULL && name == "@type") {
|
| StartAny(value);
|
| } else if (ow_ == NULL) {
|
| - // Save data before the "@type" field.
|
| - uninterpreted_events_.push_back(Event(name, value));
|
| + if (!invalid_) {
|
| + parent_->InvalidValue("Any",
|
| + StrCat("Missing or invalid @type for any field in ",
|
| + parent_->master_type_.name()));
|
| + invalid_ = true;
|
| + }
|
| } else if (depth_ == 0 && is_well_known_type_) {
|
| if (name != "value" && !invalid_) {
|
| parent_->InvalidValue("Any",
|
| @@ -286,7 +291,7 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
|
| if (well_known_type_render_ == NULL) {
|
| // Only Any and Struct don't have a special type render but both of
|
| // them expect a JSON object (i.e., a StartObject() call).
|
| - if (value.type() != DataPiece::TYPE_NULL && !invalid_) {
|
| + if (!invalid_) {
|
| parent_->InvalidValue("Any", "Expect a JSON object.");
|
| invalid_ = true;
|
| }
|
| @@ -351,29 +356,13 @@ void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
|
| if (!is_well_known_type_) {
|
| ow_->StartObject("");
|
| }
|
| -
|
| - // Now we know the proto type and can interpret all data fields we gathered
|
| - // before the "@type" field.
|
| - for (int i = 0; i < uninterpreted_events_.size(); ++i) {
|
| - uninterpreted_events_[i].Replay(this);
|
| - }
|
| }
|
|
|
| void ProtoStreamObjectWriter::AnyWriter::WriteAny() {
|
| if (ow_ == NULL) {
|
| - if (uninterpreted_events_.empty()) {
|
| - // We never got any content, so just return immediately, which is
|
| - // equivalent to writing an empty Any.
|
| - return;
|
| - } else {
|
| - // There are uninterpreted data, but we never got a "@type" field.
|
| - if (!invalid_) {
|
| - parent_->InvalidValue("Any", StrCat("Missing @type for any field in ",
|
| - parent_->master_type_.name()));
|
| - invalid_ = true;
|
| - }
|
| - return;
|
| - }
|
| + // If we had no object writer, we never got any content, so just return
|
| + // immediately, which is equivalent to writing an empty Any.
|
| + return;
|
| }
|
| // Render the type_url and value fields directly to the stream.
|
| // type_url has tag 1 and value has tag 2.
|
| @@ -383,41 +372,6 @@ void ProtoStreamObjectWriter::AnyWriter::WriteAny() {
|
| }
|
| }
|
|
|
| -void ProtoStreamObjectWriter::AnyWriter::Event::Replay(
|
| - AnyWriter* writer) const {
|
| - switch (type_) {
|
| - case START_OBJECT:
|
| - writer->StartObject(name_);
|
| - break;
|
| - case END_OBJECT:
|
| - writer->EndObject();
|
| - break;
|
| - case START_LIST:
|
| - writer->StartList(name_);
|
| - break;
|
| - case END_LIST:
|
| - writer->EndList();
|
| - break;
|
| - case RENDER_DATA_PIECE:
|
| - writer->RenderDataPiece(name_, value_);
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void ProtoStreamObjectWriter::AnyWriter::Event::DeepCopy() {
|
| - // DataPiece only contains a string reference. To make sure the referenced
|
| - // string value stays valid, we make a copy of the string value and update
|
| - // DataPiece to reference our own copy.
|
| - if (value_.type() == DataPiece::TYPE_STRING) {
|
| - value_.str().AppendToString(&value_storage_);
|
| - value_ = DataPiece(value_storage_, value_.use_strict_base64_decoding());
|
| - } else if (value_.type() == DataPiece::TYPE_BYTES) {
|
| - value_storage_ = value_.ToBytes().ValueOrDie();
|
| - value_ =
|
| - DataPiece(value_storage_, true, value_.use_strict_base64_decoding());
|
| - }
|
| -}
|
| -
|
| ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
|
| ItemType item_type, bool is_placeholder,
|
| bool is_list)
|
| @@ -430,9 +384,6 @@ ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
|
| if (item_type_ == ANY) {
|
| any_.reset(new AnyWriter(ow_));
|
| }
|
| - if (item_type == MAP) {
|
| - map_keys_.reset(new hash_set<string>);
|
| - }
|
| }
|
|
|
| ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
|
| @@ -447,14 +398,11 @@ ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
|
| if (item_type == ANY) {
|
| any_.reset(new AnyWriter(ow_));
|
| }
|
| - if (item_type == MAP) {
|
| - map_keys_.reset(new hash_set<string>);
|
| - }
|
| }
|
|
|
| bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
|
| StringPiece map_key) {
|
| - return InsertIfNotPresent(map_keys_.get(), map_key.ToString());
|
| + return InsertIfNotPresent(&map_keys_, map_key.ToString());
|
| }
|
|
|
| ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
|
| @@ -911,7 +859,6 @@ Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow,
|
|
|
| Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow,
|
| const DataPiece& data) {
|
| - if (data.type() == DataPiece::TYPE_NULL) return Status::OK;
|
| if (data.type() != DataPiece::TYPE_STRING) {
|
| return Status(INVALID_ARGUMENT,
|
| StrCat("Invalid data type for timestamp, value is ",
|
| @@ -942,7 +889,6 @@ static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
|
|
|
| Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
|
| const DataPiece& data) {
|
| - if (data.type() == DataPiece::TYPE_NULL) return Status::OK;
|
| if (data.type() != DataPiece::TYPE_STRING) {
|
| return Status(INVALID_ARGUMENT,
|
| StrCat("Invalid data type for field mask, value is ",
|
| @@ -953,13 +899,12 @@ Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
|
| // conversions as much as possible. Because ToSnakeCase sometimes returns the
|
| // wrong value.
|
| google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback(
|
| - NewPermanentCallback(&RenderOneFieldPath, ow));
|
| + ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow));
|
| return DecodeCompactFieldMaskPaths(data.str(), callback.get());
|
| }
|
|
|
| Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
|
| const DataPiece& data) {
|
| - if (data.type() == DataPiece::TYPE_NULL) return Status::OK;
|
| if (data.type() != DataPiece::TYPE_STRING) {
|
| return Status(INVALID_ARGUMENT,
|
| StrCat("Invalid data type for duration, value is ",
|
| @@ -1009,7 +954,6 @@ Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
|
|
|
| Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
|
| const DataPiece& data) {
|
| - if (data.type() == DataPiece::TYPE_NULL) return Status::OK;
|
| ow->ProtoWriter::RenderDataPiece("value", data);
|
| return Status::OK;
|
| }
|
| @@ -1056,7 +1000,6 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
|
| DataPiece(name, use_strict_base64_decoding()));
|
| field = Lookup("value");
|
| if (field == NULL) {
|
| - Pop();
|
| GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
|
| return this;
|
| }
|
| @@ -1097,18 +1040,13 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
|
| // Check if the field is of special type. Render it accordingly if so.
|
| const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
|
| if (type_renderer != NULL) {
|
| - // Pass through null value only for google.protobuf.Value. For other
|
| - // types we ignore null value just like for regular field types.
|
| - if (data.type() != DataPiece::TYPE_NULL ||
|
| - field->type_url() == kStructValueTypeUrl) {
|
| - Push(name, Item::MESSAGE, false, false);
|
| - status = (*type_renderer)(this, data);
|
| - if (!status.ok()) {
|
| - InvalidValue(field->type_url(),
|
| - StrCat("Field '", name, "', ", status.error_message()));
|
| - }
|
| - Pop();
|
| + Push(name, Item::MESSAGE, false, false);
|
| + status = (*type_renderer)(this, data);
|
| + if (!status.ok()) {
|
| + InvalidValue(field->type_url(),
|
| + StrCat("Field '", name, "', ", status.error_message()));
|
| }
|
| + Pop();
|
| return this;
|
| }
|
|
|
| @@ -1240,11 +1178,8 @@ bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
|
|
|
| // TODO(xiaofeng): Unify option names.
|
| return GetBoolOptionOrDefault(field_type->options(),
|
| - "google.protobuf.MessageOptions.map_entry",
|
| - false) ||
|
| - GetBoolOptionOrDefault(field_type->options(), "map_entry", false) ||
|
| - GetBoolOptionOrDefault(field_type->options(),
|
| - "proto2.MessageOptions.map_entry", false);
|
| + "google.protobuf.MessageOptions.map_entry", false) ||
|
| + GetBoolOptionOrDefault(field_type->options(), "map_entry", false);
|
| }
|
|
|
| bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
|
| @@ -1269,4 +1204,3 @@ bool ProtoStreamObjectWriter::IsStructListValue(
|
| } // namespace util
|
| } // namespace protobuf
|
| } // namespace google
|
| -
|
|
|