Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Unified Diff: third_party/protobuf/src/google/protobuf/util/internal/protostream_objectwriter.cc

Issue 2599263002: third_party/protobuf: Update to HEAD (f52e188fe4) (Closed)
Patch Set: Address comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 97a7909a185df2f61ac721b50109b57b21ef12c8..c37e671cc22a3ae6124533fe1864aa9350b557f8 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,7 +63,10 @@ ProtoStreamObjectWriter::ProtoStreamObjectWriter(
: ProtoWriter(type_resolver, type, output, listener),
master_type_(type),
current_(NULL),
- options_(options) {}
+ options_(options) {
+ set_ignore_unknown_fields(options_.ignore_unknown_fields);
+ set_use_lower_camel_for_enums(options_.use_lower_camel_for_enums);
+}
ProtoStreamObjectWriter::ProtoStreamObjectWriter(
const TypeInfo* typeinfo, const google::protobuf::Type& type,
@@ -190,17 +193,11 @@ 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. This is an invalid state. StartAny() gets called
- // whenever we see an "@type" being rendered (see AnyWriter::RenderDataPiece).
+ // before reaching here, which happens when we have data before the "@type"
+ // field.
if (ow_ == NULL) {
- // 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;
- }
+ // Save data before the "@type" field for later replay.
+ uninterpreted_events_.push_back(Event(Event::START_OBJECT, name));
} else if (is_well_known_type_ && depth_ == 1) {
// For well-known types, the only other field besides "@type" should be a
// "value" field.
@@ -220,10 +217,15 @@ void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) {
bool ProtoStreamObjectWriter::AnyWriter::EndObject() {
--depth_;
- // 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_)) {
+ 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.
ow_->EndObject();
}
// A negative depth_ implies that we have reached the end of Any
@@ -237,14 +239,9 @@ 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) {
- if (!invalid_) {
- parent_->InvalidValue("Any",
- StrCat("Missing or invalid @type for any field in ",
- parent_->master_type_.name()));
- invalid_ = true;
- }
+ // Save data before the "@type" field for later replay.
+ uninterpreted_events_.push_back(Event(Event::START_LIST, name));
} else if (is_well_known_type_ && depth_ == 1) {
if (name != "value" && !invalid_) {
parent_->InvalidValue("Any",
@@ -263,8 +260,10 @@ void ProtoStreamObjectWriter::AnyWriter::EndList() {
GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible";
depth_ = 0;
}
- // We don't write an error on the close, only on the open
- if (ow_ != NULL) {
+ if (ow_ == NULL) {
+ // Save data before the "@type" field for later replay.
+ uninterpreted_events_.push_back(Event(Event::END_LIST));
+ } else {
ow_->EndList();
}
}
@@ -276,12 +275,8 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
if (depth_ == 0 && ow_ == NULL && name == "@type") {
StartAny(value);
} else if (ow_ == NULL) {
- if (!invalid_) {
- parent_->InvalidValue("Any",
- StrCat("Missing or invalid @type for any field in ",
- parent_->master_type_.name()));
- invalid_ = true;
- }
+ // Save data before the "@type" field.
+ uninterpreted_events_.push_back(Event(name, value));
} else if (depth_ == 0 && is_well_known_type_) {
if (name != "value" && !invalid_) {
parent_->InvalidValue("Any",
@@ -291,7 +286,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 (!invalid_) {
+ if (value.type() != DataPiece::TYPE_NULL && !invalid_) {
parent_->InvalidValue("Any", "Expect a JSON object.");
invalid_ = true;
}
@@ -356,13 +351,29 @@ 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 we had no object writer, we never got any content, so just return
- // immediately, which is equivalent to writing an empty Any.
- return;
+ 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;
+ }
}
// Render the type_url and value fields directly to the stream.
// type_url has tag 1 and value has tag 2.
@@ -372,6 +383,41 @@ 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)
@@ -384,6 +430,9 @@ 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,
@@ -398,11 +447,14 @@ 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_, map_key.ToString());
+ return InsertIfNotPresent(map_keys_.get(), map_key.ToString());
}
ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
@@ -859,6 +911,7 @@ 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 ",
@@ -889,6 +942,7 @@ 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 ",
@@ -899,12 +953,13 @@ 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(
- ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow));
+ 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 ",
@@ -954,6 +1009,7 @@ 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;
}
@@ -1000,6 +1056,7 @@ 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;
}
@@ -1040,13 +1097,18 @@ 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) {
- Push(name, Item::MESSAGE, false, false);
- status = (*type_renderer)(this, data);
- if (!status.ok()) {
- InvalidValue(field->type_url(),
- StrCat("Field '", name, "', ", status.error_message()));
+ // 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();
}
- Pop();
return this;
}
@@ -1178,8 +1240,11 @@ 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);
+ "google.protobuf.MessageOptions.map_entry",
+ false) ||
+ GetBoolOptionOrDefault(field_type->options(), "map_entry", false) ||
+ GetBoolOptionOrDefault(field_type->options(),
+ "proto2.MessageOptions.map_entry", false);
}
bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
@@ -1204,3 +1269,4 @@ bool ProtoStreamObjectWriter::IsStructListValue(
} // namespace util
} // namespace protobuf
} // namespace google
+

Powered by Google App Engine
This is Rietveld 408576698