| Index: third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc
|
| diff --git a/third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc b/third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..267e2cd3a0aea84a911d68b9046bd93c8eb71402
|
| --- /dev/null
|
| +++ b/third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc
|
| @@ -0,0 +1,515 @@
|
| +// Protocol Buffers - Google's data interchange format
|
| +// Copyright 2008 Google Inc. All rights reserved.
|
| +// https://developers.google.com/protocol-buffers/
|
| +//
|
| +// Redistribution and use in source and binary forms, with or without
|
| +// modification, are permitted provided that the following conditions are
|
| +// met:
|
| +//
|
| +// * Redistributions of source code must retain the above copyright
|
| +// notice, this list of conditions and the following disclaimer.
|
| +// * Redistributions in binary form must reproduce the above
|
| +// copyright notice, this list of conditions and the following disclaimer
|
| +// in the documentation and/or other materials provided with the
|
| +// distribution.
|
| +// * Neither the name of Google Inc. nor the names of its
|
| +// contributors may be used to endorse or promote products derived from
|
| +// this software without specific prior written permission.
|
| +//
|
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +#include <google/protobuf/util/internal/default_value_objectwriter.h>
|
| +
|
| +#include <google/protobuf/stubs/hash.h>
|
| +
|
| +#include <google/protobuf/util/internal/constants.h>
|
| +#include <google/protobuf/stubs/map_util.h>
|
| +
|
| +namespace google {
|
| +namespace protobuf {
|
| +namespace util {
|
| +using util::Status;
|
| +using util::StatusOr;
|
| +namespace converter {
|
| +
|
| +DefaultValueObjectWriter::DefaultValueObjectWriter(
|
| + TypeResolver* type_resolver, const google::protobuf::Type& type,
|
| + ObjectWriter* ow)
|
| + : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
|
| + type_(type),
|
| + disable_normalize_(false),
|
| + current_(NULL),
|
| + root_(NULL),
|
| + ow_(ow) {}
|
| +
|
| +DefaultValueObjectWriter::~DefaultValueObjectWriter() {
|
| + for (int i = 0; i < string_values_.size(); ++i) {
|
| + delete string_values_[i];
|
| + }
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(StringPiece name,
|
| + bool value) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderBool(name, value);
|
| + } else {
|
| + RenderDataPiece(name, DataPiece(value));
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32(
|
| + StringPiece name, int32 value) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderInt32(name, value);
|
| + } else {
|
| + RenderDataPiece(name, DataPiece(value));
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32(
|
| + StringPiece name, uint32 value) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderUint32(name, value);
|
| + } else {
|
| + RenderDataPiece(name, DataPiece(value));
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64(
|
| + StringPiece name, int64 value) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderInt64(name, value);
|
| + } else {
|
| + RenderDataPiece(name, DataPiece(value));
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64(
|
| + StringPiece name, uint64 value) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderUint64(name, value);
|
| + } else {
|
| + RenderDataPiece(name, DataPiece(value));
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble(
|
| + StringPiece name, double value) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderDouble(name, value);
|
| + } else {
|
| + RenderDataPiece(name, DataPiece(value));
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat(
|
| + StringPiece name, float value) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderBool(name, value);
|
| + } else {
|
| + RenderDataPiece(name, DataPiece(value));
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString(
|
| + StringPiece name, StringPiece value) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderString(name, value);
|
| + } else {
|
| + // Since StringPiece is essentially a pointer, takes a copy of "value" to
|
| + // avoid ownership issues.
|
| + string_values_.push_back(new string(value.ToString()));
|
| + RenderDataPiece(name, DataPiece(*string_values_.back()));
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
|
| + StringPiece name, StringPiece value) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderBytes(name, value);
|
| + } else {
|
| + RenderDataPiece(name, DataPiece(value));
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
|
| + StringPiece name) {
|
| + if (current_ == NULL) {
|
| + ow_->RenderNull(name);
|
| + } else {
|
| + RenderDataPiece(name, DataPiece::NullData());
|
| + }
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter*
|
| +DefaultValueObjectWriter::DisableCaseNormalizationForNextKey() {
|
| + disable_normalize_ = true;
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter::Node::Node(const string& name,
|
| + const google::protobuf::Type* type,
|
| + NodeKind kind, const DataPiece& data,
|
| + bool is_placeholder)
|
| + : name_(name),
|
| + type_(type),
|
| + kind_(kind),
|
| + disable_normalize_(false),
|
| + is_any_(false),
|
| + data_(data),
|
| + is_placeholder_(is_placeholder) {}
|
| +
|
| +DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
|
| + StringPiece name) {
|
| + if (name.empty() || kind_ != OBJECT) {
|
| + return NULL;
|
| + }
|
| + for (int i = 0; i < children_.size(); ++i) {
|
| + Node* child = children_[i];
|
| + if (child->name() == name) {
|
| + return child;
|
| + }
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
|
| + if (disable_normalize_) {
|
| + ow->DisableCaseNormalizationForNextKey();
|
| + }
|
| + if (kind_ == PRIMITIVE) {
|
| + ObjectWriter::RenderDataPieceTo(data_, name_, ow);
|
| + return;
|
| + }
|
| + if (is_placeholder_) {
|
| + // If is_placeholder_ = true, we didn't see this node in the response, so
|
| + // skip output.
|
| + return;
|
| + }
|
| + if (kind_ == LIST) {
|
| + ow->StartList(name_);
|
| + } else {
|
| + ow->StartObject(name_);
|
| + }
|
| + for (int i = 0; i < children_.size(); ++i) {
|
| + Node* child = children_[i];
|
| + child->WriteTo(ow);
|
| + }
|
| + if (kind_ == LIST) {
|
| + ow->EndList();
|
| + } else {
|
| + ow->EndObject();
|
| + }
|
| +}
|
| +
|
| +const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType(
|
| + const google::protobuf::Type& found_type, TypeInfo* typeinfo) {
|
| + // If this field is a map, we should use the type of its "Value" as
|
| + // the type of the child node.
|
| + for (int i = 0; i < found_type.fields_size(); ++i) {
|
| + const google::protobuf::Field& sub_field = found_type.fields(i);
|
| + if (sub_field.number() != 2) {
|
| + continue;
|
| + }
|
| + if (sub_field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE) {
|
| + // This map's value type is not a message type. We don't need to
|
| + // get the field_type in this case.
|
| + break;
|
| + }
|
| + util::StatusOr<const google::protobuf::Type*> sub_type =
|
| + typeinfo->ResolveTypeUrl(sub_field.type_url());
|
| + if (!sub_type.ok()) {
|
| + GOOGLE_LOG(WARNING) << "Cannot resolve type '" << sub_field.type_url() << "'.";
|
| + } else {
|
| + return sub_type.ValueOrDie();
|
| + }
|
| + break;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +void DefaultValueObjectWriter::Node::PopulateChildren(TypeInfo* typeinfo) {
|
| + // Ignores well known types that don't require automatically populating their
|
| + // primitive children. For type "Any", we only populate its children when the
|
| + // "@type" field is set.
|
| + // TODO(tsun): remove "kStructValueType" from the list. It's being checked
|
| + // now because of a bug in the tool-chain that causes the "oneof_index"
|
| + // of kStructValueType to not be set correctly.
|
| + if (type_ == NULL || type_->name() == kAnyType ||
|
| + type_->name() == kStructType || type_->name() == kTimestampType ||
|
| + type_->name() == kDurationType || type_->name() == kStructValueType) {
|
| + return;
|
| + }
|
| + std::vector<Node*> new_children;
|
| + hash_map<string, int> orig_children_map;
|
| +
|
| + // Creates a map of child nodes to speed up lookup.
|
| + for (int i = 0; i < children_.size(); ++i) {
|
| + InsertIfNotPresent(&orig_children_map, children_[i]->name_, i);
|
| + }
|
| +
|
| + for (int i = 0; i < type_->fields_size(); ++i) {
|
| + const google::protobuf::Field& field = type_->fields(i);
|
| + hash_map<string, int>::iterator found =
|
| + orig_children_map.find(field.name());
|
| + // If the child field has already been set, we just add it to the new list
|
| + // of children.
|
| + if (found != orig_children_map.end()) {
|
| + new_children.push_back(children_[found->second]);
|
| + children_[found->second] = NULL;
|
| + continue;
|
| + }
|
| +
|
| + const google::protobuf::Type* field_type = NULL;
|
| + bool is_map = false;
|
| + NodeKind kind = PRIMITIVE;
|
| +
|
| + if (field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
|
| + kind = OBJECT;
|
| + util::StatusOr<const google::protobuf::Type*> found_result =
|
| + typeinfo->ResolveTypeUrl(field.type_url());
|
| + if (!found_result.ok()) {
|
| + // "field" is of an unknown type.
|
| + GOOGLE_LOG(WARNING) << "Cannot resolve type '" << field.type_url() << "'.";
|
| + } else {
|
| + const google::protobuf::Type* found_type = found_result.ValueOrDie();
|
| + is_map = IsMap(field, *found_type);
|
| +
|
| + if (!is_map) {
|
| + field_type = found_type;
|
| + } else {
|
| + // If this field is a map, we should use the type of its "Value" as
|
| + // the type of the child node.
|
| + field_type = GetMapValueType(*found_type, typeinfo);
|
| + kind = MAP;
|
| + }
|
| + }
|
| + }
|
| + if (!is_map &&
|
| + field.cardinality() ==
|
| + google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
|
| + kind = LIST;
|
| + }
|
| + // If the child field is of primitive type, sets its data to the default
|
| + // value of its type.
|
| + // If oneof_index() != 0, the child field is part of a "oneof", which means
|
| + // the child field is optional and we shouldn't populate its default value.
|
| + google::protobuf::scoped_ptr<Node> child(
|
| + new Node(field.name(), field_type, kind,
|
| + ((kind == PRIMITIVE && field.oneof_index() == 0)
|
| + ? CreateDefaultDataPieceForField(field)
|
| + : DataPiece::NullData()),
|
| + true));
|
| + new_children.push_back(child.release());
|
| + }
|
| + // Adds all leftover nodes in children_ to the beginning of new_child.
|
| + for (int i = 0; i < children_.size(); ++i) {
|
| + if (children_[i] == NULL) {
|
| + continue;
|
| + }
|
| + new_children.insert(new_children.begin(), children_[i]);
|
| + children_[i] = NULL;
|
| + }
|
| + children_.swap(new_children);
|
| +}
|
| +
|
| +void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) {
|
| + // If this is an "Any" node with "@type" already given and no other children
|
| + // have been added, populates its children.
|
| + if (node != NULL && node->is_any() && node->type() != NULL &&
|
| + node->type()->name() != kAnyType && node->number_of_children() == 1) {
|
| + node->PopulateChildren(typeinfo_.get());
|
| + }
|
| +}
|
| +
|
| +DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
|
| + const google::protobuf::Field& field) {
|
| + switch (field.kind()) {
|
| + case google::protobuf::Field_Kind_TYPE_DOUBLE: {
|
| + return DataPiece(static_cast<double>(0));
|
| + }
|
| + case google::protobuf::Field_Kind_TYPE_FLOAT: {
|
| + return DataPiece(static_cast<float>(0));
|
| + }
|
| + case google::protobuf::Field_Kind_TYPE_INT64:
|
| + case google::protobuf::Field_Kind_TYPE_SINT64:
|
| + case google::protobuf::Field_Kind_TYPE_SFIXED64: {
|
| + return DataPiece(static_cast<int64>(0));
|
| + }
|
| + case google::protobuf::Field_Kind_TYPE_UINT64:
|
| + case google::protobuf::Field_Kind_TYPE_FIXED64: {
|
| + return DataPiece(static_cast<uint64>(0));
|
| + }
|
| + case google::protobuf::Field_Kind_TYPE_INT32:
|
| + case google::protobuf::Field_Kind_TYPE_SINT32:
|
| + case google::protobuf::Field_Kind_TYPE_SFIXED32: {
|
| + return DataPiece(static_cast<int32>(0));
|
| + }
|
| + case google::protobuf::Field_Kind_TYPE_BOOL: {
|
| + return DataPiece(false);
|
| + }
|
| + case google::protobuf::Field_Kind_TYPE_STRING: {
|
| + return DataPiece(string());
|
| + }
|
| + case google::protobuf::Field_Kind_TYPE_BYTES: {
|
| + return DataPiece("", false);
|
| + }
|
| + case google::protobuf::Field_Kind_TYPE_UINT32:
|
| + case google::protobuf::Field_Kind_TYPE_FIXED32: {
|
| + return DataPiece(static_cast<uint32>(0));
|
| + }
|
| + default: { return DataPiece::NullData(); }
|
| + }
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
|
| + StringPiece name) {
|
| + if (current_ == NULL) {
|
| + root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(),
|
| + false));
|
| + root_->set_disable_normalize(GetAndResetDisableNormalize());
|
| + root_->PopulateChildren(typeinfo_.get());
|
| + current_ = root_.get();
|
| + return this;
|
| + }
|
| + MaybePopulateChildrenOfAny(current_);
|
| + Node* child = current_->FindChild(name);
|
| + if (current_->kind() == LIST || current_->kind() == MAP || child == NULL) {
|
| + // If current_ is a list or a map node, we should create a new child and use
|
| + // the type of current_ as the type of the new child.
|
| + google::protobuf::scoped_ptr<Node> node(new Node(
|
| + name.ToString(), ((current_->kind() == LIST || current_->kind() == MAP)
|
| + ? current_->type()
|
| + : NULL),
|
| + OBJECT, DataPiece::NullData(), false));
|
| + child = node.get();
|
| + current_->AddChild(node.release());
|
| + }
|
| +
|
| + child->set_is_placeholder(false);
|
| + child->set_disable_normalize(GetAndResetDisableNormalize());
|
| + if (child->kind() == OBJECT && child->number_of_children() == 0) {
|
| + child->PopulateChildren(typeinfo_.get());
|
| + }
|
| +
|
| + stack_.push(current_);
|
| + current_ = child;
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() {
|
| + if (stack_.empty()) {
|
| + // The root object ends here. Writes out the tree.
|
| + WriteRoot();
|
| + return this;
|
| + }
|
| + current_ = stack_.top();
|
| + stack_.pop();
|
| + return this;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::StartList(
|
| + StringPiece name) {
|
| + if (current_ == NULL) {
|
| + root_.reset(
|
| + new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), false));
|
| + root_->set_disable_normalize(GetAndResetDisableNormalize());
|
| + current_ = root_.get();
|
| + return this;
|
| + }
|
| + MaybePopulateChildrenOfAny(current_);
|
| + Node* child = current_->FindChild(name);
|
| + if (child == NULL || child->kind() != LIST) {
|
| + GOOGLE_LOG(WARNING) << "Cannot find field '" << name << "'.";
|
| + google::protobuf::scoped_ptr<Node> node(
|
| + new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false));
|
| + child = node.get();
|
| + current_->AddChild(node.release());
|
| + }
|
| + child->set_is_placeholder(false);
|
| + child->set_disable_normalize(GetAndResetDisableNormalize());
|
| +
|
| + stack_.push(current_);
|
| + current_ = child;
|
| + return this;
|
| +}
|
| +
|
| +void DefaultValueObjectWriter::WriteRoot() {
|
| + root_->WriteTo(ow_);
|
| + root_.reset(NULL);
|
| + current_ = NULL;
|
| +}
|
| +
|
| +DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() {
|
| + if (stack_.empty()) {
|
| + WriteRoot();
|
| + return this;
|
| + }
|
| + current_ = stack_.top();
|
| + stack_.pop();
|
| + return this;
|
| +}
|
| +
|
| +void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
|
| + const DataPiece& data) {
|
| + MaybePopulateChildrenOfAny(current_);
|
| + util::StatusOr<string> data_string = data.ToString();
|
| + if (current_->type() != NULL && current_->type()->name() == kAnyType &&
|
| + name == "@type" && data_string.ok()) {
|
| + const string& string_value = data_string.ValueOrDie();
|
| + // If the type of current_ is "Any" and its "@type" field is being set here,
|
| + // sets the type of current_ to be the type specified by the "@type".
|
| + util::StatusOr<const google::protobuf::Type*> found_type =
|
| + typeinfo_->ResolveTypeUrl(string_value);
|
| + if (!found_type.ok()) {
|
| + GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'.";
|
| + } else {
|
| + current_->set_type(found_type.ValueOrDie());
|
| + }
|
| + current_->set_is_any(true);
|
| + // If the "@type" field is placed after other fields, we should populate
|
| + // other children of primitive type now. Otherwise, we should wait until the
|
| + // first value field is rendered before we populate the children, because
|
| + // the "value" field of a Any message could be omitted.
|
| + if (current_->number_of_children() > 1 && current_->type() != NULL) {
|
| + current_->PopulateChildren(typeinfo_.get());
|
| + }
|
| + }
|
| + Node* child = current_->FindChild(name);
|
| + if (child == NULL || child->kind() != PRIMITIVE) {
|
| + GOOGLE_LOG(WARNING) << "Cannot find primitive field '" << name << "'.";
|
| + // No children are found, creates a new child.
|
| + google::protobuf::scoped_ptr<Node> node(
|
| + new Node(name.ToString(), NULL, PRIMITIVE, data, false));
|
| + child = node.get();
|
| + current_->AddChild(node.release());
|
| + } else {
|
| + child->set_data(data);
|
| + }
|
| + child->set_disable_normalize(GetAndResetDisableNormalize());
|
| +}
|
| +
|
| +} // namespace converter
|
| +} // namespace util
|
| +} // namespace protobuf
|
| +} // namespace google
|
|
|