diff options
Diffstat (limited to 'src/google/protobuf/util')
48 files changed, 824 insertions, 478 deletions
diff --git a/src/google/protobuf/util/delimited_message_util.cc b/src/google/protobuf/util/delimited_message_util.cc index 16378782..3ba930e7 100644 --- a/src/google/protobuf/util/delimited_message_util.cc +++ b/src/google/protobuf/util/delimited_message_util.cc @@ -12,7 +12,7 @@ bool SerializeDelimitedToFileDescriptor(const MessageLite& message, int file_des return SerializeDelimitedToZeroCopyStream(message, &output); } -bool SerializeDelimitedToOstream(const MessageLite& message, ostream* output) { +bool SerializeDelimitedToOstream(const MessageLite& message, std::ostream* output) { { io::OstreamOutputStream zero_copy_output(output); if (!SerializeDelimitedToZeroCopyStream(message, &zero_copy_output)) return false; diff --git a/src/google/protobuf/util/delimited_message_util.h b/src/google/protobuf/util/delimited_message_util.h index 302d4781..e8a7204a 100644 --- a/src/google/protobuf/util/delimited_message_util.h +++ b/src/google/protobuf/util/delimited_message_util.h @@ -32,7 +32,7 @@ namespace util { // underlying source, so instead you must keep using the same stream object. bool LIBPROTOBUF_EXPORT SerializeDelimitedToFileDescriptor(const MessageLite& message, int file_descriptor); -bool LIBPROTOBUF_EXPORT SerializeDelimitedToOstream(const MessageLite& message, ostream* output); +bool LIBPROTOBUF_EXPORT SerializeDelimitedToOstream(const MessageLite& message, std::ostream* output); // Read a single size-delimited message from the given stream. Delimited // format allows a single file or stream to contain multiple messages, diff --git a/src/google/protobuf/util/field_comparator.cc b/src/google/protobuf/util/field_comparator.cc index a1a56ee6..86ddf06a 100644 --- a/src/google/protobuf/util/field_comparator.cc +++ b/src/google/protobuf/util/field_comparator.cc @@ -36,6 +36,7 @@ #include <google/protobuf/descriptor.h> #include <google/protobuf/message.h> +#include <google/protobuf/util/message_differencer.h> #include <google/protobuf/stubs/map_util.h> #include <google/protobuf/stubs/mathlimits.h> #include <google/protobuf/stubs/mathutil.h> @@ -130,6 +131,15 @@ FieldComparator::ComparisonResult DefaultFieldComparator::Compare( } } +bool DefaultFieldComparator::Compare( + MessageDifferencer* differencer, + const Message& message1, + const Message& message2, + const google::protobuf::util::FieldContext* field_context) { + return differencer->Compare( + message1, message2, field_context->parent_fields()); +} + void DefaultFieldComparator::SetDefaultFractionAndMargin(double fraction, double margin) { default_tolerance_ = Tolerance(fraction, margin); diff --git a/src/google/protobuf/util/field_comparator.h b/src/google/protobuf/util/field_comparator.h index 26a7ba4d..63e89fb7 100644 --- a/src/google/protobuf/util/field_comparator.h +++ b/src/google/protobuf/util/field_comparator.h @@ -35,6 +35,7 @@ #include <map> #include <string> +#include <vector> #include <google/protobuf/stubs/common.h> @@ -48,6 +49,7 @@ class FieldDescriptor; namespace util { class FieldContext; +class MessageDifferencer; // Base class specifying the interface for comparing protocol buffer fields. // Regular users should consider using or subclassing DefaultFieldComparator @@ -108,14 +110,14 @@ class LIBPROTOBUF_EXPORT DefaultFieldComparator : public FieldComparator { // Creates new comparator with float comparison set to EXACT. DefaultFieldComparator(); - virtual ~DefaultFieldComparator(); + ~DefaultFieldComparator() override; - virtual ComparisonResult Compare( + ComparisonResult Compare( const google::protobuf::Message& message_1, const google::protobuf::Message& message_2, const google::protobuf::FieldDescriptor* field, int index_1, int index_2, - const google::protobuf::util::FieldContext* field_context); + const google::protobuf::util::FieldContext* field_context) override; void set_float_comparison(FloatComparison float_comparison) { float_comparison_ = float_comparison; @@ -153,6 +155,15 @@ class LIBPROTOBUF_EXPORT DefaultFieldComparator : public FieldComparator { // REQUIRES: float_comparison_ == APPROXIMATE void SetDefaultFractionAndMargin(double fraction, double margin); + protected: + // Compare using the provided message_differencer. For example, a subclass can + // use this method to compare some field in a certain way using the same + // message_differencer instance and the field context. + bool Compare(MessageDifferencer* differencer, + const google::protobuf::Message& message1, + const google::protobuf::Message& message2, + const google::protobuf::util::FieldContext* field_context); + private: // Defines the tolerance for floating point comparison (fraction and margin). struct Tolerance { diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc index 4d0d3a46..a2e2a388 100644 --- a/src/google/protobuf/util/field_mask_util.cc +++ b/src/google/protobuf/util/field_mask_util.cc @@ -31,6 +31,7 @@ #include <google/protobuf/util/field_mask_util.h> #include <google/protobuf/stubs/strutil.h> + #include <google/protobuf/stubs/map_util.h> namespace google { @@ -131,27 +132,27 @@ bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) { bool FieldMaskUtil::GetFieldDescriptors( const Descriptor* descriptor, StringPiece path, std::vector<const FieldDescriptor*>* field_descriptors) { - if (field_descriptors != NULL) { + if (field_descriptors != nullptr) { field_descriptors->clear(); } std::vector<string> parts = Split(path, "."); for (int i = 0; i < parts.size(); ++i) { const string& field_name = parts[i]; - if (descriptor == NULL) { + if (descriptor == nullptr) { return false; } const FieldDescriptor* field = descriptor->FindFieldByName(field_name); - if (field == NULL) { + if (field == nullptr) { return false; } - if (field_descriptors != NULL) { + if (field_descriptors != nullptr) { field_descriptors->push_back(field); } if (!field->is_repeated() && field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { descriptor = field->message_type(); } else { - descriptor = NULL; + descriptor = nullptr; } } return true; @@ -342,6 +343,12 @@ void FieldMaskTree::AddPath(const string& path) { void FieldMaskTree::RemovePath(const string& path, const Descriptor* descriptor) { + if (root_.children.empty()) { + // Nothing to be removed from an empty tree. We shortcut it here so an empty + // tree won't be interpreted as a field mask containing all fields by the + // code below. + return; + } std::vector<string> parts = Split(path, "."); if (parts.empty()) { return; @@ -349,16 +356,16 @@ void FieldMaskTree::RemovePath(const string& path, std::vector<Node*> nodes(parts.size()); Node* node = &root_; const Descriptor* current_descriptor = descriptor; - Node* new_branch_node = NULL; + Node* new_branch_node = nullptr; for (int i = 0; i < parts.size(); ++i) { nodes[i] = node; const FieldDescriptor* field_descriptor = current_descriptor->FindFieldByName(parts[i]); - if (field_descriptor == NULL || + if (field_descriptor == nullptr || (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE && i != parts.size() - 1)) { // Invalid path. - if (new_branch_node != NULL) { + if (new_branch_node != nullptr) { // If add any new nodes, cleanup. new_branch_node->ClearChildren(); } @@ -366,7 +373,7 @@ void FieldMaskTree::RemovePath(const string& path, } if (node->children.empty()) { - if (new_branch_node == NULL) { + if (new_branch_node == nullptr) { new_branch_node = node; } for (int i = 0; i < current_descriptor->field_count(); ++i) { @@ -374,7 +381,7 @@ void FieldMaskTree::RemovePath(const string& path, } } if (ContainsKey(node->children, parts[i])) { - node = node->children.at(parts[i]); + node = node->children[parts[i]]; if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { current_descriptor = field_descriptor->message_type(); } @@ -542,7 +549,7 @@ void FieldMaskTree::AddRequiredFieldPath( if (field->is_required()) { const string& node_name = field->name(); Node*& child = node->children[node_name]; - if (child == NULL) { + if (child == nullptr) { // Add required field path to the tree child = new Node(); } else if (child->children.empty()){ diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h index 01642c6f..f0299de9 100644 --- a/src/google/protobuf/util/field_mask_util.h +++ b/src/google/protobuf/util/field_mask_util.h @@ -70,14 +70,14 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { // Checks whether the given path is valid for type T. template <typename T> static bool IsValidPath(StringPiece path) { - return GetFieldDescriptors(T::descriptor(), path, NULL); + return GetFieldDescriptors(T::descriptor(), path, nullptr); } // Checks whether the given FieldMask is valid for type T. template <typename T> static bool IsValidFieldMask(const FieldMask& mask) { for (int i = 0; i < mask.paths_size(); ++i) { - if (!GetFieldDescriptors(T::descriptor(), mask.paths(i), NULL)) + if (!GetFieldDescriptors(T::descriptor(), mask.paths(i), nullptr)) return false; } return true; @@ -94,6 +94,13 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { // Creates a FieldMask with all fields of type T. This FieldMask only // contains fields of T but not any sub-message fields. template <typename T> + static FieldMask GetFieldMaskForAllFields() { + FieldMask out; + InternalGetFieldMaskForAllFields(T::descriptor(), &out); + return out; + } + template <typename T> + PROTOBUF_RUNTIME_DEPRECATED("Use *out = GetFieldMaskForAllFields() instead") static void GetFieldMaskForAllFields(FieldMask* out) { InternalGetFieldMaskForAllFields(T::descriptor(), out); } @@ -122,6 +129,8 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { // Returns true if path is covered by the given FieldMask. Note that path // "foo.bar" covers all paths like "foo.bar.baz", "foo.bar.quz.x", etc. + // Also note that parent paths are not covered by explicit child path, i.e. + // "foo.bar" does NOT cover "foo", even if "bar" is the only child. static bool IsPathInFieldMask(StringPiece path, const FieldMask& mask); class MergeOptions; diff --git a/src/google/protobuf/util/field_mask_util_test.cc b/src/google/protobuf/util/field_mask_util_test.cc index 7939f733..3ba30aa3 100644 --- a/src/google/protobuf/util/field_mask_util_test.cc +++ b/src/google/protobuf/util/field_mask_util_test.cc @@ -168,7 +168,7 @@ TEST(FieldMaskUtilTest, GetFieldDescriptors) { EXPECT_EQ(1, field_descriptors.size()); EXPECT_EQ("optional_int32", field_descriptors[0]->name()); EXPECT_FALSE(FieldMaskUtil::GetFieldDescriptors( - TestAllTypes::descriptor(), "optional_nonexist", NULL)); + TestAllTypes::descriptor(), "optional_nonexist", nullptr)); EXPECT_TRUE(FieldMaskUtil::GetFieldDescriptors(TestAllTypes::descriptor(), "optional_nested_message.bb", &field_descriptors)); @@ -176,10 +176,10 @@ TEST(FieldMaskUtilTest, GetFieldDescriptors) { EXPECT_EQ("optional_nested_message", field_descriptors[0]->name()); EXPECT_EQ("bb", field_descriptors[1]->name()); EXPECT_FALSE(FieldMaskUtil::GetFieldDescriptors( - TestAllTypes::descriptor(), "optional_nested_message.nonexist", NULL)); + TestAllTypes::descriptor(), "optional_nested_message.nonexist", nullptr)); // FieldMask cannot be used to specify sub-fields of a repeated message. EXPECT_FALSE(FieldMaskUtil::GetFieldDescriptors( - TestAllTypes::descriptor(), "repeated_nested_message.bb", NULL)); + TestAllTypes::descriptor(), "repeated_nested_message.bb", nullptr)); } TEST(FieldMaskUtilTest, TestIsVaildPath) { @@ -206,12 +206,12 @@ TEST(FieldMaskUtilTest, TestIsValidFieldMask) { TEST(FieldMaskUtilTest, TestGetFieldMaskForAllFields) { FieldMask mask; - FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes::NestedMessage>(&mask); + mask = FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes::NestedMessage>(); EXPECT_EQ(1, mask.paths_size()); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask)); - FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>(&mask); - EXPECT_EQ(76, mask.paths_size()); + mask = FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>(); + EXPECT_EQ(75, mask.paths_size()); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int32", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int64", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint32", mask)); @@ -386,6 +386,13 @@ TEST(FieldMaskUtilTest, TestSubtract) { FieldMaskUtil::FromString("optional_nested_message", &mask2); FieldMaskUtil::Subtract<TestAllTypes>(mask1, mask2, &out); EXPECT_EQ("", FieldMaskUtil::ToString(out)); + + // Regression test for b/72727550 + FieldMaskUtil::FromString("optional_foreign_message.c", &mask1); + FieldMaskUtil::FromString("optional_foreign_message,optional_nested_message", + &mask2); + FieldMaskUtil::Subtract<TestAllTypes>(mask1, mask2, &out); + EXPECT_EQ("", FieldMaskUtil::ToString(out)); } TEST(FieldMaskUtilTest, TestIspathInFieldMask) { diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc index 213c2c40..59bc28ae 100644 --- a/src/google/protobuf/util/internal/datapiece.cc +++ b/src/google/protobuf/util/internal/datapiece.cc @@ -64,9 +64,9 @@ StatusOr<To> ValidateNumberConversion(To after, From before) { MathUtil::Sign<From>(before) == MathUtil::Sign<To>(after)) { return after; } else { - return InvalidArgument(::google::protobuf::internal::is_integral<From>::value + return InvalidArgument(std::is_integral<From>::value ? ValueAsString(before) - : ::google::protobuf::internal::is_same<From, double>::value + : std::is_same<From, double>::value ? DoubleAsString(before) : FloatAsString(before)); } @@ -77,7 +77,7 @@ StatusOr<To> ValidateNumberConversion(To after, From before) { // except conversion between double and float. template <typename To, typename From> StatusOr<To> NumberConvertAndCheck(From before) { - if (::google::protobuf::internal::is_same<From, To>::value) return before; + if (std::is_same<From, To>::value) return before; To after = static_cast<To>(before); return ValidateNumberConversion(after, before); @@ -87,7 +87,7 @@ StatusOr<To> NumberConvertAndCheck(From before) { // point types (double, float) only. template <typename To, typename From> StatusOr<To> FloatingPointToIntConvertAndCheck(From before) { - if (::google::protobuf::internal::is_same<From, To>::value) return before; + if (std::is_same<From, To>::value) return before; To after = static_cast<To>(before); return ValidateNumberConversion(after, before); @@ -272,7 +272,8 @@ StatusOr<string> DataPiece::ToBytes() const { } StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type, - bool use_lower_camel_for_enums) const { + bool use_lower_camel_for_enums, + bool ignore_unknown_enum_values) const { if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE; if (type_ == TYPE_STRING) { @@ -280,7 +281,7 @@ StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type, string enum_name = str_.ToString(); const google::protobuf::EnumValue* value = FindEnumValueByNameOrNull(enum_type, enum_name); - if (value != NULL) return value->number(); + if (value != nullptr) return value->number(); // Check if int version of enum is sent as string. StatusOr<int32> int_value = ToInt32(); @@ -296,15 +297,19 @@ StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type, *it = *it == '-' ? '_' : ascii_toupper(*it); } value = FindEnumValueByNameOrNull(enum_type, enum_name); - if (value != NULL) return value->number(); + if (value != nullptr) return value->number(); // If use_lower_camel_for_enums is true try with enum name without // underscore. This will also accept camel case names as the enum_name has // been normalized before. if (use_lower_camel_for_enums) { value = FindEnumValueByNameWithoutUnderscoreOrNull(enum_type, enum_name); - if (value != NULL) return value->number(); + if (value != nullptr) return value->number(); } + + // If ignore_unknown_enum_values is true an unknown enum value is treated + // as the default + if (ignore_unknown_enum_values) return enum_type->enumvalue(0).number(); } else { // We don't need to check whether the value is actually declared in the // enum because we preserve unknown enum values as well. @@ -357,7 +362,8 @@ bool DataPiece::DecodeBase64(StringPiece src, string* dest) const { WebSafeBase64Escape(*dest, &encoded); // Remove trailing padding '=' characters before comparison. StringPiece src_no_padding = StringPiece(src).substr( - 0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length()); + 0, StringEndsWith(src, "=") ? src.find_last_not_of('=') + 1 + : src.length()); return encoded == src_no_padding; } return true; @@ -370,7 +376,8 @@ bool DataPiece::DecodeBase64(StringPiece src, string* dest) const { reinterpret_cast<const unsigned char*>(dest->data()), dest->length(), &encoded, false); StringPiece src_no_padding = StringPiece(src).substr( - 0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length()); + 0, StringEndsWith(src, "=") ? src.find_last_not_of('=') + 1 + : src.length()); return encoded == src_no_padding; } return true; diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h index 83516d09..95b133da 100644 --- a/src/google/protobuf/util/internal/datapiece.h +++ b/src/google/protobuf/util/internal/datapiece.h @@ -164,7 +164,8 @@ class LIBPROTOBUF_EXPORT DataPiece { // If the value is not a string, attempts to convert to a 32-bit integer. // If none of these succeeds, returns a conversion error status. util::StatusOr<int> ToEnum(const google::protobuf::Enum* enum_type, - bool use_lower_camel_for_enums) const; + bool use_lower_camel_for_enums, + bool ignore_unknown_enum_values) const; private: // Disallow implicit constructor. diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index 95b3a17d..b41feb7a 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -62,11 +62,12 @@ DefaultValueObjectWriter::DefaultValueObjectWriter( : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), own_typeinfo_(true), type_(type), - current_(NULL), - root_(NULL), + current_(nullptr), + root_(nullptr), suppress_empty_list_(false), preserve_proto_field_names_(false), - field_scrub_callback_(NULL), + use_ints_for_enums_(false), + field_scrub_callback_(nullptr), ow_(ow) {} DefaultValueObjectWriter::~DefaultValueObjectWriter() { @@ -80,7 +81,7 @@ DefaultValueObjectWriter::~DefaultValueObjectWriter() { DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(StringPiece name, bool value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderBool(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -90,7 +91,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(StringPiece name, DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32( StringPiece name, int32 value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderInt32(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -100,7 +101,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32( StringPiece name, uint32 value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderUint32(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -110,7 +111,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64( StringPiece name, int64 value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderInt64(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -120,7 +121,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64( StringPiece name, uint64 value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderUint64(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -130,7 +131,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble( StringPiece name, double value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderDouble(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -140,7 +141,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat( StringPiece name, float value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderBool(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -150,7 +151,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString( StringPiece name, StringPiece value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderString(name, value); } else { // Since StringPiece is essentially a pointer, takes a copy of "value" to @@ -163,7 +164,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( StringPiece name, StringPiece value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderBytes(name, value); } else { // Since StringPiece is essentially a pointer, takes a copy of "value" to @@ -176,7 +177,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( StringPiece name) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderNull(name); } else { RenderDataPiece(name, DataPiece::NullData()); @@ -200,10 +201,10 @@ DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode( DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode( const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, bool is_placeholder, const std::vector<string>& path, - bool suppress_empty_list, bool preserve_proto_field_names, + bool suppress_empty_list, bool preserve_proto_field_names, bool use_ints_for_enums, FieldScrubCallBack* field_scrub_callback) { return new Node(name, type, kind, data, is_placeholder, path, - suppress_empty_list, preserve_proto_field_names, + suppress_empty_list, preserve_proto_field_names, use_ints_for_enums, field_scrub_callback); } @@ -220,12 +221,13 @@ DefaultValueObjectWriter::Node::Node( path_(path), suppress_empty_list_(suppress_empty_list), preserve_proto_field_names_(false), + use_ints_for_enums_(false), field_scrub_callback_(field_scrub_callback) {} DefaultValueObjectWriter::Node::Node( const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, bool is_placeholder, const std::vector<string>& path, - bool suppress_empty_list, bool preserve_proto_field_names, + bool suppress_empty_list, bool preserve_proto_field_names, bool use_ints_for_enums, FieldScrubCallBack* field_scrub_callback) : name_(name), type_(type), @@ -236,12 +238,13 @@ DefaultValueObjectWriter::Node::Node( path_(path), suppress_empty_list_(suppress_empty_list), preserve_proto_field_names_(preserve_proto_field_names), + use_ints_for_enums_(use_ints_for_enums), field_scrub_callback_(field_scrub_callback) {} DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( StringPiece name) { if (name.empty() || kind_ != OBJECT) { - return NULL; + return nullptr; } for (int i = 0; i < children_.size(); ++i) { Node* child = children_[i]; @@ -249,7 +252,7 @@ DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( return child; } } - return NULL; + return nullptr; } void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) { @@ -317,7 +320,7 @@ const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType( } break; } - return NULL; + return nullptr; } void DefaultValueObjectWriter::Node::PopulateChildren( @@ -328,7 +331,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren( // 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 || + if (type_ == nullptr || type_->name() == kAnyType || type_->name() == kStructType || type_->name() == kTimestampType || type_->name() == kDurationType || type_->name() == kStructValueType) { return; @@ -351,7 +354,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren( path.insert(path.begin(), path_.begin(), path_.end()); } path.push_back(field.name()); - if (field_scrub_callback_ != NULL && + if (field_scrub_callback_ != nullptr && field_scrub_callback_->Run(path, &field)) { continue; } @@ -362,11 +365,11 @@ void DefaultValueObjectWriter::Node::PopulateChildren( // of children. if (found != orig_children_map.end()) { new_children.push_back(children_[found->second]); - children_[found->second] = NULL; + children_[found->second] = nullptr; continue; } - const google::protobuf::Type* field_type = NULL; + const google::protobuf::Type* field_type = nullptr; bool is_map = false; NodeKind kind = PRIMITIVE; @@ -405,22 +408,22 @@ void DefaultValueObjectWriter::Node::PopulateChildren( // If the child field is of primitive type, sets its data to the default // value of its type. - google::protobuf::scoped_ptr<Node> child(new Node( + std::unique_ptr<Node> child(new Node( preserve_proto_field_names_ ? field.name() : field.json_name(), field_type, kind, - kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo) + kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo, use_ints_for_enums_) : DataPiece::NullData(), - true, path, suppress_empty_list_, preserve_proto_field_names_, + true, path, suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_)); 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) { + if (children_[i] == nullptr) { continue; } new_children.insert(new_children.begin(), children_[i]); - children_[i] = NULL; + children_[i] = nullptr; } children_.swap(new_children); } @@ -428,14 +431,14 @@ void DefaultValueObjectWriter::Node::PopulateChildren( 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 && + if (node != nullptr && node->is_any() && node->type() != nullptr && node->type()->name() != kAnyType && node->number_of_children() == 1) { node->PopulateChildren(typeinfo_); } } DataPiece DefaultValueObjectWriter::FindEnumDefault( - const google::protobuf::Field& field, const TypeInfo* typeinfo) { + const google::protobuf::Field& field, const TypeInfo* typeinfo, bool use_ints_for_enums) { if (!field.default_value().empty()) return DataPiece(field.default_value(), true); @@ -448,12 +451,12 @@ DataPiece DefaultValueObjectWriter::FindEnumDefault( } // We treat the first value as the default if none is specified. return enum_type->enumvalue_size() > 0 - ? DataPiece(enum_type->enumvalue(0).name(), true) + ? (use_ints_for_enums ? DataPiece(enum_type->enumvalue(0).number()) : DataPiece(enum_type->enumvalue(0).name(), true)) : DataPiece::NullData(); } DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( - const google::protobuf::Field& field, const TypeInfo* typeinfo) { + const google::protobuf::Field& field, const TypeInfo* typeinfo, bool use_ints_for_enums) { switch (field.kind()) { case google::protobuf::Field_Kind_TYPE_DOUBLE: { return DataPiece(ConvertTo<double>( @@ -496,7 +499,7 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0))); } case google::protobuf::Field_Kind_TYPE_ENUM: { - return FindEnumDefault(field, typeinfo); + return FindEnumDefault(field, typeinfo, use_ints_for_enums); } default: { return DataPiece::NullData(); } } @@ -504,11 +507,11 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( StringPiece name) { - if (current_ == NULL) { + if (current_ == nullptr) { std::vector<string> path; root_.reset(CreateNewNode(string(name), &type_, OBJECT, DataPiece::NullData(), false, path, - suppress_empty_list_, preserve_proto_field_names_, + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); root_->PopulateChildren(typeinfo_); current_ = root_.get(); @@ -516,17 +519,17 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( } MaybePopulateChildrenOfAny(current_); Node* child = current_->FindChild(name); - if (current_->kind() == LIST || current_->kind() == MAP || child == NULL) { + if (current_->kind() == LIST || current_->kind() == MAP || child == nullptr) { // 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( + std::unique_ptr<Node> node( CreateNewNode(string(name), ((current_->kind() == LIST || current_->kind() == MAP) ? current_->type() - : NULL), + : nullptr), OBJECT, DataPiece::NullData(), false, - child == NULL ? current_->path() : child->path(), - suppress_empty_list_, preserve_proto_field_names_, + child == nullptr ? current_->path() : child->path(), + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); @@ -555,22 +558,22 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() { DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( StringPiece name) { - if (current_ == NULL) { + if (current_ == nullptr) { std::vector<string> path; root_.reset(CreateNewNode(string(name), &type_, LIST, DataPiece::NullData(), false, path, suppress_empty_list_, - preserve_proto_field_names_, + preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); current_ = root_.get(); return this; } MaybePopulateChildrenOfAny(current_); Node* child = current_->FindChild(name); - if (child == NULL || child->kind() != LIST) { - google::protobuf::scoped_ptr<Node> node( - CreateNewNode(string(name), NULL, LIST, DataPiece::NullData(), false, - child == NULL ? current_->path() : child->path(), - suppress_empty_list_, preserve_proto_field_names_, + if (child == nullptr || child->kind() != LIST) { + std::unique_ptr<Node> node( + CreateNewNode(string(name), nullptr, LIST, DataPiece::NullData(), false, + child == nullptr ? current_->path() : child->path(), + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); @@ -584,8 +587,8 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( void DefaultValueObjectWriter::WriteRoot() { root_->WriteTo(ow_); - root_.reset(NULL); - current_ = NULL; + root_.reset(nullptr); + current_ = nullptr; } DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() { @@ -601,7 +604,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() { void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, const DataPiece& data) { MaybePopulateChildrenOfAny(current_); - if (current_->type() != NULL && current_->type()->name() == kAnyType && + if (current_->type() != nullptr && current_->type()->name() == kAnyType && name == "@type") { util::StatusOr<string> data_string = data.ToString(); if (data_string.ok()) { @@ -621,18 +624,18 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, // 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) { + if (current_->number_of_children() > 1 && current_->type() != nullptr) { current_->PopulateChildren(typeinfo_); } } } Node* child = current_->FindChild(name); - if (child == NULL || child->kind() != PRIMITIVE) { + if (child == nullptr || child->kind() != PRIMITIVE) { // No children are found, creates a new child. - google::protobuf::scoped_ptr<Node> node( - CreateNewNode(string(name), NULL, PRIMITIVE, data, false, - child == NULL ? current_->path() : child->path(), - suppress_empty_list_, preserve_proto_field_names_, + std::unique_ptr<Node> node( + CreateNewNode(string(name), nullptr, PRIMITIVE, data, false, + child == nullptr ? current_->path() : child->path(), + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); current_->AddChild(node.release()); } else { diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h index 09c6d23f..7d245c9c 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.h +++ b/src/google/protobuf/util/internal/default_value_objectwriter.h @@ -32,9 +32,6 @@ #define GOOGLE_PROTOBUF_UTIL_CONVERTER_DEFAULT_VALUE_OBJECTWRITER_H__ #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <stack> #include <vector> @@ -77,7 +74,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { FieldScrubCallBack; // A unique pointer to a DefaultValueObjectWriter::FieldScrubCallBack. - typedef google::protobuf::scoped_ptr<FieldScrubCallBack> FieldScrubCallBackPtr; + typedef std::unique_ptr<FieldScrubCallBack> FieldScrubCallBackPtr; DefaultValueObjectWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, @@ -86,37 +83,37 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { virtual ~DefaultValueObjectWriter(); // ObjectWriter methods. - virtual DefaultValueObjectWriter* StartObject(StringPiece name); + virtual DefaultValueObjectWriter* StartObject(StringPiece name) override; - virtual DefaultValueObjectWriter* EndObject(); + virtual DefaultValueObjectWriter* EndObject() override; - virtual DefaultValueObjectWriter* StartList(StringPiece name); + virtual DefaultValueObjectWriter* StartList(StringPiece name) override; - virtual DefaultValueObjectWriter* EndList(); + virtual DefaultValueObjectWriter* EndList() override; - virtual DefaultValueObjectWriter* RenderBool(StringPiece name, bool value); + virtual DefaultValueObjectWriter* RenderBool(StringPiece name, bool value) override; - virtual DefaultValueObjectWriter* RenderInt32(StringPiece name, int32 value); + virtual DefaultValueObjectWriter* RenderInt32(StringPiece name, int32 value) override; virtual DefaultValueObjectWriter* RenderUint32(StringPiece name, - uint32 value); + uint32 value) override; - virtual DefaultValueObjectWriter* RenderInt64(StringPiece name, int64 value); + virtual DefaultValueObjectWriter* RenderInt64(StringPiece name, int64 value) override; virtual DefaultValueObjectWriter* RenderUint64(StringPiece name, - uint64 value); + uint64 value) override; virtual DefaultValueObjectWriter* RenderDouble(StringPiece name, - double value); + double value) override; - virtual DefaultValueObjectWriter* RenderFloat(StringPiece name, float value); + virtual DefaultValueObjectWriter* RenderFloat(StringPiece name, float value) override; virtual DefaultValueObjectWriter* RenderString(StringPiece name, - StringPiece value); + StringPiece value) override; virtual DefaultValueObjectWriter* RenderBytes(StringPiece name, - StringPiece value); + StringPiece value) override; - virtual DefaultValueObjectWriter* RenderNull(StringPiece name); + virtual DefaultValueObjectWriter* RenderNull(StringPiece name) override; // Register the callback for scrubbing of fields. Owership of // field_scrub_callback pointer is also transferred to this class @@ -131,6 +128,12 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { preserve_proto_field_names_ = value; } + // If set to true, enums are rendered as ints from output when default values + // are written. + void set_print_enums_as_ints(bool value) { + use_ints_for_enums_ = value; + } + protected: enum NodeKind { PRIMITIVE = 0, @@ -150,7 +153,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { Node(const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, bool is_placeholder, const std::vector<string>& path, bool suppress_empty_list, - bool preserve_proto_field_names, + bool preserve_proto_field_names, bool use_ints_for_enums, FieldScrubCallBack* field_scrub_callback); virtual ~Node() { for (int i = 0; i < children_.size(); ++i) { @@ -233,6 +236,9 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Whether to preserve original proto field names bool preserve_proto_field_names_; + // Whether to always print enums as ints + bool use_ints_for_enums_; + // Pointer to function for determining whether a field needs to be scrubbed // or not. This callback is owned by the creator of this node. FieldScrubCallBack* field_scrub_callback_; @@ -256,11 +262,12 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { const std::vector<string>& path, bool suppress_empty_list, bool preserve_proto_field_names, + bool use_ints_for_enums, FieldScrubCallBack* field_scrub_callback); // Creates a DataPiece containing the default value of the type of the field. static DataPiece CreateDefaultDataPieceForField( - const google::protobuf::Field& field, const TypeInfo* typeinfo); + const google::protobuf::Field& field, const TypeInfo* typeinfo, bool use_ints_for_enums); protected: // Returns a pointer to current Node in tree. @@ -272,7 +279,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { void MaybePopulateChildrenOfAny(Node* node); // Writes the root_ node to ow_ and resets the root_ and current_ pointer to - // NULL. + // nullptr. void WriteRoot(); // Adds or replaces the data_ of a primitive child node. @@ -282,7 +289,8 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // there is no default. For proto3, where we cannot specify an explicit // default, a zero value will always be returned. static DataPiece FindEnumDefault(const google::protobuf::Field& field, - const TypeInfo* typeinfo); + const TypeInfo* typeinfo, + bool use_ints_for_enums); // Type information for all the types used in the descriptor. Used to find // google::protobuf::Type of nested messages/enums. @@ -297,7 +305,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // The current Node. Owned by its parents. Node* current_; // The root Node. - google::protobuf::scoped_ptr<Node> root_; + std::unique_ptr<Node> root_; // The stack to hold the path of Nodes from current_ to root_; std::stack<Node*> stack_; @@ -307,6 +315,9 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Whether to preserve original proto field names bool preserve_proto_field_names_; + // Whether to always print enums as ints + bool use_ints_for_enums_; + // Unique Pointer to function for determining whether a field needs to be // scrubbed or not. FieldScrubCallBackPtr field_scrub_callback_; diff --git a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc index e1dd697a..0c4af61b 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc @@ -60,7 +60,7 @@ class BaseDefaultValueObjectWriterTest TypeInfoTestHelper helper_; MockObjectWriter mock_; ExpectingObjectWriter expects_; - google::protobuf::scoped_ptr<DefaultValueObjectWriter> testing_; + std::unique_ptr<DefaultValueObjectWriter> testing_; }; // Tests to cover some basic DefaultValueObjectWriter use cases. More tests are @@ -156,7 +156,7 @@ class DefaultValueObjectWriterSuppressListTest : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) { testing_->set_suppress_empty_list(true); } - ~DefaultValueObjectWriterSuppressListTest() {} + ~DefaultValueObjectWriterSuppressListTest() override {} }; INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h index 1dc814a3..e3baa224 100644 --- a/src/google/protobuf/util/internal/error_listener.h +++ b/src/google/protobuf/util/internal/error_listener.h @@ -33,9 +33,6 @@ #include <algorithm> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <string> #include <vector> @@ -79,16 +76,16 @@ class LIBPROTOBUF_EXPORT ErrorListener { class LIBPROTOBUF_EXPORT NoopErrorListener : public ErrorListener { public: NoopErrorListener() {} - virtual ~NoopErrorListener() {} + virtual ~NoopErrorListener() override {} virtual void InvalidName(const LocationTrackerInterface& loc, - StringPiece invalid_name, StringPiece message) {} + StringPiece invalid_name, StringPiece message) override {} - virtual void InvalidValue(const LocationTrackerInterface& loc, - StringPiece type_name, StringPiece value) {} + virtual void InvalidValue(const LocationTrackerInterface &loc, StringPiece type_name, + StringPiece value) override {} - virtual void MissingField(const LocationTrackerInterface& loc, - StringPiece missing_name) {} + virtual void MissingField(const LocationTrackerInterface &loc, + StringPiece missing_name) override {} private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NoopErrorListener); diff --git a/src/google/protobuf/util/internal/field_mask_utility.cc b/src/google/protobuf/util/internal/field_mask_utility.cc index 38835f67..778a4510 100644 --- a/src/google/protobuf/util/internal/field_mask_utility.cc +++ b/src/google/protobuf/util/internal/field_mask_utility.cc @@ -30,6 +30,7 @@ #include <google/protobuf/util/internal/field_mask_utility.h> +#include <google/protobuf/util/internal/utility.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/status_macros.h> @@ -53,7 +54,7 @@ string AppendPathSegmentToPrefix(StringPiece prefix, StringPiece segment) { return prefix.ToString(); } // If the segment is a map key, appends it to the prefix without the ".". - if (segment.starts_with("[\"")) { + if (StringStartsWith(segment, "[\"")) { return StrCat(prefix, segment); } return StrCat(prefix, ".", segment); diff --git a/src/google/protobuf/util/internal/json_escaping.h b/src/google/protobuf/util/internal/json_escaping.h index 9b8b2afd..5495c57f 100644 --- a/src/google/protobuf/util/internal/json_escaping.h +++ b/src/google/protobuf/util/internal/json_escaping.h @@ -28,8 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef NET_PROTO2_UTIL_CONVERTER_STRINGS_JSON_ESCAPING_H_ -#define NET_PROTO2_UTIL_CONVERTER_STRINGS_JSON_ESCAPING_H_ +#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL__JSON_ESCAPING_H__ +#define GOOGLE_PROTOBUF_UTIL_INTERNAL__JSON_ESCAPING_H__ #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/bytestream.h> @@ -86,6 +86,6 @@ class JsonEscaping { } // namespace converter } // namespace util } // namespace protobuf -} // namespace google -#endif // NET_PROTO2_UTIL_CONVERTER_STRINGS_JSON_ESCAPING_H_ +} // namespace google +#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL__JSON_ESCAPING_H__ diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc index 6e4edd88..a431177a 100644 --- a/src/google/protobuf/util/internal/json_objectwriter.cc +++ b/src/google/protobuf/util/internal/json_objectwriter.cc @@ -57,7 +57,7 @@ JsonObjectWriter::~JsonObjectWriter() { JsonObjectWriter* JsonObjectWriter::StartObject(StringPiece name) { WritePrefix(name); WriteChar('{'); - Push(); + PushObject(); return this; } @@ -71,7 +71,7 @@ JsonObjectWriter* JsonObjectWriter::EndObject() { JsonObjectWriter* JsonObjectWriter::StartList(StringPiece name) { WritePrefix(name); WriteChar('['); - Push(); + PushArray(); return this; } @@ -172,8 +172,7 @@ void JsonObjectWriter::WritePrefix(StringPiece name) { bool not_first = !element()->is_first(); if (not_first) WriteChar(','); if (not_first || !element()->is_root()) NewLine(); - bool empty_key_ok = GetAndResetEmptyKeyOk(); - if (!name.empty() || empty_key_ok) { + if (!name.empty() || element()->is_json_object()) { WriteChar('"'); if (!name.empty()) { ArrayByteSource source(name); @@ -184,12 +183,6 @@ void JsonObjectWriter::WritePrefix(StringPiece name) { } } -bool JsonObjectWriter::GetAndResetEmptyKeyOk() { - bool retval = empty_name_ok_for_next_key_; - empty_name_ok_for_next_key_ = false; - return retval; -} - } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/json_objectwriter.h b/src/google/protobuf/util/internal/json_objectwriter.h index 31edc292..4c25b465 100644 --- a/src/google/protobuf/util/internal/json_objectwriter.h +++ b/src/google/protobuf/util/internal/json_objectwriter.h @@ -32,9 +32,6 @@ #define GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__ #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <string> #include <google/protobuf/io/coded_stream.h> @@ -89,46 +86,41 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { public: JsonObjectWriter(StringPiece indent_string, google::protobuf::io::CodedOutputStream* out) - : element_(new Element(NULL)), + : element_(new Element(/*parent=*/nullptr, /*is_json_object=*/false)), stream_(out), sink_(out), indent_string_(indent_string.ToString()), - use_websafe_base64_for_bytes_(false), - empty_name_ok_for_next_key_(false) {} + use_websafe_base64_for_bytes_(false) {} virtual ~JsonObjectWriter(); // ObjectWriter methods. - virtual JsonObjectWriter* StartObject(StringPiece name); - virtual JsonObjectWriter* EndObject(); - virtual JsonObjectWriter* StartList(StringPiece name); - virtual JsonObjectWriter* EndList(); - virtual JsonObjectWriter* RenderBool(StringPiece name, bool value); - virtual JsonObjectWriter* RenderInt32(StringPiece name, int32 value); - virtual JsonObjectWriter* RenderUint32(StringPiece name, uint32 value); - virtual JsonObjectWriter* RenderInt64(StringPiece name, int64 value); - virtual JsonObjectWriter* RenderUint64(StringPiece name, uint64 value); - virtual JsonObjectWriter* RenderDouble(StringPiece name, double value); - virtual JsonObjectWriter* RenderFloat(StringPiece name, float value); - virtual JsonObjectWriter* RenderString(StringPiece name, StringPiece value); - virtual JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value); - virtual JsonObjectWriter* RenderNull(StringPiece name); + virtual JsonObjectWriter* StartObject(StringPiece name) override; + virtual JsonObjectWriter* EndObject() override; + virtual JsonObjectWriter* StartList(StringPiece name) override; + virtual JsonObjectWriter* EndList() override; + virtual JsonObjectWriter* RenderBool(StringPiece name, bool value) override; + virtual JsonObjectWriter* RenderInt32(StringPiece name, int32 value) override; + virtual JsonObjectWriter* RenderUint32(StringPiece name, uint32 value) override; + virtual JsonObjectWriter* RenderInt64(StringPiece name, int64 value) override; + virtual JsonObjectWriter* RenderUint64(StringPiece name, uint64 value) override; + virtual JsonObjectWriter* RenderDouble(StringPiece name, double value) override; + virtual JsonObjectWriter* RenderFloat(StringPiece name, float value) override; + virtual JsonObjectWriter* RenderString(StringPiece name, StringPiece value) override; + virtual JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value) override; + virtual JsonObjectWriter* RenderNull(StringPiece name) override; virtual JsonObjectWriter* RenderNullAsEmpty(StringPiece name); void set_use_websafe_base64_for_bytes(bool value) { use_websafe_base64_for_bytes_ = value; } - // Whether empty strings should be rendered for the next JSON key. This - // setting is only valid until the next key is rendered, after which it gets - // reset to false. - virtual void empty_name_ok_for_next_key() { - empty_name_ok_for_next_key_ = true; - } - protected: class LIBPROTOBUF_EXPORT Element : public BaseElement { public: - explicit Element(Element* parent) : BaseElement(parent), is_first_(true) {} + Element(Element* parent, bool is_json_object) + : BaseElement(parent), + is_first_(true), + is_json_object_(is_json_object) {} // Called before each field of the Element is to be processed. // Returns true if this is the first call (processing the first field). @@ -140,23 +132,28 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { return false; } + // Whether we are currently renderring inside a JSON object (i.e., between + // StartObject() and EndObject()). + bool is_json_object() const { return is_json_object_; } + private: bool is_first_; + bool is_json_object_; GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Element); }; - virtual Element* element() { return element_.get(); } + Element* element() override { return element_.get(); } private: class LIBPROTOBUF_EXPORT ByteSinkWrapper : public strings::ByteSink { public: explicit ByteSinkWrapper(google::protobuf::io::CodedOutputStream* stream) : stream_(stream) {} - virtual ~ByteSinkWrapper() {} + ~ByteSinkWrapper() override {} // ByteSink methods. - virtual void Append(const char* bytes, size_t n) { + void Append(const char* bytes, size_t n) override { stream_->WriteRaw(bytes, n); } @@ -175,8 +172,15 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { return this; } - // Pushes a new element to the stack. - void Push() { element_.reset(new Element(element_.release())); } + // Pushes a new JSON array element to the stack. + void PushArray() { + element_.reset(new Element(element_.release(), /*is_json_object=*/false)); + } + + // Pushes a new JSON object element to the stack. + void PushObject() { + element_.reset(new Element(element_.release(), /*is_json_object=*/true)); + } // Pops an element off of the stack and deletes the popped element. void Pop() { @@ -204,11 +208,7 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { // Writes an individual character to the output. void WriteChar(const char c) { stream_->WriteRaw(&c, sizeof(c)); } - // Returns the current value of empty_name_ok_for_next_key_ and resets it to - // false. - bool GetAndResetEmptyKeyOk(); - - google::protobuf::scoped_ptr<Element> element_; + std::unique_ptr<Element> element_; google::protobuf::io::CodedOutputStream* stream_; ByteSinkWrapper sink_; const string indent_string_; @@ -217,11 +217,6 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { // to regular base64 encoding. bool use_websafe_base64_for_bytes_; - // Whether empty strings should be rendered for the next JSON key. This - // setting is only valid until the next key is rendered, after which it gets - // reset to false. - bool empty_name_ok_for_next_key_; - GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonObjectWriter); }; diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc index bbd9d78a..0dc710c7 100644 --- a/src/google/protobuf/util/internal/json_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc @@ -47,7 +47,7 @@ class JsonObjectWriterTest : public ::testing::Test { JsonObjectWriterTest() : str_stream_(new StringOutputStream(&output_)), out_stream_(new CodedOutputStream(str_stream_)), - ow_(NULL) {} + ow_(nullptr) {} virtual ~JsonObjectWriterTest() { delete ow_; @@ -95,6 +95,12 @@ TEST_F(JsonObjectWriterTest, EmptyList) { output_.substr(0, out_stream_->ByteCount())); } +TEST_F(JsonObjectWriterTest, EmptyObjectKey) { + ow_ = new JsonObjectWriter("", out_stream_); + ow_->StartObject("")->RenderString("", "value")->EndObject(); + EXPECT_EQ("{\"\":\"value\"}", output_.substr(0, out_stream_->ByteCount())); +} + TEST_F(JsonObjectWriterTest, ObjectInObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc index 2ada3583..1c63b31d 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.cc +++ b/src/google/protobuf/util/internal/json_stream_parser.cc @@ -36,9 +36,6 @@ #include <cstdlib> #include <cstring> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> @@ -157,7 +154,7 @@ util::Status JsonStreamParser::FinishParse() { } // Storage for UTF8-coerced string. - google::protobuf::scoped_array<char> utf8; + std::unique_ptr<char[]> utf8; if (coerce_to_utf8_) { utf8.reset(new char[leftover_.size()]); char* coerced = internal::UTF8CoerceToStructurallyValid(leftover_, utf8.get(), ' '); diff --git a/src/google/protobuf/util/internal/object_location_tracker.h b/src/google/protobuf/util/internal/object_location_tracker.h index 8586cecc..f9b90bc4 100644 --- a/src/google/protobuf/util/internal/object_location_tracker.h +++ b/src/google/protobuf/util/internal/object_location_tracker.h @@ -47,10 +47,10 @@ class ObjectLocationTracker : public LocationTrackerInterface { // Creates an empty location tracker. ObjectLocationTracker() {} - virtual ~ObjectLocationTracker() {} + ~ObjectLocationTracker() override {} // Returns empty because nothing is tracked. - virtual string ToString() const { return ""; } + string ToString() const override { return ""; } private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectLocationTracker); diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h index b6fbd19b..5781aa1e 100644 --- a/src/google/protobuf/util/internal/object_writer.h +++ b/src/google/protobuf/util/internal/object_writer.h @@ -119,13 +119,6 @@ class LIBPROTOBUF_EXPORT ObjectWriter { return use_strict_base64_decoding_; } - // Whether empty strings should be rendered for the next name for Start/Render - // calls. This setting is only valid until the next key is rendered, after - // which it gets reset. - // It is up to the derived classes to interpret this and render accordingly. - // Default implementation ignores this setting. - virtual void empty_name_ok_for_next_key() {} - protected: ObjectWriter() : use_strict_base64_decoding_(true) {} diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc index 8bebf2ab..b7a52db6 100644 --- a/src/google/protobuf/util/internal/proto_writer.cc +++ b/src/google/protobuf/util/internal/proto_writer.cc @@ -66,7 +66,7 @@ ProtoWriter::ProtoWriter(TypeResolver* type_resolver, done_(false), ignore_unknown_fields_(false), use_lower_camel_for_enums_(false), - element_(NULL), + element_(nullptr), size_insert_(), output_(output), buffer_(), @@ -85,7 +85,7 @@ ProtoWriter::ProtoWriter(const TypeInfo* typeinfo, done_(false), ignore_unknown_fields_(false), use_lower_camel_for_enums_(false), - element_(NULL), + element_(nullptr), size_insert_(), output_(output), buffer_(), @@ -99,14 +99,14 @@ ProtoWriter::~ProtoWriter() { if (own_typeinfo_) { delete typeinfo_; } - if (element_ == NULL) return; + if (element_ == nullptr) return; // Cleanup explicitly in order to avoid destructor stack overflow when input // is deeply nested. // Cast to BaseElement to avoid doing additional checks (like missing fields) // during pop(). - google::protobuf::scoped_ptr<BaseElement> element( + std::unique_ptr<BaseElement> element( static_cast<BaseElement*>(element_.get())->pop<BaseElement>()); - while (element != NULL) { + while (element != nullptr) { element.reset(element->pop<BaseElement>()); } } @@ -267,8 +267,9 @@ inline Status WriteString(int field_number, const DataPiece& data, inline Status WriteEnum(int field_number, const DataPiece& data, const google::protobuf::Enum* enum_type, CodedOutputStream* stream, - bool use_lower_camel_for_enums) { - StatusOr<int> e = data.ToEnum(enum_type, use_lower_camel_for_enums); + bool use_lower_camel_for_enums, + bool ignore_unknown_values) { + StatusOr<int> e = data.ToEnum(enum_type, use_lower_camel_for_enums, ignore_unknown_values); if (e.ok()) { WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream); } @@ -294,9 +295,9 @@ std::set<const google::protobuf::Field*> GetRequiredFields( ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type, ProtoWriter* enclosing) - : BaseElement(NULL), + : BaseElement(nullptr), ow_(enclosing), - parent_field_(NULL), + parent_field_(nullptr), typeinfo_(typeinfo), proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3), type_(type), @@ -374,7 +375,7 @@ ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() { // all enclosing messages. int size = ow_->size_insert_[size_index_].size; int length = CodedOutputStream::VarintSize32(size); - for (ProtoElement* e = parent(); e != NULL; e = e->parent()) { + for (ProtoElement* e = parent(); e != nullptr; e = e->parent()) { // Only nested messages have size field, lists do not have size field. if (e->size_index_ >= 0) { ow_->size_insert_[e->size_index_].size += length; @@ -394,7 +395,7 @@ void ProtoWriter::ProtoElement::RegisterField( } string ProtoWriter::ProtoElement::ToString() const { - if (parent() == NULL) return ""; + if (parent() == nullptr) return ""; string loc = parent()->ToString(); if (!ow_->IsRepeated(*parent_field_) || parent()->parent_field_ != parent_field_) { @@ -439,7 +440,7 @@ void ProtoWriter::MissingField(StringPiece missing_name) { ProtoWriter* ProtoWriter::StartObject(StringPiece name) { // Starting the root message. Create the root ProtoElement and return. - if (element_ == NULL) { + if (element_ == nullptr) { if (!name.empty()) { InvalidName(name, "Root element should not be named."); } @@ -447,9 +448,9 @@ ProtoWriter* ProtoWriter::StartObject(StringPiece name) { return this; } - const google::protobuf::Field* field = NULL; + const google::protobuf::Field* field = nullptr; field = BeginNamed(name, false); - if (field == NULL) return this; + if (field == nullptr) return this; // Check to see if this field is a oneof and that no oneof in that group has // already been set. @@ -459,7 +460,7 @@ ProtoWriter* ProtoWriter::StartObject(StringPiece name) { } const google::protobuf::Type* type = LookupType(field); - if (type == NULL) { + if (type == nullptr) { ++invalid_depth_; InvalidName(name, StrCat("Missing descriptor for field: ", field->type_url())); @@ -475,14 +476,14 @@ ProtoWriter* ProtoWriter::EndObject() { return this; } - if (element_ != NULL) { + if (element_ != nullptr) { element_.reset(element_->pop()); } // If ending the root element, // then serialize the full message with calculated sizes. - if (element_ == NULL) { + if (element_ == nullptr) { WriteRootMessage(); } return this; @@ -490,7 +491,7 @@ ProtoWriter* ProtoWriter::EndObject() { ProtoWriter* ProtoWriter::StartList(StringPiece name) { const google::protobuf::Field* field = BeginNamed(name, true); - if (field == NULL) return this; + if (field == nullptr) return this; if (!ValidOneof(*field, name)) { ++invalid_depth_; @@ -498,7 +499,7 @@ ProtoWriter* ProtoWriter::StartList(StringPiece name) { } const google::protobuf::Type* type = LookupType(field); - if (type == NULL) { + if (type == nullptr) { ++invalid_depth_; InvalidName(name, StrCat("Missing descriptor for field: ", field->type_url())); @@ -511,7 +512,7 @@ ProtoWriter* ProtoWriter::StartList(StringPiece name) { ProtoWriter* ProtoWriter::EndList() { if (invalid_depth_ > 0) { --invalid_depth_; - } else if (element_ != NULL) { + } else if (element_ != nullptr) { element_.reset(element_->pop()); } return this; @@ -523,12 +524,12 @@ ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name, if (invalid_depth_ > 0) return this; const google::protobuf::Field* field = Lookup(name); - if (field == NULL) return this; + if (field == nullptr) return this; if (!ValidOneof(*field, name)) return this; const google::protobuf::Type* type = LookupType(field); - if (type == NULL) { + if (type == nullptr) { InvalidName(name, StrCat("Missing descriptor for field: ", field->type_url())); return this; @@ -539,7 +540,7 @@ ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name, bool ProtoWriter::ValidOneof(const google::protobuf::Field& field, StringPiece unnormalized_name) { - if (element_ == NULL) return true; + if (element_ == nullptr) return true; if (field.oneof_index() > 0) { if (element_->IsOneofIndexTaken(field.oneof_index())) { @@ -665,7 +666,8 @@ ProtoWriter* ProtoWriter::RenderPrimitiveField( case google::protobuf::Field_Kind_TYPE_ENUM: { status = WriteEnum(field.number(), data, typeinfo_->GetEnumByTypeUrl(field.type_url()), - stream_.get(), use_lower_camel_for_enums_); + stream_.get(), use_lower_camel_for_enums_, + ignore_unknown_fields_); break; } default: // TYPE_GROUP or TYPE_MESSAGE @@ -692,18 +694,18 @@ const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name, bool is_list) { if (invalid_depth_ > 0) { ++invalid_depth_; - return NULL; + return nullptr; } const google::protobuf::Field* field = Lookup(name); - if (field == NULL) { + if (field == nullptr) { ++invalid_depth_; // InvalidName() already called in Lookup(). - return NULL; + return nullptr; } if (is_list && !IsRepeated(*field)) { ++invalid_depth_; InvalidName(name, "Proto field is not repeating, cannot start list."); - return NULL; + return nullptr; } return field; } @@ -711,23 +713,23 @@ const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name, const google::protobuf::Field* ProtoWriter::Lookup( StringPiece unnormalized_name) { ProtoElement* e = element(); - if (e == NULL) { + if (e == nullptr) { InvalidName(unnormalized_name, "Root element must be a message."); - return NULL; + return nullptr; } if (unnormalized_name.empty()) { // Objects in repeated field inherit the same field descriptor. - if (e->parent_field() == NULL) { + if (e->parent_field() == nullptr) { InvalidName(unnormalized_name, "Proto fields must have a name."); } else if (!IsRepeated(*e->parent_field())) { InvalidName(unnormalized_name, "Proto fields must have a name."); - return NULL; + return nullptr; } return e->parent_field(); } const google::protobuf::Field* field = typeinfo_->FindField(&e->type(), unnormalized_name); - if (field == NULL && !ignore_unknown_fields_) { + if (field == nullptr && !ignore_unknown_fields_) { InvalidName(unnormalized_name, "Cannot find field."); } return field; @@ -746,7 +748,7 @@ void ProtoWriter::WriteRootMessage() { int curr_pos = 0; // Calls the destructor of CodedOutputStream to remove any uninitialized // memory from the Cord before we read it. - stream_.reset(NULL); + stream_.reset(nullptr); const void* data; int length; google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size()); diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h index 0db8485c..5bdafcc9 100644 --- a/src/google/protobuf/util/internal/proto_writer.h +++ b/src/google/protobuf/util/internal/proto_writer.h @@ -78,43 +78,43 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { // Constructor. Does not take ownership of any parameter passed in. ProtoWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener); - virtual ~ProtoWriter(); + virtual ~ProtoWriter() override; // ObjectWriter methods. - ProtoWriter* StartObject(StringPiece name); - ProtoWriter* EndObject(); - ProtoWriter* StartList(StringPiece name); - ProtoWriter* EndList(); - ProtoWriter* RenderBool(StringPiece name, bool value) { + ProtoWriter* StartObject(StringPiece name) override; + ProtoWriter* EndObject() override; + ProtoWriter* StartList(StringPiece name) override; + ProtoWriter* EndList() override; + ProtoWriter* RenderBool(StringPiece name, bool value) override { return RenderDataPiece(name, DataPiece(value)); } - ProtoWriter* RenderInt32(StringPiece name, int32 value) { + ProtoWriter* RenderInt32(StringPiece name, int32 value) override { return RenderDataPiece(name, DataPiece(value)); } - ProtoWriter* RenderUint32(StringPiece name, uint32 value) { + ProtoWriter* RenderUint32(StringPiece name, uint32 value) override { return RenderDataPiece(name, DataPiece(value)); } - ProtoWriter* RenderInt64(StringPiece name, int64 value) { + ProtoWriter* RenderInt64(StringPiece name, int64 value) override { return RenderDataPiece(name, DataPiece(value)); } - ProtoWriter* RenderUint64(StringPiece name, uint64 value) { + ProtoWriter* RenderUint64(StringPiece name, uint64 value) override { return RenderDataPiece(name, DataPiece(value)); } - ProtoWriter* RenderDouble(StringPiece name, double value) { + ProtoWriter* RenderDouble(StringPiece name, double value) override { return RenderDataPiece(name, DataPiece(value)); } - ProtoWriter* RenderFloat(StringPiece name, float value) { + ProtoWriter* RenderFloat(StringPiece name, float value) override { return RenderDataPiece(name, DataPiece(value)); } - ProtoWriter* RenderString(StringPiece name, StringPiece value) { + ProtoWriter* RenderString(StringPiece name, StringPiece value) override { return RenderDataPiece(name, DataPiece(value, use_strict_base64_decoding())); } - virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) { + ProtoWriter* RenderBytes(StringPiece name, StringPiece value) override { return RenderDataPiece( name, DataPiece(value, false, use_strict_base64_decoding())); } - ProtoWriter* RenderNull(StringPiece name) { + ProtoWriter* RenderNull(StringPiece name) override { return RenderDataPiece(name, DataPiece::NullData()); } @@ -126,11 +126,11 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { // Returns the location tracker to use for tracking locations for errors. const LocationTrackerInterface& location() { - return element_ != NULL ? *element_ : *tracker_; + return element_ != nullptr ? *element_ : *tracker_; } // When true, we finished writing to output a complete message. - bool done() { return done_; } + bool done() override { return done_; } // Returns the proto stream object. google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); } @@ -163,7 +163,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { ProtoElement(ProtoElement* parent, const google::protobuf::Field* field, const google::protobuf::Type& type, bool is_list); - virtual ~ProtoElement() {} + virtual ~ProtoElement() override {} // Called just before the destructor for clean up: // - reports any missing required fields @@ -173,7 +173,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { ProtoElement* pop(); // Accessors - // parent_field() may be NULL if we are at root. + // parent_field() may be nullptr if we are at root. const google::protobuf::Field* parent_field() const { return parent_field_; } @@ -183,9 +183,9 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { void RegisterField(const google::protobuf::Field* field); // To report location on error messages. - virtual string ToString() const; + virtual string ToString() const override; - virtual ProtoElement* parent() const { + virtual ProtoElement* parent() const override { return static_cast<ProtoElement*>(BaseElement::parent()); } @@ -204,7 +204,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { ProtoWriter* ow_; // Describes the element as a field in the parent message. - // parent_field_ is NULL if and only if this element is the root element. + // parent_field_ is nullptr if and only if this element is the root element. const google::protobuf::Field* parent_field_; // TypeInfo to lookup types. @@ -242,7 +242,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener); - ProtoElement* element() { return element_.get(); } + ProtoElement* element() override { return element_.get(); } // Helper methods for calling ErrorListener. See error_listener.h. void InvalidName(StringPiece unknown_name, StringPiece message); @@ -259,7 +259,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { // extensions are found. const google::protobuf::Field* Lookup(StringPiece name); - // Lookup the field type in the type descriptor. Returns NULL if the type + // Lookup the field type in the type descriptor. Returns nullptr if the type // is not known. const google::protobuf::Type* LookupType( const google::protobuf::Field* field); @@ -309,7 +309,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { // Indicates whether we finished writing root message completely. bool done_; - // If true, don't report unknown field names to the listener. + // If true, don't report unknown field names and enum values to the listener. bool ignore_unknown_fields_; // If true, check if enum name in camel case or without underscore matches the @@ -321,7 +321,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { // size_insert_: sizes of nested messages. // pos - position to insert the size field. // size - size value to be inserted. - google::protobuf::scoped_ptr<ProtoElement> element_; + std::unique_ptr<ProtoElement> element_; std::deque<SizeInfo> size_insert_; // Variables for output generation: @@ -332,7 +332,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { strings::ByteSink* output_; string buffer_; google::protobuf::io::StringOutputStream adapter_; - google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_; + std::unique_ptr<google::protobuf::io::CodedOutputStream> stream_; // Variables for error tracking and reporting: // listener_ : a place to report any errors found. @@ -340,7 +340,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { // tracker_ : the root location tracker interface. ErrorListener* listener_; int invalid_depth_; - google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_; + std::unique_ptr<LocationTrackerInterface> tracker_; GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter); }; diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc index 02360a1a..b0d86c17 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource.cc @@ -73,14 +73,14 @@ namespace { static int kDefaultMaxRecursionDepth = 64; -// Finds a field with the given number. NULL if none found. +// Finds a field with the given number. nullptr if none found. const google::protobuf::Field* FindFieldByNumber( const google::protobuf::Type& type, int number); // Returns true if the field is packable. bool IsPackable(const google::protobuf::Field& field); -// Finds an enum value with the given number. NULL if none found. +// Finds an enum value with the given number. nullptr if none found. const google::protobuf::EnumValue* FindEnumValueByNumber( const google::protobuf::Enum& tech_enum, int number); @@ -127,7 +127,7 @@ ProtoStreamObjectSource::ProtoStreamObjectSource( render_unknown_fields_(false), render_unknown_enum_values_(true), add_trailing_zeros_for_timestamp_and_duration_(false) { - GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; + GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr."; } ProtoStreamObjectSource::ProtoStreamObjectSource( @@ -145,7 +145,7 @@ ProtoStreamObjectSource::ProtoStreamObjectSource( render_unknown_fields_(false), render_unknown_enum_values_(true), add_trailing_zeros_for_timestamp_and_duration_(false) { - GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; + GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr."; } ProtoStreamObjectSource::~ProtoStreamObjectSource() { @@ -165,7 +165,7 @@ const google::protobuf::Field* ProtoStreamObjectSource::FindAndVerifyField( const google::protobuf::Field* field = FindFieldByNumber(type, tag >> 3); // Verify if the field corresponds to the wire type in tag. // If there is any discrepancy, mark the field as not found. - if (field != NULL) { + if (field != nullptr) { WireFormatLite::WireType expected_type = WireFormatLite::WireTypeForFieldType( static_cast<WireFormatLite::FieldType>(field->kind())); @@ -173,7 +173,7 @@ const google::protobuf::Field* ProtoStreamObjectSource::FindAndVerifyField( if (actual_type != expected_type && (!IsPackable(*field) || actual_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) { - field = NULL; + field = nullptr; } } return field; @@ -186,11 +186,11 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type, ObjectWriter* ow) const { const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); - if (type_renderer != NULL) { + if (type_renderer != nullptr) { return (*type_renderer)(this, type, name, ow); } - const google::protobuf::Field* field = NULL; + const google::protobuf::Field* field = nullptr; string field_name; // last_tag set to dummy value that is different from tag. uint32 tag = stream_->ReadTag(), last_tag = tag + 1; @@ -203,7 +203,7 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type, if (tag != last_tag) { // Update field only if tag is changed. last_tag = tag; field = FindAndVerifyField(type, tag); - if (field != NULL) { + if (field != nullptr) { if (preserve_proto_field_names_) { field_name = field->name(); } else { @@ -211,11 +211,11 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type, } } } - if (field == NULL) { + if (field == nullptr) { // If we didn't find a field, skip this unknown tag. // TODO(wpoon): Check return boolean value. WireFormat::SkipField(stream_, tag, - render_unknown_fields_ ? &unknown_fields : NULL); + render_unknown_fields_ ? &unknown_fields : nullptr); tag = stream_->ReadTag(); continue; } @@ -282,8 +282,8 @@ StatusOr<uint32> ProtoStreamObjectSource::RenderMap( for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) { const google::protobuf::Field* field = FindAndVerifyField(*field_type, tag); - if (field == NULL) { - WireFormat::SkipField(stream_, tag, NULL); + if (field == nullptr) { + WireFormat::SkipField(stream_, tag, nullptr); continue; } // Map field numbers are key = 1 and value = 2 @@ -294,14 +294,12 @@ StatusOr<uint32> ProtoStreamObjectSource::RenderMap( // An absent map key is treated as the default. const google::protobuf::Field* key_field = FindFieldByNumber(*field_type, 1); - if (key_field == NULL) { + if (key_field == nullptr) { // The Type info for this map entry is incorrect. It should always // have a field named "key" and with field number 1. return Status(util::error::INTERNAL, "Invalid map entry."); } ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field)); - // Key is empty, force it to render as empty (for string values). - ow->empty_name_ok_for_next_key(); } RETURN_IF_ERROR(RenderField(field, map_key, ow)); } else { @@ -527,7 +525,7 @@ Status ProtoStreamObjectSource::RenderStruct(const ProtoStreamObjectSource* os, const google::protobuf::Type& type, StringPiece field_name, ObjectWriter* ow) { - const google::protobuf::Field* field = NULL; + const google::protobuf::Field* field = nullptr; uint32 tag = os->stream_->ReadTag(); ow->StartObject(field_name); while (tag != 0) { @@ -545,12 +543,12 @@ Status ProtoStreamObjectSource::RenderStruct(const ProtoStreamObjectSource* os, Status ProtoStreamObjectSource::RenderStructValue( const ProtoStreamObjectSource* os, const google::protobuf::Type& type, StringPiece field_name, ObjectWriter* ow) { - const google::protobuf::Field* field = NULL; + const google::protobuf::Field* field = nullptr; for (uint32 tag = os->stream_->ReadTag(); tag != 0; tag = os->stream_->ReadTag()) { field = os->FindAndVerifyField(type, tag); - if (field == NULL) { - WireFormat::SkipField(os->stream_, tag, NULL); + if (field == nullptr) { + WireFormat::SkipField(os->stream_, tag, nullptr); continue; } RETURN_IF_ERROR(os->RenderField(field, field_name, ow)); @@ -573,8 +571,8 @@ Status ProtoStreamObjectSource::RenderStructListValue( while (tag != 0) { const google::protobuf::Field* field = os->FindAndVerifyField(type, tag); - if (field == NULL) { - WireFormat::SkipField(os->stream_, tag, NULL); + if (field == nullptr) { + WireFormat::SkipField(os->stream_, tag, nullptr); tag = os->stream_->ReadTag(); continue; } @@ -595,8 +593,8 @@ Status ProtoStreamObjectSource::RenderAny(const ProtoStreamObjectSource* os, // First read out the type_url and value from the proto stream for (tag = os->stream_->ReadTag(); tag != 0; tag = os->stream_->ReadTag()) { const google::protobuf::Field* field = os->FindAndVerifyField(type, tag); - if (field == NULL) { - WireFormat::SkipField(os->stream_, tag, NULL); + if (field == nullptr) { + WireFormat::SkipField(os->stream_, tag, nullptr); continue; } // 'type_url' has field number of 1 and 'value' has field number 2 @@ -650,6 +648,13 @@ Status ProtoStreamObjectSource::RenderAny(const ProtoStreamObjectSource* os, // using a nested ProtoStreamObjectSource using our nested type information. ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type); + // TODO(htuch): This is somewhat fragile, since new options may be omitted. + // We should probably do this via the constructor or some object grouping + // options. + nested_os.set_use_lower_camel_for_enums(os->use_lower_camel_for_enums_); + nested_os.set_use_ints_for_enums(os->use_ints_for_enums_); + nested_os.set_preserve_proto_field_names(os->preserve_proto_field_names_); + // We manually call start and end object here so we can inject the @type. ow->StartObject(field_name); ow->RenderString("@type", type_url); @@ -669,7 +674,7 @@ Status ProtoStreamObjectSource::RenderFieldMask( tag = os->stream_->ReadTag()) { if (paths_field_tag == 0) { const google::protobuf::Field* field = os->FindAndVerifyField(type, tag); - if (field != NULL && field->number() == 1 && + if (field != nullptr && field->number() == 1 && field->name() == "paths") { paths_field_tag = tag; } @@ -756,7 +761,7 @@ Status ProtoStreamObjectSource::RenderField( // Get the nested message type for this field. const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(field->type_url()); - if (type == NULL) { + if (type == nullptr) { return Status(util::error::INTERNAL, StrCat("Invalid configuration. Could not find the type: ", field->type_url())); @@ -765,7 +770,7 @@ Status ProtoStreamObjectSource::RenderField( // Short-circuit any special type rendering to save call-stack space. const TypeRenderer* type_renderer = FindTypeRenderer(type->name()); - bool use_type_renderer = type_renderer != NULL; + bool use_type_renderer = type_renderer != nullptr; if (use_type_renderer) { RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow)); @@ -875,14 +880,15 @@ Status ProtoStreamObjectSource::RenderNonMessageField( typeinfo_->GetEnumByTypeUrl(field->type_url()); // Lookup the name of the enum, and render that. Unknown enum values // are printed as integers. - if (en != NULL) { + if (en != nullptr) { const google::protobuf::EnumValue* enum_value = FindEnumValueByNumber(*en, buffer32); - if (enum_value != NULL) { + if (enum_value != nullptr) { if (use_ints_for_enums_) { ow->RenderInt32(field_name, buffer32); } else if (use_lower_camel_for_enums_) { - ow->RenderString(field_name, ToCamelCase(enum_value->name())); + ow->RenderString(field_name, + EnumValueNameToLowerCamelCase(enum_value->name())); } else { ow->RenderString(field_name, enum_value->name()); } @@ -1004,10 +1010,10 @@ const string ProtoStreamObjectSource::ReadFieldValueAsString( const google::protobuf::Enum* en = typeinfo_->GetEnumByTypeUrl(field.type_url()); // Lookup the name of the enum, and render that. Skips unknown enums. - if (en != NULL) { + if (en != nullptr) { const google::protobuf::EnumValue* enum_value = FindEnumValueByNumber(*en, buffer32); - if (enum_value != NULL) { + if (enum_value != nullptr) { result = enum_value->name(); } } @@ -1051,8 +1057,8 @@ std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos( for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) { const google::protobuf::Field* field = FindAndVerifyField(type, tag); - if (field == NULL) { - WireFormat::SkipField(stream_, tag, NULL); + if (field == nullptr) { + WireFormat::SkipField(stream_, tag, nullptr); continue; } // 'seconds' has field number of 1 and 'nanos' has field number 2 @@ -1090,7 +1096,7 @@ const google::protobuf::Field* FindFieldByNumber( return &type.fields(i); } } - return NULL; + return nullptr; } // TODO(skarvaje): Replace FieldDescriptor by implementing IsTypePackable() @@ -1111,7 +1117,7 @@ const google::protobuf::EnumValue* FindEnumValueByNumber( return &ev; } } - return NULL; + return nullptr; } // TODO(skarvaje): Look into optimizing this by not doing computation on diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h index b56efdf4..acd081d9 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.h +++ b/src/google/protobuf/util/internal/protostream_objectsource.h @@ -78,9 +78,9 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { TypeResolver* type_resolver, const google::protobuf::Type& type); - virtual ~ProtoStreamObjectSource(); + virtual ~ProtoStreamObjectSource() override; - virtual util::Status NamedWriteTo(StringPiece name, ObjectWriter* ow) const; + virtual util::Status NamedWriteTo(StringPiece name, ObjectWriter* ow) const override; // Sets whether or not to use lowerCamelCase casing for enum values. If set to // false, enum values are output without any case conversions. diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc index 36bb1ba9..4d86b856 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc @@ -31,9 +31,6 @@ #include <google/protobuf/util/internal/protostream_objectsource.h> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <sstream> #include <google/protobuf/stubs/casts.h> @@ -103,6 +100,7 @@ class ProtostreamObjectSourceTest ow_(&mock_), use_lower_camel_for_enums_(false), use_ints_for_enums_(false), + use_preserve_proto_field_names_(false), add_trailing_zeros_(false), render_unknown_enum_values_(true) { helper_.ResetTypeInfo(Book::descriptor(), Proto3Message::descriptor()); @@ -122,10 +120,11 @@ class ProtostreamObjectSourceTest ArrayInputStream arr_stream(proto.data(), proto.size()); CodedInputStream in_stream(&arr_stream); - google::protobuf::scoped_ptr<ProtoStreamObjectSource> os( + std::unique_ptr<ProtoStreamObjectSource> os( helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor))); if (use_lower_camel_for_enums_) os->set_use_lower_camel_for_enums(true); if (use_ints_for_enums_) os->set_use_ints_for_enums(true); + if (use_preserve_proto_field_names_) os->set_preserve_proto_field_names(true); os->set_max_recursion_depth(64); return os->WriteTo(&mock_); } @@ -275,6 +274,8 @@ class ProtostreamObjectSourceTest void UseIntsForEnums() { use_ints_for_enums_ = true; } + void UsePreserveProtoFieldNames() { use_preserve_proto_field_names_ = true; } + void AddTrailingZeros() { add_trailing_zeros_ = true; } void SetRenderUnknownEnumValues(bool value) { @@ -287,6 +288,7 @@ class ProtostreamObjectSourceTest ExpectingObjectWriter ow_; bool use_lower_camel_for_enums_; bool use_ints_for_enums_; + bool use_preserve_proto_field_names_; bool add_trailing_zeros_; bool render_unknown_enum_values_; }; @@ -490,7 +492,7 @@ TEST_P(ProtostreamObjectSourceTest, DoTest(book, Book::descriptor()); } -TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputTest) { +TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputMacroCase) { Book book; book.set_type(Book::ACTION_AND_ADVENTURE); @@ -500,6 +502,26 @@ TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputTest) { DoTest(book, Book::descriptor()); } +TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputSnakeCase) { + Book book; + book.set_type(Book::arts_and_photography); + + UseLowerCamelForEnums(); + + ow_.StartObject("")->RenderString("type", "artsAndPhotography")->EndObject(); + DoTest(book, Book::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputWithNumber) { + Book book; + book.set_type(Book::I18N_Tech); + + UseLowerCamelForEnums(); + + ow_.StartObject("")->RenderString("type", "i18nTech")->EndObject(); + DoTest(book, Book::descriptor()); +} + TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) { Book book; book.set_type(Book::ACTION_AND_ADVENTURE); @@ -519,6 +541,16 @@ TEST_P(ProtostreamObjectSourceTest, UseIntsForEnumsTest) { DoTest(book, Book::descriptor()); } +TEST_P(ProtostreamObjectSourceTest, UsePreserveProtoFieldNames) { + Book book; + book.set_snake_field("foo"); + + UsePreserveProtoFieldNames(); + + ow_.StartObject("")->RenderString("snake_field", "foo")->EndObject(); + DoTest(book, Book::descriptor()); +} + TEST_P(ProtostreamObjectSourceTest, UnknownEnumAreDroppedWhenRenderUnknownEnumValuesIsUnset) { Proto3Message message; @@ -752,6 +784,69 @@ TEST_P(ProtostreamObjectSourceAnysTest, BasicAny) { DoTest(out, AnyOut::descriptor()); } +TEST_P(ProtostreamObjectSourceAnysTest, LowerCamelEnumOutputSnakeCase) { + AnyOut out; + ::google::protobuf::Any* any = out.mutable_any(); + + Book book; + book.set_type(Book::arts_and_photography); + any->PackFrom(book); + + UseLowerCamelForEnums(); + + ow_.StartObject("") + ->StartObject("any") + ->RenderString("@type", + "type.googleapis.com/google.protobuf.testing.Book") + ->RenderString("type", "artsAndPhotography") + ->EndObject() + ->EndObject(); + + DoTest(out, AnyOut::descriptor()); +} + +TEST_P(ProtostreamObjectSourceAnysTest, UseIntsForEnumsTest) { + AnyOut out; + ::google::protobuf::Any* any = out.mutable_any(); + + Book book; + book.set_type(Book::ACTION_AND_ADVENTURE); + any->PackFrom(book); + + UseIntsForEnums(); + + ow_.StartObject("") + ->StartObject("any") + ->RenderString("@type", + "type.googleapis.com/google.protobuf.testing.Book") + ->RenderInt32("type", 3) + ->EndObject() + ->EndObject(); + + DoTest(out, AnyOut::descriptor()); +} + +TEST_P(ProtostreamObjectSourceAnysTest, UsePreserveProtoFieldNames) { + AnyOut out; + ::google::protobuf::Any* any = out.mutable_any(); + + Book book; + book.set_snake_field("foo"); + any->PackFrom(book); + + UsePreserveProtoFieldNames(); + + ow_.StartObject("") + ->StartObject("any") + ->RenderString("@type", + "type.googleapis.com/google.protobuf.testing.Book") + ->RenderString("snake_field", "foo") + ->EndObject() + ->EndObject(); + + DoTest(out, AnyOut::descriptor()); +} + TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) { AnyOut out; ::google::protobuf::Any* any = out.mutable_any(); diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc index 97f96819..a1a7030a 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc @@ -62,7 +62,7 @@ ProtoStreamObjectWriter::ProtoStreamObjectWriter( const ProtoStreamObjectWriter::Options& options) : ProtoWriter(type_resolver, type, output, listener), master_type_(type), - current_(NULL), + current_(nullptr), options_(options) { set_ignore_unknown_fields(options_.ignore_unknown_fields); set_use_lower_camel_for_enums(options_.use_lower_camel_for_enums); @@ -73,18 +73,18 @@ ProtoStreamObjectWriter::ProtoStreamObjectWriter( strings::ByteSink* output, ErrorListener* listener) : ProtoWriter(typeinfo, type, output, listener), master_type_(type), - current_(NULL), + current_(nullptr), options_(ProtoStreamObjectWriter::Options::Defaults()) {} ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { - if (current_ == NULL) return; + if (current_ == nullptr) return; // Cleanup explicitly in order to avoid destructor stack overflow when input // is deeply nested. // Cast to BaseElement to avoid doing additional checks (like missing fields) // during pop(). - google::protobuf::scoped_ptr<BaseElement> element( + std::unique_ptr<BaseElement> element( static_cast<BaseElement*>(current_.get())->pop<BaseElement>()); - while (element != NULL) { + while (element != nullptr) { element.reset(element->pop<BaseElement>()); } } @@ -186,7 +186,7 @@ ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent) output_(&data_), depth_(0), is_well_known_type_(false), - well_known_type_render_(NULL) {} + well_known_type_render_(nullptr) {} ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {} @@ -195,7 +195,7 @@ void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) { // 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. - if (ow_ == NULL) { + if (ow_ == nullptr) { // 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) { @@ -217,7 +217,7 @@ void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) { bool ProtoStreamObjectWriter::AnyWriter::EndObject() { --depth_; - if (ow_ == NULL) { + if (ow_ == nullptr) { if (depth_ >= 0) { // Save data before the "@type" field for later replay. uninterpreted_events_.push_back(Event(Event::END_OBJECT)); @@ -239,7 +239,7 @@ bool ProtoStreamObjectWriter::AnyWriter::EndObject() { void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) { ++depth_; - if (ow_ == NULL) { + if (ow_ == nullptr) { // 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) { @@ -260,7 +260,7 @@ void ProtoStreamObjectWriter::AnyWriter::EndList() { GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible"; depth_ = 0; } - if (ow_ == NULL) { + if (ow_ == nullptr) { // Save data before the "@type" field for later replay. uninterpreted_events_.push_back(Event(Event::END_LIST)); } else { @@ -272,9 +272,9 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece( StringPiece name, const DataPiece& value) { // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type" // should go to the contained ow_ as they indicate nested Anys. - if (depth_ == 0 && ow_ == NULL && name == "@type") { + if (depth_ == 0 && ow_ == nullptr && name == "@type") { StartAny(value); - } else if (ow_ == NULL) { + } else if (ow_ == nullptr) { // Save data before the "@type" field. uninterpreted_events_.push_back(Event(name, value)); } else if (depth_ == 0 && is_well_known_type_) { @@ -283,7 +283,7 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece( "Expect a \"value\" field for well-known types."); invalid_ = true; } - if (well_known_type_render_ == NULL) { + if (well_known_type_render_ == nullptr) { // 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_) { @@ -327,7 +327,7 @@ void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) { const google::protobuf::Type* type = resolved_type.ValueOrDie(); well_known_type_render_ = FindTypeRenderer(type_url_); - if (well_known_type_render_ != NULL || + if (well_known_type_render_ != nullptr || // Explicitly list Any and Struct here because they don't have a // custom renderer. type->name() == kAnyType || type->name() == kStructType) { @@ -360,7 +360,7 @@ void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) { } void ProtoStreamObjectWriter::AnyWriter::WriteAny() { - if (ow_ == NULL) { + if (ow_ == nullptr) { if (uninterpreted_events_.empty()) { // We never got any content, so just return immediately, which is // equivalent to writing an empty Any. @@ -421,7 +421,7 @@ void ProtoStreamObjectWriter::AnyWriter::Event::DeepCopy() { ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing, ItemType item_type, bool is_placeholder, bool is_list) - : BaseElement(NULL), + : BaseElement(nullptr), ow_(enclosing), any_(), item_type_(item_type), @@ -467,7 +467,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( // Starting the root message. Create the root Item and return. // ANY message type does not need special handling, just set the ItemType // to ANY. - if (current_ == NULL) { + if (current_ == nullptr) { ProtoWriter::StartObject(name); current_.reset(new Item( this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE, @@ -534,21 +534,21 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( Push("", Item::MESSAGE, false, false); ProtoWriter::RenderDataPiece("key", DataPiece(name, use_strict_base64_decoding())); - Push("value", Item::MESSAGE, true, false); + Push("value", IsAny(*Lookup("value")) ? Item::ANY : Item::MESSAGE, true, false); // Make sure we are valid so far after starting map fields. if (invalid_depth() > 0) return this; // If top of stack is g.p.Struct type, start the struct the map field within // it. - if (element() != NULL && IsStruct(*element()->parent_field())) { + if (element() != nullptr && IsStruct(*element()->parent_field())) { // Render "fields": [ Push("fields", Item::MAP, true, true); return this; } // If top of stack is g.p.Value type, start the Struct within it. - if (element() != NULL && IsStructValue(*element()->parent_field())) { + if (element() != nullptr && IsStructValue(*element()->parent_field())) { // Render // "struct_value": { // "fields": [ @@ -559,7 +559,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( } const google::protobuf::Field* field = BeginNamed(name, false); - if (field == NULL) return this; + if (field == nullptr) return this; if (IsStruct(*field)) { // Start a struct object. @@ -607,7 +607,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() { return this; } - if (current_ == NULL) return this; + if (current_ == nullptr) return this; if (current_->IsAny()) { if (current_->any()->EndObject()) return this; @@ -627,7 +627,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { // Since we cannot have a top-level repeated item in protobuf, the only way // this is valid is if we start a special type google.protobuf.ListValue or // google.protobuf.Value. - if (current_ == NULL) { + if (current_ == nullptr) { if (!name.empty()) { InvalidName(name, "Root element should not be named."); IncrementInvalidDepth(); @@ -706,7 +706,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { if (invalid_depth() > 0) return this; // case i and ii above. Start "list_value" field within g.p.Value - if (element() != NULL && element()->parent_field() != NULL) { + if (element() != nullptr && element()->parent_field() != nullptr) { // Render // "list_value": { // "values": [ // Start this list @@ -734,7 +734,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { // When name is empty and stack is not empty, we are rendering an item within // a list. if (name.empty()) { - if (element() != NULL && element()->parent_field() != NULL) { + if (element() != nullptr && element()->parent_field() != nullptr) { if (IsStructValue(*element()->parent_field())) { // Since it is g.p.Value, we bind directly to the list_value. // Render @@ -765,7 +765,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { // name is not empty const google::protobuf::Field* field = Lookup(name); - if (field == NULL) { + if (field == nullptr) { IncrementInvalidDepth(); return this; } @@ -837,7 +837,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() { return this; } - if (current_ == NULL) return this; + if (current_ == nullptr) return this; if (current_->IsAny()) { current_->any()->EndList(); @@ -961,7 +961,7 @@ Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, // TODO(tsun): figure out how to do proto descriptor based snake case // conversions as much as possible. Because ToSnakeCase sometimes returns the // wrong value. - google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback( + std::unique_ptr<ResultCallback1<util::Status, StringPiece> > callback( ::google::protobuf::NewPermanentCallback(&RenderOneFieldPath, ow)); return DecodeCompactFieldMaskPaths(data.str(), callback.get()); } @@ -977,13 +977,13 @@ Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow, StringPiece value(data.str()); - if (!value.ends_with("s")) { + if (!StringEndsWith(value, "s")) { return Status(INVALID_ARGUMENT, "Illegal duration format; duration must end with 's'"); } value = value.substr(0, value.size() - 1); int sign = 1; - if (value.starts_with("-")) { + if (StringStartsWith(value, "-")) { sign = -1; value = value.substr(1); } @@ -1028,10 +1028,10 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( Status status; if (invalid_depth() > 0) return this; - if (current_ == NULL) { + if (current_ == nullptr) { const TypeRenderer* type_renderer = FindTypeRenderer(GetFullTypeWithUrl(master_type_.name())); - if (type_renderer == NULL) { + if (type_renderer == nullptr) { InvalidName(name, "Root element must be a message."); return this; } @@ -1054,7 +1054,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( return this; } - const google::protobuf::Field* field = NULL; + const google::protobuf::Field* field = nullptr; if (current_->IsMap()) { if (!ValidMapKey(name)) return this; @@ -1064,14 +1064,14 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( ProtoWriter::RenderDataPiece("key", DataPiece(name, use_strict_base64_decoding())); field = Lookup("value"); - if (field == NULL) { + if (field == nullptr) { Pop(); GOOGLE_LOG(DFATAL) << "Map does not have a value field."; return this; } const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); - if (type_renderer != NULL) { + if (type_renderer != nullptr) { // Map's value type is a special type. Render it like a message: // "value": { // ... Render special type ... @@ -1101,11 +1101,11 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( } field = Lookup(name); - if (field == NULL) return this; + if (field == nullptr) return this; // 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) { + if (type_renderer != nullptr) { // 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 || @@ -1199,7 +1199,7 @@ ProtoStreamObjectWriter::FindTypeRenderer(const string& type_url) { } bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) { - if (current_ == NULL) return true; + if (current_ == nullptr) return true; if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) { listener()->InvalidName( @@ -1224,10 +1224,10 @@ void ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type, void ProtoStreamObjectWriter::Pop() { // Pop all placeholder items sending StartObject or StartList events to // ProtoWriter according to is_list value. - while (current_ != NULL && current_->is_placeholder()) { + while (current_ != nullptr && current_->is_placeholder()) { PopOneElement(); } - if (current_ != NULL) { + if (current_ != nullptr) { PopOneElement(); } } diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h index ab534912..d9bb432e 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.h +++ b/src/google/protobuf/util/internal/protostream_objectwriter.h @@ -112,18 +112,18 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { strings::ByteSink* output, ErrorListener* listener, const ProtoStreamObjectWriter::Options& options = ProtoStreamObjectWriter::Options::Defaults()); - virtual ~ProtoStreamObjectWriter(); + virtual ~ProtoStreamObjectWriter() override; // ObjectWriter methods. - virtual ProtoStreamObjectWriter* StartObject(StringPiece name); - virtual ProtoStreamObjectWriter* EndObject(); - virtual ProtoStreamObjectWriter* StartList(StringPiece name); - virtual ProtoStreamObjectWriter* EndList(); + virtual ProtoStreamObjectWriter* StartObject(StringPiece name) override; + virtual ProtoStreamObjectWriter* EndObject() override; + virtual ProtoStreamObjectWriter* StartList(StringPiece name) override; + virtual ProtoStreamObjectWriter* EndList() override; // Renders a DataPiece 'value' into a field whose wire type is determined // from the given field 'name'. virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name, - const DataPiece& value); + const DataPiece& value) override; protected: // Function that renders a well known type with modified behavior. @@ -216,7 +216,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { ProtoStreamObjectWriter* parent_; // The nested object writer, used to write events. - google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_; + std::unique_ptr<ProtoStreamObjectWriter> ow_; // The type_url_ that this Any represents. string type_url_; @@ -263,7 +263,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { // Constructor for a field of a message. Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list); - virtual ~Item() {} + virtual ~Item() override {} // These functions return true if the element type is corresponding to the // type in function name. @@ -272,7 +272,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { AnyWriter* any() const { return any_.get(); } - virtual Item* parent() const { + virtual Item* parent() const override { return static_cast<Item*>(BaseElement::parent()); } @@ -292,14 +292,14 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { ProtoStreamObjectWriter* ow_; // A writer for Any objects, handles all Any-related nonsense. - google::protobuf::scoped_ptr<AnyWriter> any_; + std::unique_ptr<AnyWriter> any_; // The type of this element, see enum for permissible types. ItemType item_type_; // Set of map keys already seen for the type_. Used to validate incoming // messages so no map key appears more than once. - google::protobuf::scoped_ptr<hash_set<string> > map_keys_; + std::unique_ptr<hash_set<string> > map_keys_; // Conveys whether this Item is a placeholder or not. Placeholder items are // pushed to stack to account for special types. @@ -392,7 +392,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { const google::protobuf::Type& master_type_; // The current element, variable for internal state processing. - google::protobuf::scoped_ptr<Item> current_; + std::unique_ptr<Item> current_; // Reference to the options that control this class's behavior. const ProtoStreamObjectWriter::Options options_; diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc index 87d35b08..9c50e7dd 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc @@ -146,7 +146,7 @@ class BaseProtoStreamObjectWriterTest void CheckOutput(const Message& expected, int expected_length) { size_t nbytes; - google::protobuf::scoped_array<char> buffer(output_->GetBuffer(&nbytes)); + std::unique_ptr<char[]> buffer(output_->GetBuffer(&nbytes)); if (expected_length >= 0) { EXPECT_EQ(expected_length, nbytes); } @@ -154,7 +154,7 @@ class BaseProtoStreamObjectWriterTest std::stringbuf str_buf(str, std::ios_base::in); std::istream istream(&str_buf); - google::protobuf::scoped_ptr<Message> message(expected.New()); + std::unique_ptr<Message> message(expected.New()); message->ParsePartialFromIstream(&istream); if (!MessageDifferencer::Equivalent(expected, *message)) { @@ -170,8 +170,8 @@ class BaseProtoStreamObjectWriterTest testing::TypeInfoTestHelper helper_; MockErrorListener listener_; - google::protobuf::scoped_ptr<GrowingArrayByteSink> output_; - google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_; + std::unique_ptr<GrowingArrayByteSink> output_; + std::unique_ptr<ProtoStreamObjectWriter> ow_; ProtoStreamObjectWriter::Options options_; }; @@ -1679,6 +1679,22 @@ TEST_P(ProtoStreamObjectWriterMapTest, RepeatedMapKeyTest) { ->EndObject(); } +TEST_P(ProtoStreamObjectWriterMapTest, AnyInMap) { + MapIn mm; + google::protobuf::DoubleValue d; + d.set_value(40.2); + (*mm.mutable_map_any())["foo"].PackFrom(d); + ow_->StartObject("") + ->StartObject("map_any") + ->StartObject("foo") + ->RenderString("@type", "type.googleapis.com/google.protobuf.DoubleValue") + ->RenderDouble("value", 40.2) + ->EndObject() + ->EndObject() + ->EndObject(); + CheckOutput(mm); +} + class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest { protected: ProtoStreamObjectWriterAnyTest() { diff --git a/src/google/protobuf/util/internal/structured_objectwriter.h b/src/google/protobuf/util/internal/structured_objectwriter.h index 3f065d6b..8e63222b 100644 --- a/src/google/protobuf/util/internal/structured_objectwriter.h +++ b/src/google/protobuf/util/internal/structured_objectwriter.h @@ -32,9 +32,6 @@ #define GOOGLE_PROTOBUF_UTIL_CONVERTER_STRUCTURED_OBJECTWRITER_H__ #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <google/protobuf/stubs/casts.h> #include <google/protobuf/stubs/common.h> @@ -80,7 +77,7 @@ class LIBPROTOBUF_EXPORT StructuredObjectWriter : public ObjectWriter { } // Returns true if this element is the root. - bool is_root() const { return parent_ == NULL; } + bool is_root() const { return parent_ == nullptr; } // Returns the number of hops from this element to the root element. int level() const { return level_; } @@ -91,10 +88,10 @@ class LIBPROTOBUF_EXPORT StructuredObjectWriter : public ObjectWriter { private: // Pointer to the parent Element. - google::protobuf::scoped_ptr<BaseElement> parent_; + std::unique_ptr<BaseElement> parent_; // Number of hops to the root Element. - // The root Element has NULL parent_ and a level_ of 0. + // The root Element has nullptr parent_ and a level_ of 0. const int level_; GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(BaseElement); diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto index 869271f4..5e08a291 100644 --- a/src/google/protobuf/util/internal/testdata/books.proto +++ b/src/google/protobuf/util/internal/testdata/books.proto @@ -65,9 +65,13 @@ message Book { KIDS = 2; ACTION_AND_ADVENTURE = 3; arts_and_photography = 4; + I18N_Tech = 5; } optional Type type = 11; + // Useful for testing JSON snake/camel-case conversions. + optional string snake_field = 12; + extensions 200 to 499; } diff --git a/src/google/protobuf/util/internal/testdata/maps.proto b/src/google/protobuf/util/internal/testdata/maps.proto index 0f381b32..765254ea 100644 --- a/src/google/protobuf/util/internal/testdata/maps.proto +++ b/src/google/protobuf/util/internal/testdata/maps.proto @@ -32,6 +32,8 @@ syntax = "proto3"; package google.protobuf.testing; +import "google/protobuf/any.proto"; + // Top-level test cases proto used by MarshallingTest. See description // at the top of the class MarshallingTest for details on how to write // test cases. @@ -103,6 +105,7 @@ message MapIn { string other = 1; repeated string things = 2; map<string, string> map_input = 3; + map<string, google.protobuf.Any> map_any = 4; } message MapOut { diff --git a/src/google/protobuf/util/internal/type_info.cc b/src/google/protobuf/util/internal/type_info.cc index 85d0d5c9..e32e71d0 100644 --- a/src/google/protobuf/util/internal/type_info.cc +++ b/src/google/protobuf/util/internal/type_info.cc @@ -59,7 +59,7 @@ class TypeInfoForTypeResolver : public TypeInfo { } virtual util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl( - StringPiece type_url) const { + StringPiece type_url) const override { std::map<StringPiece, StatusOrType>::iterator it = cached_types_.find(type_url); if (it != cached_types_.end()) { @@ -69,7 +69,7 @@ class TypeInfoForTypeResolver : public TypeInfo { // cached_types_ map. const string& string_type_url = *string_storage_.insert(type_url.ToString()).first; - google::protobuf::scoped_ptr<google::protobuf::Type> type(new google::protobuf::Type()); + std::unique_ptr<google::protobuf::Type> type(new google::protobuf::Type()); util::Status status = type_resolver_->ResolveMessageType(string_type_url, type.get()); StatusOrType result = @@ -79,13 +79,13 @@ class TypeInfoForTypeResolver : public TypeInfo { } virtual const google::protobuf::Type* GetTypeByTypeUrl( - StringPiece type_url) const { + StringPiece type_url) const override { StatusOrType result = ResolveTypeUrl(type_url); return result.ok() ? result.ValueOrDie() : NULL; } virtual const google::protobuf::Enum* GetEnumByTypeUrl( - StringPiece type_url) const { + StringPiece type_url) const override { std::map<StringPiece, StatusOrEnum>::iterator it = cached_enums_.find(type_url); if (it != cached_enums_.end()) { @@ -95,7 +95,7 @@ class TypeInfoForTypeResolver : public TypeInfo { // cached_enums_ map. const string& string_type_url = *string_storage_.insert(type_url.ToString()).first; - google::protobuf::scoped_ptr<google::protobuf::Enum> enum_type( + std::unique_ptr<google::protobuf::Enum> enum_type( new google::protobuf::Enum()); util::Status status = type_resolver_->ResolveEnumType(string_type_url, enum_type.get()); @@ -105,8 +105,10 @@ class TypeInfoForTypeResolver : public TypeInfo { return result.ok() ? result.ValueOrDie() : NULL; } + virtual const google::protobuf::Field* FindField( - const google::protobuf::Type* type, StringPiece camel_case_name) const { + const google::protobuf::Type* type, + StringPiece camel_case_name) const override { std::map<const google::protobuf::Type*, CamelCaseNameTable>::const_iterator it = indexed_types_.find(type); const CamelCaseNameTable& camel_case_name_table = diff --git a/src/google/protobuf/util/internal/type_info_test_helper.cc b/src/google/protobuf/util/internal/type_info_test_helper.cc index 737ba9e4..281a7f58 100644 --- a/src/google/protobuf/util/internal/type_info_test_helper.cc +++ b/src/google/protobuf/util/internal/type_info_test_helper.cc @@ -31,9 +31,6 @@ #include <google/protobuf/util/internal/type_info_test_helper.h> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <vector> #include <google/protobuf/stubs/logging.h> diff --git a/src/google/protobuf/util/internal/type_info_test_helper.h b/src/google/protobuf/util/internal/type_info_test_helper.h index 1a196715..5a077e04 100644 --- a/src/google/protobuf/util/internal/type_info_test_helper.h +++ b/src/google/protobuf/util/internal/type_info_test_helper.h @@ -32,9 +32,6 @@ #define GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_TEST_HELPER_H__ #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <vector> #include <google/protobuf/io/coded_stream.h> @@ -86,8 +83,8 @@ class TypeInfoTestHelper { private: TypeInfoSource type_; - google::protobuf::scoped_ptr<TypeInfo> typeinfo_; - google::protobuf::scoped_ptr<TypeResolver> type_resolver_; + std::unique_ptr<TypeInfo> typeinfo_; + std::unique_ptr<TypeResolver> type_resolver_; }; } // namespace testing } // namespace converter diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc index 11780ee8..b8d917ce 100644 --- a/src/google/protobuf/util/internal/utility.cc +++ b/src/google/protobuf/util/internal/utility.cc @@ -52,7 +52,7 @@ bool GetBoolOptionOrDefault( const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, const string& option_name, bool default_value) { const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); - if (opt == NULL) { + if (opt == nullptr) { return default_value; } return GetBoolFromAny(opt->value()); @@ -62,7 +62,7 @@ int64 GetInt64OptionOrDefault( const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, const string& option_name, int64 default_value) { const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); - if (opt == NULL) { + if (opt == nullptr) { return default_value; } return GetInt64FromAny(opt->value()); @@ -72,7 +72,7 @@ double GetDoubleOptionOrDefault( const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, const string& option_name, double default_value) { const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); - if (opt == NULL) { + if (opt == nullptr) { return default_value; } return GetDoubleFromAny(opt->value()); @@ -82,7 +82,7 @@ string GetStringOptionOrDefault( const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, const string& option_name, const string& default_value) { const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); - if (opt == NULL) { + if (opt == nullptr) { return default_value; } return GetStringFromAny(opt->value()); @@ -144,12 +144,12 @@ const google::protobuf::Option* FindOptionOrNull( return &opt; } } - return NULL; + return nullptr; } const google::protobuf::Field* FindFieldInTypeOrNull( const google::protobuf::Type* type, StringPiece field_name) { - if (type != NULL) { + if (type != nullptr) { for (int i = 0; i < type->fields_size(); ++i) { const google::protobuf::Field& field = type->fields(i); if (field.name() == field_name) { @@ -157,12 +157,12 @@ const google::protobuf::Field* FindFieldInTypeOrNull( } } } - return NULL; + return nullptr; } const google::protobuf::Field* FindJsonFieldInTypeOrNull( const google::protobuf::Type* type, StringPiece json_name) { - if (type != NULL) { + if (type != nullptr) { for (int i = 0; i < type->fields_size(); ++i) { const google::protobuf::Field& field = type->fields(i); if (field.json_name() == json_name) { @@ -170,12 +170,12 @@ const google::protobuf::Field* FindJsonFieldInTypeOrNull( } } } - return NULL; + return nullptr; } const google::protobuf::Field* FindFieldInTypeByNumberOrNull( const google::protobuf::Type* type, int32 number) { - if (type != NULL) { + if (type != nullptr) { for (int i = 0; i < type->fields_size(); ++i) { const google::protobuf::Field& field = type->fields(i); if (field.number() == number) { @@ -183,12 +183,12 @@ const google::protobuf::Field* FindFieldInTypeByNumberOrNull( } } } - return NULL; + return nullptr; } const google::protobuf::EnumValue* FindEnumValueByNameOrNull( const google::protobuf::Enum* enum_type, StringPiece enum_name) { - if (enum_type != NULL) { + if (enum_type != nullptr) { for (int i = 0; i < enum_type->enumvalue_size(); ++i) { const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i); if (enum_value.name() == enum_name) { @@ -196,12 +196,12 @@ const google::protobuf::EnumValue* FindEnumValueByNameOrNull( } } } - return NULL; + return nullptr; } const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( const google::protobuf::Enum* enum_type, int32 value) { - if (enum_type != NULL) { + if (enum_type != nullptr) { for (int i = 0; i < enum_type->enumvalue_size(); ++i) { const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i); if (enum_value.number() == value) { @@ -209,12 +209,12 @@ const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( } } } - return NULL; + return nullptr; } const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull( const google::protobuf::Enum* enum_type, StringPiece enum_name) { - if (enum_type != NULL) { + if (enum_type != nullptr) { for (int i = 0; i < enum_type->enumvalue_size(); ++i) { const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i); string enum_name_without_underscore = enum_value.name(); @@ -235,7 +235,14 @@ const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull( } } } - return NULL; + return nullptr; +} + +string EnumValueNameToLowerCamelCase(const StringPiece input) { + string input_string(input); + std::transform(input_string.begin(), input_string.end(), input_string.begin(), + ::tolower); + return ToCamelCase(input_string); } string ToCamelCase(const StringPiece input) { @@ -353,8 +360,6 @@ bool IsMap(const google::protobuf::Field& field, google::protobuf::Field_Cardinality_CARDINALITY_REPEATED && (GetBoolOptionOrDefault(type.options(), "map_entry", false) || GetBoolOptionOrDefault(type.options(), - "google.protobuf.MessageOptions.map_entry", false) || - GetBoolOptionOrDefault(type.options(), "google.protobuf.MessageOptions.map_entry", false)); } @@ -362,9 +367,6 @@ bool IsMap(const google::protobuf::Field& field, bool IsMessageSetWireFormat(const google::protobuf::Type& type) { return GetBoolOptionOrDefault(type.options(), "message_set_wire_format", false) || - GetBoolOptionOrDefault(type.options(), - "google.protobuf.MessageOptions.message_set_wire_format", - false) || GetBoolOptionOrDefault( type.options(), "google.protobuf.MessageOptions.message_set_wire_format", false); @@ -403,6 +405,13 @@ bool SafeStrToFloat(StringPiece str, float* value) { return true; } +bool StringStartsWith(StringPiece text, StringPiece prefix) { + return text.starts_with(prefix); +} + +bool StringEndsWith(StringPiece text, StringPiece suffix) { + return text.ends_with(suffix); +} } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h index 667e660c..d8e06a97 100644 --- a/src/google/protobuf/util/internal/utility.h +++ b/src/google/protobuf/util/internal/utility.h @@ -32,9 +32,6 @@ #define GOOGLE_PROTOBUF_UTIL_CONVERTER_UTILITY_H__ #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <string> #include <utility> @@ -121,13 +118,13 @@ LIBPROTOBUF_EXPORT const StringPiece GetTypeWithoutUrl(StringPiece type_url); LIBPROTOBUF_EXPORT const string GetFullTypeWithUrl(StringPiece simple_type); // Finds and returns option identified by name and option_name within the -// provided map. Returns NULL if none found. +// provided map. Returns nullptr if none found. const google::protobuf::Option* FindOptionOrNull( const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, const string& option_name); // Finds and returns the field identified by field_name in the passed tech Type -// object. Returns NULL if none found. +// object. Returns nullptr if none found. const google::protobuf::Field* FindFieldInTypeOrNull( const google::protobuf::Type* type, StringPiece field_name); @@ -141,17 +138,17 @@ const google::protobuf::Field* FindFieldInTypeByNumberOrNull( const google::protobuf::Type* type, int32 number); // Finds and returns the EnumValue identified by enum_name in the passed tech -// Enum object. Returns NULL if none found. +// Enum object. Returns nullptr if none found. const google::protobuf::EnumValue* FindEnumValueByNameOrNull( const google::protobuf::Enum* enum_type, StringPiece enum_name); // Finds and returns the EnumValue identified by value in the passed tech -// Enum object. Returns NULL if none found. +// Enum object. Returns nullptr if none found. const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( const google::protobuf::Enum* enum_type, int32 value); // Finds and returns the EnumValue identified by enum_name without underscore in -// the passed tech Enum object. Returns NULL if none found. +// the passed tech Enum object. Returns nullptr if none found. // For Ex. if enum_name is ACTIONANDADVENTURE it can get accepted if // EnumValue's name is action_and_adventure or ACTION_AND_ADVENTURE. const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull( @@ -160,6 +157,9 @@ const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull( // Converts input to camel-case and returns it. LIBPROTOBUF_EXPORT string ToCamelCase(const StringPiece input); +// Converts enum name string to camel-case and returns it. +string EnumValueNameToLowerCamelCase(const StringPiece input); + // Converts input to snake_case and returns it. LIBPROTOBUF_EXPORT string ToSnakeCase(StringPiece input); @@ -200,6 +200,12 @@ inline string ValueAsString(double value) { // Converts a string to float. Unlike safe_strtof, conversion will fail if the // value fits into double but not float (e.g., DBL_MAX). LIBPROTOBUF_EXPORT bool SafeStrToFloat(StringPiece str, float* value); + +// Returns whether a StringPiece begins with the provided prefix. +bool StringStartsWith(StringPiece text, StringPiece prefix); + +// Returns whether a StringPiece ends with the provided suffix. +bool StringEndsWith(StringPiece text, StringPiece suffix); } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto index 8a0441c8..cbc3f81f 100644 --- a/src/google/protobuf/util/json_format_proto3.proto +++ b/src/google/protobuf/util/json_format_proto3.proto @@ -181,3 +181,9 @@ message TestCustomJsonName { message TestExtensions { .protobuf_unittest.TestAllExtensions extensions = 1; } + +message TestEnumValue{ + EnumType enum_value1 = 1; + EnumType enum_value2 = 2; + EnumType enum_value3 = 3; +}
\ No newline at end of file diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc index ce3569ce..7a7f299f 100644 --- a/src/google/protobuf/util/json_util.cc +++ b/src/google/protobuf/util/json_util.cc @@ -50,7 +50,9 @@ namespace util { namespace internal { ZeroCopyStreamByteSink::~ZeroCopyStreamByteSink() { - stream_->BackUp(buffer_size_); + if (buffer_size_ > 0) { + stream_->BackUp(buffer_size_); + } } void ZeroCopyStreamByteSink::Append(const char* bytes, size_t len) { @@ -95,6 +97,8 @@ util::Status BinaryToJsonStream(TypeResolver* resolver, resolver, type, &json_writer); default_value_writer.set_preserve_proto_field_names( options.preserve_proto_field_names); + default_value_writer.set_print_enums_as_ints( + options.always_print_enums_as_ints); return proto_source.WriteTo(&default_value_writer); } else { return proto_source.WriteTo(&json_writer); @@ -115,30 +119,32 @@ util::Status BinaryToJsonString(TypeResolver* resolver, namespace { class StatusErrorListener : public converter::ErrorListener { public: + StatusErrorListener() {} - virtual ~StatusErrorListener() {} + virtual ~StatusErrorListener() override {} util::Status GetStatus() { return status_; } virtual void InvalidName(const converter::LocationTrackerInterface& loc, - StringPiece unknown_name, StringPiece message) { + StringPiece unknown_name, StringPiece message) override { status_ = util::Status(util::error::INVALID_ARGUMENT, - loc.ToString() + ": " + message.ToString()); + loc.ToString() + ": invalid name " + + string(unknown_name) + ": " + string(message)); } virtual void InvalidValue(const converter::LocationTrackerInterface& loc, - StringPiece type_name, StringPiece value) { + StringPiece type_name, StringPiece value) override { status_ = util::Status(util::error::INVALID_ARGUMENT, - loc.ToString() + ": invalid value " + value.ToString() + - " for type " + type_name.ToString()); + loc.ToString() + ": invalid value " + string(value) + + " for type " + string(type_name)); } virtual void MissingField(const converter::LocationTrackerInterface& loc, - StringPiece missing_name) { + StringPiece missing_name) override { status_ = util::Status( util::error::INVALID_ARGUMENT, - loc.ToString() + ": missing field " + missing_name.ToString()); + loc.ToString() + ": missing field " + string(missing_name)); } private: diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h index dee3ddba..e7868307 100644 --- a/src/google/protobuf/util/json_util.h +++ b/src/google/protobuf/util/json_util.h @@ -56,10 +56,10 @@ struct JsonPrintOptions { // Whether to add spaces, line breaks and indentation to make the JSON output // easy to read. bool add_whitespace; - // Whether to always print primitive fields. By default primitive fields with - // default values will be omitted in JSON joutput. For example, an int32 field - // set to 0 will be omitted. Set this flag to true will override the default - // behavior and print primitive fields regardless of their values. + // Whether to always print primitive fields. By default proto3 primitive + // fields with default values will be omitted in JSON output. For example, an + // int32 field set to 0 will be omitted. Set this flag to true will override + // the default behavior and print primitive fields regardless of their values. bool always_print_primitive_fields; // Whether to always print enums as ints. By default they are rendered as // strings. @@ -182,7 +182,7 @@ class LIBPROTOBUF_EXPORT ZeroCopyStreamByteSink : public strings::ByteSink { : stream_(stream), buffer_(NULL), buffer_size_(0) {} ~ZeroCopyStreamByteSink(); - virtual void Append(const char* bytes, size_t len); + virtual void Append(const char* bytes, size_t len) override; private: io::ZeroCopyOutputStream* stream_; diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc index 25c7e96c..a2a84b57 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/util/json_util_test.cc @@ -34,6 +34,7 @@ #include <string> #include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/descriptor_database.h> #include <google/protobuf/dynamic_message.h> #include <google/protobuf/util/internal/testdata/maps.pb.h> @@ -47,12 +48,13 @@ namespace protobuf { namespace util { namespace { +using google::protobuf::testing::MapIn; using proto3::FOO; using proto3::BAR; using proto3::TestMessage; using proto3::TestMap; using proto3::TestOneof; -using google::protobuf::testing::MapIn; +using proto3::TestEnumValue; static const char kTypeUrlPrefix[] = "type.googleapis.com"; @@ -81,7 +83,7 @@ class JsonUtilTest : public ::testing::Test { return FromJson(json, message, JsonParseOptions()); } - google::protobuf::scoped_ptr<TypeResolver> resolver_; + std::unique_ptr<TypeResolver> resolver_; }; TEST_F(JsonUtilTest, TestWhitespaces) { @@ -216,6 +218,29 @@ TEST_F(JsonUtilTest, TestAlwaysPrintEnumsAsInts) { EXPECT_EQ(proto3::BAR, parsed.repeated_enum_value(1)); } +TEST_F(JsonUtilTest, TestPrintEnumsAsIntsWithDefaultValue) { + TestEnumValue orig; + //orig.set_enum_value1(proto3::FOO) + orig.set_enum_value2(proto3::FOO); + orig.set_enum_value3(proto3::BAR); + + JsonPrintOptions print_options; + print_options.always_print_enums_as_ints = true; + print_options.always_print_primitive_fields = true; + + string expected_json = "{\"enumValue1\":0,\"enumValue2\":0,\"enumValue3\":1}"; + EXPECT_EQ(expected_json, ToJson(orig, print_options)); + + TestEnumValue parsed; + JsonParseOptions parse_options; + ASSERT_TRUE(FromJson(expected_json, &parsed, parse_options)); + + EXPECT_EQ(proto3::FOO, parsed.enum_value1()); + EXPECT_EQ(proto3::FOO, parsed.enum_value2()); + EXPECT_EQ(proto3::BAR, parsed.enum_value3()); + +} + TEST_F(JsonUtilTest, ParseMessage) { // Some random message but good enough to verify that the parsing warpper // functions are working properly. @@ -259,7 +284,7 @@ TEST_F(JsonUtilTest, ParsePrimitiveMapIn) { JsonPrintOptions print_options; print_options.always_print_primitive_fields = true; JsonParseOptions parse_options; - EXPECT_EQ("{\"other\":\"\",\"things\":[],\"mapInput\":{}}", + EXPECT_EQ("{\"other\":\"\",\"things\":[],\"mapInput\":{},\"mapAny\":{}}", ToJson(message, print_options)); MapIn other; ASSERT_TRUE(FromJson(ToJson(message, print_options), &other, parse_options)); @@ -312,7 +337,7 @@ TEST_F(JsonUtilTest, TestDynamicMessage) { DescriptorPool pool(&database); // A dynamic version of the test proto. DynamicMessageFactory factory; - google::protobuf::scoped_ptr<Message> message(factory.GetPrototype( + std::unique_ptr<Message> message(factory.GetPrototype( pool.FindMessageTypeByName("proto3.TestMessage"))->New()); EXPECT_TRUE(FromJson(input, message.get())); @@ -332,6 +357,64 @@ TEST_F(JsonUtilTest, TestDynamicMessage) { EXPECT_EQ(ToJson(generated, options), ToJson(*message, options)); } +TEST_F(JsonUtilTest, TestParsingUnknownEnumsAs0) { + TestMessage m; + { + JsonParseOptions options; + ASSERT_FALSE(options.ignore_unknown_fields); + string input = + "{\n" + " \"enum_value\":\"UNKNOWN_VALUE\"\n" + "}"; + m.set_enum_value(proto3::BAR); + EXPECT_FALSE(FromJson(input, &m, options)); + ASSERT_EQ(proto3::BAR, m.enum_value()); // Keep previous value + + options.ignore_unknown_fields = true; + EXPECT_TRUE(FromJson(input, &m, options)); + EXPECT_EQ(0, m.enum_value()); // Unknown enum value must be decoded as 0 + } + // Integer values are read as usual + { + JsonParseOptions options; + string input = + "{\n" + " \"enum_value\":12345\n" + "}"; + m.set_enum_value(proto3::BAR); + EXPECT_TRUE(FromJson(input, &m, options)); + ASSERT_EQ(12345, m.enum_value()); + + options.ignore_unknown_fields = true; + EXPECT_TRUE(FromJson(input, &m, options)); + EXPECT_EQ(12345, m.enum_value()); + } + + // Trying to pass an object as an enum field value is always treated as an error + { + JsonParseOptions options; + string input = + "{\n" + " \"enum_value\":{}\n" + "}"; + options.ignore_unknown_fields = true; + EXPECT_FALSE(FromJson(input, &m, options)); + options.ignore_unknown_fields = false; + EXPECT_FALSE(FromJson(input, &m, options)); + } + // Trying to pass an array as an enum field value is always treated as an error + { + JsonParseOptions options; + string input = + "{\n" + " \"enum_value\":[]\n" + "}"; + EXPECT_FALSE(FromJson(input, &m, options)); + options.ignore_unknown_fields = true; + EXPECT_FALSE(FromJson(input, &m, options)); + } +} + typedef std::pair<char*, int> Segment; // A ZeroCopyOutputStream that writes to multiple buffers. class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream { @@ -457,6 +540,25 @@ TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) { } } +TEST_F(JsonUtilTest, TestWrongJsonInput) { + const char json[] = "{\"unknown_field\":\"some_value\"}"; + io::ArrayInputStream input_stream(json, strlen(json)); + char proto_buffer[10000]; + io::ArrayOutputStream output_stream(proto_buffer, sizeof(proto_buffer)); + std::string message_type = "type.googleapis.com/proto3.TestMessage"; + TypeResolver* resolver = NewTypeResolverForDescriptorPool( + "type.googleapis.com", DescriptorPool::generated_pool()); + + auto result_status = util::JsonToBinaryStream( + resolver, message_type, &input_stream, &output_stream); + + delete resolver; + + EXPECT_FALSE(result_status.ok()); + EXPECT_EQ(result_status.error_code(), + util::error::INVALID_ARGUMENT); +} + } // namespace } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index e964e041..7d3976f8 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -40,9 +40,6 @@ #include <algorithm> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <utility> #include <google/protobuf/stubs/callback.h> @@ -93,7 +90,7 @@ class MessageDifferencer::MultipleFieldsMapKeyComparator virtual bool IsMatch( const Message& message1, const Message& message2, - const std::vector<SpecificField>& parent_fields) const { + const std::vector<SpecificField>& parent_fields) const override { for (int i = 0; i < key_field_paths_.size(); ++i) { if (!IsMatchInternal(message1, message2, parent_fields, key_field_paths_[i], 0)) { @@ -363,9 +360,6 @@ void MessageDifferencer::TreatAsMapUsingKeyComparator( const MapKeyComparator* key_comparator) { GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: " << field->full_name(); - GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type()) - << "Field has to be message type. Field name is: " - << field->full_name(); GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end()) << "Cannot treat this repeated field as both Map and Set for " << "comparison."; @@ -493,8 +487,8 @@ bool MessageDifferencer::Compare( } // Expand google.protobuf.Any payload if possible. if (descriptor1->full_name() == internal::kAnyFullTypeName) { - google::protobuf::scoped_ptr<Message> data1; - google::protobuf::scoped_ptr<Message> data2; + std::unique_ptr<Message> data1; + std::unique_ptr<Message> data2; if (UnpackAny(message1, &data1) && UnpackAny(message2, &data2)) { // Avoid DFATAL for different descriptors in google.protobuf.Any payloads. if (data1->GetDescriptor() != data2->GetDescriptor()) { @@ -1071,7 +1065,7 @@ struct UnknownFieldOrdering { } // namespace bool MessageDifferencer::UnpackAny(const Message& any, - google::protobuf::scoped_ptr<Message>* data) { + std::unique_ptr<Message>* data) { const Reflection* reflection = any.GetReflection(); const FieldDescriptor* type_url_field; const FieldDescriptor* value_field; @@ -1344,7 +1338,7 @@ class MaximumMatcher { int count1_; int count2_; - google::protobuf::scoped_ptr<NodeMatchCallback> match_callback_; + std::unique_ptr<NodeMatchCallback> match_callback_; std::map<std::pair<int, int>, bool> cached_match_results_; std::vector<int>* match_list1_; std::vector<int>* match_list2_; @@ -1462,11 +1456,27 @@ bool MessageDifferencer::MatchRepeatedFieldIndices( if (match_count != count1 && reporter_ == NULL) return false; success = success && (match_count == count1); } else { - for (int i = 0; i < count1; ++i) { + int start_offset = 0; + // If the two repeated fields are treated as sets, optimize for the case + // where both start with same items stored in the same order. + if (IsTreatedAsSet(repeated_field)) { + start_offset = std::min(count1, count2); + for (int i = 0; i < count1 && i < count2; i++) { + if (IsMatch(repeated_field, key_comparator, &message1, &message2, + parent_fields, i, i)) { + match_list1->at(i) = i; + match_list2->at(i) = i; + } else { + start_offset = i; + break; + } + } + } + for (int i = start_offset; i < count1; ++i) { // Indicates any matched elements for this repeated field. bool match = false; - for (int j = 0; j < count2; j++) { + for (int j = start_offset; j < count2; j++) { if (match_list2->at(j) != -1) continue; match = IsMatch(repeated_field, key_comparator, @@ -1751,6 +1761,13 @@ void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored( printer_->Print("\n"); // Print for newlines. } +MessageDifferencer::MapKeyComparator* +MessageDifferencer::CreateMultipleFieldsMapKeyComparator( + const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) { + return new MultipleFieldsMapKeyComparator(this, key_field_paths); +} + + } // namespace util } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h index b7d4de00..b3e65515 100644 --- a/src/google/protobuf/util/message_differencer.h +++ b/src/google/protobuf/util/message_differencer.h @@ -64,6 +64,7 @@ class Printer; namespace util { +class DefaultFieldComparator; class FieldContext; // declared below MessageDifferencer // A basic differencer that can be used to determine @@ -174,10 +175,8 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // If "field" is a repeated field which is being treated as a map or // a set (see TreatAsMap() and TreatAsSet(), below), new_index indicates - // the index the position to which the element has moved. This only - // applies to ReportMoved() and (in the case of TreatAsMap()) - // ReportModified(). In all other cases, "new_index" will have the same - // value as "index". + // the index the position to which the element has moved. If the element + // has not moved, "new_index" will have the same value as "index". int new_index; // For unknown fields, these are the pointers to the UnknownFieldSet @@ -372,7 +371,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // repeated fields have different numbers of elements, the // unpaired elements are reported using ReportAdded() or // ReportDeleted(). - AS_SET, // Treat all the repeated fields as sets by default. + AS_SET, // Treat all the repeated fields as sets. // See TreatAsSet(), as below. }; @@ -386,6 +385,11 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // the only differences between the compared messages is that some fields // have been moved, then the comparison returns true. // + // Note that despite the name of this method, this is really + // comparison as multisets: if one side of the comparison has a duplicate + // in the repeated field but the other side doesn't, this will count as + // a mismatch. + // // If the scope of comparison is set to PARTIAL, then in addition to what's // above, extra values added to repeated fields of the second message will // not cause the comparison to fail. @@ -470,6 +474,10 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { const FieldDescriptor* field, const MapKeyComparator* key_comparator); + // Initiates and returns a new instance of MultipleFieldsMapKeyComparator. + MapKeyComparator* CreateMultipleFieldsMapKeyComparator( + const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths); + // Add a custom ignore criteria that is evaluated in addition to the // ignored fields added with IgnoreField. // Takes ownership of ignore_criteria. @@ -589,7 +597,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { public: explicit StreamReporter(io::ZeroCopyOutputStream* output); explicit StreamReporter(io::Printer* printer); // delimiter '$' - virtual ~StreamReporter(); + virtual ~StreamReporter() override; // When set to true, the stream reporter will also output aggregates nodes // (i.e. messages and groups) whose subfields have been modified. When @@ -599,32 +607,33 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { } // The following are implementations of the methods described above. + virtual void ReportAdded(const Message& message1, const Message& message2, - const std::vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path) override; virtual void ReportDeleted(const Message& message1, const Message& message2, - const std::vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path) override; virtual void ReportModified(const Message& message1, const Message& message2, - const std::vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path) override; virtual void ReportMoved(const Message& message1, const Message& message2, - const std::vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path) override; virtual void ReportMatched(const Message& message1, const Message& message2, - const std::vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path) override; virtual void ReportIgnored(const Message& message1, const Message& message2, - const std::vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path) override; - virtual void ReportUnknownFieldIgnored( + void ReportUnknownFieldIgnored( const Message& message1, const Message& message2, - const std::vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path) override; protected: // Prints the specified path of fields to the buffer. message is used to @@ -660,6 +669,8 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { }; private: + friend class DefaultFieldComparator; + // A MapKeyComparator to be used in TreatAsMapUsingKeyComparator. // Implementation of this class needs to do field value comparison which // relies on some private methods of MessageDifferencer. That's why this @@ -671,7 +682,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { public: explicit MapEntryKeyComparator(MessageDifferencer* message_differencer); virtual bool IsMatch(const Message& message1, const Message& message2, - const std::vector<SpecificField>& parent_fields) const; + const std::vector<SpecificField>& parent_fields) const override; private: MessageDifferencer* message_differencer_; @@ -811,7 +822,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // If "any" is of type google.protobuf.Any, extract its payload using // DynamicMessageFactory and store in "data". - bool UnpackAny(const Message& any, google::protobuf::scoped_ptr<Message>* data); + bool UnpackAny(const Message& any, std::unique_ptr<Message>* data); // Checks if index is equal to new_index in all the specific fields. static bool CheckPathChanged(const std::vector<SpecificField>& parent_fields); @@ -852,7 +863,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { string* output_string_; - google::protobuf::scoped_ptr<DynamicMessageFactory> dynamic_message_factory_; + std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer); }; diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc index 75cffd9f..a263d983 100755..100644 --- a/src/google/protobuf/util/message_differencer_unittest.cc +++ b/src/google/protobuf/util/message_differencer_unittest.cc @@ -127,6 +127,27 @@ TEST(MessageDifferencerTest, RepeatedFieldInequalityTest) { EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); } +TEST(MessageDifferencerTest, RepeatedFieldSetOptimizationTest) { + util::MessageDifferencer differencer; + protobuf_unittest::TestDiffMessage msg1; + protobuf_unittest::TestDiffMessage msg2; + protobuf_unittest::TestDiffMessage::Item* item1 = msg1.add_item(); + protobuf_unittest::TestDiffMessage::Item* item2 = msg2.add_item(); + differencer.TreatAsSet(item1->GetDescriptor()->FindFieldByName("ra")); + differencer.TreatAsSet(item2->GetDescriptor()->FindFieldByName("ra")); + for (int i = 0; i < 1000; i++) { + item1->add_ra(i); + item2->add_ra(i); + } + EXPECT_TRUE(differencer.Compare(msg1, msg2)); + item2->add_ra(1001); + EXPECT_FALSE(differencer.Compare(msg1, msg2)); + item1->add_ra(1001); + EXPECT_TRUE(differencer.Compare(msg1, msg2)); + item1->add_ra(1002); + EXPECT_FALSE(differencer.Compare(msg1, msg2)); +} + TEST(MessageDifferencerTest, MapFieldEqualityTest) { // Create the testing protos unittest::TestMap msg1; diff --git a/src/google/protobuf/util/package_info.h b/src/google/protobuf/util/package_info.h index e37e6dc0..96019203 100644 --- a/src/google/protobuf/util/package_info.h +++ b/src/google/protobuf/util/package_info.h @@ -38,7 +38,7 @@ namespace protobuf { // Utility classes. // -// This package contains various utilities for message comprasion, JSON +// This package contains various utilities for message comparison, JSON // conversion, well known types, etc. namespace util {} diff --git a/src/google/protobuf/util/time_util.cc b/src/google/protobuf/util/time_util.cc index 46a6f5a8..d4912837 100644 --- a/src/google/protobuf/util/time_util.cc +++ b/src/google/protobuf/util/time_util.cc @@ -30,13 +30,14 @@ #include <google/protobuf/util/time_util.h> -#include <google/protobuf/stubs/time.h> #include <google/protobuf/stubs/int128.h> -#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/stringprintf.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/time.h> #include <google/protobuf/duration.pb.h> #include <google/protobuf/timestamp.pb.h> + namespace google { namespace protobuf { namespace util { diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc index febaa41f..aa48ef60 100644 --- a/src/google/protobuf/util/type_resolver_util.cc +++ b/src/google/protobuf/util/type_resolver_util.cc @@ -60,7 +60,7 @@ class DescriptorPoolTypeResolver : public TypeResolver { const DescriptorPool* pool) : url_prefix_(url_prefix), pool_(pool) {} - Status ResolveMessageType(const string& type_url, Type* type) { + Status ResolveMessageType(const string& type_url, Type* type) override { string type_name; Status status = ParseTypeUrl(type_url, &type_name); if (!status.ok()) { @@ -75,7 +75,7 @@ class DescriptorPoolTypeResolver : public TypeResolver { return Status(); } - Status ResolveEnumType(const string& type_url, Enum* enum_type) { + Status ResolveEnumType(const string& type_url, Enum* enum_type) override { string type_name; Status status = ParseTypeUrl(type_url, &type_name); if (!status.ok()) { @@ -95,11 +95,6 @@ class DescriptorPoolTypeResolver : public TypeResolver { type->Clear(); type->set_name(descriptor->full_name()); for (int i = 0; i < descriptor->field_count(); ++i) { - const FieldDescriptor* field = descriptor->field(i); - if (field->type() == FieldDescriptor::TYPE_GROUP) { - // Group fields cannot be represented with Type. We discard them. - continue; - } ConvertFieldDescriptor(descriptor->field(i), type->add_fields()); } for (int i = 0; i < descriptor->oneof_decl_count(); ++i) { @@ -141,7 +136,8 @@ class DescriptorPoolTypeResolver : public TypeResolver { if (descriptor->has_default_value()) { field->set_default_value(DefaultValueAsString(descriptor)); } - if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) { + if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE || + descriptor->type() == FieldDescriptor::TYPE_GROUP) { field->set_type_url(GetTypeUrl(descriptor->message_type())); } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { field->set_type_url(GetTypeUrl(descriptor->enum_type())); diff --git a/src/google/protobuf/util/type_resolver_util_test.cc b/src/google/protobuf/util/type_resolver_util_test.cc index 8a0bf652..9dea17ae 100644 --- a/src/google/protobuf/util/type_resolver_util_test.cc +++ b/src/google/protobuf/util/type_resolver_util_test.cc @@ -32,9 +32,6 @@ #include <limits> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <string> #include <vector> @@ -153,7 +150,7 @@ class DescriptorPoolTypeResolverTest : public testing::Test { } protected: - google::protobuf::scoped_ptr<TypeResolver> resolver_; + std::unique_ptr<TypeResolver> resolver_; }; TEST_F(DescriptorPoolTypeResolverTest, TestAllTypes) { @@ -193,6 +190,13 @@ TEST_F(DescriptorPoolTypeResolverTest, TestAllTypes) { Field::TYPE_BYTES, "optional_bytes", 15)); EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, + Field::TYPE_GROUP, "optionalgroup", 16)); + + EXPECT_TRUE(CheckFieldTypeUrl( + type, "optionalgroup", + GetTypeUrl<protobuf_unittest::TestAllTypes::OptionalGroup>())); + + EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_MESSAGE, "optional_nested_message", 18)); EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_MESSAGE, "optional_foreign_message", 19)); @@ -249,6 +253,13 @@ TEST_F(DescriptorPoolTypeResolverTest, TestAllTypes) { Field::TYPE_BYTES, "repeated_bytes", 45)); EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, + Field::TYPE_GROUP, "repeatedgroup", 46)); + + EXPECT_TRUE(CheckFieldTypeUrl( + type, "repeatedgroup", + GetTypeUrl<protobuf_unittest::TestAllTypes::RepeatedGroup>())); + + EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_MESSAGE, "repeated_nested_message", 48)); EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_MESSAGE, "repeated_foreign_message", 49)); @@ -271,13 +282,6 @@ TEST_F(DescriptorPoolTypeResolverTest, TestAllTypes) { EXPECT_TRUE(CheckFieldTypeUrl( type, "repeated_foreign_enum", GetTypeUrl("protobuf_unittest.ForeignEnum"))); - - // Groups are discarded when converting to Type. - const Descriptor* descriptor = protobuf_unittest::TestAllTypes::descriptor(); - EXPECT_TRUE(descriptor->FindFieldByName("optionalgroup") != NULL); - EXPECT_TRUE(descriptor->FindFieldByName("repeatedgroup") != NULL); - ASSERT_FALSE(HasField(type, "optionalgroup")); - ASSERT_FALSE(HasField(type, "repeatedgroup")); } TEST_F(DescriptorPoolTypeResolverTest, TestPackedField) { |