From 46e8ff63cb67a6520711da5317aaaef04d0414d0 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Mon, 5 Oct 2015 11:59:43 -0700 Subject: Down-integrate from google internal. --- src/google/protobuf/any.cc | 17 +- src/google/protobuf/any.h | 1 + src/google/protobuf/arena.cc | 12 +- src/google/protobuf/arena.h | 29 +- src/google/protobuf/arena_unittest.cc | 4 +- .../compiler/command_line_interface_unittest.cc | 10 +- src/google/protobuf/compiler/cpp/cpp_map_field.cc | 6 +- src/google/protobuf/compiler/cpp/cpp_message.cc | 2 +- .../protobuf/compiler/java/java_enum_field_lite.cc | 6 +- .../protobuf/compiler/java/java_map_field_lite.cc | 2 +- .../protobuf/compiler/java/java_message_lite.cc | 28 +- src/google/protobuf/compiler/parser.cc | 25 ++ src/google/protobuf/compiler/parser.h | 4 + src/google/protobuf/compiler/parser_unittest.cc | 30 ++ .../protobuf/compiler/python/python_generator.cc | 20 +- src/google/protobuf/descriptor.cc | 91 +++++- src/google/protobuf/descriptor.h | 39 ++- src/google/protobuf/descriptor.pb.cc | 316 ++++++++++++++------- src/google/protobuf/descriptor.pb.h | 74 ++++- src/google/protobuf/descriptor.proto | 6 + .../protobuf/descriptor_database_unittest.cc | 6 +- src/google/protobuf/descriptor_unittest.cc | 110 ++++++- src/google/protobuf/dynamic_message.cc | 8 +- src/google/protobuf/dynamic_message_unittest.cc | 15 +- src/google/protobuf/extension_set.cc | 18 +- src/google/protobuf/extension_set.h | 15 +- src/google/protobuf/extension_set_unittest.cc | 5 +- .../generated_message_reflection_unittest.cc | 11 +- src/google/protobuf/generated_message_util.cc | 2 +- src/google/protobuf/io/coded_stream_unittest.cc | 6 +- .../protobuf/io/zero_copy_stream_impl_lite.h | 8 +- .../protobuf/io/zero_copy_stream_unittest.cc | 6 +- src/google/protobuf/map_field_inl.h | 3 +- src/google/protobuf/map_proto2_unittest.proto | 6 + src/google/protobuf/map_test.cc | 6 +- src/google/protobuf/message.cc | 1 - src/google/protobuf/message.h | 2 +- src/google/protobuf/repeated_field.h | 2 +- src/google/protobuf/stubs/stringpiece.h | 13 + src/google/protobuf/stubs/stringpiece_unittest.cc | 18 ++ src/google/protobuf/text_format.cc | 17 +- src/google/protobuf/text_format_unittest.cc | 10 +- src/google/protobuf/unittest_import.proto | 7 + .../protobuf/util/default_value_objectwriter.h | 218 ++++++++++++++ src/google/protobuf/util/field_comparator_test.cc | 2 +- src/google/protobuf/util/field_mask_util.cc | 10 +- src/google/protobuf/util/field_mask_util.h | 11 +- .../util/internal/default_value_objectwriter.h | 2 +- .../protobuf/util/internal/json_objectwriter.cc | 6 +- .../util/internal/protostream_objectsource.cc | 22 +- .../util/internal/protostream_objectsource.h | 4 +- .../util/internal/protostream_objectwriter.cc | 41 ++- .../util/internal/protostream_objectwriter.h | 20 ++ .../util/internal/protostream_objectwriter_test.cc | 137 +++++++-- src/google/protobuf/util/internal/utility.cc | 15 +- src/google/protobuf/util/internal/utility.h | 6 +- src/google/protobuf/util/json_format_proto3.proto | 10 + src/google/protobuf/util/json_util.cc | 6 +- src/google/protobuf/util/message_differencer.cc | 52 +++- src/google/protobuf/util/message_differencer.h | 27 ++ src/google/protobuf/util/time_util.h | 7 +- src/google/protobuf/util/type_resolver_util.cc | 71 ++--- 62 files changed, 1325 insertions(+), 359 deletions(-) create mode 100644 src/google/protobuf/util/default_value_objectwriter.h (limited to 'src') diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc index c6ed37ae..7351d377 100644 --- a/src/google/protobuf/any.cc +++ b/src/google/protobuf/any.cc @@ -43,6 +43,7 @@ string GetTypeUrl(const Descriptor* message) { const char kAnyFullTypeName[] = "google.protobuf.Any"; const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/"; +const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/"; AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value) : type_url_(type_url), value_(value) { @@ -70,11 +71,17 @@ bool AnyMetadata::InternalIs(const Descriptor* descriptor) const { } bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) { - const int prefix_len = strlen(kTypeGoogleApisComPrefix); - if (strncmp(type_url.c_str(), kTypeGoogleApisComPrefix, prefix_len) == 0) { - full_type_name->assign(type_url.data() + prefix_len, - type_url.size() - prefix_len); - return true; + static const char* prefix[] = { + kTypeGoogleApisComPrefix, + kTypeGoogleProdComPrefix + }; + for (int i = 0; i < 2; i++) { + const int prefix_len = strlen(prefix[i]); + if (strncmp(type_url.c_str(), prefix[i], prefix_len) == 0) { + full_type_name->assign(type_url.data() + prefix_len, + type_url.size() - prefix_len); + return true; + } } return false; } diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h index 7eeb6b70..f760ad5d 100644 --- a/src/google/protobuf/any.h +++ b/src/google/protobuf/any.h @@ -70,6 +70,7 @@ class LIBPROTOBUF_EXPORT AnyMetadata { extern const char kAnyFullTypeName[]; // "google.protobuf.Any". extern const char kTypeGoogleApisComPrefix[]; // "type.googleapis.com/". +extern const char kTypeGoogleProdComPrefix[]; // "type.googleprod.com/". // Get the proto type name from Any::type_url value. For example, passing // "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index 907a6a20..74b09655 100755 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -38,17 +38,17 @@ namespace google { namespace protobuf { google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_; -#ifdef PROTOBUF_USE_DLLS -Arena::ThreadCache& Arena::thread_cache() { - static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL }; - return thread_cache_; -} -#elif defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) +#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) Arena::ThreadCache& Arena::thread_cache() { static internal::ThreadLocalStorage* thread_cache_ = new internal::ThreadLocalStorage(); return *thread_cache_->Get(); } +#elif defined(PROTOBUF_USE_DLLS) +Arena::ThreadCache& Arena::thread_cache() { + static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL }; + return thread_cache_; +} #else GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL }; #endif diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index 074a9e54..16e0d50e 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -38,7 +38,16 @@ #if __cplusplus >= 201103L #include #endif +#if defined(_MSC_VER) && !_HAS_EXCEPTIONS +// Work around bugs in MSVC header when _HAS_EXCEPTIONS=0. +#include #include +namespace std { +using type_info = ::type_info; +} +#else +#include +#endif #include #include @@ -533,15 +542,15 @@ class LIBPROTOBUF_EXPORT Arena { static const size_t kHeaderSize = sizeof(Block); static google::protobuf::internal::SequenceNumber lifecycle_id_generator_; -#ifdef PROTOBUF_USE_DLLS - // Thread local variables cannot be exposed through DLL interface but we can - // wrap them in static functions. - static ThreadCache& thread_cache(); -#elif defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) +#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) // Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread // local storage class we implemented. // iOS also does not support the GOOGLE_THREAD_LOCAL keyword. static ThreadCache& thread_cache(); +#elif defined(PROTOBUF_USE_DLLS) + // Thread local variables cannot be exposed through DLL interface but we can + // wrap them in static functions. + static ThreadCache& thread_cache(); #else static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_; static ThreadCache& thread_cache() { return thread_cache_; } @@ -581,11 +590,13 @@ class LIBPROTOBUF_EXPORT Arena { template static double DestructorSkippable(...); + // The raw_skippable_value const bool variable is separated from the typedef + // line below as a work-around of an NVCC 7.0 (and earlier) compiler bug. + static const bool raw_skippable_value = + sizeof(DestructorSkippable(static_cast(0))) == + sizeof(char) || google::protobuf::internal::has_trivial_destructor::value == true; // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type. - typedef google::protobuf::internal::integral_constant(static_cast(0))) == - sizeof(char) || google::protobuf::internal::has_trivial_destructor::value == true> - type; + typedef google::protobuf::internal::integral_constant type; static const type value; }; diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index c9ca1fd1..6b67f446 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc @@ -362,7 +362,7 @@ TEST(ArenaTest, ReleaseMessage) { Arena arena; TestAllTypes* arena_message = Arena::CreateMessage(&arena); arena_message->mutable_optional_nested_message()->set_bb(118); - scoped_ptr nested( + google::protobuf::scoped_ptr nested( arena_message->release_optional_nested_message()); EXPECT_EQ(118, nested->bb()); @@ -383,7 +383,7 @@ TEST(ArenaTest, ReleaseString) { Arena arena; TestAllTypes* arena_message = Arena::CreateMessage(&arena); arena_message->set_optional_string("hello"); - scoped_ptr released_str( + google::protobuf::scoped_ptr released_str( arena_message->release_optional_string()); EXPECT_EQ("hello", *released_str); diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 9560d0e0..46ea5c4e 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -63,13 +63,13 @@ #include #include -namespace google { -namespace protobuf { -namespace compiler { // Disable the whole test when we use tcmalloc for "draconian" heap checks, in // which case tcmalloc will print warnings that fail the plugin tests. #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN +namespace google { +namespace protobuf { +namespace compiler { #if defined(_WIN32) #ifndef STDIN_FILENO @@ -1800,8 +1800,8 @@ TEST_F(EncodeDecodeTest, ProtoParseError) { } // anonymous namespace -#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN - } // namespace compiler } // namespace protobuf + +#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN } // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 25acc61b..e5e2f07d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -66,7 +66,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["wrapper"] = "EntryWrapper"; break; case FieldDescriptor::CPPTYPE_ENUM: - (*variables)["val_cpp"] = ClassName(val->enum_type(), false); + (*variables)["val_cpp"] = ClassName(val->enum_type(), true); (*variables)["wrapper"] = "EnumEntryWrapper"; break; default: @@ -200,7 +200,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { case FieldDescriptor::CPPTYPE_ENUM: printer->Print(variables_, "(*mutable_$name$())[entry->key()] =\n" - " static_cast<$val_cpp$>(*entry->mutable_value());\n"); + " static_cast< $val_cpp$ >(*entry->mutable_value());\n"); break; default: printer->Print(variables_, @@ -215,7 +215,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { " DO_(entry->ParseFromString(data));\n" " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n" " (*mutable_$name$())[entry->key()] =\n" - " static_cast<$val_cpp$>(*entry->mutable_value());\n" + " static_cast< $val_cpp$ >(*entry->mutable_value());\n" " } else {\n"); if (HasDescriptorMethods(descriptor_->file())) { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index fc1ce962..8cc8c7ba 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -350,7 +350,7 @@ void CollectMapInfo(const Descriptor* descriptor, (*variables)["val"] = FieldMessageTypeName(val); break; case FieldDescriptor::CPPTYPE_ENUM: - (*variables)["val"] = ClassName(val->enum_type(), false); + (*variables)["val"] = ClassName(val->enum_type(), true); break; default: (*variables)["val"] = PrimitiveTypeName(val->cpp_type()); diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc index 2c3608c2..e8bf15d0 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -299,7 +299,7 @@ GenerateParsingCode(io::Printer* printer) const { "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, - " unknownFields.mergeVarintField($number$, rawValue);\n"); + " super.mergeVarintField($number$, rawValue);\n"); } printer->Print(variables_, "} else {\n" @@ -492,7 +492,7 @@ GenerateParsingCode(io::Printer* printer) const { "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, - " unknownFields.mergeVarintField($number$, rawValue);\n"); + " super.mergeVarintField($number$, rawValue);\n"); } printer->Print(variables_, "} else {\n" @@ -850,7 +850,7 @@ GenerateParsingCode(io::Printer* printer) const { "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, - " unknownFields.mergeVarintField($number$, rawValue);\n"); + " super.mergeVarintField($number$, rawValue);\n"); } printer->Print(variables_, "} else {\n" diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc index 4fe656d3..d2039403 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -405,7 +405,7 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print( variables_, "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n" - " unknownFields.mergeLengthDelimitedField($number$, bytes);\n" + " super.mergeLengthDelimitedField($number$, bytes);\n" "} else {\n" " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n" "}\n"); diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 8b6c75b8..94ed2c39 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -1029,12 +1029,6 @@ GenerateParsingConstructor(io::Printer* printer) { "bit_field_name", GetBitFieldName(i)); } - if (PreserveUnknownFields(descriptor_)) { - printer->Print( - "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n" - " com.google.protobuf.UnknownFieldSetLite.newBuilder();\n"); - } - printer->Print( "try {\n"); printer->Indent(); @@ -1056,13 +1050,10 @@ GenerateParsingConstructor(io::Printer* printer) { if (PreserveUnknownFields(descriptor_)) { if (descriptor_->extension_range_count() > 0) { - // Lite runtime directly invokes parseUnknownField to reduce method - // counts. printer->Print( "default: {\n" - " if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n" - " input, unknownFields,\n" - " extensionRegistry, tag)) {\n" + " if (!parseUnknownField(getDefaultInstanceForType(),\n" + " input, extensionRegistry, tag)) {\n" " done = true;\n" // it's an endgroup tag " }\n" " break;\n" @@ -1070,8 +1061,7 @@ GenerateParsingConstructor(io::Printer* printer) { } else { printer->Print( "default: {\n" - " if (!parseUnknownField(input, unknownFields,\n" - " extensionRegistry, tag)) {\n" + " if (!parseUnknownField(tag, input)) {\n" " done = true;\n" // it's an endgroup tag " }\n" " break;\n" @@ -1146,16 +1136,8 @@ GenerateParsingConstructor(io::Printer* printer) { field_generators_.get(field).GenerateParsingDoneCode(printer); } - if (PreserveUnknownFields(descriptor_)) { - // Make unknown fields immutable. - printer->Print("this.unknownFields = unknownFields.build();\n"); - } - - if (descriptor_->extension_range_count() > 0) { - // Make extensions immutable. - printer->Print( - "makeExtensionsImmutable(extensions);\n"); - } + printer->Print( + "doneParsing();\n"); printer->Outdent(); printer->Outdent(); diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index 4d018425..a389a4fc 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -993,6 +993,9 @@ bool Parser::ParseFieldOptions(FieldDescriptorProto* field, // We intentionally pass field_location rather than location here, since // the default value is not actually an option. DO(ParseDefaultAssignment(field, field_location, containing_file)); + } else if (LookingAt("json_name")) { + // Like default value, this "json_name" is not an actual option. + DO(ParseJsonName(field, field_location, containing_file)); } else { DO(ParseOption(field->mutable_options(), location, containing_file, OPTION_ASSIGNMENT)); @@ -1140,6 +1143,28 @@ bool Parser::ParseDefaultAssignment( return true; } +bool Parser::ParseJsonName( + FieldDescriptorProto* field, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file) { + if (field->has_json_name()) { + AddError("Already set option \"json_name\"."); + field->clear_json_name(); + } + + DO(Consume("json_name")); + DO(Consume("=")); + + LocationRecorder location(field_location, + FieldDescriptorProto::kJsonNameFieldNumber); + location.RecordLegacyLocation( + field, DescriptorPool::ErrorCollector::OPTION_VALUE); + DO(ConsumeString(field->mutable_json_name(), + "Expected string for JSON name.")); + return true; +} + + bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option, const LocationRecorder& part_location, const FileDescriptorProto* containing_file) { diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index 007b001c..3ba1e170 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -439,6 +439,10 @@ class LIBPROTOBUF_EXPORT Parser { const LocationRecorder& field_location, const FileDescriptorProto* containing_file); + bool ParseJsonName(FieldDescriptorProto* field, + const LocationRecorder& field_location, + const FileDescriptorProto* containing_file); + enum OptionStyle { OPTION_ASSIGNMENT, // just "name = value" OPTION_STATEMENT // "option name = value;" diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index cc6f1efb..0d729e0b 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -452,6 +452,20 @@ TEST_F(ParseMessageTest, FieldDefaults) { #undef ETC } +TEST_F(ParseMessageTest, FieldJsonName) { + ExpectParsesTo( + "message TestMessage {\n" + " optional string foo = 1 [json_name = \"@type\"];\n" + "}\n", + "message_type {" + " name: \"TestMessage\"" + " field {\n" + " name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1" + " json_name: \"@type\"\n" + " }\n" + "}\n"); +} + TEST_F(ParseMessageTest, FieldOptions) { ExpectParsesTo( "message TestMessage {\n" @@ -1126,6 +1140,22 @@ TEST_F(ParseErrorTest, DefaultValueTooLarge) { "6:36: Integer out of range.\n"); } +TEST_F(ParseErrorTest, JsonNameNotString) { + ExpectHasErrors( + "message TestMessage {\n" + " optional string foo = 1 [json_name=1];\n" + "}\n", + "1:37: Expected string for JSON name.\n"); +} + +TEST_F(ParseErrorTest, DuplicateJsonName) { + ExpectHasErrors( + "message TestMessage {\n" + " optional uint32 foo = 1 [json_name=\"a\",json_name=\"b\"];\n" + "}\n", + "1:41: Already set option \"json_name\".\n"); +} + TEST_F(ParseErrorTest, EnumValueOutOfRange) { ExpectHasErrors( "enum TestEnum {\n" diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index e81af700..4d500f90 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -28,6 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//#PY25 compatible generated code for GAE. // Copyright 2007 Google Inc. All Rights Reserved. // Author: robinson@google.com (Will Robinson) // @@ -166,6 +167,7 @@ void PrintTopBoilerplate( printer->Print( "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" "# source: $filename$\n" + "\nimport sys\n_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))" //##PY25 "\n", "filename", file->name()); if (HasTopLevelEnums(file)) { @@ -257,9 +259,12 @@ string StringifyDefaultValue(const FieldDescriptor& field) { case FieldDescriptor::CPPTYPE_ENUM: return SimpleItoa(field.default_value_enum()->number()); case FieldDescriptor::CPPTYPE_STRING: - return "b\"" + CEscape(field.default_value_string()) + - (field.type() != FieldDescriptor::TYPE_STRING ? "\"" : - "\".decode('utf-8')"); +//##!PY25 return "b\"" + CEscape(field.default_value_string()) + +//##!PY25 (field.type() != FieldDescriptor::TYPE_STRING ? "\"" : +//##!PY25 "\".decode('utf-8')"); + return "_b(\"" + CEscape(field.default_value_string()) + //##PY25 + (field.type() != FieldDescriptor::TYPE_STRING ? "\")" : //##PY25 + "\").decode('utf-8')"); //##PY25 case FieldDescriptor::CPPTYPE_MESSAGE: return "None"; } @@ -385,7 +390,8 @@ void Generator::PrintFileDescriptor() const { printer_->Print(m, file_descriptor_template); printer_->Indent(); printer_->Print( - "serialized_pb=b'$value$'\n", +//##!PY25 "serialized_pb=b'$value$'\n", + "serialized_pb=_b('$value$')\n", //##PY25 "value", strings::CHexEscape(file_descriptor_serialized_)); if (file_->dependency_count() != 0) { printer_->Print(",\ndependencies=["); @@ -1029,8 +1035,10 @@ string Generator::OptionsValue( return "None"; } else { string full_class_name = "descriptor_pb2." + class_name; - return "_descriptor._ParseOptions(" + full_class_name + "(), b'" - + CEscape(serialized_options)+ "')"; +//##!PY25 return "_descriptor._ParseOptions(" + full_class_name + "(), b'" +//##!PY25 + CEscape(serialized_options)+ "')"; + return "_descriptor._ParseOptions(" + full_class_name + "(), _b('" //##PY25 + + CEscape(serialized_options)+ "'))"; //##PY25 } } diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 5256b83c..b40fe95a 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -34,6 +34,10 @@ #include #include +#include +#ifndef _SHARED_PTR_H +#include +#endif #include #include #include @@ -1726,6 +1730,20 @@ void FileDescriptor::CopyTo(FileDescriptorProto* proto) const { } } +void FileDescriptor::CopyJsonNameTo(FileDescriptorProto* proto) const { + if (message_type_count() != proto->message_type_size() || + extension_count() != proto->extension_size()) { + GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size."; + return; + } + for (int i = 0; i < message_type_count(); i++) { + message_type(i)->CopyJsonNameTo(proto->mutable_message_type(i)); + } + for (int i = 0; i < extension_count(); i++) { + extension(i)->CopyJsonNameTo(proto->mutable_extension(i)); + } +} + void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const { if (source_code_info_ && source_code_info_ != &SourceCodeInfo::default_instance()) { @@ -1770,9 +1788,30 @@ void Descriptor::CopyTo(DescriptorProto* proto) const { } } +void Descriptor::CopyJsonNameTo(DescriptorProto* proto) const { + if (field_count() != proto->field_size() || + nested_type_count() != proto->nested_type_size() || + extension_count() != proto->extension_size()) { + GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size."; + return; + } + for (int i = 0; i < field_count(); i++) { + field(i)->CopyJsonNameTo(proto->mutable_field(i)); + } + for (int i = 0; i < nested_type_count(); i++) { + nested_type(i)->CopyJsonNameTo(proto->mutable_nested_type(i)); + } + for (int i = 0; i < extension_count(); i++) { + extension(i)->CopyJsonNameTo(proto->mutable_extension(i)); + } +} + void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const { proto->set_name(name()); proto->set_number(number()); + if (has_json_name_) { + proto->set_json_name(json_name()); + } // Some compilers do not allow static_cast directly between two enum types, // so we must cast to int first. @@ -1819,6 +1858,10 @@ void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const { } } +void FieldDescriptor::CopyJsonNameTo(FieldDescriptorProto* proto) const { + proto->set_json_name(json_name()); +} + void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const { proto->set_name(name()); } @@ -4136,6 +4179,14 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, tables_->AllocateString(ToCamelCase(proto.name(), /* lower_first = */ true)); + if (proto.has_json_name()) { + result->has_json_name_ = true; + result->json_name_ = tables_->AllocateString(proto.json_name()); + } else { + result->has_json_name_ = false; + result->json_name_ = result->camelcase_name_; + } + // Some compilers do not allow static_cast directly between two enum types, // so we must cast to int first. result->type_ = static_cast( @@ -5040,6 +5091,20 @@ void DescriptorBuilder::ValidateProto3( } } +static string ToLowercaseWithoutUnderscores(const string& name) { + string result; + for (int i = 0; i < name.size(); ++i) { + if (name[i] != '_') { + if (name[i] >= 'A' && name[i] <= 'Z') { + result.push_back(name[i] - 'A' + 'a'); + } else { + result.push_back(name[i]); + } + } + } + return result; +} + void DescriptorBuilder::ValidateProto3Message( Descriptor* message, const DescriptorProto& proto) { for (int i = 0; i < message->nested_type_count(); ++i) { @@ -5067,6 +5132,25 @@ void DescriptorBuilder::ValidateProto3Message( DescriptorPool::ErrorCollector::OTHER, "MessageSet is not supported in proto3."); } + + // In proto3, we reject field names if they conflict in camelCase. + // Note that we currently enforce a stricter rule: Field names must be + // unique after being converted to lowercase with underscores removed. + map name_to_field; + for (int i = 0; i < message->field_count(); ++i) { + string lowercase_name = ToLowercaseWithoutUnderscores( + message->field(i)->name()); + if (name_to_field.find(lowercase_name) != name_to_field.end()) { + AddError(message->full_name(), proto, + DescriptorPool::ErrorCollector::OTHER, + "The JSON camcel-case name of field \"" + + message->field(i)->name() + "\" conflicts with field \"" + + name_to_field[lowercase_name]->name() + "\". This is not " + + "allowed in proto3."); + } else { + name_to_field[lowercase_name] = message->field(i); + } + } } void DescriptorBuilder::ValidateProto3Field( @@ -5602,7 +5686,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( // First set the value on the UnknownFieldSet corresponding to the // innermost message. - scoped_ptr unknown_fields(new UnknownFieldSet()); + google::protobuf::scoped_ptr unknown_fields(new UnknownFieldSet()); if (!SetOptionValue(field, unknown_fields.get())) { return false; // SetOptionValue() already added the error. } @@ -5612,7 +5696,8 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( for (vector::reverse_iterator iter = intermediate_fields.rbegin(); iter != intermediate_fields.rend(); ++iter) { - scoped_ptr parent_unknown_fields(new UnknownFieldSet()); + google::protobuf::scoped_ptr parent_unknown_fields( + new UnknownFieldSet()); switch ((*iter)->type()) { case FieldDescriptor::TYPE_MESSAGE: { io::StringOutputStream outstr( @@ -5998,7 +6083,7 @@ bool DescriptorBuilder::OptionInterpreter::SetAggregateOption( } const Descriptor* type = option_field->message_type(); - scoped_ptr dynamic(dynamic_factory_.GetPrototype(type)->New()); + google::protobuf::scoped_ptr dynamic(dynamic_factory_.GetPrototype(type)->New()); GOOGLE_CHECK(dynamic.get() != NULL) << "Could not create an instance of " << option_field->DebugString(); diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 2ab316a5..e7e8c6af 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -54,6 +54,10 @@ #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__ #define GOOGLE_PROTOBUF_DESCRIPTOR_H__ +#include +#ifndef _SHARED_PTR_H +#include +#endif #include #include #include @@ -111,8 +115,17 @@ class UnknownField; // Defined in generated_message_reflection.h. namespace internal { - class GeneratedMessageReflection; -} +class GeneratedMessageReflection; +} // namespace internal + +// Defined in command_line_interface.cc +namespace compiler { +class CommandLineInterface; +} // namespace compiler + +namespace descriptor_unittest { +class DescriptorTest; +} // namespace descriptor_unittest // NB, all indices are zero-based. struct SourceLocation { @@ -343,6 +356,12 @@ class LIBPROTOBUF_EXPORT Descriptor { private: typedef MessageOptions OptionsType; + // Allows tests to test CopyTo(proto, true). + friend class ::google::protobuf::descriptor_unittest::DescriptorTest; + + // Fill the json_name field of FieldDescriptorProto. + void CopyJsonNameTo(DescriptorProto* proto) const; + // Internal version of DebugString; controls the level of indenting for // correct depth. Takes |options| to control debug-string options, and // |include_opening_clause| to indicate whether the "message ... " part of the @@ -484,6 +503,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { const string& name() const; // Name of this field within the message. const string& full_name() const; // Fully-qualified name of the field. + const string& json_name() const; // JSON name of this field. const FileDescriptor* file() const;// File in which this field was defined. bool is_extension() const; // Is this an extension field? int number() const; // Declared tag number. @@ -624,6 +644,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { private: typedef FieldOptions OptionsType; + // Fill the json_name field of FieldDescriptorProto. + void CopyJsonNameTo(FieldDescriptorProto* proto) const; + // See Descriptor::DebugString(). enum PrintLabelFlag { PRINT_LABEL, OMIT_LABEL }; void DebugString(int depth, PrintLabelFlag print_label_flag, @@ -645,6 +668,12 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { const string* full_name_; const string* lowercase_name_; const string* camelcase_name_; + // Whether the user has specified the json_name field option in the .proto + // file. + bool has_json_name_; + // If has_json_name_ is true, it's the value specified by the user. + // Otherwise, it has the same value as lowercase_name_. + const string* json_name_; const FileDescriptor* file_; int number_; Type type_; @@ -1202,6 +1231,9 @@ class LIBPROTOBUF_EXPORT FileDescriptor { // Write the source code information of this FileDescriptor into the given // FileDescriptorProto. See CopyTo() above. void CopySourceCodeInfoTo(FileDescriptorProto* proto) const; + // Fill the json_name field of FieldDescriptorProto for all fields. Can only + // be called after CopyTo(). + void CopyJsonNameTo(FileDescriptorProto* proto) const; // See Descriptor::DebugString(). string DebugString() const; @@ -1559,7 +1591,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // This class contains a lot of hash maps with complicated types that // we'd like to keep out of the header. class Tables; - scoped_ptr tables_; + google::protobuf::scoped_ptr tables_; bool enforce_dependencies_; bool allow_unknown_; @@ -1618,6 +1650,7 @@ PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, json_name) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*) diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index fe23c0ab..921d2cd0 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -200,7 +200,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _internal_metadata_), -1); FieldDescriptorProto_descriptor_ = file->message_type(3); - static const int FieldDescriptorProto_offsets_[9] = { + static const int FieldDescriptorProto_offsets_[10] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, number_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, label_), @@ -209,6 +209,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, extendee_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, default_value_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, oneof_index_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, json_name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, options_), }; FieldDescriptorProto_reflection_ = @@ -663,101 +664,101 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "tobuf.DescriptorProto.ReservedRange\022\025\n\rr" "eserved_name\030\n \003(\t\032,\n\016ExtensionRange\022\r\n\005" "start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\032+\n\rReservedRang" - "e\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\251\005\n\024FieldD" + "e\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\274\005\n\024FieldD" "escriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\003" " \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobuf.Fi" "eldDescriptorProto.Label\0228\n\004type\030\005 \001(\0162*" ".google.protobuf.FieldDescriptorProto.Ty" "pe\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 \001(\t\022" "\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_index\030\t " - "\001(\005\022.\n\007options\030\010 \001(\0132\035.google.protobuf.F" - "ieldOptions\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020\001\022\016\n" - "\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYPE_UI" - "NT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED64\020\006" - "\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n\013TYP" - "E_STRING\020\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_MESSA" - "GE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n" - "\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_" - "SFIXED64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT" - "64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n\016LAB" - "EL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\"$\n\024One" - "ofDescriptorProto\022\014\n\004name\030\001 \001(\t\"\214\001\n\023Enum" - "DescriptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002" - " \003(\0132).google.protobuf.EnumValueDescript" - "orProto\022-\n\007options\030\003 \001(\0132\034.google.protob" - "uf.EnumOptions\"l\n\030EnumValueDescriptorPro" - "to\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007opti" - "ons\030\003 \001(\0132!.google.protobuf.EnumValueOpt" - "ions\"\220\001\n\026ServiceDescriptorProto\022\014\n\004name\030" - "\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.protobuf." - "MethodDescriptorProto\0220\n\007options\030\003 \001(\0132\037" - ".google.protobuf.ServiceOptions\"\301\001\n\025Meth" - "odDescriptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\ninput" - "_type\030\002 \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n\007opti" - "ons\030\004 \001(\0132\036.google.protobuf.MethodOption" - "s\022\037\n\020client_streaming\030\005 \001(\010:\005false\022\037\n\020se" - "rver_streaming\030\006 \001(\010:\005false\"\252\005\n\013FileOpti" - "ons\022\024\n\014java_package\030\001 \001(\t\022\034\n\024java_outer_" - "classname\030\010 \001(\t\022\"\n\023java_multiple_files\030\n" - " \001(\010:\005false\022,\n\035java_generate_equals_and_" - "hash\030\024 \001(\010:\005false\022%\n\026java_string_check_u" - "tf8\030\033 \001(\010:\005false\022F\n\014optimize_for\030\t \001(\0162)" - ".google.protobuf.FileOptions.OptimizeMod" - "e:\005SPEED\022\022\n\ngo_package\030\013 \001(\t\022\"\n\023cc_gener" - "ic_services\030\020 \001(\010:\005false\022$\n\025java_generic" - "_services\030\021 \001(\010:\005false\022\"\n\023py_generic_ser" - "vices\030\022 \001(\010:\005false\022\031\n\ndeprecated\030\027 \001(\010:\005" - "false\022\037\n\020cc_enable_arenas\030\037 \001(\010:\005false\022\031" - "\n\021objc_class_prefix\030$ \001(\t\022\030\n\020csharp_name" - "space\030% \001(\t\022\'\n\037javanano_use_deprecated_p" - "ackage\030& \001(\010\022C\n\024uninterpreted_option\030\347\007 " - "\003(\0132$.google.protobuf.UninterpretedOptio" - "n\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZ" - "E\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016Mes" - "sageOptions\022&\n\027message_set_wire_format\030\001" - " \001(\010:\005false\022.\n\037no_standard_descriptor_ac" - "cessor\030\002 \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:" - "\005false\022\021\n\tmap_entry\030\007 \001(\010\022C\n\024uninterpret" - "ed_option\030\347\007 \003(\0132$.google.protobuf.Unint" - "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptio" - "ns\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Fiel" - "dOptions.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?" - "\n\006jstype\030\006 \001(\0162$.google.protobuf.FieldOp" - "tions.JSType:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005f" - "alse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030" - "\n \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 " - "\003(\0132$.google.protobuf.UninterpretedOptio" - "n\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRI" - "NG_PIECE\020\002\"5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJ" - "S_STRING\020\001\022\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n" - "\013EnumOptions\022\023\n\013allow_alias\030\002 \001(\010\022\031\n\ndep" - "recated\030\003 \001(\010:\005false\022C\n\024uninterpreted_op" - "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre" - "tedOption*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValueOptions" - "\022\031\n\ndeprecated\030\001 \001(\010:\005false\022C\n\024uninterpr" - "eted_option\030\347\007 \003(\0132$.google.protobuf.Uni" - "nterpretedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOp" - "tions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024unin" - "terpreted_option\030\347\007 \003(\0132$.google.protobu" - "f.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMeth" - "odOptions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024" - "uninterpreted_option\030\347\007 \003(\0132$.google.pro" - "tobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n" - "\023UninterpretedOption\022;\n\004name\030\002 \003(\0132-.goo" - "gle.protobuf.UninterpretedOption.NamePar" - "t\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_" - "int_value\030\004 \001(\004\022\032\n\022negative_int_value\030\005 " - "\001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_valu" - "e\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010Name" - "Part\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension\030" - "\002 \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003" - "(\0132(.google.protobuf.SourceCodeInfo.Loca" - "tion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004s" - "pan\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022" - "\031\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_de" - "tached_comments\030\006 \003(\tB;\n\023com.google.prot" - "obufB\020DescriptorProtosH\001Z\ndescriptor\242\002\003G" - "PB", 4962); + "\001(\005\022\021\n\tjson_name\030\n \001(\t\022.\n\007options\030\010 \001(\0132" + "\035.google.protobuf.FieldOptions\"\266\002\n\004Type\022" + "\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE" + "_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020" + "\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n" + "\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GR" + "OUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022" + "\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_" + "SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SI" + "NT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LABE" + "L_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LABE" + "L_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n\004" + "name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004na" + "me\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protobu" + "f.EnumValueDescriptorProto\022-\n\007options\030\003 " + "\001(\0132\034.google.protobuf.EnumOptions\"l\n\030Enu" + "mValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006n" + "umber\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.pr" + "otobuf.EnumValueOptions\"\220\001\n\026ServiceDescr" + "iptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003(\013" + "2&.google.protobuf.MethodDescriptorProto" + "\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Serv" + "iceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n\004" + "name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output" + "_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.pr" + "otobuf.MethodOptions\022\037\n\020client_streaming" + "\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010:" + "\005false\"\252\005\n\013FileOptions\022\024\n\014java_package\030\001" + " \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023ja" + "va_multiple_files\030\n \001(\010:\005false\022,\n\035java_g" + "enerate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026" + "java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014o" + "ptimize_for\030\t \001(\0162).google.protobuf.File" + "Options.OptimizeMode:\005SPEED\022\022\n\ngo_packag" + "e\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005fa" + "lse\022$\n\025java_generic_services\030\021 \001(\010:\005fals" + "e\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n" + "\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_ar" + "enas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030$" + " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022\'\n\037javana" + "no_use_deprecated_package\030& \001(\010\022C\n\024unint" + "erpreted_option\030\347\007 \003(\0132$.google.protobuf" + ".UninterpretedOption\":\n\014OptimizeMode\022\t\n\005" + "SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003" + "*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027messag" + "e_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_sta" + "ndard_descriptor_accessor\030\002 \001(\010:\005false\022\031" + "\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007" + " \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go" + "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200" + "\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(\0162#.g" + "oogle.protobuf.FieldOptions.CType:\006STRIN" + "G\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$.goog" + "le.protobuf.FieldOptions.JSType:\tJS_NORM" + "AL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecated\030\003 " + "\001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024unint" + "erpreted_option\030\347\007 \003(\0132$.google.protobuf" + ".UninterpretedOption\"/\n\005CType\022\n\n\006STRING\020" + "\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JSType\022" + "\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS_NUMB" + "ER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow" + "_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022" + "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google." + "protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"" + "}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(\010:" + "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." + "google.protobuf.UninterpretedOption*\t\010\350\007" + "\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated\030!" + " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003" + "(\0132$.google.protobuf.UninterpretedOption" + "*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndeprecat" + "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030" + "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" + "tion*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOption\022" + ";\n\004name\030\002 \003(\0132-.google.protobuf.Uninterp" + "retedOption.NamePart\022\030\n\020identifier_value" + "\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022ne" + "gative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006" + " \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggregate_" + "value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part\030\001 \002" + "(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016SourceCodeI" + "nfo\022:\n\010location\030\001 \003(\0132(.google.protobuf." + "SourceCodeInfo.Location\032\206\001\n\010Location\022\020\n\004" + "path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020lead" + "ing_comments\030\003 \001(\t\022\031\n\021trailing_comments\030" + "\004 \001(\t\022!\n\031leading_detached_comments\030\006 \003(\t" + "B;\n\023com.google.protobufB\020DescriptorProto" + "sH\001Z\ndescriptor\242\002\003GPB", 4981); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -4109,6 +4110,7 @@ const int FieldDescriptorProto::kTypeNameFieldNumber; const int FieldDescriptorProto::kExtendeeFieldNumber; const int FieldDescriptorProto::kDefaultValueFieldNumber; const int FieldDescriptorProto::kOneofIndexFieldNumber; +const int FieldDescriptorProto::kJsonNameFieldNumber; const int FieldDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER @@ -4141,6 +4143,7 @@ void FieldDescriptorProto::SharedCtor() { extendee_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); oneof_index_ = 0; + json_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); options_ = NULL; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -4155,6 +4158,7 @@ void FieldDescriptorProto::SharedDtor() { type_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); extendee_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + json_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (this != default_instance_) { delete options_; } @@ -4204,8 +4208,13 @@ void FieldDescriptorProto::Clear() { } oneof_index_ = 0; } - if (has_options()) { - if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); + if (_has_bits_[8 / 32] & 768u) { + if (has_json_name()) { + json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + } + if (has_options()) { + if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); + } } ::memset(_has_bits_, 0, sizeof(_has_bits_)); if (_internal_metadata_.have_unknown_fields()) { @@ -4369,6 +4378,23 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(82)) goto parse_json_name; + break; + } + + // optional string json_name = 10; + case 10: { + if (tag == 82) { + parse_json_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_json_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->json_name().data(), this->json_name().length(), + ::google::protobuf::internal::WireFormat::PARSE, + "google.protobuf.FieldDescriptorProto.json_name"); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -4466,6 +4492,16 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->oneof_index(), output); } + // optional string json_name = 10; + if (has_json_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->json_name().data(), this->json_name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.FieldDescriptorProto.json_name"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 10, this->json_name(), output); + } + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); @@ -4549,6 +4585,17 @@ void FieldDescriptorProto::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(9, this->oneof_index(), target); } + // optional string json_name = 10; + if (has_json_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->json_name().data(), this->json_name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.FieldDescriptorProto.json_name"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 10, this->json_name(), target); + } + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); @@ -4616,13 +4663,22 @@ int FieldDescriptorProto::ByteSize() const { } } - // optional .google.protobuf.FieldOptions options = 8; - if (has_options()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - *this->options_); - } + if (_has_bits_[8 / 32] & 768u) { + // optional string json_name = 10; + if (has_json_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->json_name()); + } + // optional .google.protobuf.FieldOptions options = 8; + if (has_options()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + *this->options_); + } + + } if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( @@ -4679,6 +4735,10 @@ void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) { } } if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) { + if (from.has_json_name()) { + set_has_json_name(); + json_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.json_name_); + } if (from.has_options()) { mutable_options()->::google::protobuf::FieldOptions::MergeFrom(from.options()); } @@ -4721,6 +4781,7 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { extendee_.Swap(&other->extendee_); default_value_.Swap(&other->default_value_); std::swap(oneof_index_, other->oneof_index_); + json_name_.Swap(&other->json_name_); std::swap(options_, other->options_); std::swap(_has_bits_[0], other->_has_bits_[0]); _internal_metadata_.Swap(&other->_internal_metadata_); @@ -5048,15 +5109,68 @@ void FieldDescriptorProto::clear_oneof_index() { // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index) } +// optional string json_name = 10; +bool FieldDescriptorProto::has_json_name() const { + return (_has_bits_[0] & 0x00000100u) != 0; +} +void FieldDescriptorProto::set_has_json_name() { + _has_bits_[0] |= 0x00000100u; +} +void FieldDescriptorProto::clear_has_json_name() { + _has_bits_[0] &= ~0x00000100u; +} +void FieldDescriptorProto::clear_json_name() { + json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + clear_has_json_name(); +} + const ::std::string& FieldDescriptorProto::json_name() const { + // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name) + return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void FieldDescriptorProto::set_json_name(const ::std::string& value) { + set_has_json_name(); + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name) +} + void FieldDescriptorProto::set_json_name(const char* value) { + set_has_json_name(); + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.json_name) +} + void FieldDescriptorProto::set_json_name(const char* value, size_t size) { + set_has_json_name(); + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.json_name) +} + ::std::string* FieldDescriptorProto::mutable_json_name() { + set_has_json_name(); + // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name) + return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + ::std::string* FieldDescriptorProto::release_json_name() { + clear_has_json_name(); + return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void FieldDescriptorProto::set_allocated_json_name(::std::string* json_name) { + if (json_name != NULL) { + set_has_json_name(); + } else { + clear_has_json_name(); + } + json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name) +} + // optional .google.protobuf.FieldOptions options = 8; bool FieldDescriptorProto::has_options() const { - return (_has_bits_[0] & 0x00000100u) != 0; + return (_has_bits_[0] & 0x00000200u) != 0; } void FieldDescriptorProto::set_has_options() { - _has_bits_[0] |= 0x00000100u; + _has_bits_[0] |= 0x00000200u; } void FieldDescriptorProto::clear_has_options() { - _has_bits_[0] &= ~0x00000100u; + _has_bits_[0] &= ~0x00000200u; } void FieldDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 931ff02d..60255162 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -1133,6 +1133,18 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa ::google::protobuf::int32 oneof_index() const; void set_oneof_index(::google::protobuf::int32 value); + // optional string json_name = 10; + bool has_json_name() const; + void clear_json_name(); + static const int kJsonNameFieldNumber = 10; + const ::std::string& json_name() const; + void set_json_name(const ::std::string& value); + void set_json_name(const char* value); + void set_json_name(const char* value, size_t size); + ::std::string* mutable_json_name(); + ::std::string* release_json_name(); + void set_allocated_json_name(::std::string* json_name); + // optional .google.protobuf.FieldOptions options = 8; bool has_options() const; void clear_options(); @@ -1160,6 +1172,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline void clear_has_default_value(); inline void set_has_oneof_index(); inline void clear_has_oneof_index(); + inline void set_has_json_name(); + inline void clear_has_json_name(); inline void set_has_options(); inline void clear_has_options(); @@ -1174,6 +1188,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa int type_; ::google::protobuf::int32 oneof_index_; ::google::protobuf::internal::ArenaStringPtr default_value_; + ::google::protobuf::internal::ArenaStringPtr json_name_; ::google::protobuf::FieldOptions* options_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); @@ -4678,15 +4693,68 @@ inline void FieldDescriptorProto::set_oneof_index(::google::protobuf::int32 valu // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index) } +// optional string json_name = 10; +inline bool FieldDescriptorProto::has_json_name() const { + return (_has_bits_[0] & 0x00000100u) != 0; +} +inline void FieldDescriptorProto::set_has_json_name() { + _has_bits_[0] |= 0x00000100u; +} +inline void FieldDescriptorProto::clear_has_json_name() { + _has_bits_[0] &= ~0x00000100u; +} +inline void FieldDescriptorProto::clear_json_name() { + json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + clear_has_json_name(); +} +inline const ::std::string& FieldDescriptorProto::json_name() const { + // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name) + return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void FieldDescriptorProto::set_json_name(const ::std::string& value) { + set_has_json_name(); + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name) +} +inline void FieldDescriptorProto::set_json_name(const char* value) { + set_has_json_name(); + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.json_name) +} +inline void FieldDescriptorProto::set_json_name(const char* value, size_t size) { + set_has_json_name(); + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.json_name) +} +inline ::std::string* FieldDescriptorProto::mutable_json_name() { + set_has_json_name(); + // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name) + return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline ::std::string* FieldDescriptorProto::release_json_name() { + clear_has_json_name(); + return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void FieldDescriptorProto::set_allocated_json_name(::std::string* json_name) { + if (json_name != NULL) { + set_has_json_name(); + } else { + clear_has_json_name(); + } + json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name) +} + // optional .google.protobuf.FieldOptions options = 8; inline bool FieldDescriptorProto::has_options() const { - return (_has_bits_[0] & 0x00000100u) != 0; + return (_has_bits_[0] & 0x00000200u) != 0; } inline void FieldDescriptorProto::set_has_options() { - _has_bits_[0] |= 0x00000100u; + _has_bits_[0] |= 0x00000200u; } inline void FieldDescriptorProto::clear_has_options() { - _has_bits_[0] &= ~0x00000100u; + _has_bits_[0] &= ~0x00000200u; } inline void FieldDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 8f90a956..801d85e4 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -191,6 +191,12 @@ message FieldDescriptorProto { // list. This field is a member of that oneof. optional int32 oneof_index = 9; + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + optional string json_name = 10; + optional FieldOptions options = 8; } diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc index a87fa049..1fc3816e 100644 --- a/src/google/protobuf/descriptor_database_unittest.cc +++ b/src/google/protobuf/descriptor_database_unittest.cc @@ -35,6 +35,10 @@ // This file makes extensive use of RFC 3092. :) #include +#include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -177,7 +181,7 @@ class DescriptorDatabaseTest EXPECT_FALSE(test_case_->AddToDatabase(file_proto)); } - scoped_ptr test_case_; + google::protobuf::scoped_ptr test_case_; DescriptorDatabase* database_; }; diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index e9b027db..ccd0650d 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -34,6 +34,10 @@ // // This file makes extensive use of RFC 3092. :) +#include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -461,6 +465,16 @@ class DescriptorTest : public testing::Test { // map map_int32_int32 = 1; // } // + // // in "json.proto" + // message TestMessage4 { + // optional int32 field_name1 = 1; + // optional int32 fieldName2 = 2; + // optional int32 FieldName3 = 3; + // optional int32 _field_name4 = 4; + // optional int32 FIELD_NAME5 = 5; + // optional int32 field_name6 = 6 [json_name = "@type"]; + // } + // // We cheat and use TestForeign as the type for qux rather than create // an actual nested type. // @@ -526,6 +540,30 @@ class DescriptorTest : public testing::Test { FieldDescriptorProto::TYPE_MESSAGE) ->set_type_name("MapInt32Int32Entry"); + FileDescriptorProto json_file; + json_file.set_name("json.proto"); + json_file.set_syntax("proto3"); + DescriptorProto* message4 = AddMessage(&json_file, "TestMessage4"); + AddField(message4, "field_name1", 1, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddField(message4, "fieldName2", 2, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddField(message4, "FieldName3", 3, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddField(message4, "_field_name4", 4, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddField(message4, "FIELD_NAME5", 5, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddField(message4, "field_name6", 6, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32) + ->set_json_name("@type"); + // Build the descriptors and get the pointers. foo_file_ = pool_.BuildFile(foo_file); ASSERT_TRUE(foo_file_ != NULL); @@ -536,6 +574,9 @@ class DescriptorTest : public testing::Test { map_file_ = pool_.BuildFile(map_file); ASSERT_TRUE(map_file_ != NULL); + json_file_ = pool_.BuildFile(json_file); + ASSERT_TRUE(json_file_ != NULL); + ASSERT_EQ(1, foo_file_->enum_type_count()); enum_ = foo_file_->enum_type(0); @@ -562,6 +603,14 @@ class DescriptorTest : public testing::Test { ASSERT_EQ(1, message3_->field_count()); map_ = message3_->field(0); + + ASSERT_EQ(1, json_file_->message_type_count()); + message4_ = json_file_->message_type(0); + } + + void CopyWithJsonName(const Descriptor* message, DescriptorProto* proto) { + message->CopyTo(proto); + message->CopyJsonNameTo(proto); } DescriptorPool pool_; @@ -569,10 +618,12 @@ class DescriptorTest : public testing::Test { const FileDescriptor* foo_file_; const FileDescriptor* bar_file_; const FileDescriptor* map_file_; + const FileDescriptor* json_file_; const Descriptor* message_; const Descriptor* message2_; const Descriptor* message3_; + const Descriptor* message4_; const Descriptor* foreign_; const EnumDescriptor* enum_; @@ -664,6 +715,35 @@ TEST_F(DescriptorTest, FieldFullName) { EXPECT_EQ("corge.grault.TestMessage2.quux", quux2_->full_name()); } +TEST_F(DescriptorTest, FieldJsonName) { + EXPECT_EQ("fieldName1", message4_->field(0)->json_name()); + EXPECT_EQ("fieldName2", message4_->field(1)->json_name()); + EXPECT_EQ("fieldName3", message4_->field(2)->json_name()); + EXPECT_EQ("fieldName4", message4_->field(3)->json_name()); + EXPECT_EQ("fIELDNAME5", message4_->field(4)->json_name()); + EXPECT_EQ("@type", message4_->field(5)->json_name()); + + DescriptorProto proto; + message4_->CopyTo(&proto); + ASSERT_EQ(6, proto.field_size()); + EXPECT_FALSE(proto.field(0).has_json_name()); + EXPECT_FALSE(proto.field(1).has_json_name()); + EXPECT_FALSE(proto.field(2).has_json_name()); + EXPECT_FALSE(proto.field(3).has_json_name()); + EXPECT_FALSE(proto.field(4).has_json_name()); + EXPECT_EQ("@type", proto.field(5).json_name()); + + proto.Clear(); + CopyWithJsonName(message4_, &proto); + ASSERT_EQ(6, proto.field_size()); + EXPECT_EQ("fieldName1", proto.field(0).json_name()); + EXPECT_EQ("fieldName2", proto.field(1).json_name()); + EXPECT_EQ("fieldName3", proto.field(2).json_name()); + EXPECT_EQ("fieldName4", proto.field(3).json_name()); + EXPECT_EQ("fIELDNAME5", proto.field(4).json_name()); + EXPECT_EQ("@type", proto.field(5).json_name()); +} + TEST_F(DescriptorTest, FieldFile) { EXPECT_EQ(foo_file_, foo_->file()); EXPECT_EQ(foo_file_, bar_->file()); @@ -1900,7 +1980,7 @@ class MiscTest : public testing::Test { return field != NULL ? field->enum_type() : NULL; } - scoped_ptr pool_; + google::protobuf::scoped_ptr pool_; }; TEST_F(MiscTest, TypeNames) { @@ -2330,7 +2410,7 @@ class AllowUnknownDependenciesTest const FieldDescriptor* qux_field_; SimpleDescriptorDatabase db_; // used if in FALLBACK_DATABASE mode. - scoped_ptr pool_; + google::protobuf::scoped_ptr pool_; }; TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) { @@ -5681,6 +5761,32 @@ TEST_F(ValidationErrorTest, ValidateProto3Extension) { "defining options.\n"); } +// Test that field names that may conflict in JSON is not allowed by protoc. +TEST_F(ValidationErrorTest, ValidateProto3JsonName) { + // The comparison is case-insensitive. + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type {" + " name: 'Foo'" + " field { name:'name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }" + "}", + "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"Name\" " + "conflicts with field \"name\". This is not allowed in proto3.\n"); + // Underscores are ignored. + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type {" + " name: 'Foo'" + " field { name:'ab' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }" + "}", + "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"_a__b_\" " + "conflicts with field \"ab\". This is not allowed in proto3.\n"); +} + // =================================================================== // DescriptorDatabase diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 2324d952..091fc975 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -64,6 +64,10 @@ #include #include +#include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -229,8 +233,8 @@ class DynamicMessage : public Message { // Warning: The order in which the following pointers are defined is // important (the prototype must be deleted *before* the offsets). - scoped_array offsets; - scoped_ptr reflection; + google::protobuf::scoped_array offsets; + google::protobuf::scoped_ptr reflection; // Don't use a scoped_ptr to hold the prototype: the destructor for // DynamicMessage needs to know whether it is the prototype, and does so by // looking back at this field. This would assume details about the diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc index b9796c76..70e437d7 100644 --- a/src/google/protobuf/dynamic_message_unittest.cc +++ b/src/google/protobuf/dynamic_message_unittest.cc @@ -40,6 +40,11 @@ // reflection_ops_unittest, cover the rest of the functionality used by // DynamicMessage. +#include +#ifndef _SHARED_PTR_H +#include +#endif + #include #include #include @@ -144,7 +149,7 @@ TEST_F(DynamicMessageTest, IndependentOffsets) { // Check that all fields have independent offsets by setting each // one to a unique value then checking that they all still have those // unique values (i.e. they don't stomp each other). - scoped_ptr message(prototype_->New()); + google::protobuf::scoped_ptr message(prototype_->New()); TestUtil::ReflectionTester reflection_tester(descriptor_); reflection_tester.SetAllFieldsViaReflection(message.get()); @@ -153,7 +158,7 @@ TEST_F(DynamicMessageTest, IndependentOffsets) { TEST_F(DynamicMessageTest, Extensions) { // Check that extensions work. - scoped_ptr message(extensions_prototype_->New()); + google::protobuf::scoped_ptr message(extensions_prototype_->New()); TestUtil::ReflectionTester reflection_tester(extensions_descriptor_); reflection_tester.SetAllFieldsViaReflection(message.get()); @@ -162,7 +167,7 @@ TEST_F(DynamicMessageTest, Extensions) { TEST_F(DynamicMessageTest, PackedFields) { // Check that packed fields work properly. - scoped_ptr message(packed_prototype_->New()); + google::protobuf::scoped_ptr message(packed_prototype_->New()); TestUtil::ReflectionTester reflection_tester(packed_descriptor_); reflection_tester.SetPackedFieldsViaReflection(message.get()); @@ -171,7 +176,7 @@ TEST_F(DynamicMessageTest, PackedFields) { TEST_F(DynamicMessageTest, Oneof) { // Check that oneof fields work properly. - scoped_ptr message(oneof_prototype_->New()); + google::protobuf::scoped_ptr message(oneof_prototype_->New()); // Check default values. const Descriptor* descriptor = message->GetDescriptor(); @@ -232,7 +237,7 @@ TEST_F(DynamicMessageTest, SpaceUsed) { // Since we share the implementation with generated messages, we don't need // to test very much here. Just make sure it appears to be working. - scoped_ptr message(prototype_->New()); + google::protobuf::scoped_ptr message(prototype_->New()); TestUtil::ReflectionTester reflection_tester(descriptor_); int initial_space_used = message->SpaceUsed(); diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index 919bd83b..9afb2361 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -594,20 +595,21 @@ void ExtensionSet::SetAllocatedMessage(int number, FieldType type, ClearExtension(number); return; } + ::google::protobuf::Arena* message_arena = message->GetArena(); Extension* extension; if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = false; extension->is_lazy = false; - if (message->GetArena() == arena_) { + if (message_arena == arena_) { extension->message_value = message; + } else if (message_arena == NULL) { + extension->message_value = message; + arena_->Own(message); // not NULL because not equal to message_arena } else { extension->message_value = message->New(arena_); extension->message_value->CheckTypeAndMergeFrom(*message); - if (message->GetArena() == NULL) { - delete message; - } } } else { GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); @@ -617,14 +619,14 @@ void ExtensionSet::SetAllocatedMessage(int number, FieldType type, if (arena_ == NULL) { delete extension->message_value; } - if (message->GetArena() == arena_) { + if (message_arena == arena_) { extension->message_value = message; + } else if (message_arena == NULL) { + extension->message_value = message; + arena_->Own(message); // not NULL because not equal to message_arena } else { extension->message_value = message->New(arena_); extension->message_value->CheckTypeAndMergeFrom(*message); - if (message->GetArena() == NULL) { - delete message; - } } } } diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index 09681259..40704608 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -724,8 +724,7 @@ class RepeatedPrimitiveTypeTraits { static const RepeatedFieldType* GetDefaultRepeatedField(); }; -LIBPROTOBUF_EXPORT extern ProtobufOnceType -repeated_primitive_generic_type_traits_once_init_; +extern ProtobufOnceType repeated_primitive_generic_type_traits_once_init_; class LIBPROTOBUF_EXPORT RepeatedPrimitiveGenericTypeTraits { private: @@ -766,7 +765,7 @@ template<> inline void RepeatedPrimitiveTypeTraits::Add( \ } \ template<> inline const RepeatedField* \ RepeatedPrimitiveTypeTraits::GetDefaultRepeatedField() { \ - GoogleOnceInit( \ + ::google::protobuf::GoogleOnceInit( \ &repeated_primitive_generic_type_traits_once_init_, \ &RepeatedPrimitiveGenericTypeTraits::InitializeDefaultRepeatedFields); \ return RepeatedPrimitiveGenericTypeTraits:: \ @@ -822,8 +821,7 @@ class LIBPROTOBUF_EXPORT StringTypeTraits { } }; -LIBPROTOBUF_EXPORT extern ProtobufOnceType -repeated_string_type_traits_once_init_; +extern ProtobufOnceType repeated_string_type_traits_once_init_; class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { public: @@ -868,7 +866,7 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { } static const RepeatedFieldType* GetDefaultRepeatedField() { - GoogleOnceInit(&repeated_string_type_traits_once_init_, + ::google::protobuf::GoogleOnceInit(&repeated_string_type_traits_once_init_, &InitializeDefaultRepeatedFields); return default_repeated_field_; } @@ -1034,8 +1032,7 @@ class RepeatedMessageTypeTraits { static const RepeatedFieldType* GetDefaultRepeatedField(); }; -LIBPROTOBUF_EXPORT extern ProtobufOnceType -repeated_message_generic_type_traits_once_init_; +extern ProtobufOnceType repeated_message_generic_type_traits_once_init_; // This class exists only to hold a generic default empty repeated field for all // message-type repeated field extensions. @@ -1052,7 +1049,7 @@ class LIBPROTOBUF_EXPORT RepeatedMessageGenericTypeTraits { template inline const typename RepeatedMessageTypeTraits::RepeatedFieldType* RepeatedMessageTypeTraits::GetDefaultRepeatedField() { - GoogleOnceInit( + ::google::protobuf::GoogleOnceInit( &repeated_message_generic_type_traits_once_init_, &RepeatedMessageGenericTypeTraits::InitializeDefaultRepeatedFields); return reinterpret_cast( diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 1569120d..f40fcbc2 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -360,9 +360,8 @@ TEST(ExtensionSetTest, ArenaSetAllocatedMessageAndRelease) { unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage(); message->SetAllocatedExtension(unittest::optional_foreign_message_extension, foreign_message); - // foreign_message is copied underneath, as foreign_message is on heap - // and extension_set is on an arena. - EXPECT_NE(foreign_message, + // foreign_message is now owned by the arena. + EXPECT_EQ(foreign_message, message->MutableExtension( unittest::optional_foreign_message_extension)); diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc index df043844..85ebdef1 100644 --- a/src/google/protobuf/generated_message_reflection_unittest.cc +++ b/src/google/protobuf/generated_message_reflection_unittest.cc @@ -43,6 +43,11 @@ // rather than generated accessors. #include +#include +#ifndef _SHARED_PTR_H +#include +#endif + #include #include #include @@ -354,7 +359,7 @@ TEST(GeneratedMessageReflectionTest, ReleaseLast) { ASSERT_EQ(2, message.repeated_foreign_message_size()); const protobuf_unittest::ForeignMessage* expected = message.mutable_repeated_foreign_message(1); - scoped_ptr released(message.GetReflection()->ReleaseLast( + google::protobuf::scoped_ptr released(message.GetReflection()->ReleaseLast( &message, descriptor->FindFieldByName("repeated_foreign_message"))); EXPECT_EQ(expected, released.get()); } @@ -377,9 +382,9 @@ TEST(GeneratedMessageReflectionTest, ReleaseLastExtensions) { unittest::repeated_foreign_message_extension)); const protobuf_unittest::ForeignMessage* expected = message.MutableExtension( unittest::repeated_foreign_message_extension, 1); - scoped_ptr released(message.GetReflection()->ReleaseLast( + google::protobuf::scoped_ptr released(message.GetReflection()->ReleaseLast( &message, descriptor->file()->FindExtensionByName( - "repeated_foreign_message_extension"))); + "repeated_foreign_message_extension"))); EXPECT_EQ(expected, released.get()); } diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc index afaca2ee..7b813f8a 100644 --- a/src/google/protobuf/generated_message_util.cc +++ b/src/google/protobuf/generated_message_util.cc @@ -63,7 +63,6 @@ void InitEmptyString() { int StringSpaceUsedExcludingSelf(const string& str) { const void* start = &str; const void* end = &str + 1; - if (start <= str.data() && str.data() < end) { // The string's data is stored inside the string object itself. return 0; @@ -73,6 +72,7 @@ int StringSpaceUsedExcludingSelf(const string& str) { } + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index 630c9086..d1782e39 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -34,6 +34,10 @@ // // This file contains tests and benchmarks. +#include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -679,7 +683,7 @@ TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnStack) { } TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) { - scoped_array buffer(new uint8[8]); + google::protobuf::scoped_array buffer(new uint8[8]); CodedInputStream coded_input(buffer.get(), 8); string str; EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30)); diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h index 9cdf0378..a598ef2e 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -44,6 +44,10 @@ #ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ #define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ +#include +#ifndef _SHARED_PTR_H +#include +#endif #include #include #include @@ -235,7 +239,7 @@ class LIBPROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream // Data is read into this buffer. It may be NULL if no buffer is currently // in use. Otherwise, it points to an array of size buffer_size_. - scoped_array buffer_; + google::protobuf::scoped_array buffer_; const int buffer_size_; // Number of valid bytes currently in the buffer (i.e. the size last @@ -324,7 +328,7 @@ class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStrea // Data is written from this buffer. It may be NULL if no buffer is // currently in use. Otherwise, it points to an array of size buffer_size_. - scoped_array buffer_; + google::protobuf::scoped_array buffer_; const int buffer_size_; // Number of valid bytes currently in the buffer (i.e. the size last diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index 3850e76c..8c7358c1 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc @@ -57,6 +57,10 @@ #include #include #include +#include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -197,7 +201,7 @@ void IoTest::WriteString(ZeroCopyOutputStream* output, const string& str) { } void IoTest::ReadString(ZeroCopyInputStream* input, const string& str) { - scoped_array buffer(new char[str.size() + 1]); + google::protobuf::scoped_array buffer(new char[str.size() + 1]); buffer[str.size()] = '\0'; EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size()); EXPECT_STREQ(str.c_str(), buffer.get()); diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index 16c4a08f..f116697c 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -155,7 +155,8 @@ void TypeDefinedMapFieldBase::CopyIterator( this_iter->key_.SetType(that_iter.key_.type()); // MapValueRef::type() fails when containing data is null. However, if // this_iter points to MapEnd, data can be null. - this_iter->value_.SetType((FieldDescriptor::CppType)that_iter.value_.type_); + this_iter->value_.SetType( + static_cast(that_iter.value_.type_)); SetMapIteratorValue(this_iter); } diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto index 6f9d6165..916cc546 100644 --- a/src/google/protobuf/map_proto2_unittest.proto +++ b/src/google/protobuf/map_proto2_unittest.proto @@ -31,6 +31,8 @@ syntax = "proto2"; +import "google/protobuf/unittest_import.proto"; + // We don't put this in a package within proto2 because we need to make sure // that the generated code doesn't depend on being in the proto2 namespace. // In map_test_util.h we do "using namespace unittest = protobuf_unittest". @@ -58,3 +60,7 @@ message TestEnumMapPlusExtra { map known_map_field = 101; map unknown_map_field = 102; } + +message TestImportEnumMap { + map import_enum_amp = 1; +} diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index 16a24c25..451b02e8 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -2154,7 +2154,7 @@ TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) { // Check that all fields have independent offsets by setting each // one to a unique value then checking that they all still have those // unique values (i.e. they don't stomp each other). - scoped_ptr message(map_prototype_->New()); + google::protobuf::scoped_ptr message(map_prototype_->New()); MapReflectionTester reflection_tester(map_descriptor_); reflection_tester.SetMapFieldsViaReflection(message.get()); @@ -2163,7 +2163,7 @@ TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) { TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) { // Check that map fields work properly. - scoped_ptr message(map_prototype_->New()); + google::protobuf::scoped_ptr message(map_prototype_->New()); // Check set functions. MapReflectionTester reflection_tester(map_descriptor_); @@ -2177,7 +2177,7 @@ TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) { // Since we share the implementation with generated messages, we don't need // to test very much here. Just make sure it appears to be working. - scoped_ptr message(map_prototype_->New()); + google::protobuf::scoped_ptr message(map_prototype_->New()); MapReflectionTester reflection_tester(map_descriptor_); int initial_space_used = message->SpaceUsed(); diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 2f6416d0..d9c200c6 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -55,7 +55,6 @@ #include #include #include -#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index 348e7c7f..7c27afd9 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -971,7 +971,7 @@ class LIBPROTOBUF_EXPORT Reflection { return false; } - // Returns a MaIterator referring to the first element in the map field. + // Returns a MapIterator referring to the first element in the map field. // If the map field is empty, this function returns the same as // reflection::MapEnd. Mutation to the field may invalidate the iterator. virtual MapIterator MapBegin( diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index b10e7a95..5530fefe 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -649,7 +649,7 @@ inline const Message& GenericTypeHandler::default_instance() { // StringTypeHandler is exported. So, we factor out StringTypeHandlerBase, // export that, then make StringTypeHandler be a subclass which is NOT // exported. -// TODO(kenton): Now that StringSpaceUsedExcludingSelf() is in the lite +// TODO(kenton): Now that StringSpaceUsedExcludingSelf() is in the lite // library, this can be cleaned up. class LIBPROTOBUF_EXPORT StringTypeHandlerBase { public: diff --git a/src/google/protobuf/stubs/stringpiece.h b/src/google/protobuf/stubs/stringpiece.h index 353a60d3..ec3ffd5b 100644 --- a/src/google/protobuf/stubs/stringpiece.h +++ b/src/google/protobuf/stubs/stringpiece.h @@ -149,6 +149,7 @@ #include #include +#include namespace google { namespace protobuf { @@ -437,4 +438,16 @@ extern std::ostream& operator<<(std::ostream& o, StringPiece piece); } // namespace protobuf } // namespace google +GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START +template<> struct hash { + size_t operator()(const StringPiece& s) const { + size_t result = 0; + for (const char *str = s.data(), *end = str + s.size(); str < end; str++) { + result = 5 * result + *str; + } + return result; + } +}; +GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END + #endif // STRINGS_STRINGPIECE_H_ diff --git a/src/google/protobuf/stubs/stringpiece_unittest.cc b/src/google/protobuf/stubs/stringpiece_unittest.cc index 9b5dae13..1cb7d12b 100644 --- a/src/google/protobuf/stubs/stringpiece_unittest.cc +++ b/src/google/protobuf/stubs/stringpiece_unittest.cc @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -745,6 +746,23 @@ TEST(StringPiece, Comparisons2) { EXPECT_TRUE(abc.ends_with("nopqrstuvwxyz")); } +TEST(StringPiece, HashFunction) { + hash_set set; + + set.insert(StringPiece("hello")); + EXPECT_EQ(1, set.size()); + + // Insert a StringPiece of the same value again and should NOT increment + // size of the set. + set.insert(StringPiece("hello")); + EXPECT_EQ(1, set.size()); + + // Insert a StringPiece with different value and check that size of the set + // has been increment by one. + set.insert(StringPiece("world")); + EXPECT_EQ(2, set.size()); +} + TEST(ComparisonOpsTest, StringCompareNotAmbiguous) { EXPECT_EQ("hello", string("hello")); EXPECT_LT("hello", string("world")); diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index 4d8c1f91..38b9069b 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -377,8 +377,8 @@ class TextFormat::Parser::ParserImpl { if (internal::GetAnyFieldDescriptors(*message, &any_type_url_field, &any_value_field) && TryConsume("[")) { - string full_type_name; - DO(ConsumeAnyTypeUrl(&full_type_name)); + string full_type_name, prefix; + DO(ConsumeAnyTypeUrl(&full_type_name, &prefix)); DO(Consume("]")); string serialized_value; DO(ConsumeAnyValue(full_type_name, @@ -386,7 +386,7 @@ class TextFormat::Parser::ParserImpl { &serialized_value)); reflection->SetString( message, any_type_url_field, - string(internal::kTypeGoogleApisComPrefix) + full_type_name); + string(prefix + full_type_name)); reflection->SetString(message, any_value_field, serialized_value); return true; // Fall through. @@ -981,7 +981,8 @@ class TextFormat::Parser::ParserImpl { } // Consumes Any::type_url value, of form "type.googleapis.com/full.type.Name" - bool ConsumeAnyTypeUrl(string* full_type_name) { + // or "type.googleprod.com/full.type.Name" + bool ConsumeAnyTypeUrl(string* full_type_name, string* prefix) { // TODO(saito) Extend Consume() to consume multiple tokens at once, so that // this code can be written as just DO(Consume(kGoogleApisTypePrefix)). string url1, url2, url3; @@ -993,10 +994,12 @@ class TextFormat::Parser::ParserImpl { DO(Consume("/")); DO(ConsumeFullTypeName(full_type_name)); - const string prefix = url1 + "." + url2 + "." + url3 + "/"; - if (prefix != internal::kTypeGoogleApisComPrefix) { + *prefix = url1 + "." + url2 + "." + url3 + "/"; + if (*prefix != internal::kTypeGoogleApisComPrefix && + *prefix != internal::kTypeGoogleProdComPrefix) { ReportError("TextFormat::Parser for Any supports only " - "type.googleapi.com, but found \"" + prefix + "\""); + "type.googleapis.com and type.googleprod.com, " + "but found \"" + *prefix + "\""); return false; } return true; diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 1aafd8e6..8d61be19 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -37,6 +37,10 @@ #include #include #include +#include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -931,7 +935,7 @@ class TextFormatParserTest : public testing::Test { protected: void ExpectFailure(const string& input, const string& message, int line, int col) { - scoped_ptr proto(new unittest::TestAllTypes); + google::protobuf::scoped_ptr proto(new unittest::TestAllTypes); ExpectFailure(input, message, line, col, proto.get()); } @@ -992,7 +996,7 @@ class TextFormatParserTest : public testing::Test { }; TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) { - scoped_ptr message(new unittest::TestAllTypes); + google::protobuf::scoped_ptr message(new unittest::TestAllTypes); const Descriptor* d = message->GetDescriptor(); string stringData = @@ -1057,7 +1061,7 @@ TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) { } TEST_F(TextFormatParserTest, ParseFieldValueFromString) { - scoped_ptr message(new unittest::TestAllTypes); + google::protobuf::scoped_ptr message(new unittest::TestAllTypes); const Descriptor* d = message->GetDescriptor(); #define EXPECT_FIELD(name, value, valuestring) \ diff --git a/src/google/protobuf/unittest_import.proto b/src/google/protobuf/unittest_import.proto index 7e165220..8d03e388 100644 --- a/src/google/protobuf/unittest_import.proto +++ b/src/google/protobuf/unittest_import.proto @@ -64,3 +64,10 @@ enum ImportEnum { IMPORT_BAZ = 9; } + +// To use an enum in a map, it must has the first value as 0. +enum ImportEnumForMap { + UNKNOWN = 0; + FOO = 1; + BAR = 2; +} diff --git a/src/google/protobuf/util/default_value_objectwriter.h b/src/google/protobuf/util/default_value_objectwriter.h new file mode 100644 index 00000000..11b9f801 --- /dev/null +++ b/src/google/protobuf/util/default_value_objectwriter.h @@ -0,0 +1,218 @@ +#ifndef NET_PROTO2_UTIL_CONVERTER_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H_ +#define NET_PROTO2_UTIL_CONVERTER_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H_ + +#include +#include +#include + +#include "base/macros.h" +#include "net/proto2/util/converter/internal/type_info.h" +#include "net/proto2/util/converter/public/datapiece.h" +#include "net/proto2/util/converter/public/object_writer.h" +#include "net/proto2/util/converter/public/utility.h" +#include "net/proto2/util/public/type_resolver.h" +#include "strings/stringpiece.h" + +namespace proto2 { +namespace util { +namespace converter { + +// An ObjectWriter that renders non-repeated primitive fields of proto messages +// with their default values. DefaultValueObjectWriter holds objects, lists and +// fields it receives in a tree structure and writes them out to another +// ObjectWriter when EndObject() is called on the root object. It also writes +// out all non-repeated primitive fields that haven't been explicitly rendered +// with their default values (0 for numbers, "" for strings, etc). +class DefaultValueObjectWriter : public ObjectWriter { + public: +#ifndef PROTO2_OPENSOURCE + DefaultValueObjectWriter(const TypeInfo& typeinfo, + const google::protobuf::Type& type, + ObjectWriter* ow); +#endif // !PROTO2_OPENSOURCE + DefaultValueObjectWriter(TypeResolver* type_resolver, + const google::protobuf::Type& type, + ObjectWriter* ow); + + virtual ~DefaultValueObjectWriter(); + + // ObjectWriter methods. + virtual DefaultValueObjectWriter* StartObject(StringPiece name); + + virtual DefaultValueObjectWriter* EndObject(); + + virtual DefaultValueObjectWriter* StartList(StringPiece name); + + virtual DefaultValueObjectWriter* EndList(); + + virtual DefaultValueObjectWriter* RenderBool(StringPiece name, bool value); + + virtual DefaultValueObjectWriter* RenderInt32(StringPiece name, int32 value); + + virtual DefaultValueObjectWriter* RenderUint32(StringPiece name, + uint32 value); + + virtual DefaultValueObjectWriter* RenderInt64(StringPiece name, int64 value); + + virtual DefaultValueObjectWriter* RenderUint64(StringPiece name, + uint64 value); + + virtual DefaultValueObjectWriter* RenderDouble(StringPiece name, + double value); + + virtual DefaultValueObjectWriter* RenderFloat(StringPiece name, float value); + + virtual DefaultValueObjectWriter* RenderString(StringPiece name, + StringPiece value); +#ifdef PROTO2_OPENSOURCE + virtual DefaultValueObjectWriter* RenderBytes(StringPiece name, + StringPiece value); +#else // PROTO2_OPENSOURCE + virtual DefaultValueObjectWriter* RenderCord(StringPiece name, + const Cord& value); +#endif // !PROTO2_OPENSOURCE + + virtual DefaultValueObjectWriter* RenderNull(StringPiece name); + + virtual DefaultValueObjectWriter* DisableCaseNormalizationForNextKey(); + + private: + enum NodeKind { + PRIMITIVE = 0, + OBJECT = 1, + LIST = 2, + MAP = 3, + }; + + // "Node" represents a node in the tree that holds the input of + // DefaultValueObjectWriter. + class Node { + public: + Node(const string& name, const google::protobuf::Type* type, NodeKind kind, + const DataPiece& data, bool is_placeholder); + virtual ~Node() { + for (int i = 0; i < children_.size(); ++i) { + delete children_[i]; + } + } + + // Adds a child to this node. Takes ownership of this child. + void AddChild(Node* child) { children_.push_back(child); } + + // Finds the child given its name. + Node* FindChild(StringPiece name); + + // Populates children of this Node based on its type. If there are already + // children created, they will be merged to the result. Caller should pass + // in TypeInfo for looking up types of the children. + void PopulateChildren(const TypeInfo* typeinfo); + + // If this node is a leaf (has data), writes the current node to the + // ObjectWriter; if not, then recursively writes the children to the + // ObjectWriter. + void WriteTo(ObjectWriter* ow); + + // Accessors + const string& name() const { return name_; } + + const google::protobuf::Type* type() { return type_; } + + void set_type(const google::protobuf::Type* type) { type_ = type; } + + NodeKind kind() { return kind_; } + + int number_of_children() { return children_.size(); } + + void set_data(const DataPiece& data) { data_ = data; } + + void set_disable_normalize(bool disable_normalize) { + disable_normalize_ = disable_normalize; + } + + bool is_any() { return is_any_; } + + void set_is_any(bool is_any) { is_any_ = is_any; } + + void set_is_placeholder(bool is_placeholder) { + is_placeholder_ = is_placeholder; + } + + private: + // Returns the Value Type of a map given the Type of the map entry and a + // TypeInfo instance. + const google::protobuf::Type* GetMapValueType( + const google::protobuf::Type& entry_type, const TypeInfo* typeinfo); + + // Calls WriteTo() on every child in children_. + void WriteChildren(ObjectWriter* ow); + + // The name of this node. + string name_; + // google::protobuf::Type of this node. Owned by TypeInfo. + const google::protobuf::Type* type_; + // The kind of this node. + NodeKind kind_; + // Whether to disable case normalization of the name. + bool disable_normalize_; + // Whether this is a node for "Any". + bool is_any_; + // The data of this node when it is a leaf node. + DataPiece data_; + // Children of this node. + std::vector children_; + // Whether this node is a placeholder for an object or list automatically + // generated when creating the parent node. Should be set to false after + // the parent node's StartObject()/StartList() method is called with this + // node's name. + bool is_placeholder_; + }; + + // Populates children of "node" if it is an "any" Node and its real type has + // been given. + void MaybePopulateChildrenOfAny(Node* node); + + // Writes the root_ node to ow_ and resets the root_ and current_ pointer to + // nullptr. + void WriteRoot(); + + // Creates a DataPiece containing the default value of the type of the field. + static DataPiece CreateDefaultDataPieceForField( + const google::protobuf::Field& field); + + // Returns disable_normalize_ and reset it to false. + bool GetAndResetDisableNormalize() { + return disable_normalize_ ? (disable_normalize_ = false, true) : false; + } + + // Adds or replaces the data_ of a primitive child node. + void RenderDataPiece(StringPiece name, const DataPiece& data); + + // Type information for all the types used in the descriptor. Used to find + // google::protobuf::Type of nested messages/enums. + const TypeInfo* typeinfo_; + // Whether the TypeInfo object is owned by this class. + bool own_typeinfo_; + // google::protobuf::Type of the root message type. + const google::protobuf::Type& type_; + // Holds copies of strings passed to RenderString. + vector string_values_; + + // Whether to disable case normalization of the next node. + bool disable_normalize_; + // The current Node. Owned by its parents. + Node* current_; + // The root Node. + std::unique_ptr root_; + // The stack to hold the path of Nodes from current_ to root_; + std::stack stack_; + + ObjectWriter* ow_; + + DISALLOW_COPY_AND_ASSIGN(DefaultValueObjectWriter); +}; + +} // namespace converter +} // namespace util +} // namespace proto2 + +#endif // NET_PROTO2_UTIL_CONVERTER_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H_ diff --git a/src/google/protobuf/util/field_comparator_test.cc b/src/google/protobuf/util/field_comparator_test.cc index 845839ac..748c7d11 100644 --- a/src/google/protobuf/util/field_comparator_test.cc +++ b/src/google/protobuf/util/field_comparator_test.cc @@ -34,8 +34,8 @@ #include #include -#include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc index 82034bd4..29ca9c1e 100644 --- a/src/google/protobuf/util/field_mask_util.cc +++ b/src/google/protobuf/util/field_mask_util.cc @@ -43,7 +43,7 @@ string FieldMaskUtil::ToString(const FieldMask& mask) { return Join(mask.paths(), ","); } -void FieldMaskUtil::FromString(const string& str, FieldMask* out) { +void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) { out->Clear(); vector paths = Split(str, ","); for (int i = 0; i < paths.size(); ++i) { @@ -53,7 +53,7 @@ void FieldMaskUtil::FromString(const string& str, FieldMask* out) { } bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor, - const string& path) { + StringPiece path) { vector parts = Split(path, "."); for (int i = 0; i < parts.size(); ++i) { const string& field_name = parts[i]; @@ -386,15 +386,15 @@ void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2, intersection.MergeToFieldMask(out); } -bool FieldMaskUtil::IsPathInFieldMask(const string& path, - const FieldMask& mask) { +bool FieldMaskUtil::IsPathInFieldMask(StringPiece path, const FieldMask& mask) { for (int i = 0; i < mask.paths_size(); ++i) { const string& mask_path = mask.paths(i); if (path == mask_path) { return true; } else if (mask_path.length() < path.length()) { // Also check whether mask.paths(i) is a prefix of path. - if (path.compare(0, mask_path.length() + 1, mask_path + ".") == 0) { + if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") == + 0) { return true; } } diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h index c99c34f8..92f69893 100644 --- a/src/google/protobuf/util/field_mask_util.h +++ b/src/google/protobuf/util/field_mask_util.h @@ -35,6 +35,7 @@ #include #include +#include namespace google { namespace protobuf { @@ -47,11 +48,11 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { // Converts FieldMask to/from string, formatted according to proto3 JSON // spec for FieldMask (e.g., "foo,bar,baz.quz"). static string ToString(const FieldMask& mask); - static void FromString(const string& str, FieldMask* out); + static void FromString(StringPiece str, FieldMask* out); // Checks whether the given path is valid for type T. template - static bool IsValidPath(const string& path) { + static bool IsValidPath(StringPiece path) { return InternalIsValidPath(T::descriptor(), path); } @@ -67,7 +68,7 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { // Adds a path to FieldMask after checking whether the given path is valid. // This method check-fails if the path is not a valid path for type T. template - static void AddPathToFieldMask(const string& path, FieldMask* mask) { + static void AddPathToFieldMask(StringPiece path, FieldMask* mask) { GOOGLE_CHECK(IsValidPath(path)); mask->add_paths(path); } @@ -96,7 +97,7 @@ 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. - static bool IsPathInFieldMask(const string& path, const FieldMask& mask); + static bool IsPathInFieldMask(StringPiece path, const FieldMask& mask); class MergeOptions; // Merges fields specified in a FieldMask into another message. @@ -105,7 +106,7 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { private: static bool InternalIsValidPath(const Descriptor* descriptor, - const string& path); + StringPiece path); static void InternalGetFieldMaskForAllFields(const Descriptor* descriptor, FieldMask* out); diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h index d4547601..bcb526e8 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.h +++ b/src/google/protobuf/util/internal/default_value_objectwriter.h @@ -110,7 +110,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // "Node" represents a node in the tree that holds the input of // DefaultValueObjectWriter. - class Node { + class LIBPROTOBUF_EXPORT Node { public: Node(const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, bool is_placeholder); diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc index f81e3306..94d2ab7a 100644 --- a/src/google/protobuf/util/internal/json_objectwriter.cc +++ b/src/google/protobuf/util/internal/json_objectwriter.cc @@ -37,8 +37,8 @@ #include #include #include -#include #include +#include namespace google { namespace protobuf { @@ -116,7 +116,7 @@ JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name, JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name, double value) { - if (google::protobuf::MathLimits::IsFinite(value)) { + if (MathLimits::IsFinite(value)) { return RenderSimple(name, SimpleDtoa(value)); } @@ -126,7 +126,7 @@ JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name, JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, float value) { - if (google::protobuf::MathLimits::IsFinite(value)) { + if (MathLimits::IsFinite(value)) { return RenderSimple(name, SimpleFtoa(value)); } diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc index 996e1f8c..aebf19a1 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource.cc @@ -47,7 +47,6 @@ #include #include #include -#include #include @@ -140,6 +139,7 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type, const uint32 end_tag, bool include_start_and_end, ObjectWriter* ow) const { + const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); if (type_renderer != NULL) { return (*type_renderer)(this, type, name, ow); @@ -332,10 +332,9 @@ Status ProtoStreamObjectSource::RenderDuration( if (seconds < 0) { if (nanos > 0) { return Status(util::error::INTERNAL, - StrCat( - "Duration nanos is non-negative, but seconds is " - "negative for field: ", - field_name)); + StrCat("Duration nanos is non-negative, but seconds is " + "negative for field: ", + field_name)); } sign = "-"; seconds = -seconds; @@ -648,6 +647,7 @@ Status ProtoStreamObjectSource::RenderFieldMask( return Status::OK; } + hash_map* ProtoStreamObjectSource::renderers_ = NULL; GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_); @@ -670,13 +670,16 @@ void ProtoStreamObjectSource::InitRendererMap() { &ProtoStreamObjectSource::RenderInt32; (*renderers_)["google.protobuf.UInt32Value"] = &ProtoStreamObjectSource::RenderUInt32; - (*renderers_)["google.protobuf.BoolValue"] = &ProtoStreamObjectSource::RenderBool; + (*renderers_)["google.protobuf.BoolValue"] = + &ProtoStreamObjectSource::RenderBool; (*renderers_)["google.protobuf.StringValue"] = &ProtoStreamObjectSource::RenderString; (*renderers_)["google.protobuf.BytesValue"] = &ProtoStreamObjectSource::RenderBytes; - (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny; - (*renderers_)["google.protobuf.Struct"] = &ProtoStreamObjectSource::RenderStruct; + (*renderers_)["google.protobuf.Any"] = + &ProtoStreamObjectSource::RenderAny; + (*renderers_)["google.protobuf.Struct"] = + &ProtoStreamObjectSource::RenderStruct; (*renderers_)["google.protobuf.Value"] = &ProtoStreamObjectSource::RenderStructValue; (*renderers_)["google.protobuf.ListValue"] = @@ -835,6 +838,7 @@ Status ProtoStreamObjectSource::RenderField( StrCat("Invalid configuration. Could not find the type: ", field->type_url())); } + RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow)); if (!stream_->ConsumedEntireMessage()) { return Status(util::error::INVALID_ARGUMENT, @@ -988,7 +992,7 @@ std::pair ProtoStreamObjectSource::ReadSecondsAndNanos( uint32 nanos = 0; uint32 tag = 0; int64 signed_seconds = 0; - int64 signed_nanos = 0; + int32 signed_nanos = 0; for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) { const google::protobuf::Field* field = FindAndVerifyField(type, tag); diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h index f52383a1..3cd37aa1 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.h +++ b/src/google/protobuf/util/internal/protostream_objectsource.h @@ -188,8 +188,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { // Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter. static util::Status RenderStructListValue( - const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, + const ProtoStreamObjectSource* os, const google::protobuf::Type& type, StringPiece name, ObjectWriter* ow); // Render the "Any" type. @@ -211,6 +210,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { util::Status RenderField(const google::protobuf::Field* field, StringPiece field_name, ObjectWriter* ow) const; + // Reads field value according to Field spec in 'field' and returns the read // value as string. This only works for primitive datatypes (no message // types). diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc index a935ac39..bd245999 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc @@ -33,13 +33,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -397,8 +397,8 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece( const TypeRenderer* type_renderer = FindTypeRenderer(GetFullTypeWithUrl(ow_->master_type_.name())); if (type_renderer) { - // TODO(rikka): Don't just ignore the util::Status object! - (*type_renderer)(ow_.get(), value); + Status status = (*type_renderer)(ow_.get(), value); + if (!status.ok()) ow_->InvalidValue("Any", status.error_message()); } else { ow_->RenderDataPiece(name, value); } @@ -600,6 +600,11 @@ void ProtoStreamObjectWriter::ProtoElement::TakeOneofIndex(int32 index) { InsertIfNotPresent(&oneof_indices_, index); } +bool ProtoStreamObjectWriter::ProtoElement::InsertMapKeyIfNotPresent( + StringPiece map_key) { + return InsertIfNotPresent(&map_keys_, map_key); +} + inline void ProtoStreamObjectWriter::InvalidName(StringPiece unknown_name, StringPiece message) { listener_->InvalidName(location(), ToSnakeCase(unknown_name), message); @@ -643,6 +648,11 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( return this; } else if (element_ != NULL && (element_->IsMap() || element_->IsStructMap())) { + if (!ValidMapKey(name)) { + ++invalid_depth_; + return this; + } + field = StartMapEntry(name); if (element_->IsStructMapEntry()) { // If the top element is a map entry, this means we are starting another @@ -698,7 +708,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( element_.reset( new ProtoElement(element_.release(), field, *type, ProtoElement::MAP)); } else { - WriteTag(*field); + WriteTag(*field); element_.reset(new ProtoElement(element_.release(), field, *type, ProtoElement::MESSAGE)); } @@ -863,6 +873,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() { // struct. SkipElements(); + // If ending the root element, // then serialize the full message with calculated sizes. if (element_ == NULL) { @@ -914,6 +925,11 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { // Check if we need to start a map. This can heppen when there is either a map // or a struct type within a list. if (element_->IsMap() || element_->IsStructMap()) { + if (!ValidMapKey(name)) { + ++invalid_depth_; + return this; + } + field = StartMapEntry(name); if (field == NULL) return this; @@ -969,7 +985,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { ProtoElement::MESSAGE)); InvalidValue("Map", "Cannot bind a list to map."); ++invalid_depth_; - element_->pop(); + element_.reset(element_->pop()); return this; } @@ -1188,6 +1204,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( type_url = GetFullTypeWithUrl(master_type_.name()); } else { if (element_->IsMap() || element_->IsStructMap()) { + if (!ValidMapKey(name)) return this; is_map_entry = true; field = StartMapEntry(name); } else { @@ -1462,6 +1479,19 @@ bool ProtoStreamObjectWriter::ValidOneof(const google::protobuf::Field& field, return true; } +bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) { + if (element_ == NULL) return true; + + if (!element_->InsertMapKeyIfNotPresent(unnormalized_name)) { + InvalidName( + unnormalized_name, + StrCat("Repeated map key: '", unnormalized_name, "' is already set.")); + return false; + } + + return true; +} + const google::protobuf::Field* ProtoStreamObjectWriter::BeginNamed( StringPiece name, bool is_list) { if (invalid_depth_ > 0) { @@ -1614,6 +1644,7 @@ void ProtoStreamObjectWriter::WriteTag(const google::protobuf::Field& field) { stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type)); } + } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h index 8f49120b..19f747fe 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.h +++ b/src/google/protobuf/util/internal/protostream_objectwriter.h @@ -259,6 +259,13 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter // generate an error. void TakeOneofIndex(int32 index); + // Inserts map key into hash set if and only if the key did NOT already + // exist in hash set. + // The hash set (map_keys_) is ONLY used to keep track of map keys. + // Return true if insert successfully; returns false if the map key was + // already present. + bool InsertMapKeyIfNotPresent(StringPiece map_key); + private: // Used for access to variables of the enclosing instance of // ProtoStreamObjectWriter. @@ -296,6 +303,10 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter // incoming messages so no more than one oneof is set. hash_set oneof_indices_; + // Set of map keys already seen for the type_. Used to validate incoming + // messages so no map key appears more than once. + hash_set map_keys_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement); }; @@ -378,6 +389,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter // Helper method to write proto tags based on the given field. void WriteTag(const google::protobuf::Field& field); + // Helper function to render primitive data types in DataPiece. void RenderSimpleDataPiece(const google::protobuf::Field& field, const google::protobuf::Type& type, @@ -424,6 +436,14 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter bool ValidOneof(const google::protobuf::Field& field, StringPiece unnormalized_name); + // Returns true if the map key for type_ is not duplicated key. + // If map key is duplicated key, this function returns false. + // Note that caller should make sure that the current proto element (element_) + // is of element type MAP or STRUCT_MAP. + // It also calls the appropriate error callback and unnormalzied_name is used + // for error string. + bool ValidMapKey(StringPiece unnormalized_name); + // Variables for describing the structure of the input tree: // master_type_: descriptor for the whole protobuf message. // typeinfo_ : the TypeInfo object to lookup types. diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc index 96e5ccfb..941fa71a 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -139,7 +140,9 @@ class BaseProtoStreamObjectWriterTest google::protobuf::scoped_ptr message(expected.New()); message->ParsePartialFromIstream(&istream); - EXPECT_EQ(expected.DebugString(), message->DebugString()); + if (!MessageDifferencer::Equivalent(expected, *message)) { + EXPECT_EQ(expected.DebugString(), message->DebugString()); + } } void CheckOutput(const Message& expected) { CheckOutput(expected, -1); } @@ -851,15 +854,19 @@ class ProtoStreamObjectWriterTimestampDurationTest } }; +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtoStreamObjectWriterTimestampDurationTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) { TimestampDuration timestamp; EXPECT_CALL( listener_, - InvalidValue( - _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), - StringPiece("Field 'ts', Illegal timestamp format; timestamps " - "must end with 'Z'"))); + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: "))); ow_->StartObject("")->RenderString("ts", "")->EndObject(); CheckOutput(timestamp); @@ -870,10 +877,9 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError2) { EXPECT_CALL( listener_, - InvalidValue( - _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), - StringPiece( - "Field 'ts', Invalid time format: Failed to parse input"))); + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: Z"))); ow_->StartObject("")->RenderString("ts", "Z")->EndObject(); CheckOutput(timestamp); @@ -884,10 +890,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError3) { EXPECT_CALL( listener_, - InvalidValue( - _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), - StringPiece("Field 'ts', Invalid time format, failed to parse nano " - "seconds"))); + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "1970-01-01T00:00:00.ABZ"))); ow_->StartObject("") ->RenderString("ts", "1970-01-01T00:00:00.ABZ") @@ -902,7 +908,8 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) { listener_, InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), - StringPiece("Field 'ts', Timestamp value exceeds limits"))); + StringPiece("Field 'ts', Invalid time format: " + "-8032-10-18T00:00:00.000Z"))); ow_->StartObject("") ->RenderString("ts", "-8032-10-18T00:00:00.000Z") @@ -1008,6 +1015,11 @@ class ProtoStreamObjectWriterStructTest } }; +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtoStreamObjectWriterStructTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + // TODO(skarvaje): Write tests for failure cases. TEST_P(ProtoStreamObjectWriterStructTest, StructRenderSuccess) { StructType struct_type; @@ -1046,12 +1058,62 @@ TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) { CheckOutput(struct_type); } +TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) { + EXPECT_CALL( + listener_, + InvalidName(_, StringPiece("k1"), + StringPiece("Repeated map key: 'k1' is already set."))); + ow_->StartObject("") + ->StartObject("object") + ->RenderString("k1", "v1") + ->RenderString("k1", "v2") + ->EndObject() + ->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapListKeyTest) { + EXPECT_CALL( + listener_, + InvalidName(_, StringPiece("k1"), + StringPiece("Repeated map key: 'k1' is already set."))); + ow_->StartObject("") + ->StartObject("object") + ->RenderString("k1", "v1") + ->StartList("k1") + ->RenderString("", "v2") + ->EndList() + ->EndObject() + ->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) { + EXPECT_CALL( + listener_, + InvalidName(_, StringPiece("k1"), + StringPiece("Repeated map key: 'k1' is already set."))); + ow_->StartObject("") + ->StartObject("object") + ->StartObject("k1") + ->RenderString("sub_k1", "v1") + ->EndObject() + ->StartObject("k1") + ->RenderString("sub_k2", "v2") + ->EndObject() + ->EndObject() + ->EndObject(); +} + class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest { protected: ProtoStreamObjectWriterMapTest() : BaseProtoStreamObjectWriterTest(MapIn::descriptor()) {} }; +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtoStreamObjectWriterMapTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) { MapIn mm; EXPECT_CALL(listener_, @@ -1066,17 +1128,37 @@ TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) { CheckOutput(mm); } +TEST_P(ProtoStreamObjectWriterMapTest, RepeatedMapKeyTest) { + EXPECT_CALL( + listener_, + InvalidName(_, StringPiece("k1"), + StringPiece("Repeated map key: 'k1' is already set."))); + ow_->StartObject("") + ->RenderString("other", "test") + ->StartObject("map_input") + ->RenderString("k1", "v1") + ->RenderString("k1", "v2") + ->EndObject() + ->EndObject(); +} + class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest { protected: ProtoStreamObjectWriterAnyTest() { vector descriptors; descriptors.push_back(AnyOut::descriptor()); descriptors.push_back(google::protobuf::DoubleValue::descriptor()); + descriptors.push_back(google::protobuf::Timestamp::descriptor()); descriptors.push_back(google::protobuf::Any::descriptor()); ResetTypeInfo(descriptors); } }; +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtoStreamObjectWriterAnyTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + TEST_P(ProtoStreamObjectWriterAnyTest, AnyRenderSuccess) { AnyOut any; google::protobuf::Any* any_type = any.mutable_any(); @@ -1119,8 +1201,6 @@ TEST_P(ProtoStreamObjectWriterAnyTest, RecursiveAny) { ->EndObject() ->EndObject() ->EndObject(); - - CheckOutput(out, 115); } TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) { @@ -1155,8 +1235,6 @@ TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) { ->EndObject() ->EndObject() ->EndObject(); - - CheckOutput(out, 159); } TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) { @@ -1263,6 +1341,23 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyNullInputFails) { CheckOutput(any); } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) { + EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"), + StringPiece("Invalid time format: "))); + + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Timestamp"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp") + ->RenderString("value", "") + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + class ProtoStreamObjectWriterFieldMaskTest : public BaseProtoStreamObjectWriterTest { protected: @@ -1274,6 +1369,11 @@ class ProtoStreamObjectWriterFieldMaskTest } }; +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtoStreamObjectWriterFieldMaskTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + TEST_P(ProtoStreamObjectWriterFieldMaskTest, SimpleFieldMaskTest) { FieldMaskTest expected; expected.set_id("1"); @@ -1683,6 +1783,7 @@ TEST_P(ProtoStreamObjectWriterOneOfsTest, ow_->RenderString("strData", "blah"); ow_->RenderInt32("intData", 123); ow_->EndObject(); + ow_->EndObject(); } } // namespace converter diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc index 5d7dcc87..61899c24 100644 --- a/src/google/protobuf/util/internal/utility.cc +++ b/src/google/protobuf/util/internal/utility.cc @@ -298,16 +298,21 @@ bool IsMap(const google::protobuf::Field& field, "google.protobuf.MessageOptions.map_entry", false)); } +bool IsMessageSetWireFormat(const google::protobuf::Type& type) { + return GetBoolOptionOrDefault( + type.options(), "google.protobuf.MessageOptions.message_set_wire_format", false); +} + string DoubleAsString(double value) { - if (google::protobuf::MathLimits::IsPosInf(value)) return "Infinity"; - if (google::protobuf::MathLimits::IsNegInf(value)) return "-Infinity"; - if (google::protobuf::MathLimits::IsNaN(value)) return "NaN"; + if (MathLimits::IsPosInf(value)) return "Infinity"; + if (MathLimits::IsNegInf(value)) return "-Infinity"; + if (MathLimits::IsNaN(value)) return "NaN"; return SimpleDtoa(value); } string FloatAsString(float value) { - if (google::protobuf::MathLimits::IsFinite(value)) return SimpleFtoa(value); + if (MathLimits::IsFinite(value)) return SimpleFtoa(value); return DoubleAsString(value); } @@ -318,7 +323,7 @@ bool SafeStrToFloat(StringPiece str, float *value) { } *value = static_cast(double_value); - if (google::protobuf::MathLimits::IsInf(*value)) { + if (MathLimits::IsInf(*value)) { return false; } return true; diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h index 87f7602a..5ba97bd2 100644 --- a/src/google/protobuf/util/internal/utility.h +++ b/src/google/protobuf/util/internal/utility.h @@ -138,9 +138,6 @@ const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( const google::protobuf::Enum* enum_type, int32 value); // Converts input to camel-case and returns it. -// Tests are in wrappers/translator/snake2camel_objectwriter_test.cc -// TODO(skarvaje): Isolate tests for this function and put them in -// utility_test.cc LIBPROTOBUF_EXPORT string ToCamelCase(const StringPiece input); // Converts input to snake_case and returns it. @@ -157,6 +154,9 @@ LIBPROTOBUF_EXPORT bool IsValidBoolString(const string& bool_string); LIBPROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field, const google::protobuf::Type& type); +// Returns true if the given type has special MessageSet wire format. +bool IsMessageSetWireFormat(const google::protobuf::Type& type); + // Infinity/NaN-aware conversion to string. LIBPROTOBUF_EXPORT string DoubleAsString(double value); LIBPROTOBUF_EXPORT string FloatAsString(float value); diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto index 7a282868..e8137677 100644 --- a/src/google/protobuf/util/json_format_proto3.proto +++ b/src/google/protobuf/util/json_format_proto3.proto @@ -100,6 +100,16 @@ message TestMap { map string_map = 6; } +message TestNestedMap { + map bool_map = 1; + map int32_map = 2; + map int64_map = 3; + map uint32_map = 4; + map uint64_map = 5; + map string_map = 6; + map map_map = 7; +} + message TestWrapper { google.protobuf.BoolValue bool_value = 1; google.protobuf.Int32Value int32_value = 2; diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc index 6cd40fd5..c3b8d502 100644 --- a/src/google/protobuf/util/json_util.cc +++ b/src/google/protobuf/util/json_util.cc @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -83,13 +82,12 @@ util::Status BinaryToJsonStream(TypeResolver* resolver, io::CodedOutputStream out_stream(json_output); converter::JsonObjectWriter json_writer(options.add_whitespace ? " " : "", &out_stream); - converter::Snake2CamelObjectWriter snake2camel_writer(&json_writer); if (options.always_print_primitive_fields) { converter::DefaultValueObjectWriter default_value_writer( - resolver, type, &snake2camel_writer); + resolver, type, &json_writer); return proto_source.WriteTo(&default_value_writer); } else { - return proto_source.WriteTo(&snake2camel_writer); + return proto_source.WriteTo(&json_writer); } } diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index d709da57..9a268973 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -946,6 +946,18 @@ bool MessageDifferencer::IsIgnored( return false; } +bool MessageDifferencer::IsUnknownFieldIgnored( + const Message& message1, const Message& message2, + const SpecificField& field, const vector& parent_fields) { + for (int i = 0; i < ignore_criteria_.size(); ++i) { + if (ignore_criteria_[i]->IsUnknownFieldIgnored(message1, message2, field, + parent_fields)) { + return true; + } + } + return false; +} + const MessageDifferencer::MapKeyComparator* MessageDifferencer ::GetMapKeyComparator(const FieldDescriptor* field) { if (!field->is_repeated()) return NULL; @@ -1127,15 +1139,6 @@ bool MessageDifferencer::CompareUnknownFields( continue; } - if (change_type == ADDITION || change_type == DELETION || - change_type == MODIFICATION) { - if (reporter_ == NULL) { - // We found a difference and we have no reproter. - return false; - } - is_different = true; - } - // Build the SpecificField. This is slightly complicated. SpecificField specific_field; specific_field.unknown_field_number = focus_field->number(); @@ -1160,6 +1163,25 @@ bool MessageDifferencer::CompareUnknownFields( specific_field.new_index = index2 - current_repeated_start2; } + if (IsUnknownFieldIgnored(message1, message2, specific_field, + *parent_field)) { + if (reporter_ != NULL) { + parent_field->push_back(specific_field); + reporter_->ReportUnknownFieldIgnored(message1, message2, *parent_field); + parent_field->pop_back(); + } + return true; + } + + if (change_type == ADDITION || change_type == DELETION || + change_type == MODIFICATION) { + if (reporter_ == NULL) { + // We found a difference and we have no reproter. + return false; + } + is_different = true; + } + parent_field->push_back(specific_field); switch (change_type) { @@ -1625,6 +1647,18 @@ void MessageDifferencer::StreamReporter::ReportIgnored( printer_->Print("\n"); // Print for newlines. } +void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored( + const Message& message1, const Message& message2, + const vector& field_path) { + printer_->Print("ignored: "); + PrintPath(field_path, true); + if (CheckPathChanged(field_path)) { + printer_->Print(" -> "); + PrintPath(field_path, false); + } + printer_->Print("\n"); // Print for newlines. +} + } // 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 e002a0f3..34c173db 100644 --- a/src/google/protobuf/util/message_differencer.h +++ b/src/google/protobuf/util/message_differencer.h @@ -278,6 +278,13 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { const Message& message2, const vector& field_path) { } + // Report that an unkown field is ignored. (see comment above). + // Note this is a different function since the last SpecificField in field + // path has a null field. This could break existing Reporter. + virtual void ReportUnknownFieldIgnored( + const Message& message1, const Message& message2, + const vector& field_path) {} + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reporter); }; @@ -317,6 +324,16 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { const Message& message2, const FieldDescriptor* field, const vector& parent_fields) = 0; + + // Returns true if the unknown field should be ignored. + // Note: This will be called for unknown fields as well in which case + // field.field will be null. + virtual bool IsUnknownFieldIgnored( + const Message& message1, const Message& message2, + const SpecificField& field, + const vector& parent_fields) { + return false; + } }; // To add a Reporter, construct default here, then use ReportDifferencesTo or @@ -583,6 +600,10 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { const Message& message2, const vector& field_path); + virtual void ReportUnknownFieldIgnored( + const Message& message1, const Message& message2, + const vector& field_path); + protected: // Prints the specified path of fields to the buffer. virtual void PrintPath(const vector& field_path, @@ -722,6 +743,12 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { const FieldDescriptor* field, const vector& parent_fields); + // Returns true if this unknown field is to be ignored when this + // MessageDifferencer compares messages. + bool IsUnknownFieldIgnored(const Message& message1, const Message& message2, + const SpecificField& field, + const vector& parent_fields); + // Returns MapKeyComparator* when this field has been configured to // be treated as a map. If not, returns NULL. const MapKeyComparator* GetMapKeyComparator(const FieldDescriptor* field); diff --git a/src/google/protobuf/util/time_util.h b/src/google/protobuf/util/time_util.h index 58dbf8e6..1bac0897 100644 --- a/src/google/protobuf/util/time_util.h +++ b/src/google/protobuf/util/time_util.h @@ -41,7 +41,6 @@ #endif #include -#include #include namespace google { @@ -243,10 +242,8 @@ inline ostream& operator<<(ostream& out, const Duration& d) { // Overloaded operators for Timestamp // // Assignement operators. -LIBPROTOBUF_EXPORT -Timestamp& operator+=(Timestamp& t, const Duration& d); // NOLINT -LIBPROTOBUF_EXPORT -Timestamp& operator-=(Timestamp& t, const Duration& d); // NOLINT +LIBPROTOBUF_EXPORT Timestamp& operator+=(Timestamp& t, const Duration& d); // NOLINT +LIBPROTOBUF_EXPORT Timestamp& operator-=(Timestamp& t, const Duration& d); // NOLINT // Relational operators. inline bool operator<(const Timestamp& t1, const Timestamp& t2) { if (t1.seconds() == t2.seconds()) { diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc index 908634eb..a0996954 100644 --- a/src/google/protobuf/util/type_resolver_util.cc +++ b/src/google/protobuf/util/type_resolver_util.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -53,8 +54,7 @@ using util::Status; using util::error::INVALID_ARGUMENT; using util::error::NOT_FOUND; -bool SplitTypeUrl(const string& type_url, - string* url_prefix, +bool SplitTypeUrl(const string& type_url, string* url_prefix, string* message_name) { size_t pos = type_url.find_last_of("/"); if (pos == string::npos) { @@ -65,60 +65,19 @@ bool SplitTypeUrl(const string& type_url, return true; } -// This code is originally defined in -// //google/protobuf/util/converter/utility.h. Copied here due to component -// dependency. -// TODO(xiaofeng): Remove this when converter code is in components. -string ToCamelCase(const StringPiece input) { - bool capitalize_next = false; - bool was_cap = true; - bool is_cap = false; - bool first_word = true; - string result; - result.reserve(input.size()); - - for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) { - is_cap = ascii_isupper(input[i]); - if (input[i] == '_') { - capitalize_next = true; - if (!result.empty()) first_word = false; - continue; - } else if (first_word) { - // Consider when the current character B is capitalized, - // first word ends when: - // 1) following a lowercase: "...aB..." - // 2) followed by a lowercase: "...ABc..." - if (!result.empty() && is_cap && - (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) { - first_word = false; - } else { - result.push_back(ascii_tolower(input[i])); - continue; - } - } else if (capitalize_next) { - capitalize_next = false; - if (ascii_islower(input[i])) { - result.push_back(ascii_toupper(input[i])); - continue; - } - } - result.push_back(input[i]); - } - return result; -} - class DescriptorPoolTypeResolver : public TypeResolver { public: DescriptorPoolTypeResolver(const string& url_prefix, const DescriptorPool* pool) - : url_prefix_(url_prefix), pool_(pool) { - } + : url_prefix_(url_prefix), pool_(pool) {} Status ResolveMessageType(const string& type_url, Type* type) { string url_prefix, message_name; if (!SplitTypeUrl(type_url, &url_prefix, &message_name) || url_prefix != url_prefix_) { - return Status(INVALID_ARGUMENT, "Failed to parse type url: " + type_url); + return Status(INVALID_ARGUMENT, + StrCat("Invalid type URL, type URLs must be of the form '", + url_prefix_, "/', got: ", type_url)); } if (url_prefix != url_prefix_) { return Status(INVALID_ARGUMENT, @@ -126,7 +85,8 @@ class DescriptorPoolTypeResolver : public TypeResolver { } const Descriptor* descriptor = pool_->FindMessageTypeByName(message_name); if (descriptor == NULL) { - return Status(NOT_FOUND, "Cannot found the type: " + message_name); + return Status(NOT_FOUND, + "Invalid type URL, unknown type: " + message_name); } ConvertDescriptor(descriptor, type); return Status(); @@ -136,7 +96,9 @@ class DescriptorPoolTypeResolver : public TypeResolver { string url_prefix, type_name; if (!SplitTypeUrl(type_url, &url_prefix, &type_name) || url_prefix != url_prefix_) { - return Status(INVALID_ARGUMENT, "Failed to parse type url: " + type_url); + return Status(INVALID_ARGUMENT, + StrCat("Invalid type URL, type URLs must be of the form '", + url_prefix_, "/', got: ", type_url)); } if (url_prefix != url_prefix_) { return Status(INVALID_ARGUMENT, @@ -144,7 +106,7 @@ class DescriptorPoolTypeResolver : public TypeResolver { } const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name); if (descriptor == NULL) { - return Status(NOT_FOUND, "Cannot found the type: " + type_name); + return Status(NOT_FOUND, "Invalid type URL, unknown type: " + type_name); } ConvertEnumDescriptor(descriptor, enum_type); return Status(); @@ -197,7 +159,7 @@ class DescriptorPoolTypeResolver : public TypeResolver { } field->set_number(descriptor->number()); field->set_name(descriptor->name()); - field->set_json_name(ToCamelCase(descriptor->name())); + field->set_json_name(converter::ToCamelCase(descriptor->name())); if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) { field->set_type_url(GetTypeUrl(descriptor->message_type())); } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { @@ -221,8 +183,7 @@ class DescriptorPoolTypeResolver : public TypeResolver { descriptor->file()->name()); for (int i = 0; i < descriptor->value_count(); ++i) { const EnumValueDescriptor* value_descriptor = descriptor->value(i); - EnumValue* value = - enum_type->mutable_enumvalue()->Add(); + EnumValue* value = enum_type->mutable_enumvalue()->Add(); value->set_name(value_descriptor->name()); value->set_number(value_descriptor->number()); @@ -245,8 +206,8 @@ class DescriptorPoolTypeResolver : public TypeResolver { } // namespace -TypeResolver* NewTypeResolverForDescriptorPool( - const string& url_prefix, const DescriptorPool* pool) { +TypeResolver* NewTypeResolverForDescriptorPool(const string& url_prefix, + const DescriptorPool* pool) { return new DescriptorPoolTypeResolver(url_prefix, pool); } -- cgit v1.2.3