aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am24
-rw-r--r--src/google/protobuf/any.cc30
-rw-r--r--src/google/protobuf/any.h3
-rw-r--r--src/google/protobuf/any.pb.cc7
-rw-r--r--src/google/protobuf/any.pb.h2
-rw-r--r--src/google/protobuf/any.proto17
-rw-r--r--src/google/protobuf/api.pb.cc15
-rw-r--r--src/google/protobuf/api.pb.h4
-rw-r--r--src/google/protobuf/api.proto5
-rwxr-xr-xsrc/google/protobuf/arena.cc15
-rw-r--r--src/google/protobuf/arena.h102
-rw-r--r--src/google/protobuf/arena_unittest.cc4
-rwxr-xr-xsrc/google/protobuf/arenastring.h1
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc59
-rw-r--r--src/google/protobuf/compiler/command_line_interface.h3
-rw-r--r--src/google/protobuf/compiler/command_line_interface_unittest.cc28
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc25
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc5
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc34
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc1
-rw-r--r--src/google/protobuf/compiler/cpp/test_large_enum_value.proto43
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_doc_comment.cc114
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_doc_comment.h (renamed from src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc)38
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_enum.cc5
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_generator.cc25
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_helpers.cc88
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_helpers.h12
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_map_field.cc5
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_message.cc25
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_message_field.cc3
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_names.h23
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_primitive_field.cc3
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_reflection_class.cc (renamed from src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc)57
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_reflection_class.h (renamed from src/google/protobuf/compiler/csharp/csharp_umbrella_class.h)17
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc2
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc2
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc2
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc3
-rw-r--r--src/google/protobuf/compiler/importer.cc13
-rw-r--r--src/google/protobuf/compiler/importer.h9
-rw-r--r--src/google/protobuf/compiler/importer_unittest.cc8
-rw-r--r--src/google/protobuf/compiler/java/java_enum.cc16
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field_lite.cc46
-rw-r--r--src/google/protobuf/compiler/java/java_enum_lite.cc32
-rw-r--r--src/google/protobuf/compiler/java/java_file.cc34
-rw-r--r--src/google/protobuf/compiler/java/java_map_field_lite.cc2
-rw-r--r--src/google/protobuf/compiler/java/java_message.cc19
-rw-r--r--src/google/protobuf/compiler/java/java_message_builder.cc2
-rw-r--r--src/google/protobuf/compiler/java/java_message_lite.cc28
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field_lite.cc38
-rw-r--r--src/google/protobuf/compiler/java/java_string_field.cc80
-rw-r--r--src/google/protobuf/compiler/java/java_string_field.h1
-rw-r--r--src/google/protobuf/compiler/java/java_string_field_lite.cc66
-rw-r--r--src/google/protobuf/compiler/java/java_string_field_lite.h1
-rwxr-xr-xsrc/google/protobuf/compiler/js/js_generator.cc2622
-rwxr-xr-xsrc/google/protobuf/compiler/js/js_generator.h265
-rw-r--r--src/google/protobuf/compiler/main.cc8
-rw-r--r--src/google/protobuf/compiler/mock_code_generator.cc6
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_file.cc2
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers.cc101
-rw-r--r--src/google/protobuf/compiler/parser.cc83
-rw-r--r--src/google/protobuf/compiler/parser.h6
-rw-r--r--src/google/protobuf/compiler/parser_unittest.cc86
-rw-r--r--src/google/protobuf/compiler/plugin.pb.cc15
-rw-r--r--src/google/protobuf/compiler/plugin.pb.h2
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc20
-rw-r--r--src/google/protobuf/compiler/subprocess.cc1
-rw-r--r--src/google/protobuf/descriptor.cc159
-rw-r--r--src/google/protobuf/descriptor.h39
-rw-r--r--src/google/protobuf/descriptor.pb.cc428
-rw-r--r--src/google/protobuf/descriptor.pb.h74
-rw-r--r--src/google/protobuf/descriptor.proto9
-rw-r--r--src/google/protobuf/descriptor_database_unittest.cc6
-rw-r--r--src/google/protobuf/descriptor_unittest.cc303
-rw-r--r--src/google/protobuf/duration.pb.cc7
-rw-r--r--src/google/protobuf/duration.proto9
-rw-r--r--src/google/protobuf/dynamic_message.cc10
-rw-r--r--src/google/protobuf/dynamic_message_unittest.cc15
-rw-r--r--src/google/protobuf/empty.pb.cc49
-rw-r--r--src/google/protobuf/empty.pb.h13
-rw-r--r--src/google/protobuf/empty.proto8
-rw-r--r--src/google/protobuf/extension_set.cc18
-rw-r--r--src/google/protobuf/extension_set.h15
-rw-r--r--src/google/protobuf/extension_set_unittest.cc5
-rw-r--r--src/google/protobuf/field_mask.pb.cc7
-rw-r--r--src/google/protobuf/field_mask.proto11
-rw-r--r--src/google/protobuf/generated_message_reflection_unittest.cc11
-rw-r--r--src/google/protobuf/generated_message_util.cc2
-rw-r--r--src/google/protobuf/io/coded_stream.cc18
-rw-r--r--src/google/protobuf/io/coded_stream.h6
-rw-r--r--src/google/protobuf/io/coded_stream_unittest.cc6
-rw-r--r--src/google/protobuf/io/strtod.cc11
-rw-r--r--src/google/protobuf/io/strtod.h5
-rw-r--r--src/google/protobuf/io/tokenizer.cc2
-rw-r--r--src/google/protobuf/io/tokenizer_unittest.cc2
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl_lite.cc31
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl_lite.h32
-rw-r--r--src/google/protobuf/io/zero_copy_stream_unittest.cc6
-rw-r--r--src/google/protobuf/map.h32
-rw-r--r--src/google/protobuf/map_field_inl.h3
-rw-r--r--src/google/protobuf/map_lite_test_util.h2
-rw-r--r--src/google/protobuf/map_proto2_unittest.proto6
-rw-r--r--src/google/protobuf/map_test.cc6
-rw-r--r--src/google/protobuf/map_test_util.h2
-rw-r--r--src/google/protobuf/map_test_util_impl.h2
-rw-r--r--src/google/protobuf/map_type_handler.h24
-rw-r--r--src/google/protobuf/message.cc9
-rw-r--r--src/google/protobuf/message.h2
-rw-r--r--src/google/protobuf/metadata.h2
-rw-r--r--src/google/protobuf/proto_cast.h59
-rw-r--r--src/google/protobuf/proto_cast_test.cc60
-rw-r--r--src/google/protobuf/repeated_field.h28
-rw-r--r--src/google/protobuf/source_context.pb.cc7
-rw-r--r--src/google/protobuf/source_context.proto7
-rw-r--r--src/google/protobuf/struct.pb.cc15
-rw-r--r--src/google/protobuf/struct.proto9
-rw-r--r--src/google/protobuf/stubs/atomicops.h4
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_power.h (renamed from src/google/protobuf/stubs/atomicops_internals_aix.h)0
-rw-r--r--src/google/protobuf/stubs/callback.h87
-rw-r--r--src/google/protobuf/stubs/common.h2
-rw-r--r--src/google/protobuf/stubs/common_unittest.cc2
-rwxr-xr-xsrc/google/protobuf/stubs/hash.h13
-rw-r--r--src/google/protobuf/stubs/int128.cc3
-rw-r--r--src/google/protobuf/stubs/once_unittest.cc6
-rw-r--r--src/google/protobuf/stubs/platform_macros.h4
-rw-r--r--src/google/protobuf/stubs/stringpiece.h13
-rw-r--r--src/google/protobuf/stubs/stringpiece_unittest.cc1
-rw-r--r--src/google/protobuf/stubs/strutil.cc86
-rw-r--r--src/google/protobuf/stubs/strutil.h24
-rw-r--r--src/google/protobuf/test_util.h2
-rw-r--r--src/google/protobuf/test_util_lite.h2
-rw-r--r--src/google/protobuf/testing/googletest.cc7
-rw-r--r--src/google/protobuf/text_format.cc56
-rw-r--r--src/google/protobuf/text_format.h14
-rw-r--r--src/google/protobuf/text_format_unittest.cc10
-rw-r--r--src/google/protobuf/timestamp.pb.cc49
-rw-r--r--src/google/protobuf/timestamp.pb.h13
-rw-r--r--src/google/protobuf/timestamp.proto11
-rw-r--r--src/google/protobuf/type.pb.cc183
-rw-r--r--src/google/protobuf/type.pb.h59
-rw-r--r--src/google/protobuf/type.proto60
-rw-r--r--src/google/protobuf/unittest_custom_options.proto27
-rw-r--r--src/google/protobuf/unittest_import.proto7
-rw-r--r--src/google/protobuf/unittest_well_known_types.proto2
-rw-r--r--src/google/protobuf/unknown_enum_impl.h154
-rw-r--r--src/google/protobuf/unknown_enum_test.proto62
-rw-r--r--src/google/protobuf/util/field_comparator.h2
-rw-r--r--src/google/protobuf/util/field_comparator_test.cc6
-rw-r--r--src/google/protobuf/util/field_mask_util.cc10
-rw-r--r--src/google/protobuf/util/field_mask_util.h11
-rw-r--r--src/google/protobuf/util/internal/datapiece.cc74
-rw-r--r--src/google/protobuf/util/internal/datapiece.h3
-rw-r--r--src/google/protobuf/util/internal/default_value_objectwriter.cc90
-rw-r--r--src/google/protobuf/util/internal/default_value_objectwriter.h25
-rw-r--r--src/google/protobuf/util/internal/default_value_objectwriter_test.cc35
-rw-r--r--src/google/protobuf/util/internal/error_listener.h2
-rw-r--r--src/google/protobuf/util/internal/json_escaping.cc4
-rw-r--r--src/google/protobuf/util/internal/json_objectwriter.cc6
-rw-r--r--src/google/protobuf/util/internal/json_objectwriter_test.cc205
-rw-r--r--src/google/protobuf/util/internal/json_stream_parser.cc2
-rw-r--r--src/google/protobuf/util/internal/json_stream_parser_test.cc1
-rw-r--r--src/google/protobuf/util/internal/object_writer.h5
-rw-r--r--src/google/protobuf/util/internal/proto_writer.cc744
-rw-r--r--src/google/protobuf/util/internal/proto_writer.h315
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource.cc203
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource.h19
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource_test.cc10
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.cc1567
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.h326
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter_test.cc270
-rw-r--r--src/google/protobuf/util/internal/snake2camel_objectwriter.h165
-rw-r--r--src/google/protobuf/util/internal/testdata/books.proto2
-rw-r--r--src/google/protobuf/util/internal/testdata/default_value.proto7
-rw-r--r--src/google/protobuf/util/internal/testdata/default_value_test.proto7
-rw-r--r--src/google/protobuf/util/internal/type_info.cc3
-rw-r--r--src/google/protobuf/util/internal/utility.cc42
-rw-r--r--src/google/protobuf/util/internal/utility.h11
-rw-r--r--src/google/protobuf/util/json_format_proto3.proto19
-rw-r--r--src/google/protobuf/util/json_util.cc6
-rw-r--r--src/google/protobuf/util/json_util_test.cc2
-rw-r--r--src/google/protobuf/util/message_differencer.cc82
-rw-r--r--src/google/protobuf/util/message_differencer.h37
-rwxr-xr-xsrc/google/protobuf/util/message_differencer_unittest.cc58
-rw-r--r--src/google/protobuf/util/time_util.h7
-rw-r--r--src/google/protobuf/util/type_resolver_util.cc114
-rw-r--r--src/google/protobuf/util/type_resolver_util_test.cc14
-rw-r--r--src/google/protobuf/wire_format_lite.cc6
-rw-r--r--src/google/protobuf/wire_format_lite_inl.h10
-rw-r--r--src/google/protobuf/wrappers.pb.cc467
-rw-r--r--src/google/protobuf/wrappers.pb.h205
-rw-r--r--src/google/protobuf/wrappers.proto9
195 files changed, 8711 insertions, 3533 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index caae2933..462eb3e1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -58,7 +58,7 @@ MAINTAINERCLEANFILES = \
nobase_include_HEADERS = \
google/protobuf/stubs/atomic_sequence_num.h \
google/protobuf/stubs/atomicops.h \
- google/protobuf/stubs/atomicops_internals_aix.h \
+ google/protobuf/stubs/atomicops_internals_power.h \
google/protobuf/stubs/atomicops_internals_arm64_gcc.h \
google/protobuf/stubs/atomicops_internals_arm_gcc.h \
google/protobuf/stubs/atomicops_internals_arm_qnx.h \
@@ -148,15 +148,16 @@ nobase_include_HEADERS = \
google/protobuf/compiler/plugin.h \
google/protobuf/compiler/plugin.pb.h \
google/protobuf/compiler/cpp/cpp_generator.h \
+ google/protobuf/compiler/csharp/csharp_generator.h \
+ google/protobuf/compiler/csharp/csharp_names.h \
google/protobuf/compiler/java/java_generator.h \
google/protobuf/compiler/java/java_names.h \
google/protobuf/compiler/javanano/javanano_generator.h \
+ google/protobuf/compiler/js/js_generator.h \
google/protobuf/compiler/objectivec/objectivec_generator.h \
google/protobuf/compiler/objectivec/objectivec_helpers.h \
google/protobuf/compiler/python/python_generator.h \
google/protobuf/compiler/ruby/ruby_generator.h \
- google/protobuf/compiler/csharp/csharp_generator.h \
- google/protobuf/compiler/csharp/csharp_names.h \
google/protobuf/util/type_resolver.h \
google/protobuf/util/field_comparator.h \
google/protobuf/util/field_mask_util.h \
@@ -276,9 +277,9 @@ libprotobuf_la_SOURCES = \
google/protobuf/util/internal/protostream_objectsource.h \
google/protobuf/util/internal/protostream_objectwriter.cc \
google/protobuf/util/internal/protostream_objectwriter.h \
- google/protobuf/util/internal/snake2camel_objectwriter.h \
+ google/protobuf/util/internal/proto_writer.cc \
+ google/protobuf/util/internal/proto_writer.h \
google/protobuf/util/internal/structured_objectwriter.h \
- google/protobuf/util/internal/testdata \
google/protobuf/util/internal/type_info.cc \
google/protobuf/util/internal/type_info.h \
google/protobuf/util/internal/type_info_test_helper.cc \
@@ -386,6 +387,7 @@ libprotoc_la_SOURCES = \
google/protobuf/compiler/java/java_string_field_lite.h \
google/protobuf/compiler/java/java_doc_comment.cc \
google/protobuf/compiler/java/java_doc_comment.h \
+ google/protobuf/compiler/js/js_generator.cc \
google/protobuf/compiler/javanano/javanano_enum.cc \
google/protobuf/compiler/javanano/javanano_enum.h \
google/protobuf/compiler/javanano/javanano_enum_field.cc \
@@ -434,6 +436,8 @@ libprotoc_la_SOURCES = \
google/protobuf/compiler/objectivec/objectivec_primitive_field.h \
google/protobuf/compiler/python/python_generator.cc \
google/protobuf/compiler/ruby/ruby_generator.cc \
+ google/protobuf/compiler/csharp/csharp_doc_comment.cc \
+ google/protobuf/compiler/csharp/csharp_doc_comment.h \
google/protobuf/compiler/csharp/csharp_enum.cc \
google/protobuf/compiler/csharp/csharp_enum.h \
google/protobuf/compiler/csharp/csharp_enum_field.cc \
@@ -451,6 +455,8 @@ libprotoc_la_SOURCES = \
google/protobuf/compiler/csharp/csharp_message_field.h \
google/protobuf/compiler/csharp/csharp_primitive_field.cc \
google/protobuf/compiler/csharp/csharp_primitive_field.h \
+ google/protobuf/compiler/csharp/csharp_reflection_class.cc \
+ google/protobuf/compiler/csharp/csharp_reflection_class.h \
google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc \
google/protobuf/compiler/csharp/csharp_repeated_enum_field.h \
google/protobuf/compiler/csharp/csharp_repeated_message_field.cc \
@@ -459,8 +465,6 @@ libprotoc_la_SOURCES = \
google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h \
google/protobuf/compiler/csharp/csharp_source_generator_base.cc \
google/protobuf/compiler/csharp/csharp_source_generator_base.h \
- google/protobuf/compiler/csharp/csharp_umbrella_class.cc \
- google/protobuf/compiler/csharp/csharp_umbrella_class.h \
google/protobuf/compiler/csharp/csharp_wrapper_field.cc \
google/protobuf/compiler/csharp/csharp_wrapper_field.h
@@ -511,6 +515,7 @@ protoc_inputs = \
google/protobuf/util/internal/testdata/struct.proto \
google/protobuf/util/internal/testdata/timestamp_duration.proto \
google/protobuf/util/json_format_proto3.proto \
+ google/protobuf/util/message_differencer_unittest.proto \
google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto
EXTRA_DIST = \
@@ -622,7 +627,9 @@ protoc_outputs = \
google/protobuf/util/internal/testdata/timestamp_duration.pb.cc \
google/protobuf/util/internal/testdata/timestamp_duration.pb.h \
google/protobuf/util/json_format_proto3.pb.cc \
- google/protobuf/util/json_format_proto3.pb.h
+ google/protobuf/util/json_format_proto3.pb.h \
+ google/protobuf/util/message_differencer_unittest.pb.cc \
+ google/protobuf/util/message_differencer_unittest.pb.h
BUILT_SOURCES = $(protoc_outputs)
@@ -735,6 +742,7 @@ protobuf_test_SOURCES = \
google/protobuf/util/internal/protostream_objectwriter_test.cc \
google/protobuf/util/internal/type_info_test_helper.cc \
google/protobuf/util/json_util_test.cc \
+ google/protobuf/util/message_differencer_unittest.cc \
google/protobuf/util/time_util_test.cc \
google/protobuf/util/type_resolver_util_test.cc \
$(COMMON_TEST_SOURCES)
diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc
index c6ed37ae..f3ca06bf 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) {
@@ -64,17 +65,30 @@ bool AnyMetadata::UnpackTo(Message* message) const {
}
bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
- return type_url_->GetNoArena(
- &::google::protobuf::internal::GetEmptyString()) ==
- GetTypeUrl(descriptor);
+ const string type_url = type_url_->GetNoArena(
+ &::google::protobuf::internal::GetEmptyString());
+ const string full_name = descriptor->full_name();
+ if (type_url.length() < full_name.length()) {
+ return false;
+ }
+ return (0 == type_url.compare(
+ type_url.length() - full_name.length(),
+ full_name.length(),
+ full_name));
}
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..c8dbef13 100644
--- a/src/google/protobuf/any.h
+++ b/src/google/protobuf/any.h
@@ -70,11 +70,12 @@ 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
// *full_type_name. Returns false if type_url does not start with
-// "type.googleapis.com".
+// "type.googleapis.com" or "type.googleprod.com".
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name);
// See if message is of type google.protobuf.Any, if so, return the descriptors
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index cbb5d233..0bf523b3 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/any.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/any.pb.h"
+#include <google/protobuf/any.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -119,10 +120,10 @@ bool Any::UnpackTo(::google::protobuf::Message* message) const {
return _any_metadata_.UnpackTo(message);
}
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Any::kTypeUrlFieldNumber;
const int Any::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Any::Any()
: ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) {
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index c324c4af..97982ecf 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -27,7 +27,7 @@
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/unknown_field_set.h>
-#include "google/protobuf/any.h"
+#include <google/protobuf/any.h>
// @@protoc_insertion_point(includes)
namespace google {
diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto
index 423699be..e8a18bc3 100644
--- a/src/google/protobuf/any.proto
+++ b/src/google/protobuf/any.proto
@@ -27,21 +27,22 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package google.protobuf;
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "AnyProto";
-option java_package = "com.google.protobuf";
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "AnyProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
option objc_class_prefix = "GPB";
-
// `Any` contains an arbitrary serialized message along with a URL
// that describes the type of the serialized message.
//
+//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
@@ -62,8 +63,8 @@ option objc_class_prefix = "GPB";
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
-// `value` which holds the custom JSON in addition to the the `@type`
-// field. Example (for message [google.protobuf.Duration][google.protobuf.Duration]):
+// `value` which holds the custom JSON in addition to the `@type`
+// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
@@ -80,7 +81,7 @@ message Any {
// * If no schema is provided, `https` is assumed.
// * The last segment of the URL's path must represent the fully
// qualified name of the type (as in `path/google.protobuf.Duration`).
- // * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type]
+ // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index 0a2c4ec0..e589a89d 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/api.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/api.pb.h"
+#include <google/protobuf/api.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -186,7 +187,7 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Api::kNameFieldNumber;
const int Api::kMethodsFieldNumber;
const int Api::kOptionsFieldNumber;
@@ -194,7 +195,7 @@ const int Api::kVersionFieldNumber;
const int Api::kSourceContextFieldNumber;
const int Api::kMixinsFieldNumber;
const int Api::kSyntaxFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Api::Api()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -904,7 +905,7 @@ void Api::clear_syntax() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Method::kNameFieldNumber;
const int Method::kRequestTypeUrlFieldNumber;
const int Method::kRequestStreamingFieldNumber;
@@ -912,7 +913,7 @@ const int Method::kResponseTypeUrlFieldNumber;
const int Method::kResponseStreamingFieldNumber;
const int Method::kOptionsFieldNumber;
const int Method::kSyntaxFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Method::Method()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1608,10 +1609,10 @@ void Method::clear_syntax() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Mixin::kNameFieldNumber;
const int Mixin::kRootFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Mixin::Mixin()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index 3c5a6f31..e1dca4e4 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -27,8 +27,8 @@
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/unknown_field_set.h>
-#include "google/protobuf/source_context.pb.h"
-#include "google/protobuf/type.pb.h"
+#include <google/protobuf/source_context.pb.h>
+#include <google/protobuf/type.pb.h>
// @@protoc_insertion_point(includes)
namespace google {
diff --git a/src/google/protobuf/api.proto b/src/google/protobuf/api.proto
index 597a6497..dbe87b8f 100644
--- a/src/google/protobuf/api.proto
+++ b/src/google/protobuf/api.proto
@@ -27,6 +27,7 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package google.protobuf;
@@ -34,11 +35,11 @@ package google.protobuf;
import "google/protobuf/source_context.proto";
import "google/protobuf/type.proto";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option java_package = "com.google.protobuf";
option java_outer_classname = "ApiProto";
option java_multiple_files = true;
option java_generate_equals_and_hash = true;
-option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option objc_class_prefix = "GPB";
// Api is a light-weight descriptor for a protocol buffer service.
@@ -75,6 +76,7 @@ message Api {
// be omitted. Zero major versions must only be used for
// experimental, none-GA apis.
//
+ //
string version = 4;
// Source context for the protocol buffer service represented by this
@@ -141,7 +143,6 @@ message Method {
//
// package google.storage.v2;
// service Storage {
-// // (-- see AccessControl.GetAcl --)
// rpc GetAcl(GetAclRequest) returns (Acl);
//
// // Get a data record.
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index 907a6a20..cd0b21a7 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<ThreadCache>* thread_cache_ =
new internal::ThreadLocalStorage<ThreadCache>();
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
@@ -61,6 +61,9 @@ void Arena::Init() {
cleanup_list_ = 0;
if (options_.initial_block != NULL && options_.initial_block_size > 0) {
+ GOOGLE_CHECK_GE(options_.initial_block_size, sizeof(Block))
+ << ": Initial block size too small for header.";
+
// Add first unowned block to list.
Block* first_block = reinterpret_cast<Block*>(options_.initial_block);
first_block->size = options_.initial_block_size;
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index 074a9e54..6a35183e 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -38,7 +38,16 @@
#if __cplusplus >= 201103L
#include <google/protobuf/stubs/type_traits.h>
#endif
+#if defined(_MSC_VER) && !_HAS_EXCEPTIONS
+// Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
+#include <exception>
#include <typeinfo>
+namespace std {
+using type_info = ::type_info;
+}
+#else
+#include <typeinfo>
+#endif
#include <google/protobuf/stubs/atomic_sequence_num.h>
#include <google/protobuf/stubs/atomicops.h>
@@ -481,27 +490,28 @@ class LIBPROTOBUF_EXPORT Arena {
return GetArenaInternal(value, static_cast<T*>(0));
}
- // Helper typetrait that indicates support for arenas in a type T at compile
- // time. This is public only to allow construction of higher-level templated
- // utilities. is_arena_constructable<T>::value is an instance of
- // google::protobuf::internal::true_type if the message type T has arena support enabled, and
- // google::protobuf::internal::false_type otherwise.
- //
- // This is inside Arena because only Arena has the friend relationships
- // necessary to see the underlying generated code traits.
- template<typename T>
- struct is_arena_constructable {
+ private:
+ struct InternalIsArenaConstructableHelper {
template<typename U>
static char ArenaConstructable(
const typename U::InternalArenaConstructable_*);
template<typename U>
static double ArenaConstructable(...);
+ };
- // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
- typedef google::protobuf::internal::integral_constant<bool,
- sizeof(ArenaConstructable<const T>(static_cast<const T*>(0))) ==
- sizeof(char)> type;
- static const type value;
+ public:
+ // Helper typetrait that indicates support for arenas in a type T at compile
+ // time. This is public only to allow construction of higher-level templated
+ // utilities. is_arena_constructable<T>::value is true if the message type T
+ // has arena support enabled, and false otherwise.
+ //
+ // This is inside Arena because only Arena has the friend relationships
+ // necessary to see the underlying generated code traits.
+ template<typename T>
+ struct is_arena_constructable :
+ public google::protobuf::internal::integral_constant<bool,
+ sizeof(InternalIsArenaConstructableHelper::ArenaConstructable<
+ const T>(static_cast<const T*>(0))) == sizeof(char)> {
};
private:
@@ -533,15 +543,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_; }
@@ -563,32 +573,30 @@ class LIBPROTOBUF_EXPORT Arena {
return google::protobuf::internal::has_trivial_destructor<T>::value;
}
- // Helper typetrait that indicates whether the desctructor of type T should be
- // called when arena is destroyed at compile time. This is only to allow
- // construction of higher-level templated utilities.
- // is_destructor_skippable<T>::value is an instance of google::protobuf::internal::true_type if the
- // destructor of the message type T should not be called when arena is
- // destroyed or google::protobuf::internal::has_trivial_destructor<T>::value == true, and
- // google::protobuf::internal::false_type otherwise.
- //
- // This is inside Arena because only Arena has the friend relationships
- // necessary to see the underlying generated code traits.
- template<typename T>
- struct is_destructor_skippable {
+ private:
+ struct InternalIsDestructorSkippableHelper {
template<typename U>
static char DestructorSkippable(
const typename U::DestructorSkippable_*);
template<typename U>
static double DestructorSkippable(...);
-
- // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
- typedef google::protobuf::internal::integral_constant<bool,
- sizeof(DestructorSkippable<const T>(static_cast<const T*>(0))) ==
- sizeof(char) || google::protobuf::internal::has_trivial_destructor<T>::value == true>
- type;
- static const type value;
};
+ public:
+ // Helper typetrait that indicates whether the desctructor of type T should be
+ // called when arena is destroyed at compile time. This is only to allow
+ // construction of higher-level templated utilities.
+ // is_destructor_skippable<T>::value is true if the destructor of the message
+ // type T should not be called when arena is destroyed or false otherwise.
+ // This is inside Arena because only Arena has the friend relationships
+ // necessary to see the underlying generated code traits.
+ template<typename T>
+ struct is_destructor_skippable
+ : public google::protobuf::internal::integral_constant<
+ bool,
+ sizeof(InternalIsDestructorSkippableHelper::DestructorSkippable<
+ const T>(static_cast<const T*>(0))) == sizeof(char) ||
+ google::protobuf::internal::has_trivial_destructor<T>::value> {};
// CreateMessage<T> requires that T supports arenas, but this private method
// works whether or not T supports arenas. These are not exposed to user code
@@ -769,8 +777,10 @@ class LIBPROTOBUF_EXPORT Arena {
// which needs to declare google::protobuf::Map as friend of generated message.
template <typename T>
static void CreateInArenaStorage(T* ptr, Arena* arena) {
- CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>::value);
- RegisterDestructorInternal(ptr, arena, is_destructor_skippable<T>::value);
+ CreateInArenaStorageInternal(ptr, arena,
+ typename is_arena_constructable<T>::type());
+ RegisterDestructorInternal(ptr, arena,
+ typename is_destructor_skippable<T>::type());
}
template <typename T>
@@ -899,16 +909,6 @@ class LIBPROTOBUF_EXPORT Arena {
// Defined above for supporting environments without RTTI.
#undef RTTI_TYPE_ID
-template<typename T>
-const typename Arena::is_arena_constructable<T>::type
- Arena::is_arena_constructable<T>::value =
- typename Arena::is_arena_constructable<T>::type();
-
-template<typename T>
-const typename Arena::is_destructor_skippable<T>::type
- Arena::is_destructor_skippable<T>::value =
- typename Arena::is_destructor_skippable<T>::type();
-
} // namespace protobuf
} // namespace google
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<TestAllTypes>(&arena);
arena_message->mutable_optional_nested_message()->set_bb(118);
- scoped_ptr<TestAllTypes::NestedMessage> nested(
+ google::protobuf::scoped_ptr<TestAllTypes::NestedMessage> 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<TestAllTypes>(&arena);
arena_message->set_optional_string("hello");
- scoped_ptr<string> released_str(
+ google::protobuf::scoped_ptr<string> released_str(
arena_message->release_optional_string());
EXPECT_EQ("hello", *released_str);
diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h
index 1dacdc68..ef57033b 100755
--- a/src/google/protobuf/arenastring.h
+++ b/src/google/protobuf/arenastring.h
@@ -36,7 +36,6 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/fastmem.h>
-
#include <google/protobuf/arena.h>
#include <google/protobuf/generated_message_util.h>
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index a77cdc23..3a816b05 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -276,15 +276,35 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
// implements MultiFileErrorCollector ------------------------------
void AddError(const string& filename, int line, int column,
const string& message) {
+ AddErrorOrWarning(filename, line, column, message, "error", std::cerr);
+ }
+
+ void AddWarning(const string& filename, int line, int column,
+ const string& message) {
+ AddErrorOrWarning(filename, line, column, message, "warning", std::clog);
+ }
+ // implements io::ErrorCollector -----------------------------------
+ void AddError(int line, int column, const string& message) {
+ AddError("input", line, column, message);
+ }
+
+ void AddWarning(int line, int column, const string& message) {
+ AddErrorOrWarning("input", line, column, message, "warning", std::clog);
+ }
+
+ private:
+ void AddErrorOrWarning(
+ const string& filename, int line, int column,
+ const string& message, const string& type, ostream& out) {
// Print full path when running under MSVS
string dfile;
if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
tree_ != NULL &&
tree_->VirtualFileToDiskFile(filename, &dfile)) {
- std::cerr << dfile;
+ out << dfile;
} else {
- std::cerr << filename;
+ out << filename;
}
// Users typically expect 1-based line/column numbers, so we add 1
@@ -293,24 +313,22 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
// Allow for both GCC- and Visual-Studio-compatible output.
switch (format_) {
case CommandLineInterface::ERROR_FORMAT_GCC:
- std::cerr << ":" << (line + 1) << ":" << (column + 1);
+ out << ":" << (line + 1) << ":" << (column + 1);
break;
case CommandLineInterface::ERROR_FORMAT_MSVS:
- std::cerr << "(" << (line + 1)
- << ") : error in column=" << (column + 1);
+ out << "(" << (line + 1) << ") : "
+ << type << " in column=" << (column + 1);
break;
}
}
- std::cerr << ": " << message << std::endl;
- }
-
- // implements io::ErrorCollector -----------------------------------
- void AddError(int line, int column, const string& message) {
- AddError("input", line, column, message);
+ if (type == "warning") {
+ out << ": warning: " << message << std::endl;
+ } else {
+ out << ": " << message << std::endl;
+ }
}
- private:
const ErrorFormat format_;
DiskSourceTree *tree_;
};
@@ -1358,7 +1376,7 @@ void CommandLineInterface::PrintHelpText() {
" defined in the given proto files. Groups share\n"
" the same field number space with the parent \n"
" message. Extension ranges are counted as \n"
-" occupied fields numbers."
+" occupied fields numbers.\n"
<< std::endl;
if (!plugin_prefix_.empty()) {
std::cerr <<
@@ -1448,6 +1466,7 @@ bool CommandLineInterface::GenerateDependencyManifestFile(
for (int i = 0; i < parsed_files.size(); i++) {
GetTransitiveDependencies(parsed_files[i],
false,
+ false,
&already_seen,
file_set.mutable_file());
}
@@ -1527,6 +1546,7 @@ bool CommandLineInterface::GeneratePluginOutput(
for (int i = 0; i < parsed_files.size(); i++) {
request.add_file_to_generate(parsed_files[i]->name());
GetTransitiveDependencies(parsed_files[i],
+ true, // Include json_name for plugins.
true, // Include source code info.
&already_seen, request.mutable_proto_file());
}
@@ -1659,6 +1679,7 @@ bool CommandLineInterface::WriteDescriptorSet(
set<const FileDescriptor*> already_seen;
for (int i = 0; i < parsed_files.size(); i++) {
GetTransitiveDependencies(parsed_files[i],
+ true, // Include json_name
source_info_in_descriptor_set_,
&already_seen, file_set.mutable_file());
}
@@ -1670,6 +1691,7 @@ bool CommandLineInterface::WriteDescriptorSet(
}
FileDescriptorProto* file_proto = file_set.add_file();
parsed_files[i]->CopyTo(file_proto);
+ parsed_files[i]->CopyJsonNameTo(file_proto);
if (source_info_in_descriptor_set_) {
parsed_files[i]->CopySourceCodeInfoTo(file_proto);
}
@@ -1704,7 +1726,9 @@ bool CommandLineInterface::WriteDescriptorSet(
}
void CommandLineInterface::GetTransitiveDependencies(
- const FileDescriptor* file, bool include_source_code_info,
+ const FileDescriptor* file,
+ bool include_json_name,
+ bool include_source_code_info,
set<const FileDescriptor*>* already_seen,
RepeatedPtrField<FileDescriptorProto>* output) {
if (!already_seen->insert(file).second) {
@@ -1714,13 +1738,18 @@ void CommandLineInterface::GetTransitiveDependencies(
// Add all dependencies.
for (int i = 0; i < file->dependency_count(); i++) {
- GetTransitiveDependencies(file->dependency(i), include_source_code_info,
+ GetTransitiveDependencies(file->dependency(i),
+ include_json_name,
+ include_source_code_info,
already_seen, output);
}
// Add this file.
FileDescriptorProto* new_descriptor = output->Add();
file->CopyTo(new_descriptor);
+ if (include_json_name) {
+ file->CopyJsonNameTo(new_descriptor);
+ }
if (include_source_code_info) {
file->CopySourceCodeInfoTo(new_descriptor);
}
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index 7e611c44..f196ffc5 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -262,8 +262,11 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// in order. Any files in *already_seen will not be added, and each file
// added will be inserted into *already_seen. If include_source_code_info is
// true then include the source code information in the FileDescriptorProtos.
+ // If include_json_name is true, populate the json_name field of
+ // FieldDescriptorProto for all fields.
static void GetTransitiveDependencies(
const FileDescriptor* file,
+ bool include_json_name,
bool include_source_code_info,
set<const FileDescriptor*>* already_seen,
RepeatedPtrField<FileDescriptorProto>* output);
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 9560d0e0..dda007d4 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -294,6 +294,10 @@ void CommandLineInterfaceTest::Run(const string& command) {
if (!disallow_plugins_) {
cli_.AllowPlugins("prefix-");
#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
+ string plugin_path;
+#ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH
+ plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH;
+#else
const char* possible_paths[] = {
// When building with shared libraries, libtool hides the real executable
// in .libs and puts a fake wrapper in the current directory.
@@ -311,15 +315,13 @@ void CommandLineInterfaceTest::Run(const string& command) {
"test_plugin.exe", // Other Win32 (MSVC)
"test_plugin", // Unix
};
-
- string plugin_path;
-
for (int i = 0; i < GOOGLE_ARRAYSIZE(possible_paths); i++) {
if (access(possible_paths[i], F_OK) == 0) {
plugin_path = possible_paths[i];
break;
}
}
+#endif
if (plugin_path.empty()) {
#else
@@ -884,6 +886,10 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) {
EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
// Descriptor set should not have source code info.
EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+ // Descriptor set should have json_name.
+ EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name());
+ EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name());
+ EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name());
}
TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) {
@@ -917,6 +923,10 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) {
EXPECT_EQ("baz.proto", descriptor_set.file(2).name());
// Descriptor set should not have source code info.
EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+ // Descriptor set should have json_name.
+ EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name());
+ EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name());
+ EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name());
}
TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
@@ -1411,6 +1421,18 @@ TEST_F(CommandLineInterfaceTest, PluginReceivesSourceCodeInfo) {
"Saw message type MockCodeGenerator_HasSourceCodeInfo: 1.");
}
+TEST_F(CommandLineInterfaceTest, PluginReceivesJsonName) {
+ CreateTempFile("foo.proto",
+ "syntax = \"proto2\";\n"
+ "message MockCodeGenerator_HasJsonName {\n"
+ " optional int32 value = 1;\n"
+ "}\n");
+
+ Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
+
+ ExpectErrorSubstring("Saw json_name: 1");
+}
+
TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
// Test what happens if the plugin isn't found.
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index de4d7cc7..1a11bce8 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -278,9 +278,9 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
if (descriptor_->containing_type() != NULL) {
// We need to "define" the static constants which were declared in the
// header, to give the linker a place to put them. Or at least the C++
- // standard says we have to. MSVC actually insists tha we do _not_ define
- // them again in the .cc file.
- printer->Print("#ifndef _MSC_VER\n");
+ // standard says we have to. MSVC actually insists that we do _not_ define
+ // them again in the .cc file, prior to VC++ 2015.
+ printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
vars["parent"] = ClassName(descriptor_->containing_type(), false);
vars["nested_name"] = descriptor_->name();
@@ -297,7 +297,7 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
"const int $parent$::$nested_name$_ARRAYSIZE;\n");
}
- printer->Print("#endif // _MSC_VER\n");
+ printer->Print("#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\n");
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 468ca484..c42f1627 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -155,7 +155,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
// Likewise, class members need to declare the field constant variable.
if (descriptor_->extension_scope() != NULL) {
printer->Print(vars,
- "#ifndef _MSC_VER\n"
+ "#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"
"const int $scope$$constant_name$;\n"
"#endif\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 5dae4cdd..37e4bae4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -237,6 +237,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer) {
}
void FileGenerator::GenerateSource(io::Printer* printer) {
+ bool well_known = IsWellKnownMessage(file_);
string header =
StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h");
printer->Print(
@@ -246,16 +247,19 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
// The generated code calls accessors that might be deprecated. We don't
// want the compiler to warn in generated code.
"#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
- "#include \"$header$\"\n"
+ "#include $left$$header$$right$\n"
"\n"
"#include <algorithm>\n" // for swap()
"\n"
"#include <google/protobuf/stubs/common.h>\n"
+ "#include <google/protobuf/stubs/port.h>\n"
"#include <google/protobuf/stubs/once.h>\n"
"#include <google/protobuf/io/coded_stream.h>\n"
"#include <google/protobuf/wire_format_lite_inl.h>\n",
"filename", file_->name(),
- "header", header);
+ "header", header,
+ "left", well_known ? "<" : "\"",
+ "right", well_known ? ">" : "\"");
// Unknown fields implementation in lite mode uses StringOutputStream
if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
@@ -598,8 +602,13 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// bytes in length". Declare a static array of characters rather than use a
// string literal.
if (breakdown_large_file && file_data.size() > 65535) {
+ // This has to be explicitly marked as a signed char because the generated
+ // code puts negative values in the array, and sometimes plain char is
+ // unsigned. That implicit narrowing conversion is not allowed in C++11.
+ // <http://stackoverflow.com/questions/4434140/narrowing-conversions-in-c0x-is-it-just-me-or-does-this-sound-like-a-breakin>
+ // has details on why.
printer->Print(
- "static const char descriptor[] = {\n");
+ "static const signed char descriptor[] = {\n");
printer->Indent();
// Only write 25 bytes per line.
@@ -841,7 +850,7 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
if (IsAnyMessage(file_)) {
printer->Print(
- "#include \"google/protobuf/any.h\"\n");
+ "#include <google/protobuf/any.h>\n");
}
}
@@ -852,14 +861,16 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
}
for (int i = 0; i < file_->dependency_count(); i++) {
+ bool well_known = IsWellKnownMessage(file_->dependency(i));
const string& name = file_->dependency(i)->name();
bool public_import = (public_import_names.count(name) != 0);
-
printer->Print(
- "#include \"$dependency$.pb.h\"$iwyu$\n",
+ "#include $left$$dependency$.pb.h$right$$iwyu$\n",
"dependency", StripProto(name),
- "iwyu", (public_import) ? " // IWYU pragma: export" : "");
+ "iwyu", (public_import) ? " // IWYU pragma: export" : "",
+ "left", well_known ? "<" : "\"",
+ "right", well_known ? ">" : "\"");
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 09845458..fb46e387 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -54,6 +54,7 @@ namespace {
static const char kAnyMessageName[] = "Any";
static const char kAnyProtoFile[] = "google/protobuf/any.proto";
+static const char kGoogleProtobufPrefix[] = "google/protobuf/";
string DotsToUnderscores(const string& name) {
return StringReplace(name, ".", "_", true);
@@ -600,6 +601,10 @@ bool IsAnyMessage(const Descriptor* descriptor) {
descriptor->file()->name() == kAnyProtoFile;
}
+bool IsWellKnownMessage(const FileDescriptor* descriptor) {
+ return !descriptor->name().compare(0, 16, kGoogleProtobufPrefix);
+}
+
enum Utf8CheckMode {
STRICT = 0, // Parsing will fail if non UTF-8 data is in string fields.
VERIFY = 1, // Only log an error but parsing will succeed.
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 985cb04c..a22d414d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -265,6 +265,8 @@ inline bool SupportsArenas(const FieldDescriptor* field) {
bool IsAnyMessage(const FileDescriptor* descriptor);
bool IsAnyMessage(const Descriptor* descriptor);
+bool IsWellKnownMessage(const FileDescriptor* descriptor);
+
void GenerateUtf8CheckCodeForString(
const FieldDescriptor* field,
bool for_parse,
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..8304ebbd 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());
@@ -1772,6 +1772,17 @@ GenerateShutdownCode(io::Printer* printer) {
void MessageGenerator::
GenerateClassMethods(io::Printer* printer) {
+ // mutable_unknown_fields wrapper function for LazyStringOutputStream
+ // callback.
+ if (!UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ "static ::std::string* MutableUnknownFieldsFor$classname$(\n"
+ " $classname$* ptr) {\n"
+ " return ptr->mutable_unknown_fields();\n"
+ "}\n"
+ "\n",
+ "classname", classname_);
+ }
if (IsAnyMessage(descriptor_)) {
printer->Print(
"void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n"
@@ -1807,7 +1818,7 @@ GenerateClassMethods(io::Printer* printer) {
}
// Generate field number constants.
- printer->Print("#ifndef _MSC_VER\n");
+ printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor *field = descriptor_->field(i);
printer->Print(
@@ -1816,7 +1827,7 @@ GenerateClassMethods(io::Printer* printer) {
"constant_name", FieldConstantName(field));
}
printer->Print(
- "#endif // !_MSC_VER\n"
+ "#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\n"
"\n");
// Define extension identifiers.
@@ -2814,7 +2825,9 @@ GenerateMergeFrom(io::Printer* printer) {
"}\n");
} else {
printer->Print(
- "mutable_unknown_fields()->append(from.unknown_fields());\n");
+ "if (!from.unknown_fields().empty()) {\n"
+ " mutable_unknown_fields()->append(from.unknown_fields());\n"
+ "}\n");
}
}
@@ -2889,11 +2902,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
"classname", classname_);
if (!UseUnknownFieldSet(descriptor_->file())) {
+ // Use LazyStringOutputString to avoid initializing unknown fields string
+ // unless it is actually needed. For the same reason, disable eager refresh
+ // on the CodedOutputStream.
printer->Print(
- " ::google::protobuf::io::StringOutputStream unknown_fields_string(\n"
- " mutable_unknown_fields());\n"
+ " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
+ " ::google::protobuf::internal::NewPermanentCallback(\n"
+ " &MutableUnknownFieldsFor$classname$, this));\n"
" ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
- " &unknown_fields_string);\n");
+ " &unknown_fields_string, false);\n",
+ "classname", classname_);
}
printer->Print(
@@ -3364,7 +3382,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
} else {
printer->Print(
"output->WriteRaw(unknown_fields().data(),\n"
- " unknown_fields().size());\n");
+ " static_cast<int>(unknown_fields().size()));\n");
}
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index b7b6039a..9942a343 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -82,6 +82,7 @@
namespace google {
namespace protobuf {
+using internal::NewPermanentCallback;
namespace compiler {
namespace cpp {
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
deleted file mode 100644
index cb6ca1b1..00000000
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ /dev/null
@@ -1,43 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
-syntax = "proto2";
-
-package protobuf_unittest;
-
-message TestLargeEnumValue {
- enum EnumWithLargeValue {
- VALUE_1 = 1;
- VALUE_MAX = 0x7fffffff;
- }
-}
diff --git a/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc b/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
new file mode 100644
index 00000000..587e0222
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
@@ -0,0 +1,114 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+// Functions to create C# XML documentation comments.
+// Currently this only includes documentation comments containing text specified as comments
+// in the .proto file; documentation comments generated just from field/message/enum/proto names
+// is inlined in the relevant code. If more control is required, that code can be moved here.
+
+void WriteDocCommentBodyImpl(io::Printer* printer, SourceLocation location) {
+ string comments = location.leading_comments.empty() ?
+ location.trailing_comments : location.leading_comments;
+ if (comments.empty()) {
+ return;
+ }
+ // XML escaping... no need for apostrophes etc as the whole text is going to be a child
+ // node of a summary element, not part of an attribute.
+ comments = StringReplace(comments, "&", "&amp;", true);
+ comments = StringReplace(comments, "<", "&lt;", true);
+ vector<string> lines = Split(comments, "\n", false /* skip_empty */);
+ // TODO: We really should work out which part to put in the summary and which to put in the remarks...
+ // but that needs to be part of a bigger effort to understand the markdown better anyway.
+ printer->Print("/// <summary>\n");
+ bool last_was_empty = false;
+ // We squash multiple blank lines down to one, and remove any trailing blank lines. We need
+ // to preserve the blank lines themselves, as this is relevant in the markdown.
+ // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
+ // (We don't skip "just whitespace" lines, either.)
+ for (std::vector<string>::iterator it = lines.begin(); it != lines.end(); ++it) {
+ string line = *it;
+ if (line.empty()) {
+ last_was_empty = true;
+ } else {
+ if (last_was_empty) {
+ printer->Print("///\n");
+ }
+ last_was_empty = false;
+ printer->Print("/// $line$\n", "line", *it);
+ }
+ }
+ printer->Print("/// </summary>\n");
+}
+
+template <typename DescriptorType>
+static void WriteDocCommentBody(
+ io::Printer* printer, const DescriptorType* descriptor) {
+ SourceLocation location;
+ if (descriptor->GetSourceLocation(&location)) {
+ WriteDocCommentBodyImpl(printer, location);
+ }
+}
+
+void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
+ WriteDocCommentBody(printer, message);
+}
+
+void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field) {
+ WriteDocCommentBody(printer, field);
+}
+
+void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor) {
+ WriteDocCommentBody(printer, enumDescriptor);
+}
+void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value) {
+ WriteDocCommentBody(printer, value);
+}
+
+void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method) {
+ WriteDocCommentBody(printer, method);
+}
+
+} // namespace csharp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc b/src/google/protobuf/compiler/csharp/csharp_doc_comment.h
index e5db844c..75eb0ea0 100644
--- a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_doc_comment.h
@@ -28,30 +28,24 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <google/protobuf/util/internal/snake2camel_objectwriter.h>
-#include <google/protobuf/util/internal/expecting_objectwriter.h>
-#include <gtest/gtest.h>
-namespace google {
-namespace protobuf {
-namespace util {
-namespace converter {
-
-class Snake2CamelObjectWriterTest : public ::testing::Test {
- protected:
- Snake2CamelObjectWriterTest() : mock_(), expects_(&mock_), testing_(&mock_) {}
- virtual ~Snake2CamelObjectWriterTest() {}
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
- MockObjectWriter mock_;
- ExpectingObjectWriter expects_;
- Snake2CamelObjectWriter testing_;
-};
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
-// All tests are deleted as they are no longer needed. This file will be removed
-// after the component dependecies are cleaned up.
-// TODO(skarvaje): Remove this file.
-
-} // namespace converter
-} // namespace util
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+ void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
+ void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field);
+ void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor);
+ void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value);
+ void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method);
+} // namespace csharp
+} // namespace compiler
} // namespace protobuf
} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc
index 0e8f9836..56681989 100644
--- a/src/google/protobuf/compiler/csharp/csharp_enum.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc
@@ -38,6 +38,7 @@
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_enum.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
@@ -57,13 +58,15 @@ EnumGenerator::~EnumGenerator() {
}
void EnumGenerator::Generate(io::Printer* printer) {
+ WriteEnumDocComment(printer, descriptor_);
WriteGeneratedCodeAttributes(printer);
printer->Print("$access_level$ enum $name$ {\n",
"access_level", class_access_level(),
"name", descriptor_->name());
printer->Indent();
for (int i = 0; i < descriptor_->value_count(); i++) {
- printer->Print("$name$ = $number$,\n",
+ WriteEnumValueDocComment(printer, descriptor_->value(i));
+ printer->Print("$name$ = $number$,\n",
"name", descriptor_->value(i)->name(),
"number", SimpleItoa(descriptor_->value(i)->number()));
}
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc
index e0a6c83a..825de542 100644
--- a/src/google/protobuf/compiler/csharp/csharp_generator.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc
@@ -36,10 +36,12 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/compiler/csharp/csharp_generator.h>
-#include <google/protobuf/compiler/csharp/csharp_umbrella_class.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
using google::protobuf::internal::scoped_ptr;
@@ -48,15 +50,10 @@ namespace protobuf {
namespace compiler {
namespace csharp {
-std::string GetOutputFile(const google::protobuf::FileDescriptor* file, const std::string file_extension)
-{
- return GetUmbrellaClassUnqualifiedName(file) + file_extension;
-}
-
void GenerateFile(const google::protobuf::FileDescriptor* file,
io::Printer* printer) {
- UmbrellaClassGenerator umbrellaGenerator(file);
- umbrellaGenerator.Generate(printer);
+ ReflectionClassGenerator reflectionClassGenerator(file);
+ reflectionClassGenerator.Generate(printer);
}
bool Generator::Generate(
@@ -75,16 +72,26 @@ bool Generator::Generate(
}
std::string file_extension = ".cs";
+ std::string base_namespace = "";
+ bool generate_directories = false;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "file_extension") {
file_extension = options[i].second;
+ } else if (options[i].first == "base_namespace") {
+ base_namespace = options[i].second;
+ generate_directories = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
}
}
- std::string filename = GetOutputFile(file, file_extension);
+ string filename_error = "";
+ std::string filename = GetOutputFile(file, file_extension, generate_directories, base_namespace, &filename_error);
+ if (filename.empty()) {
+ *error = filename_error;
+ return false;
+ }
scoped_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(filename));
io::Printer printer(output.get(), '$');
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
index 333b4912..c51fe44b 100644
--- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
@@ -117,43 +117,18 @@ std::string GetFileNamespace(const FileDescriptor* descriptor) {
return UnderscoresToCamelCase(descriptor->package(), true, true);
}
-std::string GetUmbrellaClassUnqualifiedName(const FileDescriptor* descriptor) {
- // We manually rename Descriptor to DescriptorProtoFile to avoid collisions with
- // the static Descriptor property. It would be nice to be able to do this with an
- // option, but it would be rarely used.
- if (IsDescriptorProto(descriptor)) {
- return "DescriptorProtoFile";
- }
- // umbrella_classname can no longer be set using message option.
- std::string proto_file = descriptor->name();
- int lastslash = proto_file.find_last_of("/");
- std::string base = proto_file.substr(lastslash + 1);
- return UnderscoresToPascalCase(StripDotProto(base));
+// Returns the Pascal-cased last part of the proto file. For example,
+// input of "google/protobuf/foo_bar.proto" would result in "FooBar".
+std::string GetFileNameBase(const FileDescriptor* descriptor) {
+ std::string proto_file = descriptor->name();
+ int lastslash = proto_file.find_last_of("/");
+ std::string base = proto_file.substr(lastslash + 1);
+ return UnderscoresToPascalCase(StripDotProto(base));
}
-std::string GetUmbrellaClassNestedNamespace(const FileDescriptor* descriptor) {
- // TODO(jtattermusch): reintroduce csharp_umbrella_namespace option
- bool collision = false;
- std::string umbrella_classname = GetUmbrellaClassUnqualifiedName(descriptor);
- for(int i = 0; i < descriptor->message_type_count(); i++) {
- if (descriptor->message_type(i)->name() == umbrella_classname) {
- collision = true;
- break;
- }
- }
- for (int i = 0; i < descriptor->service_count(); i++) {
- if (descriptor->service(i)->name() == umbrella_classname) {
- collision = true;
- break;
- }
- }
- for (int i = 0; i < descriptor->enum_type_count(); i++) {
- if (descriptor->enum_type(i)->name() == umbrella_classname) {
- collision = true;
- break;
- }
- }
- return collision ? "Proto" : "";
+std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) {
+ // TODO: Detect collisions with existing messages, and append an underscore if necessary.
+ return GetFileNameBase(descriptor) + "Reflection";
}
// TODO(jtattermusch): can we reuse a utility function?
@@ -218,16 +193,12 @@ std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
return "global::" + result;
}
-std::string GetUmbrellaClassName(const FileDescriptor* descriptor) {
+std::string GetReflectionClassName(const FileDescriptor* descriptor) {
std::string result = GetFileNamespace(descriptor);
if (!result.empty()) {
result += '.';
}
- std::string umbrellaNamespace = GetUmbrellaClassNestedNamespace(descriptor);
- if (!umbrellaNamespace.empty()) {
- result += umbrellaNamespace + ".";
- }
- result += GetUmbrellaClassUnqualifiedName(descriptor);
+ result += GetReflectionClassUnqualifiedName(descriptor);
return "global::" + result;
}
@@ -269,6 +240,41 @@ std::string GetPropertyName(const FieldDescriptor* descriptor) {
return property_name;
}
+std::string GetOutputFile(
+ const google::protobuf::FileDescriptor* descriptor,
+ const std::string file_extension,
+ const bool generate_directories,
+ const std::string base_namespace,
+ string* error) {
+ string relative_filename = GetFileNameBase(descriptor) + file_extension;
+ if (!generate_directories) {
+ return relative_filename;
+ }
+ string ns = GetFileNamespace(descriptor);
+ string namespace_suffix = ns;
+ if (!base_namespace.empty()) {
+ // Check that the base_namespace is either equal to or a leading part of
+ // the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't
+ // be regarded as a prefix of "Foo.Bar". The simplest option is to add "."
+ // to both.
+ string extended_ns = ns + ".";
+ if (extended_ns.find(base_namespace + ".") != 0) {
+ *error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace;
+ return ""; // This will be ignored, because we've set an error.
+ }
+ namespace_suffix = ns.substr(base_namespace.length());
+ if (namespace_suffix.find(".") == 0) {
+ namespace_suffix = namespace_suffix.substr(1);
+ }
+ }
+
+ string namespace_dir = StringReplace(namespace_suffix, ".", "/", true);
+ if (!namespace_dir.empty()) {
+ namespace_dir += "/";
+ }
+ return namespace_dir + relative_filename;
+}
+
// TODO: c&p from Java protoc plugin
// For encodings with fixed sizes, returns that size in bytes. Otherwise
// returns -1.
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h
index 4ed17a84..e96e7938 100644
--- a/src/google/protobuf/compiler/csharp/csharp_helpers.h
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h
@@ -69,14 +69,8 @@ CSharpType GetCSharpType(FieldDescriptor::Type type);
std::string StripDotProto(const std::string& proto_file);
-// Gets unqualified name of the umbrella class
-std::string GetUmbrellaClassUnqualifiedName(const FileDescriptor* descriptor);
-
-// Gets name of the nested for umbrella class (just the nested part,
-// not including the GetFileNamespace part).
-std::string GetUmbrellaClassNestedNamespace(const FileDescriptor* descriptor);
-
-std::string GetClassName(const Descriptor* descriptor);
+// Gets unqualified name of the reflection class
+std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor);
std::string GetClassName(const EnumDescriptor* descriptor);
@@ -101,8 +95,6 @@ std::string StringToBase64(const std::string& input);
std::string FileDescriptorToBase64(const FileDescriptor* descriptor);
-uint FixedMakeTag(const FieldDescriptor* descriptor);
-
FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
// Determines whether the given message is a map entry message, i.e. one implicitly created
diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
index f84ad6f7..15c68b3f 100644
--- a/src/google/protobuf/compiler/csharp/csharp_map_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
@@ -38,6 +38,7 @@
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_map_field.h>
@@ -61,7 +62,6 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
descriptor_->message_type()->FindFieldByName("value");
variables_["key_type_name"] = type_name(key_descriptor);
variables_["value_type_name"] = type_name(value_descriptor);
- variables_["true_for_wrappers"] = IsWrapperType(value_descriptor) ? "true" : "";
scoped_ptr<FieldGeneratorBase> key_generator(CreateFieldGenerator(key_descriptor, 1));
scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2));
@@ -75,7 +75,8 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
printer->Print(
variables_,
", $tag$);\n"
- "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>($true_for_wrappers$);\n");
+ "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n");
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc
index a71a7909..e0230a24 100644
--- a/src/google/protobuf/compiler/csharp/csharp_message.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -42,6 +42,7 @@
#include <google/protobuf/wire_format.h>
#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_enum.h>
#include <google/protobuf/compiler/csharp/csharp_field_base.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
@@ -101,6 +102,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
vars["class_name"] = class_name();
vars["access_level"] = class_access_level();
+ WriteMessageDocComment(printer, descriptor_);
printer->Print(
"[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
WriteGeneratedCodeAttributes(printer);
@@ -117,7 +119,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
// Access the message descriptor via the relevant file descriptor or containing message descriptor.
if (!descriptor_->containing_type()) {
- vars["descriptor_accessor"] = GetUmbrellaClassName(descriptor_->file())
+ vars["descriptor_accessor"] = GetReflectionClassName(descriptor_->file())
+ ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]";
} else {
vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type())
@@ -152,7 +154,9 @@ void MessageGenerator::Generate(io::Printer* printer) {
// Rats: we lose the debug comment here :(
printer->Print(
+ "/// <summary>Field number for the \"$field_name$\" field.</summary>\n"
"public const int $field_constant_name$ = $index$;\n",
+ "field_name", fieldDescriptor->name(),
"field_constant_name", GetFieldConstantName(fieldDescriptor),
"index", SimpleItoa(fieldDescriptor->number()));
scoped_ptr<FieldGeneratorBase> generator(
@@ -169,6 +173,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
printer->Print(
vars,
"private object $name$_;\n"
+ "/// <summary>Enum of possible cases for the \"$original_name$\" oneof.</summary>\n"
"public enum $property_name$OneofCase {\n");
printer->Indent();
printer->Print("None = 0,\n");
@@ -180,6 +185,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
printer->Outdent();
printer->Print("}\n");
+ // TODO: Should we put the oneof .proto comments here? It's unclear exactly where they should go.
printer->Print(
vars,
"private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n"
@@ -199,8 +205,11 @@ void MessageGenerator::Generate(io::Printer* printer) {
// Nested messages and enums
if (HasNestedGeneratedTypes()) {
- printer->Print("#region Nested types\n"
- "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
+ printer->Print(
+ vars,
+ "#region Nested types\n"
+ "/// <summary>Container for nested types declared in the $class_name$ message type.</summary>\n"
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
WriteGeneratedCodeAttributes(printer);
printer->Print("public static partial class Types {\n");
printer->Indent();
@@ -314,6 +323,10 @@ void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
CreateFieldGeneratorInternal(descriptor_->field(i)));
generator->WriteEquals(printer);
}
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print("if ($property_name$Case != other.$property_name$Case) return false;\n",
+ "property_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true));
+ }
printer->Outdent();
printer->Print(
" return true;\n"
@@ -330,13 +343,17 @@ void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
CreateFieldGeneratorInternal(descriptor_->field(i)));
generator->WriteHash(printer);
}
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+ printer->Print("hash ^= (int) $name$Case_;\n",
+ "name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false));
+ }
printer->Print("return hash;\n");
printer->Outdent();
printer->Print("}\n\n");
printer->Print(
"public override string ToString() {\n"
- " return pb::JsonFormatter.Default.Format(this);\n"
+ " return pb::JsonFormatter.ToDiagnosticString(this);\n"
"}\n\n");
}
diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
index 4f576cd1..f81f769b 100644
--- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
@@ -38,6 +38,7 @@
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_message_field.h>
@@ -61,6 +62,7 @@ void MessageFieldGenerator::GenerateMembers(io::Printer* printer) {
printer->Print(
variables_,
"private $type_name$ $name$_;\n");
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
@@ -152,6 +154,7 @@ MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {
}
void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_names.h b/src/google/protobuf/compiler/csharp/csharp_names.h
index ccd2e720..30805187 100644
--- a/src/google/protobuf/compiler/csharp/csharp_names.h
+++ b/src/google/protobuf/compiler/csharp/csharp_names.h
@@ -72,7 +72,28 @@ string GetClassName(const Descriptor* descriptor);
// The fully-qualified name of the C# class that provides
// access to the file descriptor. Proto compiler generates
// such class for each .proto file processed.
-std::string GetUmbrellaClassName(const FileDescriptor* descriptor);
+string GetReflectionClassName(const FileDescriptor* descriptor);
+
+// Generates output file name for given file descriptor. If generate_directories
+// is true, the output file will be put under directory corresponding to file's
+// namespace. base_namespace can be used to strip some of the top level
+// directories. E.g. for file with namespace "Bar.Foo" and base_namespace="Bar",
+// the resulting file will be put under directory "Foo" (and not "Bar/Foo").
+//
+// Requires:
+// descriptor != NULL
+// error != NULL
+//
+// Returns:
+// The file name to use as output file for given file descriptor. In case
+// of failure, this function will return empty string and error parameter
+// will contain the error message.
+string GetOutputFile(
+ const google::protobuf::FileDescriptor* descriptor,
+ const string file_extension,
+ const bool generate_directories,
+ const string base_namespace,
+ string* error);
} // namespace csharp
} // namespace compiler
diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
index fc043ec0..76d5b247 100644
--- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
@@ -38,6 +38,7 @@
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
@@ -68,6 +69,7 @@ void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
printer->Print(
variables_,
"private $type_name$ $name_def_message$;\n");
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
@@ -170,6 +172,7 @@ PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {
}
void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
index 399c64e1..3862f001 100644
--- a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
@@ -43,25 +43,24 @@
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_message.h>
#include <google/protobuf/compiler/csharp/csharp_names.h>
-#include <google/protobuf/compiler/csharp/csharp_umbrella_class.h>
+#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
-UmbrellaClassGenerator::UmbrellaClassGenerator(const FileDescriptor* file)
+ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file)
: SourceGeneratorBase(file),
file_(file) {
namespace_ = GetFileNamespace(file);
- umbrellaClassname_ = GetUmbrellaClassUnqualifiedName(file);
- umbrellaNamespace_ = GetUmbrellaClassNestedNamespace(file);
+ reflectionClassname_ = GetReflectionClassUnqualifiedName(file);
}
-UmbrellaClassGenerator::~UmbrellaClassGenerator() {
+ReflectionClassGenerator::~ReflectionClassGenerator() {
}
-void UmbrellaClassGenerator::Generate(io::Printer* printer) {
+void ReflectionClassGenerator::Generate(io::Printer* printer) {
WriteIntroduction(printer);
WriteDescriptor(printer);
@@ -69,12 +68,6 @@ void UmbrellaClassGenerator::Generate(io::Printer* printer) {
printer->Outdent();
printer->Print("}\n");
- // Close the namespace around the umbrella class if defined
- if (!umbrellaNamespace_.empty()) {
- printer->Outdent();
- printer->Print("}\n");
- }
-
// write children: Enums
if (file_->enum_type_count() > 0) {
printer->Print("#region Enums\n");
@@ -107,7 +100,7 @@ void UmbrellaClassGenerator::Generate(io::Printer* printer) {
printer->Print("#endregion Designer generated code\n");
}
-void UmbrellaClassGenerator::WriteIntroduction(io::Printer* printer) {
+void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) {
printer->Print(
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"// source: $file_name$\n"
@@ -126,35 +119,31 @@ void UmbrellaClassGenerator::WriteIntroduction(io::Printer* printer) {
printer->Print("\n");
}
- // Add the namespace around the umbrella class if defined
- if (!umbrellaNamespace_.empty()) {
- printer->Print("namespace $umbrella_namespace$ {\n",
- "umbrella_namespace", umbrellaNamespace_);
- printer->Indent();
- printer->Print("\n");
- }
-
printer->Print(
- "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
+ "/// <summary>Holder for reflection information generated from $file_name$</summary>\n"
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n",
+ "file_name", file_->name());
WriteGeneratedCodeAttributes(printer);
printer->Print(
- "$access_level$ static partial class $umbrella_class_name$ {\n"
+ "$access_level$ static partial class $reflection_class_name$ {\n"
"\n",
"access_level", class_access_level(),
- "umbrella_class_name", umbrellaClassname_);
+ "reflection_class_name", reflectionClassname_);
printer->Indent();
}
-void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
+void ReflectionClassGenerator::WriteDescriptor(io::Printer* printer) {
printer->Print(
"#region Descriptor\n"
+ "/// <summary>File descriptor for $file_name$</summary>\n"
"public static pbr::FileDescriptor Descriptor {\n"
" get { return descriptor; }\n"
"}\n"
"private static pbr::FileDescriptor descriptor;\n"
"\n"
- "static $umbrella_class_name$() {\n",
- "umbrella_class_name", umbrellaClassname_);
+ "static $reflection_class_name$() {\n",
+ "file_name", file_->name(),
+ "reflection_class_name", reflectionClassname_);
printer->Indent();
printer->Print(
"byte[] descriptorData = global::System.Convert.FromBase64String(\n");
@@ -166,7 +155,7 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
// TODO(jonskeet): Consider a C#-escaping format here instead of just Base64.
std::string base64 = FileDescriptorToBase64(file_);
while (base64.size() > 60) {
- printer->Print("\"$base64$\", \n", "base64", base64.substr(0, 60));
+ printer->Print("\"$base64$\",\n", "base64", base64.substr(0, 60));
base64 = base64.substr(60);
}
printer->Print("\"$base64$\"));\n", "base64", base64);
@@ -177,7 +166,7 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
// -----------------------------------------------------------------
// Invoke InternalBuildGeneratedFileFrom() to build the file.
printer->Print(
- "descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n");
+ "descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,\n");
printer->Print(" new pbr::FileDescriptor[] { ");
for (int i = 0; i < file_->dependency_count(); i++) {
// descriptor.proto is special: we don't allow access to the generated code, but there's
@@ -187,9 +176,9 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
printer->Print("pbr::FileDescriptor.DescriptorProtoFileDescriptor, ");
} else {
printer->Print(
- "$full_umbrella_class_name$.Descriptor, ",
- "full_umbrella_class_name",
- GetUmbrellaClassName(file_->dependency(i)));
+ "$full_reflection_class_name$.Descriptor, ",
+ "full_reflection_class_name",
+ GetReflectionClassName(file_->dependency(i)));
}
}
printer->Print("},\n"
@@ -237,13 +226,13 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
// The "last" parameter indicates whether this message descriptor is the last one being printed in this immediate
// context. It governs whether or not a trailing comma and newline is written after the constructor, effectively
// just controlling the formatting in the generated code.
-void UmbrellaClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) {
+void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) {
if (IsMapEntryMessage(descriptor)) {
printer->Print("null, ");
return;
}
// Generated message type
- printer->Print("new pbr::GeneratedCodeInfo(typeof($type_name$), ", "type_name", GetClassName(descriptor));
+ printer->Print("new pbr::GeneratedCodeInfo(typeof($type_name$), $type_name$.Parser, ", "type_name", GetClassName(descriptor));
// Fields
if (descriptor->field_count() > 0) {
diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
index b8bd2133..0a5b8ed5 100644
--- a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
@@ -28,8 +28,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__
-#define GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__
#include <string>
@@ -41,10 +41,10 @@ namespace protobuf {
namespace compiler {
namespace csharp {
-class UmbrellaClassGenerator : public SourceGeneratorBase {
+class ReflectionClassGenerator : public SourceGeneratorBase {
public:
- UmbrellaClassGenerator(const FileDescriptor* file);
- ~UmbrellaClassGenerator();
+ ReflectionClassGenerator(const FileDescriptor* file);
+ ~ReflectionClassGenerator();
void Generate(io::Printer* printer);
@@ -52,14 +52,13 @@ class UmbrellaClassGenerator : public SourceGeneratorBase {
const FileDescriptor* file_;
std::string namespace_;
- std::string umbrellaClassname_;
- std::string umbrellaNamespace_;
+ std::string reflectionClassname_;
void WriteIntroduction(io::Printer* printer);
void WriteDescriptor(io::Printer* printer);
void WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last);
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UmbrellaClassGenerator);
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionClassGenerator);
};
} // namespace csharp
@@ -67,4 +66,4 @@ class UmbrellaClassGenerator : public SourceGeneratorBase {
} // namespace protobuf
} // namespace google
-#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__
+#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
index 625631df..3a11b75d 100644
--- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
@@ -38,6 +38,7 @@
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/wire_format.h>
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
@@ -62,6 +63,7 @@ void RepeatedEnumFieldGenerator::GenerateMembers(io::Printer* printer) {
" = pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x);\n");
printer->Print(variables_,
"private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
index 7fbab681..fc12faed 100644
--- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
@@ -37,6 +37,7 @@
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
#include <google/protobuf/compiler/csharp/csharp_message_field.h>
@@ -75,6 +76,7 @@ void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) {
printer->Print(
variables_,
"private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
index 1163ce73..5fe0b203 100644
--- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
@@ -38,6 +38,7 @@
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/wire_format.h>
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h>
@@ -62,6 +63,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
" = pb::FieldCodec.For$capitalized_type_name$($tag$);\n");
printer->Print(variables_,
"private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
index 44f832bf..6a3750e0 100644
--- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
@@ -37,6 +37,7 @@
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
@@ -70,6 +71,7 @@ void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) {
variables_,
";\n"
"private $type_name$ $name$_;\n");
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
@@ -165,6 +167,7 @@ void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
"private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
GenerateCodecCode(printer);
printer->Print(";\n");
+ WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer);
printer->Print(
variables_,
diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc
index 8333684e..0d9093c0 100644
--- a/src/google/protobuf/compiler/importer.cc
+++ b/src/google/protobuf/compiler/importer.cc
@@ -185,6 +185,19 @@ void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddError(
owner_->error_collector_->AddError(filename, line, column, message);
}
+void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddWarning(
+ const string& filename,
+ const string& element_name,
+ const Message* descriptor,
+ ErrorLocation location,
+ const string& message) {
+ if (owner_->error_collector_ == NULL) return;
+
+ int line, column;
+ owner_->source_locations_.Find(descriptor, location, &line, &column);
+ owner_->error_collector_->AddWarning(filename, line, column, message);
+}
+
// ===================================================================
Importer::Importer(SourceTree* source_tree,
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index f010fd08..cc8fcc39 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -121,6 +121,12 @@ class LIBPROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabas
ErrorLocation location,
const string& message);
+ virtual void AddWarning(const string& filename,
+ const string& element_name,
+ const Message* descriptor,
+ ErrorLocation location,
+ const string& message);
+
private:
SourceTreeDescriptorDatabase* owner_;
};
@@ -188,6 +194,9 @@ class LIBPROTOBUF_EXPORT MultiFileErrorCollector {
virtual void AddError(const string& filename, int line, int column,
const string& message) = 0;
+ virtual void AddWarning(const string& filename, int line, int column,
+ const string& message) {}
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector);
};
diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc
index 33c9328f..be19aa2e 100644
--- a/src/google/protobuf/compiler/importer_unittest.cc
+++ b/src/google/protobuf/compiler/importer_unittest.cc
@@ -71,6 +71,7 @@ class MockErrorCollector : public MultiFileErrorCollector {
~MockErrorCollector() {}
string text_;
+ string warning_text_;
// implements ErrorCollector ---------------------------------------
void AddError(const string& filename, int line, int column,
@@ -78,6 +79,12 @@ class MockErrorCollector : public MultiFileErrorCollector {
strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n",
filename, line, column, message);
}
+
+ void AddWarning(const string& filename, int line, int column,
+ const string& message) {
+ strings::SubstituteAndAppend(&warning_text_, "$0:$1:$2: $3\n",
+ filename, line, column, message);
+ }
};
// -------------------------------------------------------------------
@@ -123,6 +130,7 @@ class ImporterTest : public testing::Test {
// Return the collected error text
string error() const { return error_collector_.text_; }
+ string warning() const { return error_collector_.warning_text_; }
MockErrorCollector error_collector_;
MockSourceTree source_tree_;
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 8a09f3a8..5fc9b002 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -85,17 +85,10 @@ EnumGenerator::~EnumGenerator() {}
void EnumGenerator::Generate(io::Printer* printer) {
WriteEnumDocComment(printer, descriptor_);
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public enum $classname$\n"
- " implements com.google.protobuf.ProtocolMessageEnum {\n",
- "classname", descriptor_->name());
- } else {
- printer->Print(
- "public enum $classname$\n"
- " implements com.google.protobuf.Internal.EnumLite {\n",
- "classname", descriptor_->name());
- }
+ printer->Print(
+ "public enum $classname$\n"
+ " implements com.google.protobuf.ProtocolMessageEnum {\n",
+ "classname", descriptor_->name());
printer->Indent();
for (int i = 0; i < canonical_values_.size(); i++) {
@@ -311,7 +304,6 @@ void EnumGenerator::Generate(io::Printer* printer) {
"}\n"
"\n");
- // index is only used for reflection; lite implementation does not need it
printer->Print("private final int index;\n");
}
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..e3e87c58 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"
@@ -596,9 +596,7 @@ GenerateInterfaceMembers(io::Printer* printer) const {
void RepeatedImmutableEnumFieldLiteGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- // TODO(dweis): Switch to IntList?
- "private com.google.protobuf.Internal.ProtobufList<\n"
- " java.lang.Integer> $name$_;\n"
+ "private com.google.protobuf.Internal.IntList $name$_;\n"
"private static final com.google.protobuf.Internal.ListAdapter.Converter<\n"
" java.lang.Integer, $type$> $name$_converter_ =\n"
" new com.google.protobuf.Internal.ListAdapter.Converter<\n"
@@ -623,7 +621,7 @@ GenerateMembers(io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
- " return $name$_converter_.convert($name$_.get(index));\n"
+ " return $name$_converter_.convert($name$_.getInt(index));\n"
"}\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
WriteFieldDocComment(printer, descriptor_);
@@ -635,7 +633,7 @@ GenerateMembers(io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public int get$capitalized_name$Value(int index) {\n"
- " return $name$_.get(index);\n"
+ " return $name$_.getInt(index);\n"
"}\n");
}
@@ -649,7 +647,7 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
"private void ensure$capitalized_name$IsMutable() {\n"
" if (!$is_mutable$) {\n"
- " $name$_ = newProtobufList($name$_);\n"
+ " $name$_ = newIntList($name$_);\n"
" }\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
@@ -660,7 +658,7 @@ GenerateMembers(io::Printer* printer) const {
" throw new NullPointerException();\n"
" }\n"
" ensure$capitalized_name$IsMutable();\n"
- " $name$_.set(index, value.getNumber());\n"
+ " $name$_.setInt(index, value.getNumber());\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
@@ -669,7 +667,7 @@ GenerateMembers(io::Printer* printer) const {
" throw new NullPointerException();\n"
" }\n"
" ensure$capitalized_name$IsMutable();\n"
- " $name$_.add(value.getNumber());\n"
+ " $name$_.addInt(value.getNumber());\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
@@ -677,13 +675,13 @@ GenerateMembers(io::Printer* printer) const {
" java.lang.Iterable<? extends $type$> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
" for ($type$ value : values) {\n"
- " $name$_.add(value.getNumber());\n"
+ " $name$_.addInt(value.getNumber());\n"
" }\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"private void clear$capitalized_name$() {\n"
- " $name$_ = emptyProtobufList();\n"
+ " $name$_ = emptyIntList();\n"
"}\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
@@ -692,13 +690,13 @@ GenerateMembers(io::Printer* printer) const {
"private void set$capitalized_name$Value(\n"
" int index, int value) {\n"
" ensure$capitalized_name$IsMutable();\n"
- " $name$_.set(index, value);\n"
+ " $name$_.setInt(index, value);\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"private void add$capitalized_name$Value(int value) {\n"
" ensure$capitalized_name$IsMutable();\n"
- " $name$_.add(value);\n"
+ " $name$_.addInt(value);\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
@@ -706,7 +704,7 @@ GenerateMembers(io::Printer* printer) const {
" java.lang.Iterable<java.lang.Integer> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
" for (int value : values) {\n"
- " $name$_.add(value);\n"
+ " $name$_.addInt(value);\n"
" }\n"
"}\n");
}
@@ -805,7 +803,7 @@ GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
void RepeatedImmutableEnumFieldLiteGenerator::
GenerateInitializationCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_ = emptyProtobufList();\n");
+ printer->Print(variables_, "$name$_ = emptyIntList();\n");
}
void RepeatedImmutableEnumFieldLiteGenerator::
@@ -840,9 +838,9 @@ GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
"if (!$is_mutable$) {\n"
- " $name$_ = newProtobufList();\n"
+ " $name$_ = newIntList();\n"
"}\n"
- "$name$_.add(rawValue);\n");
+ "$name$_.addInt(rawValue);\n");
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
@@ -850,14 +848,14 @@ 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"
" if (!$is_mutable$) {\n"
- " $name$_ = newProtobufList();\n"
+ " $name$_ = newIntList();\n"
" }\n"
- " $name$_.add(rawValue);\n"
+ " $name$_.addInt(rawValue);\n"
"}\n");
}
}
@@ -897,12 +895,12 @@ GenerateSerializationCode(io::Printer* printer) const {
" output.writeRawVarint32($name$MemoizedSerializedSize);\n"
"}\n"
"for (int i = 0; i < $name$_.size(); i++) {\n"
- " output.writeEnumNoTag($name$_.get(i));\n"
+ " output.writeEnumNoTag($name$_.getInt(i));\n"
"}\n");
} else {
printer->Print(variables_,
"for (int i = 0; i < $name$_.size(); i++) {\n"
- " output.writeEnum($number$, $name$_.get(i));\n"
+ " output.writeEnum($number$, $name$_.getInt(i));\n"
"}\n");
}
}
@@ -917,7 +915,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
"for (int i = 0; i < $name$_.size(); i++) {\n"
" dataSize += com.google.protobuf.CodedOutputStream\n"
- " .computeEnumSizeNoTag($name$_.get(i));\n"
+ " .computeEnumSizeNoTag($name$_.getInt(i));\n"
"}\n");
printer->Print(
"size += dataSize;\n");
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc
index 62186386..ed415eee 100644
--- a/src/google/protobuf/compiler/java/java_enum_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_lite.cc
@@ -85,34 +85,26 @@ EnumLiteGenerator::~EnumLiteGenerator() {}
void EnumLiteGenerator::Generate(io::Printer* printer) {
WriteEnumDocComment(printer, descriptor_);
- if (HasDescriptorMethods(descriptor_)) {
- printer->Print(
- "public enum $classname$\n"
- " implements com.google.protobuf.ProtocolMessageEnum {\n",
- "classname", descriptor_->name());
- } else {
- printer->Print(
- "public enum $classname$\n"
- " implements com.google.protobuf.Internal.EnumLite {\n",
- "classname", descriptor_->name());
- }
+ printer->Print(
+ "public enum $classname$\n"
+ " implements com.google.protobuf.Internal.EnumLite {\n",
+ "classname", descriptor_->name());
printer->Indent();
for (int i = 0; i < canonical_values_.size(); i++) {
map<string, string> vars;
vars["name"] = canonical_values_[i]->name();
- vars["index"] = SimpleItoa(canonical_values_[i]->index());
vars["number"] = SimpleItoa(canonical_values_[i]->number());
WriteEnumValueDocComment(printer, canonical_values_[i]);
if (canonical_values_[i]->options().deprecated()) {
printer->Print("@java.lang.Deprecated\n");
}
printer->Print(vars,
- "$name$($index$, $number$),\n");
+ "$name$($number$),\n");
}
if (SupportUnknownEnumValue(descriptor_->file())) {
- printer->Print("UNRECOGNIZED(-1, -1),\n");
+ printer->Print("UNRECOGNIZED(-1),\n");
}
printer->Print(
@@ -145,15 +137,7 @@ void EnumLiteGenerator::Generate(io::Printer* printer) {
printer->Print(
"\n"
- "public final int getNumber() {\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
- printer->Print(
- " if (index == -1) {\n"
- " throw new java.lang.IllegalArgumentException(\n"
- " \"Can't get the number of an unknown enum value.\");\n"
- " }\n");
- }
- printer->Print(
+ "public final int getNumber() {\n"
" return value;\n"
"}\n"
"\n"
@@ -193,7 +177,7 @@ void EnumLiteGenerator::Generate(io::Printer* printer) {
printer->Print(
"private final int value;\n\n"
- "private $classname$(int index, int value) {\n",
+ "private $classname$(int value) {\n",
"classname", descriptor_->name());
printer->Print(
" this.value = value;\n"
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 68b47ee1..c8172330 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -42,6 +42,7 @@
#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_enum_lite.h>
#include <google/protobuf/compiler/java/java_extension.h>
#include <google/protobuf/compiler/java/java_generator_factory.h>
#include <google/protobuf/compiler/java/java_helpers.h>
@@ -281,8 +282,13 @@ void FileGenerator::Generate(io::Printer* printer) {
if (!MultipleJavaFiles(file_, immutable_api_)) {
for (int i = 0; i < file_->enum_type_count(); i++) {
- EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
- .Generate(printer);
+ if (HasDescriptorMethods(file_)) {
+ EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
+ .Generate(printer);
+ } else {
+ EnumLiteGenerator(file_->enum_type(i), immutable_api_, context_.get())
+ .Generate(printer);
+ }
}
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateInterface(printer);
@@ -543,13 +549,23 @@ void FileGenerator::GenerateSiblings(const string& package_dir,
vector<string>* file_list) {
if (MultipleJavaFiles(file_, immutable_api_)) {
for (int i = 0; i < file_->enum_type_count(); i++) {
- EnumGenerator generator(file_->enum_type(i), immutable_api_,
- context_.get());
- GenerateSibling<EnumGenerator>(package_dir, java_package_,
- file_->enum_type(i),
- context, file_list, "",
- &generator,
- &EnumGenerator::Generate);
+ if (HasDescriptorMethods(file_)) {
+ EnumGenerator generator(file_->enum_type(i), immutable_api_,
+ context_.get());
+ GenerateSibling<EnumGenerator>(package_dir, java_package_,
+ file_->enum_type(i),
+ context, file_list, "",
+ &generator,
+ &EnumGenerator::Generate);
+ } else {
+ EnumLiteGenerator generator(file_->enum_type(i), immutable_api_,
+ context_.get());
+ GenerateSibling<EnumLiteGenerator>(package_dir, java_package_,
+ file_->enum_type(i),
+ context, file_list, "",
+ &generator,
+ &EnumLiteGenerator::Generate);
+ }
}
for (int i = 0; i < file_->message_type_count(); i++) {
if (immutable_api_) {
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.cc b/src/google/protobuf/compiler/java/java_message.cc
index 19ba0707..22a70c32 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -664,34 +664,34 @@ GenerateParseFromMethods(io::Printer* printer) {
"}\n"
"public static $classname$ parseFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " return PARSER.parseFrom(input);\n"
+ " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);"
"}\n"
"public static $classname$ parseFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return PARSER.parseFrom(input, extensionRegistry);\n"
+ " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);"
"}\n"
"public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
" throws java.io.IOException {\n"
- " return PARSER.parseDelimitedFrom(input);\n"
+ " return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input);"
"}\n"
"public static $classname$ parseDelimitedFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return PARSER.parseDelimitedFrom(input, extensionRegistry);\n"
+ " return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input, extensionRegistry);"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input)\n"
" throws java.io.IOException {\n"
- " return PARSER.parseFrom(input);\n"
+ " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);"
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input,\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
- " return PARSER.parseFrom(input, extensionRegistry);\n"
+ " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);"
"}\n"
"\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
@@ -1217,9 +1217,8 @@ GenerateParsingConstructor(io::Printer* printer) {
"} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
" throw new RuntimeException(e.setUnfinishedMessage(this));\n"
"} catch (java.io.IOException e) {\n"
- " throw new RuntimeException(\n"
- " new com.google.protobuf.InvalidProtocolBufferException(\n"
- " e.getMessage()).setUnfinishedMessage(this));\n"
+ " throw new RuntimeException(new com.google.protobuf.InvalidProtocolBufferException(e)\n"
+ " .setUnfinishedMessage(this));\n"
"} finally {\n");
printer->Indent();
@@ -1356,7 +1355,7 @@ void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
" if (!is(clazz)) {\n"
" throw new com.google.protobuf.InvalidProtocolBufferException(\n"
- " \"Type of the Any messsage does not match the given class.\");\n"
+ " \"Type of the Any message does not match the given class.\");\n"
" }\n"
" if (cachedUnpackValue != null) {\n"
" return (T) cachedUnpackValue;\n"
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
index 72694119..5d535034 100644
--- a/src/google/protobuf/compiler/java/java_message_builder.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -538,7 +538,7 @@ GenerateBuilderParsingMethods(io::Printer* printer) {
" parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n"
" } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
" parsedMessage = ($classname$) e.getUnfinishedMessage();\n"
- " throw e;\n"
+ " throw e.unwrapIOException();\n"
" } finally {\n"
" if (parsedMessage != null) {\n"
" mergeFrom(parsedMessage);\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/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
index 392333b8..5a7bf82d 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -87,11 +87,13 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["field_list_type"] =
"com.google.protobuf.Internal." + capitalized_type + "List";
(*variables)["new_list"] = "new" + capitalized_type + "List";
+ (*variables)["new_list_with_capacity"] =
+ "new" + capitalized_type + "ListWithCapacity";
(*variables)["empty_list"] = "empty" + capitalized_type + "List()";
(*variables)["make_name_unmodifiable"] =
(*variables)["name"] + "_.makeImmutable()";
- (*variables)["repeated_index_get"] =
- (*variables)["name"] + "_.get" + capitalized_type + "(index)";
+ (*variables)["repeated_get"] =
+ (*variables)["name"] + "_.get" + capitalized_type;
(*variables)["repeated_add"] =
(*variables)["name"] + "_.add" + capitalized_type;
(*variables)["repeated_set"] =
@@ -102,11 +104,11 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
"com.google.protobuf.Internal.ProtobufList<" +
(*variables)["boxed_type"] + ">";
(*variables)["new_list"] = "newProtobufList";
+ (*variables)["new_list_with_capacity"] = "newProtobufListWithCapacity";
(*variables)["empty_list"] = "emptyProtobufList()";
(*variables)["make_name_unmodifiable"] =
(*variables)["name"] + "_.makeImmutable()";
- (*variables)["repeated_index_get"] =
- (*variables)["name"] + "_.get(index)";
+ (*variables)["repeated_get"] = (*variables)["name"] + "_.get";
(*variables)["repeated_add"] = (*variables)["name"] + "_.add";
(*variables)["repeated_set"] = (*variables)["name"] + "_.set";
}
@@ -629,7 +631,7 @@ GenerateMembers(io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$(int index) {\n"
- " return $repeated_index_get$;\n"
+ " return $repeated_get$(index);\n"
"}\n");
if (descriptor_->options().packed() &&
@@ -773,6 +775,9 @@ GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
void RepeatedImmutablePrimitiveFieldLiteGenerator::
GenerateParsingCode(io::Printer* printer) const {
+ // TODO(dweis): Scan the input buffer to count, then initialize
+ // appropriately.
+ // TODO(dweis): Scan the input buffer to count and ensure capacity.
printer->Print(variables_,
"if (!$is_mutable$) {\n"
" $name$_ = $new_list$();\n"
@@ -785,8 +790,21 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const {
printer->Print(variables_,
"int length = input.readRawVarint32();\n"
"int limit = input.pushLimit(length);\n"
- "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n"
- " $name$_ = $new_list$();\n"
+ "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n");
+
+ int fixed_size = FixedSize(GetType(descriptor_));
+ if (fixed_size == -1) {
+ // TODO(dweis): Scan the input buffer to count, then initialize
+ // appropriately.
+ printer->Print(variables_,
+ " $name$_ = $new_list$();\n");
+ } else {
+ printer->Print(variables_,
+ " $name$_ = $new_list_with_capacity$(length/$fixed_size$);\n");
+ }
+
+ // TODO(dweis): Scan the input buffer to count and ensure capacity.
+ printer->Print(variables_,
"}\n"
"while (input.getBytesUntilLimit() > 0) {\n"
" $repeated_add$(input.read$capitalized_type$());\n"
@@ -814,12 +832,12 @@ GenerateSerializationCode(io::Printer* printer) const {
" output.writeRawVarint32($name$MemoizedSerializedSize);\n"
"}\n"
"for (int i = 0; i < $name$_.size(); i++) {\n"
- " output.write$capitalized_type$NoTag($name$_.get(i));\n"
+ " output.write$capitalized_type$NoTag($repeated_get$(i));\n"
"}\n");
} else {
printer->Print(variables_,
"for (int i = 0; i < $name$_.size(); i++) {\n"
- " output.write$capitalized_type$($number$, $name$_.get(i));\n"
+ " output.write$capitalized_type$($number$, $repeated_get$(i));\n"
"}\n");
}
}
@@ -835,7 +853,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
"for (int i = 0; i < $name$_.size(); i++) {\n"
" dataSize += com.google.protobuf.CodedOutputStream\n"
- " .compute$capitalized_type$SizeNoTag($name$_.get(i));\n"
+ " .compute$capitalized_type$SizeNoTag($repeated_get$(i));\n"
"}\n");
} else {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 72ebaeca..7f757e47 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -405,7 +405,7 @@ void ImmutableStringFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
if (CheckUtf8(descriptor_)) {
printer->Print(variables_,
- "String s = input.readStringRequireUtf8();\n"
+ "java.lang.String s = input.readStringRequireUtf8();\n"
"$set_has_field_bit_message$\n"
"$name$_ = s;\n");
} else if (!HasDescriptorMethods(descriptor_->file())) {
@@ -414,7 +414,7 @@ GenerateParsingCode(io::Printer* printer) const {
// spurious intermediary ByteString allocations, cutting overall allocations
// in half.
printer->Print(variables_,
- "String s = input.readString();\n"
+ "java.lang.String s = input.readString();\n"
"$set_has_field_bit_message$\n"
"$name$_ = s;\n");
} else {
@@ -665,7 +665,7 @@ void ImmutableStringOneofFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
if (CheckUtf8(descriptor_)) {
printer->Print(variables_,
- "String s = input.readStringRequireUtf8();\n"
+ "java.lang.String s = input.readStringRequireUtf8();\n"
"$set_oneof_case_message$;\n"
"$oneof_name$_ = s;\n");
} else if (!HasDescriptorMethods(descriptor_->file())) {
@@ -674,7 +674,7 @@ GenerateParsingCode(io::Printer* printer) const {
// spurious intermediary ByteString allocations, cutting overall allocations
// in half.
printer->Print(variables_,
- "String s = input.readString();\n"
+ "java.lang.String s = input.readString();\n"
"$set_oneof_case_message$;\n"
"$oneof_name$_ = s;\n");
} else {
@@ -773,12 +773,6 @@ GenerateMembers(io::Printer* printer) const {
" get$capitalized_name$Bytes(int index) {\n"
" return $name$_.getByteString(index);\n"
"}\n");
-
- if (descriptor_->options().packed() &&
- HasGeneratedMethods(descriptor_->containing_type())) {
- printer->Print(variables_,
- "private int $name$MemoizedSerializedSize = -1;\n");
- }
}
void RepeatedImmutableStringFieldGenerator::
@@ -939,14 +933,14 @@ void RepeatedImmutableStringFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
if (CheckUtf8(descriptor_)) {
printer->Print(variables_,
- "String s = input.readStringRequireUtf8();\n");
+ "java.lang.String s = input.readStringRequireUtf8();\n");
} else if (!HasDescriptorMethods(descriptor_->file())) {
// Lite runtime should attempt to reduce allocations by attempting to
// construct the string directly from the input stream buffer. This avoids
// spurious intermediary ByteString allocations, cutting overall allocations
// in half.
printer->Print(variables_,
- "String s = input.readString();\n");
+ "java.lang.String s = input.readString();\n");
} else {
printer->Print(variables_,
"com.google.protobuf.ByteString bs = input.readBytes();\n");
@@ -966,30 +960,6 @@ GenerateParsingCode(io::Printer* printer) const {
}
void RepeatedImmutableStringFieldGenerator::
-GenerateParsingCodeFromPacked(io::Printer* printer) const {
- printer->Print(variables_,
- "int length = input.readRawVarint32();\n"
- "int limit = input.pushLimit(length);\n"
- "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n"
- " $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
- " $set_mutable_bit_parser$;\n"
- "}\n"
- "while (input.getBytesUntilLimit() > 0) {\n");
- if (CheckUtf8(descriptor_)) {
- printer->Print(variables_,
- " String s = input.readStringRequireUtf8();\n");
- } else {
- printer->Print(variables_,
- " String s = input.readString();\n");
- }
- printer->Print(variables_,
- " $name$.add(s);\n");
- printer->Print(variables_,
- "}\n"
- "input.popLimit(limit);\n");
-}
-
-void RepeatedImmutableStringFieldGenerator::
GenerateParsingDoneCode(io::Printer* printer) const {
printer->Print(variables_,
"if ($get_mutable_bit_parser$) {\n"
@@ -999,21 +969,10 @@ GenerateParsingDoneCode(io::Printer* printer) const {
void RepeatedImmutableStringFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
- if (descriptor_->options().packed()) {
- printer->Print(variables_,
- "if (get$capitalized_name$List().size() > 0) {\n"
- " output.writeRawVarint32($tag$);\n"
- " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
- "}\n"
- "for (int i = 0; i < $name$_.size(); i++) {\n"
- " writeStringNoTag(output, $name$_.getRaw(i));\n"
- "}\n");
- } else {
- printer->Print(variables_,
- "for (int i = 0; i < $name$_.size(); i++) {\n"
- " $writeString$(output, $number$, $name$_.getRaw(i));\n"
- "}\n");
- }
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " $writeString$(output, $number$, $name$_.getRaw(i));\n"
+ "}\n");
}
void RepeatedImmutableStringFieldGenerator::
@@ -1031,23 +990,8 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(
"size += dataSize;\n");
- if (descriptor_->options().packed()) {
- printer->Print(variables_,
- "if (!get$capitalized_name$List().isEmpty()) {\n"
- " size += $tag_size$;\n"
- " size += com.google.protobuf.CodedOutputStream\n"
- " .computeInt32SizeNoTag(dataSize);\n"
- "}\n");
- } else {
- printer->Print(variables_,
- "size += $tag_size$ * get$capitalized_name$List().size();\n");
- }
-
- // cache the data size for packed fields.
- if (descriptor_->options().packed()) {
- printer->Print(variables_,
- "$name$MemoizedSerializedSize = dataSize;\n");
- }
+ printer->Print(variables_,
+ "size += $tag_size$ * get$capitalized_name$List().size();\n");
printer->Outdent();
printer->Print("}\n");
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
index 1ea44dec..a3b57351 100644
--- a/src/google/protobuf/compiler/java/java_string_field.h
+++ b/src/google/protobuf/compiler/java/java_string_field.h
@@ -131,7 +131,6 @@ class RepeatedImmutableStringFieldGenerator : public ImmutableFieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateBuildingCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
- void GenerateParsingCodeFromPacked(io::Printer* printer) const;
void GenerateParsingDoneCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc
index 092e3c29..eb5964bd 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -647,12 +647,6 @@ GenerateMembers(io::Printer* printer) const {
" $name$_.get(index));\n"
"}\n");
- if (descriptor_->options().packed() &&
- HasGeneratedMethods(descriptor_->containing_type())) {
- printer->Print(variables_,
- "private int $name$MemoizedSerializedSize = -1;\n");
- }
-
printer->Print(variables_,
"private void ensure$capitalized_name$IsMutable() {\n"
" if (!$is_mutable$) {\n"
@@ -835,29 +829,6 @@ GenerateParsingCode(io::Printer* printer) const {
}
void RepeatedImmutableStringFieldLiteGenerator::
-GenerateParsingCodeFromPacked(io::Printer* printer) const {
- printer->Print(variables_,
- "int length = input.readRawVarint32();\n"
- "int limit = input.pushLimit(length);\n"
- "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n"
- " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n"
- "}\n"
- "while (input.getBytesUntilLimit() > 0) {\n");
- if (CheckUtf8(descriptor_)) {
- printer->Print(variables_,
- " String s = input.readStringRequireUtf8();\n");
- } else {
- printer->Print(variables_,
- " String s = input.readString();\n");
- }
- printer->Print(variables_,
- " $name$.add(s);\n");
- printer->Print(variables_,
- "}\n"
- "input.popLimit(limit);\n");
-}
-
-void RepeatedImmutableStringFieldLiteGenerator::
GenerateParsingDoneCode(io::Printer* printer) const {
printer->Print(variables_,
"if ($is_mutable$) {\n"
@@ -870,21 +841,10 @@ GenerateSerializationCode(io::Printer* printer) const {
// Lite runtime should reduce allocations by serializing the string directly.
// This avoids spurious intermediary ByteString allocations, cutting overall
// allocations in half.
- if (descriptor_->options().packed()) {
- printer->Print(variables_,
- "if (get$capitalized_name$List().size() > 0) {\n"
- " output.writeRawVarint32($tag$);\n"
- " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
- "}\n"
- "for (int i = 0; i < $name$_.size(); i++) {\n"
- " output.writeStringNoTag($name$_.get(i));\n"
- "}\n");
- } else {
- printer->Print(variables_,
- "for (int i = 0; i < $name$_.size(); i++) {\n"
- " output.writeString($number$, $name$_.get(i));\n"
- "}\n");
- }
+ printer->Print(variables_,
+ "for (int i = 0; i < $name$_.size(); i++) {\n"
+ " output.writeString($number$, $name$_.get(i));\n"
+ "}\n");
}
void RepeatedImmutableStringFieldLiteGenerator::
@@ -906,23 +866,9 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(
"size += dataSize;\n");
- if (descriptor_->options().packed()) {
- printer->Print(variables_,
- "if (!get$capitalized_name$List().isEmpty()) {\n"
- " size += $tag_size$;\n"
- " size += com.google.protobuf.CodedOutputStream\n"
- " .computeInt32SizeNoTag(dataSize);\n"
- "}\n");
- } else {
- printer->Print(variables_,
- "size += $tag_size$ * get$capitalized_name$List().size();\n");
- }
- // cache the data size for packed fields.
- if (descriptor_->options().packed()) {
- printer->Print(variables_,
- "$name$MemoizedSerializedSize = dataSize;\n");
- }
+ printer->Print(variables_,
+ "size += $tag_size$ * get$capitalized_name$List().size();\n");
printer->Outdent();
printer->Print("}\n");
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h
index 9d93b307..4d9b4bd7 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.h
@@ -129,7 +129,6 @@ class RepeatedImmutableStringFieldLiteGenerator
void GenerateMergingCode(io::Printer* printer) const;
void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
void GenerateParsingCode(io::Printer* printer) const;
- void GenerateParsingCodeFromPacked(io::Printer* printer) const;
void GenerateParsingDoneCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
new file mode 100755
index 00000000..e6c3b36a
--- /dev/null
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -0,0 +1,2622 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/js/js_generator.h>
+
+#include <assert.h>
+#include <algorithm>
+#include <limits>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace js {
+
+// Sorted list of JavaScript keywords. These cannot be used as names. If they
+// appear, we prefix them with "pb_".
+const char* kKeyword[] = {
+ "abstract",
+ "boolean",
+ "break",
+ "byte",
+ "case",
+ "catch",
+ "char",
+ "class",
+ "const",
+ "continue",
+ "debugger",
+ "default",
+ "delete",
+ "do",
+ "double",
+ "else",
+ "enum",
+ "export",
+ "extends",
+ "false",
+ "final",
+ "finally",
+ "float",
+ "for",
+ "function",
+ "goto",
+ "if",
+ "implements",
+ "import",
+ "in",
+ "instanceof",
+ "int",
+ "interface",
+ "long",
+ "native",
+ "new",
+ "null",
+ "package",
+ "private",
+ "protected",
+ "public",
+ "return",
+ "short",
+ "static",
+ "super",
+ "switch",
+ "synchronized",
+ "this",
+ "throw",
+ "throws",
+ "transient",
+ "try",
+ "typeof",
+ "var",
+ "void",
+ "volatile",
+ "while",
+ "with",
+};
+
+static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*);
+
+namespace {
+
+bool IsReserved(const string& ident) {
+ for (int i = 0; i < kNumKeyword; i++) {
+ if (ident == kKeyword[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Returns a copy of |filename| with any trailing ".protodevel" or ".proto
+// suffix stripped.
+string StripProto(const string& filename) {
+ const char* suffix = HasSuffixString(filename, ".protodevel")
+ ? ".protodevel" : ".proto";
+ return StripSuffixString(filename, suffix);
+}
+
+// Returns the fully normalized JavaScript path for the given
+// file descriptor's package.
+string GetPath(const GeneratorOptions& options,
+ const FileDescriptor* file) {
+ if (!options.namespace_prefix.empty()) {
+ return options.namespace_prefix;
+ } else if (!file->package().empty()) {
+ return "proto." + file->package();
+ } else {
+ return "proto";
+ }
+}
+
+// Forward declare, so that GetPrefix can call this method,
+// which in turn, calls GetPrefix.
+string GetPath(const GeneratorOptions& options,
+ const Descriptor* descriptor);
+
+// Returns the path prefix for a message or enumeration that
+// lives under the given file and containing type.
+string GetPrefix(const GeneratorOptions& options,
+ const FileDescriptor* file_descriptor,
+ const Descriptor* containing_type) {
+ string prefix = "";
+
+ if (containing_type == NULL) {
+ prefix = GetPath(options, file_descriptor);
+ } else {
+ prefix = GetPath(options, containing_type);
+ }
+
+ if (!prefix.empty()) {
+ prefix += ".";
+ }
+
+ return prefix;
+}
+
+
+// Returns the fully normalized JavaScript path for the given
+// message descriptor.
+string GetPath(const GeneratorOptions& options,
+ const Descriptor* descriptor) {
+ return GetPrefix(
+ options, descriptor->file(),
+ descriptor->containing_type()) + descriptor->name();
+}
+
+
+// Returns the fully normalized JavaScript path for the given
+// field's containing message descriptor.
+string GetPath(const GeneratorOptions& options,
+ const FieldDescriptor* descriptor) {
+ return GetPath(options, descriptor->containing_type());
+}
+
+// Returns the fully normalized JavaScript path for the given
+// enumeration descriptor.
+string GetPath(const GeneratorOptions& options,
+ const EnumDescriptor* enum_descriptor) {
+ return GetPrefix(
+ options, enum_descriptor->file(),
+ enum_descriptor->containing_type()) + enum_descriptor->name();
+}
+
+
+// Returns the fully normalized JavaScript path for the given
+// enumeration value descriptor.
+string GetPath(const GeneratorOptions& options,
+ const EnumValueDescriptor* value_descriptor) {
+ return GetPath(
+ options,
+ value_descriptor->type()) + "." + value_descriptor->name();
+}
+
+// - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields
+// (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate,
+// and with reserved words triggering a "pb_" prefix.
+// - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields
+// (use the name directly), then append "List" if appropriate, then append "$"
+// if resulting name is equal to a reserved word.
+// - Enums: just uppercase.
+
+// Locale-independent version of ToLower that deals only with ASCII A-Z.
+char ToLowerASCII(char c) {
+ if (c >= 'A' && c <= 'Z') {
+ return (c - 'A') + 'a';
+ } else {
+ return c;
+ }
+}
+
+vector<string> ParseLowerUnderscore(const string& input) {
+ vector<string> words;
+ string running = "";
+ for (int i = 0; i < input.size(); i++) {
+ if (input[i] == '_') {
+ if (!running.empty()) {
+ words.push_back(running);
+ running.clear();
+ }
+ } else {
+ running += ToLowerASCII(input[i]);
+ }
+ }
+ if (!running.empty()) {
+ words.push_back(running);
+ }
+ return words;
+}
+
+vector<string> ParseUpperCamel(const string& input) {
+ vector<string> words;
+ string running = "";
+ for (int i = 0; i < input.size(); i++) {
+ if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) {
+ words.push_back(running);
+ running.clear();
+ }
+ running += ToLowerASCII(input[i]);
+ }
+ if (!running.empty()) {
+ words.push_back(running);
+ }
+ return words;
+}
+
+string ToLowerCamel(const vector<string>& words) {
+ string result;
+ for (int i = 0; i < words.size(); i++) {
+ string word = words[i];
+ if (i == 0 && (word[0] >= 'A' && word[0] <= 'Z')) {
+ word[0] = (word[0] - 'A') + 'a';
+ } else if (i != 0 && (word[0] >= 'a' && word[0] <= 'z')) {
+ word[0] = (word[0] - 'a') + 'A';
+ }
+ result += word;
+ }
+ return result;
+}
+
+string ToUpperCamel(const vector<string>& words) {
+ string result;
+ for (int i = 0; i < words.size(); i++) {
+ string word = words[i];
+ if (word[0] >= 'a' && word[0] <= 'z') {
+ word[0] = (word[0] - 'a') + 'A';
+ }
+ result += word;
+ }
+ return result;
+}
+
+// Based on code from descriptor.cc (Thanks Kenton!)
+// Uppercases the entire string, turning ValueName into
+// VALUENAME.
+string ToEnumCase(const string& input) {
+ string result;
+ result.reserve(input.size());
+
+ for (int i = 0; i < input.size(); i++) {
+ if ('a' <= input[i] && input[i] <= 'z') {
+ result.push_back(input[i] - 'a' + 'A');
+ } else {
+ result.push_back(input[i]);
+ }
+ }
+
+ return result;
+}
+
+string ToFileName(const string& input) {
+ string result;
+ result.reserve(input.size());
+
+ for (int i = 0; i < input.size(); i++) {
+ if ('A' <= input[i] && input[i] <= 'Z') {
+ result.push_back(input[i] - 'A' + 'a');
+ } else {
+ result.push_back(input[i]);
+ }
+ }
+
+ return result;
+}
+
+// Returns the message/response ID, if set.
+string GetMessageId(const Descriptor* desc) {
+ return string();
+}
+
+
+// Used inside Google only -- do not remove.
+bool IsResponse(const Descriptor* desc) { return false; }
+bool IgnoreField(const FieldDescriptor* field) { return false; }
+
+
+// Does JSPB ignore this entire oneof? True only if all fields are ignored.
+bool IgnoreOneof(const OneofDescriptor* oneof) {
+ for (int i = 0; i < oneof->field_count(); i++) {
+ if (!IgnoreField(oneof->field(i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+string JSIdent(const FieldDescriptor* field,
+ bool is_upper_camel,
+ bool is_map) {
+ string result;
+ if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ result = is_upper_camel ?
+ ToUpperCamel(ParseUpperCamel(field->message_type()->name())) :
+ ToLowerCamel(ParseUpperCamel(field->message_type()->name()));
+ } else {
+ result = is_upper_camel ?
+ ToUpperCamel(ParseLowerUnderscore(field->name())) :
+ ToLowerCamel(ParseLowerUnderscore(field->name()));
+ }
+ if (is_map) {
+ result += "Map";
+ } else if (field->is_repeated()) {
+ result += "List";
+ }
+ return result;
+}
+
+string JSObjectFieldName(const FieldDescriptor* field) {
+ string name = JSIdent(
+ field,
+ /* is_upper_camel = */ false,
+ /* is_map = */ false);
+ if (IsReserved(name)) {
+ name = "pb_" + name;
+ }
+ return name;
+}
+
+// Returns the field name as a capitalized portion of a getter/setter method
+// name, e.g. MyField for .getMyField().
+string JSGetterName(const FieldDescriptor* field) {
+ string name = JSIdent(field,
+ /* is_upper_camel = */ true,
+ /* is_map = */ false);
+ if (name == "Extension" || name == "JsPbMessageId") {
+ // Avoid conflicts with base-class names.
+ name += "$";
+ }
+ return name;
+}
+
+string JSMapGetterName(const FieldDescriptor* field) {
+ return JSIdent(field,
+ /* is_upper_camel = */ true,
+ /* is_map = */ true);
+}
+
+
+
+string JSOneofName(const OneofDescriptor* oneof) {
+ return ToUpperCamel(ParseLowerUnderscore(oneof->name()));
+}
+
+// Returns the index corresponding to this field in the JSPB array (underlying
+// data storage array).
+string JSFieldIndex(const FieldDescriptor* field) {
+ // Determine whether this field is a member of a group. Group fields are a bit
+ // wonky: their "containing type" is a message type created just for the
+ // group, and that type's parent type has a field with the group-message type
+ // as its message type and TYPE_GROUP as its field type. For such fields, the
+ // index we use is relative to the field number of the group submessage field.
+ // For all other fields, we just use the field number.
+ const Descriptor* containing_type = field->containing_type();
+ const Descriptor* parent_type = containing_type->containing_type();
+ if (parent_type != NULL) {
+ for (int i = 0; i < parent_type->field_count(); i++) {
+ if (parent_type->field(i)->type() == FieldDescriptor::TYPE_GROUP &&
+ parent_type->field(i)->message_type() == containing_type) {
+ return SimpleItoa(field->number() - parent_type->field(i)->number());
+ }
+ }
+ }
+ return SimpleItoa(field->number());
+}
+
+string JSOneofIndex(const OneofDescriptor* oneof) {
+ int index = -1;
+ for (int i = 0; i < oneof->containing_type()->oneof_decl_count(); i++) {
+ const OneofDescriptor* o = oneof->containing_type()->oneof_decl(i);
+ // If at least one field in this oneof is not JSPB-ignored, count the oneof.
+ for (int j = 0; j < o->field_count(); j++) {
+ const FieldDescriptor* f = o->field(j);
+ if (!IgnoreField(f)) {
+ index++;
+ break; // inner loop
+ }
+ }
+ if (o == oneof) {
+ break;
+ }
+ }
+ return SimpleItoa(index);
+}
+
+// Decodes a codepoint in \x0000 -- \xFFFF. Since JS strings are UTF-16, we only
+// need to handle the BMP (16-bit range) here.
+uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) {
+ if (*length == 0) {
+ return 0;
+ }
+ size_t expected = 0;
+ if ((*bytes & 0x80) == 0) {
+ expected = 1;
+ } else if ((*bytes & 0xe0) == 0xc0) {
+ expected = 2;
+ } else if ((*bytes & 0xf0) == 0xe0) {
+ expected = 3;
+ } else {
+ // Too long -- don't accept.
+ *length = 0;
+ return 0;
+ }
+
+ if (*length < expected) {
+ // Not enough bytes -- don't accept.
+ *length = 0;
+ return 0;
+ }
+
+ *length = expected;
+ switch (expected) {
+ case 1: return bytes[0];
+ case 2: return ((bytes[0] & 0x1F) << 6) |
+ ((bytes[1] & 0x3F) << 0);
+ case 3: return ((bytes[0] & 0x0F) << 12) |
+ ((bytes[1] & 0x3F) << 6) |
+ ((bytes[2] & 0x3F) << 0);
+ default: return 0;
+ }
+}
+
+// Escapes the contents of a string to be included within double-quotes ("") in
+// JavaScript. |is_utf8| determines whether the input data (in a C++ string of
+// chars) is UTF-8 encoded (in which case codepoints become JavaScript string
+// characters, escaped with 16-bit hex escapes where necessary) or raw binary
+// (in which case bytes become JavaScript string characters 0 -- 255).
+string EscapeJSString(const string& in, bool is_utf8) {
+ string result;
+ size_t decoded = 0;
+ for (size_t i = 0; i < in.size(); i += decoded) {
+ uint16 codepoint = 0;
+ if (is_utf8) {
+ // Decode the next UTF-8 codepoint.
+ size_t have_bytes = in.size() - i;
+ uint8 bytes[3] = {
+ static_cast<uint8>(in[i]),
+ static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0),
+ static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0),
+ };
+ codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
+ if (have_bytes == 0) {
+ break;
+ }
+ decoded = have_bytes;
+ } else {
+ codepoint = static_cast<uint16>(static_cast<uint8>(in[i]));
+ decoded = 1;
+ }
+
+ // Next byte -- used for minimal octal escapes below.
+ char next_byte = (i + decoded) < in.size() ?
+ in[i + decoded] : 0;
+ bool pad_octal = (next_byte >= '0' && next_byte <= '7');
+
+ switch (codepoint) {
+ case '\0': result += pad_octal ? "\\000" : "\\0"; break;
+ case '\b': result += "\\\b"; break;
+ case '\t': result += "\\\t"; break;
+ case '\n': result += "\\\n"; break;
+ case '\r': result += "\\\r"; break;
+ case '\f': result += "\\\f"; break;
+ case '\\': result += "\\\\"; break;
+ case '"': result += pad_octal ? "\\042" : "\\42"; break;
+ case '&': result += pad_octal ? "\\046" : "\\46"; break;
+ case '\'': result += pad_octal ? "\\047" : "\\47"; break;
+ case '<': result += pad_octal ? "\\074" : "\\74"; break;
+ case '=': result += pad_octal ? "\\075" : "\\75"; break;
+ case '>': result += pad_octal ? "\\076" : "\\76"; break;
+ default:
+ // All other non-ASCII codepoints are escaped.
+ // Original codegen uses hex for >= 0x100 and octal for others.
+ if (codepoint >= 0x20 && codepoint <= 0x7e) {
+ result += static_cast<char>(codepoint);
+ } else {
+ if (codepoint >= 0x100) {
+ result += StringPrintf("\\u%04x", codepoint);
+ } else {
+ if (pad_octal || codepoint >= 0100) {
+ result += "\\";
+ result += ('0' + ((codepoint >> 6) & 07));
+ result += ('0' + ((codepoint >> 3) & 07));
+ result += ('0' + ((codepoint >> 0) & 07));
+ } else if (codepoint >= 010) {
+ result += "\\";
+ result += ('0' + ((codepoint >> 3) & 07));
+ result += ('0' + ((codepoint >> 0) & 07));
+ } else {
+ result += "\\";
+ result += ('0' + ((codepoint >> 0) & 07));
+ }
+ }
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+string EscapeBase64(const string& in) {
+ static const char* kAlphabet =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ string result;
+
+ for (size_t i = 0; i < in.size(); i += 3) {
+ int value = (in[i] << 16) |
+ (((i + 1) < in.size()) ? (in[i + 1] << 8) : 0) |
+ (((i + 2) < in.size()) ? (in[i + 2] << 0) : 0);
+ result += kAlphabet[(value >> 18) & 0x3f];
+ result += kAlphabet[(value >> 12) & 0x3f];
+ if ((i + 1) < in.size()) {
+ result += kAlphabet[(value >> 6) & 0x3f];
+ } else {
+ result += '=';
+ }
+ if ((i + 2) < in.size()) {
+ result += kAlphabet[(value >> 0) & 0x3f];
+ } else {
+ result += '=';
+ }
+ }
+
+ return result;
+}
+
+// Post-process the result of SimpleFtoa/SimpleDtoa to *exactly* match the
+// original codegen's formatting (which is just .toString() on java.lang.Double
+// or java.lang.Float).
+string PostProcessFloat(string result) {
+ // If inf, -inf or nan, replace with +Infinity, -Infinity or NaN.
+ if (result == "inf") {
+ return "Infinity";
+ } else if (result == "-inf") {
+ return "-Infinity";
+ } else if (result == "nan") {
+ return "NaN";
+ }
+
+ // If scientific notation (e.g., "1e10"), (i) capitalize the "e", (ii)
+ // ensure that the mantissa (portion prior to the "e") has at least one
+ // fractional digit (after the decimal point), and (iii) strip any unnecessary
+ // leading zeroes and/or '+' signs from the exponent.
+ string::size_type exp_pos = result.find('e');
+ if (exp_pos != string::npos) {
+ string mantissa = result.substr(0, exp_pos);
+ string exponent = result.substr(exp_pos + 1);
+
+ // Add ".0" to mantissa if no fractional part exists.
+ if (mantissa.find('.') == string::npos) {
+ mantissa += ".0";
+ }
+
+ // Strip the sign off the exponent and store as |exp_neg|.
+ bool exp_neg = false;
+ if (!exponent.empty() && exponent[0] == '+') {
+ exponent = exponent.substr(1);
+ } else if (!exponent.empty() && exponent[0] == '-') {
+ exp_neg = true;
+ exponent = exponent.substr(1);
+ }
+
+ // Strip any leading zeroes off the exponent.
+ while (exponent.size() > 1 && exponent[0] == '0') {
+ exponent = exponent.substr(1);
+ }
+
+ return mantissa + "E" + string(exp_neg ? "-" : "") + exponent;
+ }
+
+ // Otherwise, this is an ordinary decimal number. Append ".0" if result has no
+ // decimal/fractional part in order to match output of original codegen.
+ if (result.find('.') == string::npos) {
+ result += ".0";
+ }
+
+ return result;
+}
+
+string FloatToString(float value) {
+ string result = SimpleFtoa(value);
+ return PostProcessFloat(result);
+}
+
+string DoubleToString(double value) {
+ string result = SimpleDtoa(value);
+ return PostProcessFloat(result);
+}
+
+string MaybeNumberString(const FieldDescriptor* field, const string& orig) {
+ return orig;
+}
+
+string JSFieldDefault(const FieldDescriptor* field) {
+ assert(field->has_default_value());
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return MaybeNumberString(
+ field, SimpleItoa(field->default_value_int32()));
+ case FieldDescriptor::CPPTYPE_UINT32:
+ // The original codegen is in Java, and Java protobufs store unsigned
+ // integer values as signed integer values. In order to exactly match the
+ // output, we need to reinterpret as base-2 signed. Ugh.
+ return MaybeNumberString(
+ field, SimpleItoa(static_cast<int32>(field->default_value_uint32())));
+ case FieldDescriptor::CPPTYPE_INT64:
+ return MaybeNumberString(
+ field, SimpleItoa(field->default_value_int64()));
+ case FieldDescriptor::CPPTYPE_UINT64:
+ // See above note for uint32 -- reinterpreting as signed.
+ return MaybeNumberString(
+ field, SimpleItoa(static_cast<int64>(field->default_value_uint64())));
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return SimpleItoa(field->default_value_enum()->number());
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return field->default_value_bool() ? "true" : "false";
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return FloatToString(field->default_value_float());
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return DoubleToString(field->default_value_double());
+ case FieldDescriptor::CPPTYPE_STRING:
+ if (field->type() == FieldDescriptor::TYPE_STRING) {
+ return "\"" + EscapeJSString(field->default_value_string(), true) +
+ "\"";
+ } else {
+ return "\"" + EscapeBase64(field->default_value_string()) +
+ "\"";
+ }
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return "null";
+ }
+ GOOGLE_LOG(FATAL) << "Shouldn't reach here.";
+ return "";
+}
+
+string ProtoTypeName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_BOOL:
+ return "bool";
+ case FieldDescriptor::TYPE_INT32:
+ return "int32";
+ case FieldDescriptor::TYPE_UINT32:
+ return "uint32";
+ case FieldDescriptor::TYPE_SINT32:
+ return "sint32";
+ case FieldDescriptor::TYPE_FIXED32:
+ return "fixed32";
+ case FieldDescriptor::TYPE_SFIXED32:
+ return "sfixed32";
+ case FieldDescriptor::TYPE_INT64:
+ return "int64";
+ case FieldDescriptor::TYPE_UINT64:
+ return "uint64";
+ case FieldDescriptor::TYPE_SINT64:
+ return "sint64";
+ case FieldDescriptor::TYPE_FIXED64:
+ return "fixed64";
+ case FieldDescriptor::TYPE_SFIXED64:
+ return "sfixed64";
+ case FieldDescriptor::TYPE_FLOAT:
+ return "float";
+ case FieldDescriptor::TYPE_DOUBLE:
+ return "double";
+ case FieldDescriptor::TYPE_STRING:
+ return "string";
+ case FieldDescriptor::TYPE_BYTES:
+ return "bytes";
+ case FieldDescriptor::TYPE_GROUP:
+ return GetPath(options, field->message_type());
+ case FieldDescriptor::TYPE_ENUM:
+ return GetPath(options, field->enum_type());
+ case FieldDescriptor::TYPE_MESSAGE:
+ return GetPath(options, field->message_type());
+ default:
+ return "";
+ }
+}
+
+string JSIntegerTypeName(const FieldDescriptor* field) {
+ return "number";
+}
+
+string JSTypeName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return "boolean";
+ case FieldDescriptor::CPPTYPE_INT32:
+ return JSIntegerTypeName(field);
+ case FieldDescriptor::CPPTYPE_INT64:
+ return JSIntegerTypeName(field);
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return JSIntegerTypeName(field);
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return JSIntegerTypeName(field);
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return "number";
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return "number";
+ case FieldDescriptor::CPPTYPE_STRING:
+ return "string";
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return GetPath(options, field->enum_type());
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return GetPath(options, field->message_type());
+ default:
+ return "";
+ }
+}
+
+bool HasFieldPresence(const FieldDescriptor* field);
+
+string JSFieldTypeAnnotation(const GeneratorOptions& options,
+ const FieldDescriptor* field,
+ bool force_optional,
+ bool force_present,
+ bool singular_if_not_packed,
+ bool always_singular) {
+ bool is_primitive =
+ (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM &&
+ field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE);
+
+ string jstype = JSTypeName(options, field);
+
+ if (field->is_repeated() &&
+ !always_singular &&
+ (field->is_packed() || !singular_if_not_packed)) {
+ if (!is_primitive) {
+ jstype = "!" + jstype;
+ }
+ jstype = "Array.<" + jstype + ">";
+ if (!force_optional) {
+ jstype = "!" + jstype;
+ }
+ }
+
+ if (field->is_optional() && is_primitive &&
+ (!field->has_default_value() || force_optional) && !force_present) {
+ jstype += "?";
+ } else if (field->is_required() && !is_primitive && !force_optional) {
+ jstype = "!" + jstype;
+ }
+
+ if (force_optional && HasFieldPresence(field)) {
+ jstype += "|undefined";
+ }
+ if (force_present && jstype[0] != '!' && !is_primitive) {
+ jstype = "!" + jstype;
+ }
+
+ return jstype;
+}
+
+string JSBinaryReaderMethodType(const FieldDescriptor* field) {
+ string name = field->type_name();
+ if (name[0] >= 'a' && name[0] <= 'z') {
+ name[0] = (name[0] - 'a') + 'A';
+ }
+
+ return name;
+}
+
+string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
+ bool is_writer) {
+ string name = JSBinaryReaderMethodType(field);
+ if (is_writer && field->type() == FieldDescriptor::TYPE_BYTES) {
+ // Override for `bytes` fields: treat string as raw bytes, not base64.
+ name = "BytesRawString";
+ }
+ if (field->is_packed()) {
+ name = "Packed" + name;
+ } else if (is_writer && field->is_repeated()) {
+ name = "Repeated" + name;
+ }
+ return name;
+}
+
+string JSBinaryReaderMethodName(const FieldDescriptor* field) {
+ return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+}
+
+string JSBinaryWriterMethodName(const FieldDescriptor* field) {
+ return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+}
+
+string JSReturnClause(const FieldDescriptor* desc) {
+ return "";
+}
+
+string JSReturnDoc(const GeneratorOptions& options,
+ const FieldDescriptor* desc) {
+ return "";
+}
+
+bool HasRepeatedFields(const Descriptor* desc) {
+ for (int i = 0; i < desc->field_count(); i++) {
+ if (desc->field(i)->is_repeated()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static const char* kRepeatedFieldArrayName = ".repeatedFields_";
+
+string RepeatedFieldsArrayName(const GeneratorOptions& options,
+ const Descriptor* desc) {
+ return HasRepeatedFields(desc) ?
+ (GetPath(options, desc) + kRepeatedFieldArrayName) : "null";
+}
+
+bool HasOneofFields(const Descriptor* desc) {
+ for (int i = 0; i < desc->field_count(); i++) {
+ if (desc->field(i)->containing_oneof()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static const char* kOneofGroupArrayName = ".oneofGroups_";
+
+string OneofFieldsArrayName(const GeneratorOptions& options,
+ const Descriptor* desc) {
+ return HasOneofFields(desc) ?
+ (GetPath(options, desc) + kOneofGroupArrayName) : "null";
+}
+
+string RepeatedFieldNumberList(const Descriptor* desc) {
+ std::vector<string> numbers;
+ for (int i = 0; i < desc->field_count(); i++) {
+ if (desc->field(i)->is_repeated()) {
+ numbers.push_back(JSFieldIndex(desc->field(i)));
+ }
+ }
+ return "[" + Join(numbers, ",") + "]";
+}
+
+string OneofGroupList(const Descriptor* desc) {
+ // List of arrays (one per oneof), each of which is a list of field indices
+ std::vector<string> oneof_entries;
+ for (int i = 0; i < desc->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof = desc->oneof_decl(i);
+ if (IgnoreOneof(oneof)) {
+ continue;
+ }
+
+ std::vector<string> oneof_fields;
+ for (int j = 0; j < oneof->field_count(); j++) {
+ if (IgnoreField(oneof->field(j))) {
+ continue;
+ }
+ oneof_fields.push_back(JSFieldIndex(oneof->field(j)));
+ }
+ oneof_entries.push_back("[" + Join(oneof_fields, ",") + "]");
+ }
+ return "[" + Join(oneof_entries, ",") + "]";
+}
+
+string JSOneofArray(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ return OneofFieldsArrayName(options, field->containing_type()) + "[" +
+ JSOneofIndex(field->containing_oneof()) + "]";
+}
+
+string RelativeTypeName(const FieldDescriptor* field) {
+ assert(field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM ||
+ field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
+ // For a field with an enum or message type, compute a name relative to the
+ // path name of the message type containing this field.
+ string package = field->file()->package();
+ string containing_type = field->containing_type()->full_name() + ".";
+ string type = (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) ?
+ field->enum_type()->full_name() : field->message_type()->full_name();
+
+ // |prefix| is advanced as we find separators '.' past the common package
+ // prefix that yield common prefixes in the containing type's name and this
+ // type's name.
+ int prefix = 0;
+ for (int i = 0; i < type.size() && i < containing_type.size(); i++) {
+ if (type[i] != containing_type[i]) {
+ break;
+ }
+ if (type[i] == '.' && i >= package.size()) {
+ prefix = i + 1;
+ }
+ }
+
+ return type.substr(prefix);
+}
+
+string JSExtensionsObjectName(const GeneratorOptions& options,
+ const Descriptor* desc) {
+ if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
+ return "jspb.Message.messageSetExtensions";
+ } else {
+ return GetPath(options, desc) + ".extensions";
+ }
+}
+
+string FieldDefinition(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ string qualifier = field->is_repeated() ? "repeated" :
+ (field->is_optional() ? "optional" : "required");
+ string type, name;
+ if (field->type() == FieldDescriptor::TYPE_ENUM ||
+ field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ type = RelativeTypeName(field);
+ name = field->name();
+ } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ type = "group";
+ name = field->message_type()->name();
+ } else {
+ type = ProtoTypeName(options, field);
+ name = field->name();
+ }
+ return StringPrintf("%s %s %s = %d;",
+ qualifier.c_str(),
+ type.c_str(),
+ name.c_str(),
+ field->number());
+}
+
+string FieldComments(const FieldDescriptor* field) {
+ string comments;
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) {
+ comments +=
+ " * Note that Boolean fields may be set to 0/1 when serialized from "
+ "a Java server.\n"
+ " * You should avoid comparisons like {@code val === true/false} in "
+ "those cases.\n";
+ }
+ if (field->is_repeated()) {
+ comments +=
+ " * If you change this array by adding, removing or replacing "
+ "elements, or if you\n"
+ " * replace the array itself, then you must call the setter to "
+ "update it.\n";
+ }
+ return comments;
+}
+
+bool ShouldGenerateExtension(const FieldDescriptor* field) {
+ return
+ field->is_extension() &&
+ !IgnoreField(field);
+}
+
+bool HasExtensions(const Descriptor* desc) {
+ if (desc->extension_count() > 0) {
+ return true;
+ }
+ for (int i = 0; i < desc->nested_type_count(); i++) {
+ if (HasExtensions(desc->nested_type(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool HasExtensions(const FileDescriptor* file) {
+ for (int i = 0; i < file->extension_count(); i++) {
+ if (ShouldGenerateExtension(file->extension(i))) {
+ return true;
+ }
+ }
+ for (int i = 0; i < file->message_type_count(); i++) {
+ if (HasExtensions(file->message_type(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IsExtendable(const Descriptor* desc) {
+ return desc->extension_range_count() > 0;
+}
+
+// Returns the max index in the underlying data storage array beyond which the
+// extension object is used.
+string GetPivot(const Descriptor* desc) {
+ static const int kDefaultPivot = (1 << 29); // max field number (29 bits)
+
+ // Find the max field number
+ int max_field_number = 0;
+ for (int i = 0; i < desc->field_count(); i++) {
+ if (!IgnoreField(desc->field(i)) &&
+ desc->field(i)->number() > max_field_number) {
+ max_field_number = desc->field(i)->number();
+ }
+ }
+
+ int pivot = -1;
+ if (IsExtendable(desc)) {
+ pivot = ((max_field_number + 1) < kDefaultPivot) ?
+ (max_field_number + 1) : kDefaultPivot;
+ }
+
+ return SimpleItoa(pivot);
+}
+
+// Returns true for fields that represent "null" as distinct from the default
+// value. See https://go/proto3#heading=h.kozewqqcqhuz for more information.
+bool HasFieldPresence(const FieldDescriptor* field) {
+ return
+ (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ||
+ (field->containing_oneof() != NULL) ||
+ (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3);
+}
+
+// For proto3 fields without presence, returns a string representing the default
+// value in JavaScript. See https://go/proto3#heading=h.kozewqqcqhuz for more
+// information.
+string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ case FieldDescriptor::CPPTYPE_INT64:
+ case FieldDescriptor::CPPTYPE_UINT32:
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ return "0";
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM:
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return "0";
+
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return "false";
+
+ case FieldDescriptor::CPPTYPE_STRING:
+ return "\"\"";
+
+ default:
+ // BYTES and MESSAGE are handled separately.
+ assert(false);
+ return "";
+ }
+}
+
+} // anonymous namespace
+
+void Generator::GenerateHeader(const GeneratorOptions& options,
+ io::Printer* printer) const {
+ printer->Print("/**\n"
+ " * @fileoverview\n"
+ " * @enhanceable\n"
+ " * @public\n"
+ " */\n"
+ "// GENERATED CODE -- DO NOT EDIT!\n"
+ "\n");
+}
+
+void Generator::FindProvides(const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FileDescriptor*>& files,
+ std::set<string>* provided) const {
+ for (int i = 0; i < files.size(); i++) {
+ for (int j = 0; j < files[i]->message_type_count(); j++) {
+ FindProvidesForMessage(options, printer, files[i]->message_type(j),
+ provided);
+ }
+ for (int j = 0; j < files[i]->enum_type_count(); j++) {
+ FindProvidesForEnum(options, printer, files[i]->enum_type(j),
+ provided);
+ }
+ }
+
+ printer->Print("\n");
+}
+
+void Generator::FindProvidesForMessage(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc,
+ std::set<string>* provided) const {
+ string name = GetPath(options, desc);
+ provided->insert(name);
+
+ for (int i = 0; i < desc->enum_type_count(); i++) {
+ FindProvidesForEnum(options, printer, desc->enum_type(i),
+ provided);
+ }
+ for (int i = 0; i < desc->nested_type_count(); i++) {
+ FindProvidesForMessage(options, printer, desc->nested_type(i),
+ provided);
+ }
+}
+
+void Generator::FindProvidesForEnum(const GeneratorOptions& options,
+ io::Printer* printer,
+ const EnumDescriptor* enumdesc,
+ std::set<string>* provided) const {
+ string name = GetPath(options, enumdesc);
+ provided->insert(name);
+}
+
+void Generator::FindProvidesForFields(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FieldDescriptor*>& fields,
+ std::set<string>* provided) const {
+ for (int i = 0; i < fields.size(); i++) {
+ const FieldDescriptor* field = fields[i];
+
+ if (IgnoreField(field)) {
+ continue;
+ }
+
+ string name =
+ GetPath(options, field->file()) + "." + JSObjectFieldName(field);
+ provided->insert(name);
+ }
+}
+
+void Generator::GenerateProvides(const GeneratorOptions& options,
+ io::Printer* printer,
+ std::set<string>* provided) const {
+ for (std::set<string>::iterator it = provided->begin();
+ it != provided->end(); ++it) {
+ printer->Print("goog.provide('$name$');\n",
+ "name", *it);
+ }
+}
+
+void Generator::GenerateRequires(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc,
+ std::set<string>* provided) const {
+ std::set<string> required;
+ std::set<string> forwards;
+ bool have_message = false;
+ FindRequiresForMessage(options, desc,
+ &required, &forwards, &have_message);
+
+ GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+ /* require_jspb = */ have_message,
+ /* require_extension = */ HasExtensions(desc));
+}
+
+void Generator::GenerateRequires(const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FileDescriptor*>& files,
+ std::set<string>* provided) const {
+ std::set<string> required;
+ std::set<string> forwards;
+ bool have_extensions = false;
+ bool have_message = false;
+
+ for (int i = 0; i < files.size(); i++) {
+ for (int j = 0; j < files[i]->message_type_count(); j++) {
+ FindRequiresForMessage(options,
+ files[i]->message_type(j),
+ &required, &forwards, &have_message);
+ }
+ if (!have_extensions && HasExtensions(files[i])) {
+ have_extensions = true;
+ }
+
+ for (int j = 0; j < files[i]->extension_count(); j++) {
+ const FieldDescriptor* extension = files[i]->extension(j);
+ if (IgnoreField(extension)) {
+ continue;
+ }
+ if (extension->containing_type()->full_name() !=
+ "google.protobuf.bridge.MessageSet") {
+ required.insert(GetPath(options, extension->containing_type()));
+ }
+ FindRequiresForField(options, extension, &required, &forwards);
+ have_extensions = true;
+ }
+ }
+
+ GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+ /* require_jspb = */ have_message,
+ /* require_extension = */ have_extensions);
+}
+
+void Generator::GenerateRequires(const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FieldDescriptor*>& fields,
+ std::set<string>* provided) const {
+ std::set<string> required;
+ std::set<string> forwards;
+ for (int i = 0; i < fields.size(); i++) {
+ const FieldDescriptor* field = fields[i];
+ if (IgnoreField(field)) {
+ continue;
+ }
+ FindRequiresForExtension(options, field, &required, &forwards);
+ }
+
+ GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+ /* require_jspb = */ false,
+ /* require_extension = */ fields.size() > 0);
+}
+
+void Generator::GenerateRequiresImpl(const GeneratorOptions& options,
+ io::Printer* printer,
+ std::set<string>* required,
+ std::set<string>* forwards,
+ std::set<string>* provided,
+ bool require_jspb,
+ bool require_extension) const {
+ if (require_jspb) {
+ printer->Print(
+ "goog.require('jspb.Message');\n");
+ if (options.binary) {
+ printer->Print(
+ "goog.require('jspb.BinaryReader');\n"
+ "goog.require('jspb.BinaryWriter');\n");
+ }
+ }
+ if (require_extension) {
+ printer->Print(
+ "goog.require('jspb.ExtensionFieldInfo');\n");
+ }
+
+ std::set<string>::iterator it;
+ for (it = required->begin(); it != required->end(); ++it) {
+ if (provided->find(*it) != provided->end()) {
+ continue;
+ }
+ printer->Print("goog.require('$name$');\n",
+ "name", *it);
+ }
+
+ printer->Print("\n");
+
+ for (it = forwards->begin(); it != forwards->end(); ++it) {
+ if (provided->find(*it) != provided->end()) {
+ continue;
+ }
+ printer->Print("goog.forwardDeclare('$name$');\n",
+ "name", *it);
+ }
+}
+
+bool NamespaceOnly(const Descriptor* desc) {
+ return false;
+}
+
+void Generator::FindRequiresForMessage(
+ const GeneratorOptions& options,
+ const Descriptor* desc,
+ std::set<string>* required,
+ std::set<string>* forwards,
+ bool* have_message) const {
+
+
+ if (!NamespaceOnly(desc)) {
+ *have_message = true;
+ for (int i = 0; i < desc->field_count(); i++) {
+ const FieldDescriptor* field = desc->field(i);
+ if (IgnoreField(field)) {
+ continue;
+ }
+ FindRequiresForField(options, field, required, forwards);
+ }
+ }
+
+ for (int i = 0; i < desc->extension_count(); i++) {
+ const FieldDescriptor* field = desc->extension(i);
+ if (IgnoreField(field)) {
+ continue;
+ }
+ FindRequiresForExtension(options, field, required, forwards);
+ }
+
+ for (int i = 0; i < desc->nested_type_count(); i++) {
+ FindRequiresForMessage(options, desc->nested_type(i), required, forwards,
+ have_message);
+ }
+}
+
+void Generator::FindRequiresForField(const GeneratorOptions& options,
+ const FieldDescriptor* field,
+ std::set<string>* required,
+ std::set<string>* forwards) const {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+ // N.B.: file-level extensions with enum type do *not* create
+ // dependencies, as per original codegen.
+ !(field->is_extension() && field->extension_scope() == NULL)) {
+ if (options.add_require_for_enums) {
+ required->insert(GetPath(options, field->enum_type()));
+ } else {
+ forwards->insert(GetPath(options, field->enum_type()));
+ }
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ required->insert(GetPath(options, field->message_type()));
+ }
+}
+
+void Generator::FindRequiresForExtension(const GeneratorOptions& options,
+ const FieldDescriptor* field,
+ std::set<string>* required,
+ std::set<string>* forwards) const {
+ if (field->containing_type()->full_name() != "google.protobuf.bridge.MessageSet") {
+ required->insert(GetPath(options, field->containing_type()));
+ }
+ FindRequiresForField(options, field, required, forwards);
+}
+
+void Generator::GenerateTestOnly(const GeneratorOptions& options,
+ io::Printer* printer) const {
+ if (options.testonly) {
+ printer->Print("goog.setTestOnly();\n\n");
+ }
+ printer->Print("\n");
+}
+
+void Generator::GenerateClassesAndEnums(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FileDescriptor* file) const {
+ for (int i = 0; i < file->message_type_count(); i++) {
+ GenerateClass(options, printer, file->message_type(i));
+ }
+ for (int i = 0; i < file->enum_type_count(); i++) {
+ GenerateEnum(options, printer, file->enum_type(i));
+ }
+}
+
+void Generator::GenerateClass(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ if (!NamespaceOnly(desc)) {
+ printer->Print("\n");
+ GenerateClassConstructor(options, printer, desc);
+ GenerateClassFieldInfo(options, printer, desc);
+
+
+ GenerateClassToObject(options, printer, desc);
+ if (options.binary) {
+ // These must come *before* the extension-field info generation in
+ // GenerateClassRegistration so that references to the binary
+ // serialization/deserialization functions may be placed in the extension
+ // objects.
+ GenerateClassDeserializeBinary(options, printer, desc);
+ GenerateClassSerializeBinary(options, printer, desc);
+ }
+ GenerateClassClone(options, printer, desc);
+ GenerateClassRegistration(options, printer, desc);
+ GenerateClassFields(options, printer, desc);
+ if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
+ GenerateClassExtensionFieldInfo(options, printer, desc);
+ }
+ }
+
+ // Recurse on nested types.
+ for (int i = 0; i < desc->enum_type_count(); i++) {
+ GenerateEnum(options, printer, desc->enum_type(i));
+ }
+ for (int i = 0; i < desc->nested_type_count(); i++) {
+ GenerateClass(options, printer, desc->nested_type(i));
+ }
+}
+
+void Generator::GenerateClassConstructor(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ printer->Print(
+ "/**\n"
+ " * Generated by JsPbCodeGenerator.\n"
+ " * @param {Array=} opt_data Optional initial data array, typically "
+ "from a\n"
+ " * server response, or constructed directly in Javascript. The array "
+ "is used\n"
+ " * in place and becomes part of the constructed object. It is not "
+ "cloned.\n"
+ " * If no data is provided, the constructed object will be empty, but "
+ "still\n"
+ " * valid.\n"
+ " * @extends {jspb.Message}\n"
+ " * @constructor\n"
+ " */\n"
+ "$classname$ = function(opt_data) {\n",
+ "classname", GetPath(options, desc));
+ string message_id = GetMessageId(desc);
+ printer->Print(
+ " jspb.Message.initialize(this, opt_data, $messageId$, $pivot$, "
+ "$rptfields$, $oneoffields$);\n",
+ "messageId", !message_id.empty() ?
+ ("'" + message_id + "'") :
+ (IsResponse(desc) ? "''" : "0"),
+ "pivot", GetPivot(desc),
+ "rptfields", RepeatedFieldsArrayName(options, desc),
+ "oneoffields", OneofFieldsArrayName(options, desc));
+ printer->Print(
+ "};\n"
+ "goog.inherits($classname$, jspb.Message);\n"
+ "if (goog.DEBUG && !COMPILED) {\n"
+ " $classname$.displayName = '$classname$';\n"
+ "}\n",
+ "classname", GetPath(options, desc));
+}
+
+void Generator::GenerateClassFieldInfo(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ if (HasRepeatedFields(desc)) {
+ printer->Print(
+ "/**\n"
+ " * List of repeated fields within this message type.\n"
+ " * @private {!Array<number>}\n"
+ " * @const\n"
+ " */\n"
+ "$classname$$rptfieldarray$ = $rptfields$;\n"
+ "\n",
+ "classname", GetPath(options, desc),
+ "rptfieldarray", kRepeatedFieldArrayName,
+ "rptfields", RepeatedFieldNumberList(desc));
+ }
+
+ if (HasOneofFields(desc)) {
+ printer->Print(
+ "/**\n"
+ " * Oneof group definitions for this message. Each group defines the "
+ "field\n"
+ " * numbers belonging to that group. When of these fields' value is "
+ "set, all\n"
+ " * other fields in the group are cleared. During deserialization, if "
+ "multiple\n"
+ " * fields are encountered for a group, only the last value seen will "
+ "be kept.\n"
+ " * @private {!Array<!Array<number>>}\n"
+ " * @const\n"
+ " */\n"
+ "$classname$$oneofgrouparray$ = $oneofgroups$;\n"
+ "\n",
+ "classname", GetPath(options, desc),
+ "oneofgrouparray", kOneofGroupArrayName,
+ "oneofgroups", OneofGroupList(desc));
+
+ for (int i = 0; i < desc->oneof_decl_count(); i++) {
+ if (IgnoreOneof(desc->oneof_decl(i))) {
+ continue;
+ }
+ GenerateOneofCaseDefinition(options, printer, desc->oneof_decl(i));
+ }
+ }
+}
+
+void Generator::GenerateClassXid(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ printer->Print(
+ "\n"
+ "\n"
+ "$class$.prototype.messageXid = xid('$class$');\n",
+ "class", GetPath(options, desc));
+}
+
+void Generator::GenerateOneofCaseDefinition(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const OneofDescriptor* oneof) const {
+ printer->Print(
+ "/**\n"
+ " * @enum {number}\n"
+ " */\n"
+ "$classname$.$oneof$Case = {\n"
+ " $upcase$_NOT_SET: 0",
+ "classname", GetPath(options, oneof->containing_type()),
+ "oneof", JSOneofName(oneof),
+ "upcase", ToEnumCase(oneof->name()));
+
+ for (int i = 0; i < oneof->field_count(); i++) {
+ if (IgnoreField(oneof->field(i))) {
+ continue;
+ }
+
+ printer->Print(
+ ",\n"
+ " $upcase$: $number$",
+ "upcase", ToEnumCase(oneof->field(i)->name()),
+ "number", JSFieldIndex(oneof->field(i)));
+ }
+
+ printer->Print(
+ "\n"
+ "};\n"
+ "\n"
+ "/**\n"
+ " * @return {$class$.$oneof$Case}\n"
+ " */\n"
+ "$class$.prototype.get$oneof$Case = function() {\n"
+ " return /** @type {$class$.$oneof$Case} */(jspb.Message."
+ "computeOneofCase(this, $class$.oneofGroups_[$oneofindex$]));\n"
+ "};\n"
+ "\n",
+ "class", GetPath(options, oneof->containing_type()),
+ "oneof", JSOneofName(oneof),
+ "oneofindex", JSOneofIndex(oneof));
+}
+
+void Generator::GenerateClassToObject(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ printer->Print(
+ "\n"
+ "\n"
+ "if (jspb.Message.GENERATE_TO_OBJECT) {\n"
+ "/**\n"
+ " * Creates an object representation of this proto suitable for use in "
+ "Soy templates.\n"
+ " * Field names that are reserved in JavaScript and will be renamed to "
+ "pb_name.\n"
+ " * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.\n"
+ " * For the list of reserved names please see:\n"
+ " * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.\n"
+ " * @param {boolean=} opt_includeInstance Whether to include the JSPB "
+ "instance\n"
+ " * for transitional soy proto support: http://goto/soy-param-"
+ "migration\n"
+ " * @return {!Object}\n"
+ " */\n"
+ "$classname$.prototype.toObject = function(opt_includeInstance) {\n"
+ " return $classname$.toObject(opt_includeInstance, this);\n"
+ "};\n"
+ "\n"
+ "\n"
+ "/**\n"
+ " * Static version of the {@see toObject} method.\n"
+ " * @param {boolean|undefined} includeInstance Whether to include the "
+ "JSPB\n"
+ " * instance for transitional soy proto support:\n"
+ " * http://goto/soy-param-migration\n"
+ " * @param {!$classname$} msg The msg instance to transform.\n"
+ " * @return {!Object}\n"
+ " */\n"
+ "$classname$.toObject = function(includeInstance, msg) {\n"
+ " var f, obj = {",
+ "classname", GetPath(options, desc));
+
+ bool first = true;
+ for (int i = 0; i < desc->field_count(); i++) {
+ const FieldDescriptor* field = desc->field(i);
+ if (IgnoreField(field)) {
+ continue;
+ }
+
+ if (!first) {
+ printer->Print(",\n ");
+ } else {
+ printer->Print("\n ");
+ first = false;
+ }
+
+ GenerateClassFieldToObject(options, printer, field);
+ }
+
+ if (!first) {
+ printer->Print("\n };\n\n");
+ } else {
+ printer->Print("\n\n };\n\n");
+ }
+
+ if (IsExtendable(desc)) {
+ printer->Print(
+ " jspb.Message.toObjectExtension(/** @type {!jspb.Message} */ (msg), "
+ "obj,\n"
+ " $extObject$, $class$.prototype.getExtension,\n"
+ " includeInstance);\n",
+ "extObject", JSExtensionsObjectName(options, desc),
+ "class", GetPath(options, desc));
+ }
+
+ printer->Print(
+ " if (includeInstance) {\n"
+ " obj.$$jspbMessageInstance = msg\n"
+ " }\n"
+ " return obj;\n"
+ "};\n"
+ "}\n"
+ "\n"
+ "\n",
+ "classname", GetPath(options, desc));
+}
+
+void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const {
+ printer->Print("$fieldname$: ",
+ "fieldname", JSObjectFieldName(field));
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Message field.
+ if (field->is_repeated()) {
+ {
+ printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
+ " $type$.toObject, includeInstance)",
+ "getter", JSGetterName(field),
+ "type", GetPath(options, field->message_type()));
+ }
+ } else {
+ printer->Print("(f = msg.get$getter$()) && "
+ "$type$.toObject(includeInstance, f)",
+ "getter", JSGetterName(field),
+ "type", GetPath(options, field->message_type()));
+ }
+ } else {
+ // Simple field (singular or repeated).
+ if (!HasFieldPresence(field) && !field->is_repeated()) {
+ // Delegate to the generated get<field>() method in order not to duplicate
+ // the proto3-field-default-value logic here.
+ printer->Print("msg.get$getter$()",
+ "getter", JSGetterName(field));
+ } else {
+ if (field->has_default_value()) {
+ printer->Print("jspb.Message.getField(msg, $index$) != null ? "
+ "jspb.Message.getField(msg, $index$) : $defaultValue$",
+ "index", JSFieldIndex(field),
+ "defaultValue", JSFieldDefault(field));
+ } else {
+ printer->Print("jspb.Message.getField(msg, $index$)",
+ "index", JSFieldIndex(field));
+ }
+ }
+ }
+}
+
+void Generator::GenerateClassFromObject(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ printer->Print(
+ "if (jspb.Message.GENERATE_FROM_OBJECT) {\n"
+ "/**\n"
+ " * Loads data from an object into a new instance of this proto.\n"
+ " * @param {!Object} obj The object representation of this proto to\n"
+ " * load the data from.\n"
+ " * @return {!$classname$}\n"
+ " */\n"
+ "$classname$.fromObject = function(obj) {\n"
+ " var f, msg = new $classname$();\n",
+ "classname", GetPath(options, desc));
+
+ for (int i = 0; i < desc->field_count(); i++) {
+ const FieldDescriptor* field = desc->field(i);
+ GenerateClassFieldFromObject(options, printer, field);
+ }
+
+ printer->Print(
+ " return msg;\n"
+ "};\n"
+ "}\n");
+}
+
+void Generator::GenerateClassFieldFromObject(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Message field (singular or repeated)
+ if (field->is_repeated()) {
+ {
+ printer->Print(
+ " goog.isDef(obj.$name$) && "
+ "jspb.Message.setRepeatedWrapperField(\n"
+ " msg, $index$, goog.array.map(obj.$name$, function(i) {\n"
+ " return $fieldclass$.fromObject(i);\n"
+ " }));\n",
+ "name", JSObjectFieldName(field),
+ "index", JSFieldIndex(field),
+ "fieldclass", GetPath(options, field->message_type()));
+ }
+ } else {
+ printer->Print(
+ " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
+ " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
+ "name", JSObjectFieldName(field),
+ "index", JSFieldIndex(field),
+ "fieldclass", GetPath(options, field->message_type()));
+ }
+ } else {
+ // Simple (primitive) field.
+ printer->Print(
+ " goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, "
+ "obj.$name$);\n",
+ "name", JSObjectFieldName(field),
+ "index", JSFieldIndex(field));
+ }
+}
+
+void Generator::GenerateClassClone(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ printer->Print(
+ "/**\n"
+ " * Creates a deep clone of this proto. No data is shared with the "
+ "original.\n"
+ " * @return {!$name$} The clone.\n"
+ " */\n"
+ "$name$.prototype.cloneMessage = function() {\n"
+ " return /** @type {!$name$} */ (jspb.Message.cloneMessage(this));\n"
+ "};\n\n\n",
+ "name", GetPath(options, desc));
+}
+
+void Generator::GenerateClassRegistration(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ // Register any extensions defined inside this message type.
+ for (int i = 0; i < desc->extension_count(); i++) {
+ const FieldDescriptor* extension = desc->extension(i);
+ if (ShouldGenerateExtension(extension)) {
+ GenerateExtension(options, printer, extension);
+ }
+ }
+
+}
+
+void Generator::GenerateClassFields(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ for (int i = 0; i < desc->field_count(); i++) {
+ if (!IgnoreField(desc->field(i))) {
+ GenerateClassField(options, printer, desc->field(i));
+ }
+ }
+}
+
+void Generator::GenerateClassField(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ "/**\n"
+ " * $fielddef$\n"
+ "$comment$"
+ " * @return {$type$}\n"
+ " */\n",
+ "fielddef", FieldDefinition(options, field),
+ "comment", FieldComments(field),
+ "type", JSFieldTypeAnnotation(options, field,
+ /* force_optional = */ false,
+ /* force_present = */ false,
+ /* singular_if_not_packed = */ false,
+ /* always_singular = */ false));
+ printer->Print(
+ "$class$.prototype.get$name$ = function() {\n"
+ " return /** @type{$type$} */ (\n"
+ " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, "
+ "$index$$required$));\n"
+ "};\n"
+ "\n"
+ "\n",
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(field),
+ "type", JSFieldTypeAnnotation(options, field,
+ /* force_optional = */ false,
+ /* force_present = */ false,
+ /* singular_if_not_packed = */ false,
+ /* always_singular = */ false),
+ "rpt", (field->is_repeated() ? "Repeated" : ""),
+ "index", JSFieldIndex(field),
+ "wrapperclass", GetPath(options, field->message_type()),
+ "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ?
+ ", 1" : ""));
+ printer->Print(
+ "/** @param {$optionaltype$} value $returndoc$ */\n"
+ "$class$.prototype.set$name$ = function(value) {\n"
+ " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(",
+ "optionaltype",
+ JSFieldTypeAnnotation(options, field,
+ /* force_optional = */ true,
+ /* force_present = */ false,
+ /* singular_if_not_packed = */ false,
+ /* always_singular = */ false),
+ "returndoc", JSReturnDoc(options, field),
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(field),
+ "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+ "repeatedtag", (field->is_repeated() ? "Repeated" : ""));
+
+ printer->Print(
+ "this, $index$$oneofgroup$, value);$returnvalue$\n"
+ "};\n"
+ "\n"
+ "\n",
+ "index", JSFieldIndex(field),
+ "oneofgroup", (field->containing_oneof() ?
+ (", " + JSOneofArray(options, field)) : ""),
+ "returnvalue", JSReturnClause(field));
+
+ printer->Print(
+ "$class$.prototype.clear$name$ = function() {\n"
+ " this.set$name$($clearedvalue$);$returnvalue$\n"
+ "};\n"
+ "\n"
+ "\n",
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(field),
+ "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
+ "returnvalue", JSReturnClause(field));
+
+ } else {
+ string typed_annotation;
+
+ // Simple (primitive) field, either singular or repeated.
+ {
+ typed_annotation = JSFieldTypeAnnotation(options, field,
+ /* force_optional = */ false,
+ /* force_present = */ !HasFieldPresence(field),
+ /* singular_if_not_packed = */ false,
+ /* always_singular = */ false),
+ printer->Print(
+ "/**\n"
+ " * $fielddef$\n"
+ "$comment$"
+ " * @return {$type$}\n"
+ " */\n",
+ "fielddef", FieldDefinition(options, field),
+ "comment", FieldComments(field),
+ "type", typed_annotation);
+ }
+
+ printer->Print(
+ "$class$.prototype.get$name$ = function() {\n",
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(field));
+
+ {
+ printer->Print(
+ " return /** @type {$type$} */ (",
+ "type", typed_annotation);
+ }
+
+ // For proto3 fields without presence, use special getters that will return
+ // defaults when the field is unset, possibly constructing a value if
+ // required.
+ if (!HasFieldPresence(field) && !field->is_repeated()) {
+ printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)",
+ "index", JSFieldIndex(field),
+ "default", Proto3PrimitiveFieldDefault(field));
+ } else {
+ if (field->has_default_value()) {
+ printer->Print("jspb.Message.getField(this, $index$) != null ? "
+ "jspb.Message.getField(this, $index$) : $defaultValue$",
+ "index", JSFieldIndex(field),
+ "defaultValue", JSFieldDefault(field));
+ } else {
+ printer->Print("jspb.Message.getField(this, $index$)",
+ "index", JSFieldIndex(field));
+ }
+ }
+
+ {
+ printer->Print(
+ ");\n"
+ "};\n"
+ "\n"
+ "\n");
+ }
+
+ {
+ printer->Print(
+ "/** @param {$optionaltype$} value $returndoc$ */\n",
+ "optionaltype",
+ JSFieldTypeAnnotation(options, field,
+ /* force_optional = */ true,
+ /* force_present = */ !HasFieldPresence(field),
+ /* singular_if_not_packed = */ false,
+ /* always_singular = */ false),
+ "returndoc", JSReturnDoc(options, field));
+ }
+
+ printer->Print(
+ "$class$.prototype.set$name$ = function(value) {\n"
+ " jspb.Message.set$oneoftag$Field(this, $index$",
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(field),
+ "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+ "index", JSFieldIndex(field));
+ printer->Print(
+ "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n"
+ "};\n"
+ "\n"
+ "\n",
+ "type", "",
+ "typeclose", "",
+ "oneofgroup",
+ (field->containing_oneof() ? (", " + JSOneofArray(options, field))
+ : ""),
+ "returnvalue", JSReturnClause(field), "rptvalueinit",
+ (field->is_repeated() ? " || []" : ""));
+
+
+ if (HasFieldPresence(field)) {
+ printer->Print(
+ "$class$.prototype.clear$name$ = function() {\n"
+ " jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ",
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(field),
+ "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+ "oneofgroup", (field->containing_oneof() ?
+ (", " + JSOneofArray(options, field)) : ""),
+ "index", JSFieldIndex(field));
+ printer->Print(
+ "$clearedvalue$);$returnvalue$\n"
+ "};\n"
+ "\n"
+ "\n",
+ "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
+ "returnvalue", JSReturnClause(field));
+ }
+ }
+}
+
+void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ if (IsExtendable(desc)) {
+ printer->Print(
+ "\n"
+ "/**\n"
+ " * The extensions registered with this message class. This is a "
+ "map of\n"
+ " * extension field number to fieldInfo object.\n"
+ " *\n"
+ " * For example:\n"
+ " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, "
+ "ctor: proto.example.MyMessage} }\n"
+ " *\n"
+ " * fieldName contains the JsCompiler renamed field name property "
+ "so that it\n"
+ " * works in OPTIMIZED mode.\n"
+ " *\n"
+ " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n"
+ " */\n"
+ "$class$.extensions = {};\n"
+ "\n",
+ "class", GetPath(options, desc));
+ }
+}
+
+
+void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ // TODO(cfallin): Handle lazy decoding when requested by field option and/or
+ // by default for 'bytes' fields and packed repeated fields.
+
+ printer->Print(
+ "/**\n"
+ " * Deserializes binary data (in protobuf wire format).\n"
+ " * @param {jspb.ByteSource} bytes The bytes to deserialize.\n"
+ " * @return {!$class$}\n"
+ " */\n"
+ "$class$.deserializeBinary = function(bytes) {\n"
+ " var reader = new jspb.BinaryReader(bytes);\n"
+ " var msg = new $class$;\n"
+ " return $class$.deserializeBinaryFromReader(msg, reader);\n"
+ "};\n"
+ "\n"
+ "\n"
+ "/**\n"
+ " * Deserializes binary data (in protobuf wire format) from the\n"
+ " * given reader into the given message object.\n"
+ " * @param {!$class$} msg The message object to deserialize into.\n"
+ " * @param {!jspb.BinaryReader} reader The BinaryReader to use.\n"
+ " * @return {!$class$}\n"
+ " */\n"
+ "$class$.deserializeBinaryFromReader = function(msg, reader) {\n"
+ " while (reader.nextField()) {\n"
+ " if (reader.isEndGroup()) {\n"
+ " break;\n"
+ " }\n"
+ " var field = reader.getFieldNumber();\n"
+ " switch (field) {\n",
+ "class", GetPath(options, desc));
+
+ for (int i = 0; i < desc->field_count(); i++) {
+ GenerateClassDeserializeBinaryField(options, printer, desc->field(i));
+ }
+
+ printer->Print(
+ " default:\n");
+ if (IsExtendable(desc)) {
+ printer->Print(
+ " jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n"
+ " $class$.prototype.getExtension,\n"
+ " $class$.prototype.setExtension);\n"
+ " break;\n",
+ "extobj", JSExtensionsObjectName(options, desc),
+ "class", GetPath(options, desc));
+ } else {
+ printer->Print(
+ " reader.skipField();\n"
+ " break;\n");
+ }
+
+ printer->Print(
+ " }\n"
+ " }\n"
+ " return msg;\n"
+ "};\n"
+ "\n"
+ "\n");
+}
+
+void Generator::GenerateClassDeserializeBinaryField(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const {
+
+ printer->Print(" case $num$:\n",
+ "num", SimpleItoa(field->number()));
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ " var value = new $fieldclass$;\n"
+ " reader.read$msgOrGroup$($grpfield$value,"
+ "$fieldclass$.deserializeBinaryFromReader);\n",
+ "fieldclass", GetPath(options, field->message_type()),
+ "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+ "Group" : "Message",
+ "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+ (SimpleItoa(field->number()) + ", ") : "");
+ } else {
+ printer->Print(
+ " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n",
+ "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
+ /* singular_if_not_packed = */ true,
+ /* always_singular = */ false),
+ "reader", JSBinaryReaderMethodName(field));
+ }
+
+ if (field->is_repeated() && !field->is_packed()) {
+ // Repeated fields receive a |value| one at at a time; append to array
+ // returned by get$name$().
+ printer->Print(
+ " msg.get$name$().push(value);\n",
+ "name", JSGetterName(field));
+ } else {
+ // Singular fields, and packed repeated fields, receive a |value| either as
+ // the field's value or as the array of all the field's values; set this as
+ // the field's value directly.
+ printer->Print(
+ " msg.set$name$(value);\n",
+ "name", JSGetterName(field));
+ }
+
+ printer->Print(" break;\n");
+}
+
+void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ printer->Print(
+ "/**\n"
+ " * Class method variant: serializes the given message to binary data\n"
+ " * (in protobuf wire format), writing to the given BinaryWriter.\n"
+ " * @param {!$class$} message\n"
+ " * @param {!jspb.BinaryWriter} writer\n"
+ " */\n"
+ "$class$.serializeBinaryToWriter = function(message, "
+ "writer) {\n"
+ " message.serializeBinaryToWriter(writer);\n"
+ "};\n"
+ "\n"
+ "\n"
+ "/**\n"
+ " * Serializes the message to binary data (in protobuf wire format).\n"
+ " * @return {!Uint8Array}\n"
+ " */\n"
+ "$class$.prototype.serializeBinary = function() {\n"
+ " var writer = new jspb.BinaryWriter();\n"
+ " this.serializeBinaryToWriter(writer);\n"
+ " return writer.getResultBuffer();\n"
+ "};\n"
+ "\n"
+ "\n"
+ "/**\n"
+ " * Serializes the message to binary data (in protobuf wire format),\n"
+ " * writing to the given BinaryWriter.\n"
+ " * @param {!jspb.BinaryWriter} writer\n"
+ " */\n"
+ "$class$.prototype.serializeBinaryToWriter = function (writer) {\n"
+ " var f = undefined;\n",
+ "class", GetPath(options, desc));
+
+ for (int i = 0; i < desc->field_count(); i++) {
+ GenerateClassSerializeBinaryField(options, printer, desc->field(i));
+ }
+
+ if (IsExtendable(desc)) {
+ printer->Print(
+ " jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n"
+ " $class$.prototype.getExtension);\n",
+ "extobj", JSExtensionsObjectName(options, desc),
+ "class", GetPath(options, desc));
+ }
+
+ printer->Print(
+ "};\n"
+ "\n"
+ "\n");
+}
+
+void Generator::GenerateClassSerializeBinaryField(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const {
+ printer->Print(
+ " f = this.get$name$();\n",
+ "name", JSGetterName(field));
+
+ if (field->is_repeated()) {
+ printer->Print(
+ " if (f.length > 0) {\n");
+ } else {
+ if (HasFieldPresence(field)) {
+ printer->Print(
+ " if (f != null) {\n");
+ } else {
+ // No field presence: serialize onto the wire only if value is
+ // non-default. Defaults are documented here:
+ // https://goto.google.com/lhdfm
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ case FieldDescriptor::CPPTYPE_INT64:
+ case FieldDescriptor::CPPTYPE_UINT32:
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ {
+ printer->Print(" if (f !== 0) {\n");
+ }
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM:
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ printer->Print(
+ " if (f !== 0.0) {\n");
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ printer->Print(
+ " if (f) {\n");
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ printer->Print(
+ " if (f.length > 0) {\n");
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ }
+
+ printer->Print(
+ " writer.$writer$(\n"
+ " $index$,\n"
+ " f",
+ "writer", JSBinaryWriterMethodName(field),
+ "name", JSGetterName(field),
+ "index", SimpleItoa(field->number()));
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ ",\n"
+ " $submsg$.serializeBinaryToWriter\n",
+ "submsg", GetPath(options, field->message_type()));
+ } else {
+ printer->Print("\n");
+ }
+ printer->Print(
+ " );\n"
+ " }\n");
+}
+
+void Generator::GenerateEnum(const GeneratorOptions& options,
+ io::Printer* printer,
+ const EnumDescriptor* enumdesc) const {
+ printer->Print(
+ "/**\n"
+ " * @enum {number}\n"
+ " */\n"
+ "$name$ = {\n",
+ "name", GetPath(options, enumdesc));
+
+ for (int i = 0; i < enumdesc->value_count(); i++) {
+ const EnumValueDescriptor* value = enumdesc->value(i);
+ printer->Print(
+ " $name$: $value$$comma$\n",
+ "name", ToEnumCase(value->name()),
+ "value", SimpleItoa(value->number()),
+ "comma", (i == enumdesc->value_count() - 1) ? "" : ",");
+ }
+
+ printer->Print(
+ "};\n"
+ "\n");
+}
+
+void Generator::GenerateExtension(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const {
+ string extension_scope =
+ (field->extension_scope() ?
+ GetPath(options, field->extension_scope()) :
+ GetPath(options, field->file()));
+
+ printer->Print(
+ "\n"
+ "/**\n"
+ " * A tuple of {field number, class constructor} for the extension\n"
+ " * field named `$name$`.\n"
+ " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n"
+ " */\n"
+ "$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
+ "name", JSObjectFieldName(field),
+ "class", extension_scope,
+ "extensionType", JSFieldTypeAnnotation(
+ options, field,
+ /* force_optional = */ false,
+ /* force_present = */ true,
+ /* singular_if_not_packed = */ false,
+ /* always_singular = */ false));
+ printer->Print(
+ " $index$,\n"
+ " {$name$: 0},\n"
+ " $ctor$,\n"
+ " /** @type {?function((boolean|undefined),!jspb.Message=): "
+ "!Object} */ (\n"
+ " $toObject$),\n"
+ " $repeated$",
+ "index", SimpleItoa(field->number()),
+ "name", JSObjectFieldName(field),
+ "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
+ GetPath(options, field->message_type()) : string("null")),
+ "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
+ (GetPath(options, field->message_type()) + ".toObject") :
+ string("null")),
+ "repeated", (field->is_repeated() ? "1" : "0"));
+
+ if (options.binary) {
+ printer->Print(
+ ",\n"
+ " jspb.BinaryReader.prototype.$binaryReaderFn$,\n"
+ " jspb.BinaryWriter.prototype.$binaryWriterFn$,\n"
+ " $binaryMessageSerializeFn$,\n"
+ " $binaryMessageDeserializeFn$,\n"
+ " $isPacked$);\n",
+ "binaryReaderFn", JSBinaryReaderMethodName(field),
+ "binaryWriterFn", JSBinaryWriterMethodName(field),
+ "binaryMessageSerializeFn",
+ (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+ (GetPath(options, field->message_type()) +
+ ".serializeBinaryToWriter") : "null",
+ "binaryMessageDeserializeFn",
+ (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+ (GetPath(options, field->message_type()) +
+ ".deserializeBinaryFromReader") : "null",
+ "isPacked", (field->is_packed() ? "true" : "false"));
+ } else {
+ printer->Print(");\n");
+ }
+
+ printer->Print(
+ "// This registers the extension field with the extended class, so that\n"
+ "// toObject() will function correctly.\n"
+ "$extendName$[$index$] = $class$.$name$;\n"
+ "\n",
+ "extendName", JSExtensionsObjectName(options, field->containing_type()),
+ "index", SimpleItoa(field->number()),
+ "class", extension_scope,
+ "name", JSObjectFieldName(field));
+}
+
+bool GeneratorOptions::ParseFromOptions(
+ const vector< pair< string, string > >& options,
+ string* error) {
+ for (int i = 0; i < options.size(); i++) {
+ if (options[i].first == "add_require_for_enums") {
+ if (options[i].second != "") {
+ *error = "Unexpected option value for add_require_for_enums";
+ return false;
+ }
+ add_require_for_enums = true;
+ } else if (options[i].first == "binary") {
+ if (options[i].second != "") {
+ *error = "Unexpected option value for binary";
+ return false;
+ }
+ binary = true;
+ } else if (options[i].first == "testonly") {
+ if (options[i].second != "") {
+ *error = "Unexpected option value for testonly";
+ return false;
+ }
+ testonly = true;
+ } else if (options[i].first == "error_on_name_conflict") {
+ if (options[i].second != "") {
+ *error = "Unexpected option value for error_on_name_conflict";
+ return false;
+ }
+ error_on_name_conflict = true;
+ } else if (options[i].first == "output_dir") {
+ output_dir = options[i].second;
+ } else if (options[i].first == "namespace_prefix") {
+ namespace_prefix = options[i].second;
+ } else if (options[i].first == "library") {
+ library = options[i].second;
+ } else {
+ // Assume any other option is an output directory, as long as it is a bare
+ // `key` rather than a `key=value` option.
+ if (options[i].second != "") {
+ *error = "Unknown option: " + options[i].first;
+ return false;
+ }
+ output_dir = options[i].first;
+ }
+ }
+
+ return true;
+}
+
+void Generator::GenerateFilesInDepOrder(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FileDescriptor*>& files) const {
+ // Build a std::set over all files so that the DFS can detect when it recurses
+ // into a dep not specified in the user's command line.
+ std::set<const FileDescriptor*> all_files(files.begin(), files.end());
+ // Track the in-progress set of files that have been generated already.
+ std::set<const FileDescriptor*> generated;
+ for (int i = 0; i < files.size(); i++) {
+ GenerateFileAndDeps(options, printer, files[i], &all_files, &generated);
+ }
+}
+
+void Generator::GenerateFileAndDeps(
+ const GeneratorOptions& options,
+ io::Printer* printer,
+ const FileDescriptor* root,
+ std::set<const FileDescriptor*>* all_files,
+ std::set<const FileDescriptor*>* generated) const {
+ // Skip if already generated.
+ if (generated->find(root) != generated->end()) {
+ return;
+ }
+ generated->insert(root);
+
+ // Generate all dependencies before this file's content.
+ for (int i = 0; i < root->dependency_count(); i++) {
+ const FileDescriptor* dep = root->dependency(i);
+ GenerateFileAndDeps(options, printer, dep, all_files, generated);
+ }
+
+ // Generate this file's content. Only generate if the file is part of the
+ // original set requested to be generated; i.e., don't take all transitive
+ // deps down to the roots.
+ if (all_files->find(root) != all_files->end()) {
+ GenerateClassesAndEnums(options, printer, root);
+ }
+}
+
+bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
+ const string& parameter,
+ GeneratorContext* context,
+ string* error) const {
+ vector< pair< string, string > > option_pairs;
+ ParseGeneratorParameter(parameter, &option_pairs);
+ GeneratorOptions options;
+ if (!options.ParseFromOptions(option_pairs, error)) {
+ return false;
+ }
+
+
+ // We're either generating a single library file with definitions for message
+ // and enum types in *all* FileDescriptor inputs, or we're generating a single
+ // file for each type.
+ if (options.library != "") {
+ string filename = options.output_dir + "/" + options.library + ".js";
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+ GOOGLE_CHECK(output.get());
+ io::Printer printer(output.get(), '$');
+
+ // Pull out all extensions -- we need these to generate all
+ // provides/requires.
+ vector<const FieldDescriptor*> extensions;
+ for (int i = 0; i < files.size(); i++) {
+ for (int j = 0; j < files[i]->extension_count(); j++) {
+ const FieldDescriptor* extension = files[i]->extension(j);
+ extensions.push_back(extension);
+ }
+ }
+
+ GenerateHeader(options, &printer);
+
+ std::set<string> provided;
+ FindProvides(options, &printer, files, &provided);
+ FindProvidesForFields(options, &printer, extensions, &provided);
+ GenerateProvides(options, &printer, &provided);
+ GenerateTestOnly(options, &printer);
+ GenerateRequires(options, &printer, files, &provided);
+
+ GenerateFilesInDepOrder(options, &printer, files);
+
+ for (int i = 0; i < extensions.size(); i++) {
+ if (ShouldGenerateExtension(extensions[i])) {
+ GenerateExtension(options, &printer, extensions[i]);
+ }
+ }
+
+ if (printer.failed()) {
+ return false;
+ }
+ } else {
+ // Collect all types, and print each type to a separate file. Pull out
+ // free-floating extensions while we make this pass.
+ map< string, vector<const FieldDescriptor*> > extensions_by_namespace;
+
+ // If we're generating code in file-per-type mode, avoid overwriting files
+ // by choosing the last descriptor that writes each filename and permitting
+ // only those to generate code.
+
+ // Current descriptor that will generate each filename, indexed by filename.
+ map<string, const void*> desc_by_filename;
+ // Set of descriptors allowed to generate files.
+ set<const void*> allowed_descs;
+
+ for (int i = 0; i < files.size(); i++) {
+ // Collect all (descriptor, filename) pairs.
+ map<const void*, string> descs_in_file;
+ for (int j = 0; j < files[i]->message_type_count(); j++) {
+ const Descriptor* desc = files[i]->message_type(j);
+ string filename =
+ options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+ descs_in_file[desc] = filename;
+ }
+ for (int j = 0; j < files[i]->enum_type_count(); j++) {
+ const EnumDescriptor* desc = files[i]->enum_type(j);
+ string filename =
+ options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+ descs_in_file[desc] = filename;
+ }
+
+ // For each (descriptor, filename) pair, update the
+ // descriptors-by-filename map, and if a previous descriptor was already
+ // writing the filename, remove it from the allowed-descriptors set.
+ map<const void*, string>::iterator it;
+ for (it = descs_in_file.begin(); it != descs_in_file.end(); ++it) {
+ const void* desc = it->first;
+ const string& filename = it->second;
+ if (desc_by_filename.find(filename) != desc_by_filename.end()) {
+ if (options.error_on_name_conflict) {
+ *error = "Name conflict: file name " + filename +
+ " would be generated by two descriptors";
+ return false;
+ }
+ allowed_descs.erase(desc_by_filename[filename]);
+ }
+ desc_by_filename[filename] = desc;
+ allowed_descs.insert(desc);
+ }
+ }
+
+ // Generate code.
+ for (int i = 0; i < files.size(); i++) {
+ const FileDescriptor* file = files[i];
+ for (int j = 0; j < file->message_type_count(); j++) {
+ const Descriptor* desc = file->message_type(j);
+ if (allowed_descs.find(desc) == allowed_descs.end()) {
+ continue;
+ }
+
+ string filename = options.output_dir + "/" +
+ ToFileName(desc->name()) + ".js";
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->Open(filename));
+ GOOGLE_CHECK(output.get());
+ io::Printer printer(output.get(), '$');
+
+ GenerateHeader(options, &printer);
+
+ std::set<string> provided;
+ FindProvidesForMessage(options, &printer, desc, &provided);
+ GenerateProvides(options, &printer, &provided);
+ GenerateTestOnly(options, &printer);
+ GenerateRequires(options, &printer, desc, &provided);
+
+ GenerateClass(options, &printer, desc);
+
+ if (printer.failed()) {
+ return false;
+ }
+ }
+ for (int j = 0; j < file->enum_type_count(); j++) {
+ const EnumDescriptor* enumdesc = file->enum_type(j);
+ if (allowed_descs.find(enumdesc) == allowed_descs.end()) {
+ continue;
+ }
+
+ string filename = options.output_dir + "/" +
+ ToFileName(enumdesc->name()) + ".js";
+
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->Open(filename));
+ GOOGLE_CHECK(output.get());
+ io::Printer printer(output.get(), '$');
+
+ GenerateHeader(options, &printer);
+
+ std::set<string> provided;
+ FindProvidesForEnum(options, &printer, enumdesc, &provided);
+ GenerateProvides(options, &printer, &provided);
+ GenerateTestOnly(options, &printer);
+
+ GenerateEnum(options, &printer, enumdesc);
+
+ if (printer.failed()) {
+ return false;
+ }
+ }
+ // Pull out all free-floating extensions and generate files for those too.
+ for (int j = 0; j < file->extension_count(); j++) {
+ const FieldDescriptor* extension = file->extension(j);
+ extensions_by_namespace[GetPath(options, files[i])]
+ .push_back(extension);
+ }
+ }
+
+ // Generate extensions in separate files.
+ map< string, vector<const FieldDescriptor*> >::iterator it;
+ for (it = extensions_by_namespace.begin();
+ it != extensions_by_namespace.end();
+ ++it) {
+ string filename = options.output_dir + "/" +
+ ToFileName(it->first) + ".js";
+
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->Open(filename));
+ GOOGLE_CHECK(output.get());
+ io::Printer printer(output.get(), '$');
+
+ GenerateHeader(options, &printer);
+
+ std::set<string> provided;
+ FindProvidesForFields(options, &printer, it->second, &provided);
+ GenerateProvides(options, &printer, &provided);
+ GenerateTestOnly(options, &printer);
+ GenerateRequires(options, &printer, it->second, &provided);
+
+ for (int j = 0; j < it->second.size(); j++) {
+ if (ShouldGenerateExtension(it->second[j])) {
+ GenerateExtension(options, &printer, it->second[j]);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace js
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h
new file mode 100755
index 00000000..db2dceb3
--- /dev/null
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -0,0 +1,265 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__
+
+#include <string>
+#include <set>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class FieldDescriptor;
+class OneofDescriptor;
+class FileDescriptor;
+
+namespace io { class Printer; }
+
+namespace compiler {
+namespace js {
+
+struct GeneratorOptions {
+ // Add a `goog.requires()` call for each enum type used. If not set, a forward
+ // declaration with `goog.forwardDeclare` is produced instead.
+ bool add_require_for_enums;
+ // Set this as a test-only module via `goog.setTestOnly();`.
+ bool testonly;
+ // Output path.
+ string output_dir;
+ // Namespace prefix.
+ string namespace_prefix;
+ // Create a library with name <name>_lib.js rather than a separate .js file
+ // per type?
+ string library;
+ // Error if there are two types that would generate the same output file?
+ bool error_on_name_conflict;
+ // Enable binary-format support?
+ bool binary;
+
+ GeneratorOptions()
+ : add_require_for_enums(false),
+ testonly(false),
+ output_dir("."),
+ namespace_prefix(""),
+ library(""),
+ error_on_name_conflict(false),
+ binary(false) {}
+
+ bool ParseFromOptions(
+ const vector< pair< string, string > >& options,
+ string* error);
+};
+
+class LIBPROTOC_EXPORT Generator : public CodeGenerator {
+ public:
+ Generator() {}
+ virtual ~Generator() {}
+
+ virtual bool Generate(const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* context,
+ string* error) const {
+ *error = "Unimplemented Generate() method. Call GenerateAll() instead.";
+ return false;
+ }
+
+ virtual bool HasGenerateAll() const { return true; }
+
+ virtual bool GenerateAll(const vector<const FileDescriptor*>& files,
+ const string& parameter,
+ GeneratorContext* context,
+ string* error) const;
+
+ private:
+ void GenerateHeader(const GeneratorOptions& options,
+ io::Printer* printer) const;
+
+ // Generate goog.provides() calls.
+ void FindProvides(const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FileDescriptor*>& file,
+ std::set<string>* provided) const;
+ void FindProvidesForMessage(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc,
+ std::set<string>* provided) const;
+ void FindProvidesForEnum(const GeneratorOptions& options,
+ io::Printer* printer,
+ const EnumDescriptor* enumdesc,
+ std::set<string>* provided) const;
+ // For extension fields at file scope.
+ void FindProvidesForFields(const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FieldDescriptor*>& fields,
+ std::set<string>* provided) const;
+ // Print the goog.provides() found by the methods above.
+ void GenerateProvides(const GeneratorOptions& options,
+ io::Printer* printer,
+ std::set<string>* provided) const;
+
+ // Generate goog.setTestOnly() if indicated.
+ void GenerateTestOnly(const GeneratorOptions& options,
+ io::Printer* printer) const;
+
+ // Generate goog.requires() calls.
+ void GenerateRequires(const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FileDescriptor*>& file,
+ std::set<string>* provided) const;
+ void GenerateRequires(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc,
+ std::set<string>* provided) const;
+ // For extension fields at file scope.
+ void GenerateRequires(const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FieldDescriptor*>& fields,
+ std::set<string>* provided) const;
+ void GenerateRequiresImpl(const GeneratorOptions& options,
+ io::Printer* printer,
+ std::set<string>* required,
+ std::set<string>* forwards,
+ std::set<string>* provided,
+ bool require_jspb,
+ bool require_extension) const;
+ void FindRequiresForMessage(const GeneratorOptions& options,
+ const Descriptor* desc,
+ std::set<string>* required,
+ std::set<string>* forwards,
+ bool* have_message) const;
+ void FindRequiresForField(const GeneratorOptions& options,
+ const FieldDescriptor* field,
+ std::set<string>* required,
+ std::set<string>* forwards) const;
+ void FindRequiresForExtension(const GeneratorOptions& options,
+ const FieldDescriptor* field,
+ std::set<string>* required,
+ std::set<string>* forwards) const;
+
+ // Generate definitions for all message classes and enums in all files,
+ // processing the files in dependence order.
+ void GenerateFilesInDepOrder(const GeneratorOptions& options,
+ io::Printer* printer,
+ const vector<const FileDescriptor*>& file) const;
+ // Helper for above.
+ void GenerateFileAndDeps(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FileDescriptor* root,
+ std::set<const FileDescriptor*>* all_files,
+ std::set<const FileDescriptor*>* generated) const;
+
+ // Generate definitions for all message classes and enums.
+ void GenerateClassesAndEnums(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FileDescriptor* file) const;
+
+ // Generate definition for one class.
+ void GenerateClass(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassConstructor(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassFieldInfo(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassXid(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateOneofCaseDefinition(const GeneratorOptions& options,
+ io::Printer* printer,
+ const OneofDescriptor* oneof) const;
+ void GenerateClassToObject(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassFieldToObject(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const;
+ void GenerateClassFromObject(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassFieldFromObject(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const;
+ void GenerateClassClone(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassRegistration(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassFields(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassField(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* desc) const;
+ void GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassDeserialize(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassDeserializeBinary(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassDeserializeBinaryField(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const;
+ void GenerateClassSerializeBinary(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const;
+ void GenerateClassSerializeBinaryField(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const;
+
+ // Generate definition for one enum.
+ void GenerateEnum(const GeneratorOptions& options,
+ io::Printer* printer,
+ const EnumDescriptor* enumdesc) const;
+
+ // Generate an extension definition.
+ void GenerateExtension(const GeneratorOptions& options,
+ io::Printer* printer,
+ const FieldDescriptor* field) const;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator);
+};
+
+} // namespace js
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 4815a726..97df536e 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -38,6 +38,7 @@
#include <google/protobuf/compiler/ruby/ruby_generator.h>
#include <google/protobuf/compiler/csharp/csharp_generator.h>
#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
+#include <google/protobuf/compiler/js/js_generator.h>
int main(int argc, char* argv[]) {
@@ -72,7 +73,7 @@ int main(int argc, char* argv[]) {
// CSharp
google::protobuf::compiler::csharp::Generator csharp_generator;
- cli.RegisterGenerator("--csharp_out", &csharp_generator,
+ cli.RegisterGenerator("--csharp_out", "--csharp_opt", &csharp_generator,
"Generate C# source file.");
// Objective C
@@ -80,5 +81,10 @@ int main(int argc, char* argv[]) {
cli.RegisterGenerator("--objc_out", &objc_generator,
"Generate Objective C header and source.");
+ // JavaScript
+ google::protobuf::compiler::js::Generator js_generator;
+ cli.RegisterGenerator("--js_out", &js_generator,
+ "Generate JavaScript source.");
+
return cli.Run(argc, argv);
}
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index 98261431..121d917b 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -147,6 +147,12 @@ bool MockCodeGenerator::Generate(
std::cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
<< has_source_code_info << "." << std::endl;
abort();
+ } else if (command == "HasJsonName") {
+ FieldDescriptorProto field_descriptor_proto;
+ file->message_type(i)->field(0)->CopyTo(&field_descriptor_proto);
+ std::cerr << "Saw json_name: "
+ << field_descriptor_proto.has_json_name() << std::endl;
+ abort();
} else {
GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
}
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
index 184a84a3..228c66f0 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -95,7 +95,7 @@ void FileGenerator::GenerateHeader(io::Printer *printer) {
// code is being compiled with.
printer->Print(
"#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n"
- "#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.\n"
+ "#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.\n"
"#endif\n"
"\n",
"protoc_gen_objc_version",
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index b724d35c..990aca24 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -937,41 +937,17 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) {
// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
// error cases, so it seems to be ok to use as a back door for warnings.
- // First Check: Warning - if there is a prefix, ensure it is is a reasonable
- // value according to Apple's rules.
- if (prefix.length()) {
- if (!ascii_isupper(prefix[0])) {
- cerr << endl
- << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
- << prefix << "\";' in '" << file->name() << "';"
- << " it should start with a capital letter." << endl;
- cerr.flush();
- }
- if (prefix.length() < 3) {
- cerr << endl
- << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
- << prefix << "\";' in '" << file->name() << "';"
- << " Apple recommends they should be at least 3 characters long."
- << endl;
- cerr.flush();
- }
- }
-
// Load any expected package prefixes to validate against those.
map<string, string> expected_package_prefixes;
string expect_file_path;
if (!LoadExpectedPackagePrefixes(&expected_package_prefixes,
&expect_file_path, out_error)) {
- return false;
+ // Any error, clear the entries that were read.
+ expected_package_prefixes.clear();
}
- // If there are no expected prefixes, out of here.
- if (expected_package_prefixes.size() == 0) {
- return true;
- }
-
- // Second Check: Error - See if there was an expected prefix for the package
- // and report if it doesn't match.
+ // Check: Error - See if there was an expected prefix for the package and
+ // report if it doesn't match (wrong or missing).
map<string, string>::iterator package_match =
expected_package_prefixes.find(package);
if (package_match != expected_package_prefixes.end()) {
@@ -991,32 +967,57 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) {
}
}
- // Third Check: Error - If there was a prefix make sure it wasn't expected
- // for a different package instead (overlap is allowed, but it has to be
- // listed as an expected overlap).
- if (prefix.length()) {
- for (map<string, string>::iterator i = expected_package_prefixes.begin();
- i != expected_package_prefixes.end(); ++i) {
- if (i->second == prefix) {
- *out_error =
- "protoc:0: error: Found 'option objc_class_prefix = \"" + prefix +
- "\";' in '" + file->name() +
- "'; that prefix is already used for 'package " + i->first +
- ";'. It can only be reused by listing it in the expected file (" +
- expect_file_path + ").";
- return false; // Only report first usage of the prefix.
- }
+ // If there was no prefix option, we're done at this point.
+ if (prefix.length() == 0) {
+ // No prefix, nothing left to check.
+ return true;
+ }
+
+ // Check: Error - Make sure the prefix wasn't expected for a different
+ // package (overlap is allowed, but it has to be listed as an expected
+ // overlap).
+ for (map<string, string>::iterator i = expected_package_prefixes.begin();
+ i != expected_package_prefixes.end(); ++i) {
+ if (i->second == prefix) {
+ *out_error =
+ "protoc:0: error: Found 'option objc_class_prefix = \"" + prefix +
+ "\";' in '" + file->name() +
+ "'; that prefix is already used for 'package " + i->first +
+ ";'. It can only be reused by listing it in the expected file (" +
+ expect_file_path + ").";
+ return false; // Only report first usage of the prefix.
}
}
- // Fourth Check: Warning - If there was a prefix, and it wasn't expected,
- // issue a warning suggesting it gets added to the file.
- if (prefix.length()) {
+ // Check: Warning - Make sure the prefix is is a reasonable value according
+ // to Apple's rules (the checks above implicitly whitelist anything that
+ // doesn't meet these rules).
+ if (!ascii_isupper(prefix[0])) {
+ cerr << endl
+ << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+ << prefix << "\";' in '" << file->name() << "';"
+ << " it should start with a capital letter." << endl;
+ cerr.flush();
+ }
+ if (prefix.length() < 3) {
+ // Apple reserves 2 character prefixes for themselves. They do use some
+ // 3 character prefixes, but they haven't updated the rules/docs.
+ cerr << endl
+ << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+ << prefix << "\";' in '" << file->name() << "';"
+ << " Apple recommends they should be at least 3 characters long."
+ << endl;
+ cerr.flush();
+ }
+
+ // Check: Warning - If the given package/prefix pair wasn't expected, issue a
+ // warning issue a warning suggesting it gets added to the file.
+ if (!expected_package_prefixes.empty()) {
cerr << endl
- << "protoc:0: warning: Found 'option objc_class_prefix = \"" << prefix
- << "\";' in '" << file->name() << "';"
- << " should you add it to the expected prefixes file ("
- << expect_file_path << ")?" << endl;
+ << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
+ << prefix << "\";' in '" << file->name() << "';"
+ << " consider adding it to the expected prefixes file ("
+ << expect_file_path << ")." << endl;
cerr.flush();
}
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 4d018425..ea792a9d 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -458,6 +458,61 @@ void Parser::SkipRestOfBlock() {
// ===================================================================
+bool Parser::ValidateEnum(const EnumDescriptorProto* proto) {
+ bool has_allow_alias = false;
+ bool allow_alias = false;
+
+ for (int i = 0; i < proto->options().uninterpreted_option_size(); i++) {
+ const UninterpretedOption option = proto->options().uninterpreted_option(i);
+ if (option.name_size() > 1) {
+ continue;
+ }
+ if (!option.name(0).is_extension() &&
+ option.name(0).name_part() == "allow_alias") {
+ has_allow_alias = true;
+ if (option.identifier_value() == "true") {
+ allow_alias = true;
+ }
+ break;
+ }
+ }
+
+ if (has_allow_alias && !allow_alias) {
+ string error =
+ "\"" + proto->name() +
+ "\" declares 'option allow_alias = false;' which has no effect. "
+ "Please remove the declaration.";
+ // This needlessly clutters declarations with nops.
+ AddError(error);
+ return false;
+ }
+
+ set<int> used_values;
+ bool has_duplicates = false;
+ for (int i = 0; i < proto->value_size(); ++i) {
+ const EnumValueDescriptorProto enum_value = proto->value(i);
+ if (used_values.find(enum_value.number()) != used_values.end()) {
+ has_duplicates = true;
+ break;
+ } else {
+ used_values.insert(enum_value.number());
+ }
+ }
+ if (allow_alias && !has_duplicates) {
+ string error =
+ "\"" + proto->name() +
+ "\" declares support for enum aliases but no enum values share field "
+ "numbers. Please remove the unnecessary 'option allow_alias = true;' "
+ "declaration.";
+ // Generate an error if an enum declares support for duplicate enum values
+ // and does not use it protect future authors.
+ AddError(error);
+ return false;
+ }
+
+ return true;
+}
+
bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
input_ = input;
had_errors_ = false;
@@ -993,6 +1048,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 +1198,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) {
@@ -1602,6 +1682,9 @@ bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type,
}
DO(ParseEnumBlock(enum_type, enum_location, containing_file));
+
+ DO(ValidateEnum(enum_type));
+
return true;
}
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index 007b001c..2c561c23 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;"
@@ -494,6 +498,8 @@ class LIBPROTOBUF_EXPORT Parser {
}
+ bool ValidateEnum(const EnumDescriptorProto* proto);
+
// =================================================================
io::Tokenizer* input_;
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index cc6f1efb..1d623dd9 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"
@@ -1140,6 +1170,29 @@ TEST_F(ParseErrorTest, EnumValueOutOfRange) {
"4:19: Integer out of range.\n");
}
+TEST_F(ParseErrorTest, EnumAllowAliasFalse) {
+ ExpectHasErrors(
+ "enum Foo {\n"
+ " option allow_alias = false;\n"
+ " BAR = 1;\n"
+ " BAZ = 2;\n"
+ "}\n",
+ "5:0: \"Foo\" declares 'option allow_alias = false;' which has no effect. "
+ "Please remove the declaration.\n");
+}
+
+TEST_F(ParseErrorTest, UnnecessaryEnumAllowAlias) {
+ ExpectHasErrors(
+ "enum Foo {\n"
+ " option allow_alias = true;\n"
+ " BAR = 1;\n"
+ " BAZ = 2;\n"
+ "}\n",
+ "5:0: \"Foo\" declares support for enum aliases but no enum values share "
+ "field numbers. Please remove the unnecessary 'option allow_alias = true;' "
+ "declaration.\n");
+}
+
TEST_F(ParseErrorTest, DefaultValueMissing) {
ExpectHasErrors(
"message TestMessage {\n"
@@ -1809,6 +1862,8 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
"// Detached comment before TestMessage1.\n"
"\n"
"// Message comment.\n"
+ "//\n"
+ "// More detail in message comment.\n"
"message TestMessage1 {\n"
"\n"
" // Detached comment before foo.\n"
@@ -1860,11 +1915,6 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
pool_.BuildFileCollectingErrors(parsed_desc, &collector);
ASSERT_TRUE(descriptor != NULL);
- DebugStringOptions debug_string_options;
- debug_string_options.include_comments = true;
- const string debug_string =
- descriptor->DebugStringWithOptions(debug_string_options);
-
// Ensure that each of the comments appears somewhere in the DebugString().
// We don't test the exact comment placement or formatting, because we do not
// want to be too fragile here.
@@ -1875,6 +1925,7 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
"Package comment.",
"Detached comment before TestMessage1.",
"Message comment.",
+ "More detail in message comment.",
"Detached comment before foo.",
"Field comment",
"Detached comment before NestedMessage.",
@@ -1889,11 +1940,28 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
"RPC comment",
};
- for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
- string::size_type found_pos = debug_string.find(expected_comments[i]);
- EXPECT_TRUE(found_pos != string::npos)
- << "\"" << expected_comments[i] << "\" not found.";
+ DebugStringOptions debug_string_options;
+ debug_string_options.include_comments = true;
+
+ {
+ const string debug_string =
+ descriptor->DebugStringWithOptions(debug_string_options);
+
+ for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
+ string::size_type found_pos = debug_string.find(expected_comments[i]);
+ EXPECT_TRUE(found_pos != string::npos)
+ << "\"" << expected_comments[i] << "\" not found.";
+ }
+
+ // Result of DebugStringWithOptions should be parseable.
+ SetupParser(debug_string.c_str());
+ FileDescriptorProto parsed;
+ parser_->Parse(input_.get(), &parsed);
+ EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+ ASSERT_EQ("", error_collector_.text_)
+ << "Failed to parse:\n" << debug_string;
}
+
}
TEST_F(ParseDescriptorDebugTest, TestMaps) {
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 0792d875..a2da8eee 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/compiler/plugin.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/compiler/plugin.pb.h"
+#include <google/protobuf/compiler/plugin.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -172,11 +173,11 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int CodeGeneratorRequest::kFileToGenerateFieldNumber;
const int CodeGeneratorRequest::kParameterFieldNumber;
const int CodeGeneratorRequest::kProtoFileFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
CodeGeneratorRequest::CodeGeneratorRequest()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -656,11 +657,11 @@ CodeGeneratorRequest::proto_file() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int CodeGeneratorResponse_File::kNameFieldNumber;
const int CodeGeneratorResponse_File::kInsertionPointFieldNumber;
const int CodeGeneratorResponse_File::kContentFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
CodeGeneratorResponse_File::CodeGeneratorResponse_File()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1021,10 +1022,10 @@ void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other)
// -------------------------------------------------------------------
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int CodeGeneratorResponse::kErrorFieldNumber;
const int CodeGeneratorResponse::kFileFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
CodeGeneratorResponse::CodeGeneratorResponse()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index ab79bdae..0a03e979 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -27,7 +27,7 @@
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/unknown_field_set.h>
-#include "google/protobuf/descriptor.pb.h"
+#include <google/protobuf/descriptor.pb.h>
// @@protoc_insertion_point(includes)
namespace google {
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/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 85429924..a30ac305 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -47,6 +47,7 @@
#include <google/protobuf/message.h>
#include <google/protobuf/stubs/substitute.h>
+
namespace google {
namespace protobuf {
namespace compiler {
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 5256b83c..78a34617 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -34,6 +34,10 @@
#include <google/protobuf/stubs/hash.h>
#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <set>
#include <string>
#include <vector>
@@ -152,7 +156,7 @@ const char* FileDescriptor::SyntaxName(FileDescriptor::Syntax syntax) {
static const char * const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty";
-#ifndef _MSC_VER // MSVC doesn't need these and won't even accept them.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int FieldDescriptor::kMaxNumber;
const int FieldDescriptor::kFirstReservedNumber;
const int FieldDescriptor::kLastReservedNumber;
@@ -556,7 +560,7 @@ class FileDescriptorTables {
~FileDescriptorTables();
// Empty table, used with placeholder files.
- static const FileDescriptorTables kEmpty;
+ inline static const FileDescriptorTables& GetEmptyInstance();
// -----------------------------------------------------------------
// Finding items.
@@ -661,7 +665,32 @@ FileDescriptorTables::FileDescriptorTables()
FileDescriptorTables::~FileDescriptorTables() {}
-const FileDescriptorTables FileDescriptorTables::kEmpty;
+namespace {
+
+FileDescriptorTables* file_descriptor_tables_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(file_descriptor_tables_once_init_);
+
+void DeleteFileDescriptorTables() {
+ delete file_descriptor_tables_;
+ file_descriptor_tables_ = NULL;
+}
+
+void InitFileDescriptorTables() {
+ file_descriptor_tables_ = new FileDescriptorTables();
+ internal::OnShutdown(&DeleteFileDescriptorTables);
+}
+
+inline void InitFileDescriptorTablesOnce() {
+ ::google::protobuf::GoogleOnceInit(
+ &file_descriptor_tables_once_init_, &InitFileDescriptorTables);
+}
+
+} // anonymous namespace
+
+inline const FileDescriptorTables& FileDescriptorTables::GetEmptyInstance() {
+ InitFileDescriptorTablesOnce();
+ return *file_descriptor_tables_;
+}
void DescriptorPool::Tables::AddCheckpoint() {
checkpoints_.push_back(CheckPoint(this));
@@ -1726,6 +1755,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 +1813,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 +1883,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());
}
@@ -2007,6 +2075,7 @@ class SourceLocationCommentPrinter {
}
private:
+
bool have_source_loc_;
SourceLocation source_loc_;
DebugStringOptions options_;
@@ -2908,7 +2977,8 @@ class DescriptorBuilder {
const ServiceDescriptor* parent,
MethodDescriptor* result);
- void LogUnusedDependency(const FileDescriptor* result);
+ void LogUnusedDependency(const FileDescriptorProto& proto,
+ const FileDescriptor* result);
// Must be run only after building.
//
@@ -3492,7 +3562,7 @@ FileDescriptor* DescriptorBuilder::NewPlaceholderFile(
placeholder->package_ = &internal::GetEmptyString();
placeholder->pool_ = pool_;
placeholder->options_ = &FileOptions::default_instance();
- placeholder->tables_ = &FileDescriptorTables::kEmpty;
+ placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance();
placeholder->source_code_info_ = &SourceCodeInfo::default_instance();
placeholder->is_placeholder_ = true;
placeholder->syntax_ = FileDescriptor::SYNTAX_PROTO2;
@@ -3953,7 +4023,7 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
if (!unused_dependency_.empty()) {
- LogUnusedDependency(result);
+ LogUnusedDependency(proto, result);
}
if (had_errors_) {
@@ -4100,6 +4170,7 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
}
}
+
void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
const Descriptor* parent,
FieldDescriptor* result,
@@ -4136,6 +4207,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<FieldDescriptor::Type>(
@@ -4197,8 +4276,8 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
} else if (proto.default_value() == "nan") {
result->default_value_float_ = numeric_limits<float>::quiet_NaN();
} else {
- result->default_value_float_ =
- io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
+ result->default_value_float_ = io::SafeDoubleToFloat(
+ io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos));
}
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
@@ -4370,6 +4449,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
AllocateOptions(proto.options(), result);
}
+
AddSymbol(result->full_name(), parent, result->name(),
proto, Symbol(result));
}
@@ -5040,6 +5120,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 +5161,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<string, const FieldDescriptor*> 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(
@@ -5449,11 +5562,19 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions(
// UnknownFieldSet and wait there until the message is parsed by something
// that does know about the options.
string buf;
- options->AppendToString(&buf);
- GOOGLE_CHECK(options->ParseFromString(buf))
+ GOOGLE_CHECK(options->AppendPartialToString(&buf))
+ << "Protocol message could not be serialized.";
+ GOOGLE_CHECK(options->ParsePartialFromString(buf))
<< "Protocol message serialized itself in invalid fashion.";
+ if (!options->IsInitialized()) {
+ builder_->AddWarning(
+ options_to_interpret->element_name, *original_options,
+ DescriptorPool::ErrorCollector::OTHER,
+ "Options could not be fully parsed using the proto descriptors "
+ "compiled into this binary. Missing required fields: " +
+ options->InitializationErrorString());
+ }
}
-
return !failed;
}
@@ -5602,7 +5723,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
// First set the value on the UnknownFieldSet corresponding to the
// innermost message.
- scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
+ google::protobuf::scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
if (!SetOptionValue(field, unknown_fields.get())) {
return false; // SetOptionValue() already added the error.
}
@@ -5612,7 +5733,8 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
for (vector<const FieldDescriptor*>::reverse_iterator iter =
intermediate_fields.rbegin();
iter != intermediate_fields.rend(); ++iter) {
- scoped_ptr<UnknownFieldSet> parent_unknown_fields(new UnknownFieldSet());
+ google::protobuf::scoped_ptr<UnknownFieldSet> parent_unknown_fields(
+ new UnknownFieldSet());
switch ((*iter)->type()) {
case FieldDescriptor::TYPE_MESSAGE: {
io::StringOutputStream outstr(
@@ -5998,7 +6120,7 @@ bool DescriptorBuilder::OptionInterpreter::SetAggregateOption(
}
const Descriptor* type = option_field->message_type();
- scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
+ google::protobuf::scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
GOOGLE_CHECK(dynamic.get() != NULL)
<< "Could not create an instance of " << option_field->DebugString();
@@ -6106,7 +6228,8 @@ void DescriptorBuilder::OptionInterpreter::SetUInt64(int number, uint64 value,
}
}
-void DescriptorBuilder::LogUnusedDependency(const FileDescriptor* result) {
+void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto,
+ const FileDescriptor* result) {
if (!unused_dependency_.empty()) {
std::set<string> annotation_extensions;
@@ -6132,9 +6255,9 @@ void DescriptorBuilder::LogUnusedDependency(const FileDescriptor* result) {
}
// Log warnings for unused imported files.
if (i == (*it)->extension_count()) {
- GOOGLE_LOG(WARNING) << "Warning: Unused import: \"" << result->name()
- << "\" imports \"" << (*it)->name()
- << "\" which is not used.";
+ string error_message = "Import " + (*it)->name() + " but not used.";
+ AddWarning((*it)->name(), proto, DescriptorPool::ErrorCollector::OTHER,
+ error_message);
}
}
}
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 <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <set>
#include <string>
#include <vector>
@@ -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> tables_;
+ google::protobuf::scoped_ptr<Tables> 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..eda6280f 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/descriptor.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/descriptor.pb.h"
+#include <google/protobuf/descriptor.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -200,7 +201,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 +210,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 +665,102 @@ 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"
+ "BX\n\023com.google.protobufB\020DescriptorProto"
+ "sH\001Z\ndescriptor\242\002\003GPB\252\002\032Google.Protobuf."
+ "Reflection", 5010);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
FileDescriptorSet::default_instance_ = new FileDescriptorSet();
@@ -826,9 +829,9 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int FileDescriptorSet::kFileFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
FileDescriptorSet::FileDescriptorSet()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1093,7 +1096,7 @@ FileDescriptorSet::file() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int FileDescriptorProto::kNameFieldNumber;
const int FileDescriptorProto::kPackageFieldNumber;
const int FileDescriptorProto::kDependencyFieldNumber;
@@ -1106,7 +1109,7 @@ const int FileDescriptorProto::kExtensionFieldNumber;
const int FileDescriptorProto::kOptionsFieldNumber;
const int FileDescriptorProto::kSourceCodeInfoFieldNumber;
const int FileDescriptorProto::kSyntaxFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
FileDescriptorProto::FileDescriptorProto()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2347,10 +2350,10 @@ void FileDescriptorProto::clear_syntax() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int DescriptorProto_ExtensionRange::kStartFieldNumber;
const int DescriptorProto_ExtensionRange::kEndFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2630,10 +2633,10 @@ void DescriptorProto_ExtensionRange::InternalSwap(DescriptorProto_ExtensionRange
// -------------------------------------------------------------------
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int DescriptorProto_ReservedRange::kStartFieldNumber;
const int DescriptorProto_ReservedRange::kEndFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
DescriptorProto_ReservedRange::DescriptorProto_ReservedRange()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2913,7 +2916,7 @@ void DescriptorProto_ReservedRange::InternalSwap(DescriptorProto_ReservedRange*
// -------------------------------------------------------------------
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int DescriptorProto::kNameFieldNumber;
const int DescriptorProto::kFieldFieldNumber;
const int DescriptorProto::kExtensionFieldNumber;
@@ -2924,7 +2927,7 @@ const int DescriptorProto::kOneofDeclFieldNumber;
const int DescriptorProto::kOptionsFieldNumber;
const int DescriptorProto::kReservedRangeFieldNumber;
const int DescriptorProto::kReservedNameFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
DescriptorProto::DescriptorProto()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -4054,7 +4057,7 @@ bool FieldDescriptorProto_Type_IsValid(int value) {
}
}
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE;
const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT;
const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64;
@@ -4076,7 +4079,7 @@ const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64;
const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN;
const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX;
const int FieldDescriptorProto::Type_ARRAYSIZE;
-#endif // _MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() {
protobuf_AssignDescriptorsOnce();
return FieldDescriptorProto_Label_descriptor_;
@@ -4092,15 +4095,15 @@ bool FieldDescriptorProto_Label_IsValid(int value) {
}
}
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL;
const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED;
const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED;
const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN;
const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX;
const int FieldDescriptorProto::Label_ARRAYSIZE;
-#endif // _MSC_VER
-#ifndef _MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int FieldDescriptorProto::kNameFieldNumber;
const int FieldDescriptorProto::kNumberFieldNumber;
const int FieldDescriptorProto::kLabelFieldNumber;
@@ -4109,8 +4112,9 @@ 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
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
FieldDescriptorProto::FieldDescriptorProto()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -4141,6 +4145,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 +4160,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 +4210,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 +4380,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 +4494,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 +4587,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 +4665,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 +4737,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 +4783,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 +5111,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<const char*>(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();
@@ -5095,9 +5211,9 @@ void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOption
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int OneofDescriptorProto::kNameFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
OneofDescriptorProto::OneofDescriptorProto()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -5401,11 +5517,11 @@ void OneofDescriptorProto::clear_name() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int EnumDescriptorProto::kNameFieldNumber;
const int EnumDescriptorProto::kValueFieldNumber;
const int EnumDescriptorProto::kOptionsFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
EnumDescriptorProto::EnumDescriptorProto()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -5874,11 +5990,11 @@ void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions*
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int EnumValueDescriptorProto::kNameFieldNumber;
const int EnumValueDescriptorProto::kNumberFieldNumber;
const int EnumValueDescriptorProto::kOptionsFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
EnumValueDescriptorProto::EnumValueDescriptorProto()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -6337,11 +6453,11 @@ void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumVal
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int ServiceDescriptorProto::kNameFieldNumber;
const int ServiceDescriptorProto::kMethodFieldNumber;
const int ServiceDescriptorProto::kOptionsFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
ServiceDescriptorProto::ServiceDescriptorProto()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -6810,14 +6926,14 @@ void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOp
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int MethodDescriptorProto::kNameFieldNumber;
const int MethodDescriptorProto::kInputTypeFieldNumber;
const int MethodDescriptorProto::kOutputTypeFieldNumber;
const int MethodDescriptorProto::kOptionsFieldNumber;
const int MethodDescriptorProto::kClientStreamingFieldNumber;
const int MethodDescriptorProto::kServerStreamingFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
MethodDescriptorProto::MethodDescriptorProto()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -7576,15 +7692,15 @@ bool FileOptions_OptimizeMode_IsValid(int value) {
}
}
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const FileOptions_OptimizeMode FileOptions::SPEED;
const FileOptions_OptimizeMode FileOptions::CODE_SIZE;
const FileOptions_OptimizeMode FileOptions::LITE_RUNTIME;
const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN;
const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX;
const int FileOptions::OptimizeMode_ARRAYSIZE;
-#endif // _MSC_VER
-#ifndef _MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int FileOptions::kJavaPackageFieldNumber;
const int FileOptions::kJavaOuterClassnameFieldNumber;
const int FileOptions::kJavaMultipleFilesFieldNumber;
@@ -7601,7 +7717,7 @@ const int FileOptions::kObjcClassPrefixFieldNumber;
const int FileOptions::kCsharpNamespaceFieldNumber;
const int FileOptions::kJavananoUseDeprecatedPackageFieldNumber;
const int FileOptions::kUninterpretedOptionFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
FileOptions::FileOptions()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -9052,13 +9168,13 @@ FileOptions::uninterpreted_option() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int MessageOptions::kMessageSetWireFormatFieldNumber;
const int MessageOptions::kNoStandardDescriptorAccessorFieldNumber;
const int MessageOptions::kDeprecatedFieldNumber;
const int MessageOptions::kMapEntryFieldNumber;
const int MessageOptions::kUninterpretedOptionFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
MessageOptions::MessageOptions()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -9610,14 +9726,14 @@ bool FieldOptions_CType_IsValid(int value) {
}
}
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const FieldOptions_CType FieldOptions::STRING;
const FieldOptions_CType FieldOptions::CORD;
const FieldOptions_CType FieldOptions::STRING_PIECE;
const FieldOptions_CType FieldOptions::CType_MIN;
const FieldOptions_CType FieldOptions::CType_MAX;
const int FieldOptions::CType_ARRAYSIZE;
-#endif // _MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor() {
protobuf_AssignDescriptorsOnce();
return FieldOptions_JSType_descriptor_;
@@ -9633,15 +9749,15 @@ bool FieldOptions_JSType_IsValid(int value) {
}
}
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const FieldOptions_JSType FieldOptions::JS_NORMAL;
const FieldOptions_JSType FieldOptions::JS_STRING;
const FieldOptions_JSType FieldOptions::JS_NUMBER;
const FieldOptions_JSType FieldOptions::JSType_MIN;
const FieldOptions_JSType FieldOptions::JSType_MAX;
const int FieldOptions::JSType_ARRAYSIZE;
-#endif // _MSC_VER
-#ifndef _MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int FieldOptions::kCtypeFieldNumber;
const int FieldOptions::kPackedFieldNumber;
const int FieldOptions::kJstypeFieldNumber;
@@ -9649,7 +9765,7 @@ const int FieldOptions::kLazyFieldNumber;
const int FieldOptions::kDeprecatedFieldNumber;
const int FieldOptions::kWeakFieldNumber;
const int FieldOptions::kUninterpretedOptionFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
FieldOptions::FieldOptions()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -10325,11 +10441,11 @@ FieldOptions::uninterpreted_option() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int EnumOptions::kAllowAliasFieldNumber;
const int EnumOptions::kDeprecatedFieldNumber;
const int EnumOptions::kUninterpretedOptionFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
EnumOptions::EnumOptions()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -10748,10 +10864,10 @@ EnumOptions::uninterpreted_option() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int EnumValueOptions::kDeprecatedFieldNumber;
const int EnumValueOptions::kUninterpretedOptionFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
EnumValueOptions::EnumValueOptions()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -11097,10 +11213,10 @@ EnumValueOptions::uninterpreted_option() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int ServiceOptions::kDeprecatedFieldNumber;
const int ServiceOptions::kUninterpretedOptionFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
ServiceOptions::ServiceOptions()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -11446,10 +11562,10 @@ ServiceOptions::uninterpreted_option() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int MethodOptions::kDeprecatedFieldNumber;
const int MethodOptions::kUninterpretedOptionFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
MethodOptions::MethodOptions()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -11795,10 +11911,10 @@ MethodOptions::uninterpreted_option() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int UninterpretedOption_NamePart::kNamePartFieldNumber;
const int UninterpretedOption_NamePart::kIsExtensionFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
UninterpretedOption_NamePart::UninterpretedOption_NamePart()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -12101,7 +12217,7 @@ void UninterpretedOption_NamePart::InternalSwap(UninterpretedOption_NamePart* ot
// -------------------------------------------------------------------
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int UninterpretedOption::kNameFieldNumber;
const int UninterpretedOption::kIdentifierValueFieldNumber;
const int UninterpretedOption::kPositiveIntValueFieldNumber;
@@ -12109,7 +12225,7 @@ const int UninterpretedOption::kNegativeIntValueFieldNumber;
const int UninterpretedOption::kDoubleValueFieldNumber;
const int UninterpretedOption::kStringValueFieldNumber;
const int UninterpretedOption::kAggregateValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
UninterpretedOption::UninterpretedOption()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -12968,13 +13084,13 @@ void UninterpretedOption::clear_aggregate_value() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int SourceCodeInfo_Location::kPathFieldNumber;
const int SourceCodeInfo_Location::kSpanFieldNumber;
const int SourceCodeInfo_Location::kLeadingCommentsFieldNumber;
const int SourceCodeInfo_Location::kTrailingCommentsFieldNumber;
const int SourceCodeInfo_Location::kLeadingDetachedCommentsFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
SourceCodeInfo_Location::SourceCodeInfo_Location()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -13453,9 +13569,9 @@ void SourceCodeInfo_Location::InternalSwap(SourceCodeInfo_Location* other) {
// -------------------------------------------------------------------
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int SourceCodeInfo::kLocationFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
SourceCodeInfo::SourceCodeInfo()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
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<const char*>(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..c59a6022 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -43,8 +43,7 @@ package google.protobuf;
option go_package = "descriptor";
option java_package = "com.google.protobuf";
option java_outer_classname = "DescriptorProtos";
-// Re-enable this once the tools have picked up the csharp_namespace option.
-// option csharp_namespace = "Google.ProtocolBuffers.DescriptorProtos";
+option csharp_namespace = "Google.Protobuf.Reflection";
option objc_class_prefix = "GPB";
// descriptor.proto must be optimized for speed because reflection-based
@@ -191,6 +190,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 <algorithm>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <google/protobuf/descriptor_database.h>
#include <google/protobuf/descriptor.h>
@@ -177,7 +181,7 @@ class DescriptorDatabaseTest
EXPECT_FALSE(test_case_->AddToDatabase(file_proto));
}
- scoped_ptr<DescriptorDatabaseTestCase> test_case_;
+ google::protobuf::scoped_ptr<DescriptorDatabaseTestCase> test_case_;
DescriptorDatabase* database_;
};
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index e9b027db..be8e0b72 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 <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <vector>
#include <google/protobuf/compiler/importer.h>
@@ -174,6 +178,61 @@ void AddEmptyEnum(FileDescriptorProto* file, const string& name) {
AddEnumValue(AddEnum(file, name), name + "_DUMMY", 1);
}
+class MockErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+ MockErrorCollector() {}
+ ~MockErrorCollector() {}
+
+ string text_;
+ string warning_text_;
+
+ // implements ErrorCollector ---------------------------------------
+ void AddError(const string& filename,
+ const string& element_name, const Message* descriptor,
+ ErrorLocation location, const string& message) {
+ const char* location_name = NULL;
+ switch (location) {
+ case NAME : location_name = "NAME" ; break;
+ case NUMBER : location_name = "NUMBER" ; break;
+ case TYPE : location_name = "TYPE" ; break;
+ case EXTENDEE : location_name = "EXTENDEE" ; break;
+ case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
+ case OPTION_NAME : location_name = "OPTION_NAME" ; break;
+ case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
+ case INPUT_TYPE : location_name = "INPUT_TYPE" ; break;
+ case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break;
+ case OTHER : location_name = "OTHER" ; break;
+ }
+
+ strings::SubstituteAndAppend(
+ &text_, "$0: $1: $2: $3\n",
+ filename, element_name, location_name, message);
+ }
+
+ // implements ErrorCollector ---------------------------------------
+ void AddWarning(const string& filename, const string& element_name,
+ const Message* descriptor, ErrorLocation location,
+ const string& message) {
+ const char* location_name = NULL;
+ switch (location) {
+ case NAME : location_name = "NAME" ; break;
+ case NUMBER : location_name = "NUMBER" ; break;
+ case TYPE : location_name = "TYPE" ; break;
+ case EXTENDEE : location_name = "EXTENDEE" ; break;
+ case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
+ case OPTION_NAME : location_name = "OPTION_NAME" ; break;
+ case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
+ case INPUT_TYPE : location_name = "INPUT_TYPE" ; break;
+ case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break;
+ case OTHER : location_name = "OTHER" ; break;
+ }
+
+ strings::SubstituteAndAppend(
+ &warning_text_, "$0: $1: $2: $3\n",
+ filename, element_name, location_name, message);
+ }
+};
+
// ===================================================================
// Test simple files.
@@ -461,6 +520,16 @@ class DescriptorTest : public testing::Test {
// map<int32, int32> 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 +595,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 +629,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 +658,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 +673,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 +770,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 +2035,7 @@ class MiscTest : public testing::Test {
return field != NULL ? field->enum_type() : NULL;
}
- scoped_ptr<DescriptorPool> pool_;
+ google::protobuf::scoped_ptr<DescriptorPool> pool_;
};
TEST_F(MiscTest, TypeNames) {
@@ -2330,7 +2465,7 @@ class AllowUnknownDependenciesTest
const FieldDescriptor* qux_field_;
SimpleDescriptorDatabase db_; // used if in FALLBACK_DATABASE mode.
- scoped_ptr<DescriptorPool> pool_;
+ google::protobuf::scoped_ptr<DescriptorPool> pool_;
};
TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
@@ -3040,77 +3175,95 @@ TEST(CustomOptions, UnusedImportWarning) {
->file()->CopyTo(&file_proto);
ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
-
pool.AddUnusedImportTrackFile("custom_options_import.proto");
ASSERT_TRUE(TextFormat::ParseFromString(
"name: \"custom_options_import.proto\" "
"package: \"protobuf_unittest\" "
"dependency: \"google/protobuf/unittest_custom_options.proto\" ",
&file_proto));
- pool.BuildFile(file_proto);
-}
-// ===================================================================
+ MockErrorCollector error_collector;
+ EXPECT_TRUE(pool.BuildFileCollectingErrors(file_proto, &error_collector));
+ EXPECT_EQ("", error_collector.warning_text_);
+}
-// The tests below trigger every unique call to AddError() in descriptor.cc,
-// in the order in which they appear in that file. I'm using TextFormat here
-// to specify the input descriptors because building them using code would
-// be too bulky.
+// Verifies that proto files can correctly be parsed, even if the
+// custom options defined in the file are incompatible with those
+// compiled in the binary. See http://b/19276250.
+TEST(CustomOptions, OptionsWithRequiredEnums) {
+ DescriptorPool pool;
-class MockErrorCollector : public DescriptorPool::ErrorCollector {
- public:
- MockErrorCollector() {}
- ~MockErrorCollector() {}
+ FileDescriptorProto file_proto;
+ MessageOptions::descriptor()->file()->CopyTo(&file_proto);
+ ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
- string text_;
- string warning_text_;
+ // Create a new file descriptor proto containing a subset of the
+ // messages defined in google/protobuf/unittest_custom_options.proto.
+ file_proto.Clear();
+ file_proto.set_name("unittest_custom_options.proto");
+ file_proto.set_package("protobuf_unittest");
+ file_proto.add_dependency("google/protobuf/descriptor.proto");
- // implements ErrorCollector ---------------------------------------
- void AddError(const string& filename,
- const string& element_name, const Message* descriptor,
- ErrorLocation location, const string& message) {
- const char* location_name = NULL;
- switch (location) {
- case NAME : location_name = "NAME" ; break;
- case NUMBER : location_name = "NUMBER" ; break;
- case TYPE : location_name = "TYPE" ; break;
- case EXTENDEE : location_name = "EXTENDEE" ; break;
- case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
- case OPTION_NAME : location_name = "OPTION_NAME" ; break;
- case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
- case INPUT_TYPE : location_name = "INPUT_TYPE" ; break;
- case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break;
- case OTHER : location_name = "OTHER" ; break;
- }
+ // Add the "required_enum_opt" extension.
+ FieldDescriptorProto* extension = file_proto.add_extension();
+ protobuf_unittest::OldOptionType::descriptor()->file()
+ ->FindExtensionByName("required_enum_opt")->CopyTo(extension);
+
+ // Add a test message that uses the "required_enum_opt" option.
+ DescriptorProto* test_message_type = file_proto.add_message_type();
+ protobuf_unittest::TestMessageWithRequiredEnumOption::descriptor()
+ ->CopyTo(test_message_type);
+
+ // Instruct the extension to use NewOptionType instead of
+ // OldOptionType, and add the descriptor of NewOptionType.
+ extension->set_type_name(".protobuf_unittest.NewOptionType");
+ DescriptorProto* new_option_type = file_proto.add_message_type();
+ protobuf_unittest::NewOptionType::descriptor()
+ ->CopyTo(new_option_type);
+
+ // Replace the value of the "required_enum_opt" option used in the
+ // test message with an enum value that only exists in NewOptionType.
+ ASSERT_TRUE(TextFormat::ParseFromString(
+ "uninterpreted_option { "
+ " name { "
+ " name_part: 'required_enum_opt' "
+ " is_extension: true "
+ " } "
+ " aggregate_value: 'value: NEW_VALUE' "
+ "}",
+ test_message_type->mutable_options()));
- strings::SubstituteAndAppend(
- &text_, "$0: $1: $2: $3\n",
- filename, element_name, location_name, message);
- }
+ // Add the file descriptor to the pool.
+ ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
- // implements ErrorCollector ---------------------------------------
- void AddWarning(const string& filename, const string& element_name,
- const Message* descriptor, ErrorLocation location,
- const string& message) {
- const char* location_name = NULL;
- switch (location) {
- case NAME : location_name = "NAME" ; break;
- case NUMBER : location_name = "NUMBER" ; break;
- case TYPE : location_name = "TYPE" ; break;
- case EXTENDEE : location_name = "EXTENDEE" ; break;
- case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
- case OPTION_NAME : location_name = "OPTION_NAME" ; break;
- case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
- case INPUT_TYPE : location_name = "INPUT_TYPE" ; break;
- case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break;
- case OTHER : location_name = "OTHER" ; break;
- }
+ // Find the test message.
+ const Descriptor* test_message = pool.FindMessageTypeByName(
+ "protobuf_unittest.TestMessageWithRequiredEnumOption");
+ ASSERT_TRUE(test_message != NULL);
+
+ const MessageOptions& options = test_message->options();
+ // Extract the "required_enum_opt" option. Since the binary does not
+ // know that the extension was updated, this will still return an
+ // OldOptionType message.
+ ASSERT_TRUE(
+ options.HasExtension(protobuf_unittest::required_enum_opt));
+ const protobuf_unittest::OldOptionType& old_enum_opt =
+ options.GetExtension(protobuf_unittest::required_enum_opt);
+
+ // Confirm that the required enum field is missing.
+ EXPECT_FALSE(old_enum_opt.IsInitialized());
+ EXPECT_FALSE(old_enum_opt.has_value());
+
+ string buf;
+ // Verify that the required enum field does show up when the option
+ // is re-parsed as a NewOptionType message;
+ protobuf_unittest::NewOptionType new_enum_opt;
+ EXPECT_TRUE(old_enum_opt.AppendPartialToString(&buf));
+ EXPECT_TRUE(new_enum_opt.ParseFromString(buf));
+ EXPECT_EQ(protobuf_unittest::NewOptionType::NEW_VALUE, new_enum_opt.value());
+}
- strings::SubstituteAndAppend(
- &warning_text_, "$0: $1: $2: $3\n",
- filename, element_name, location_name, message);
- }
-};
+// ===================================================================
class ValidationErrorTest : public testing::Test {
protected:
@@ -5043,7 +5196,6 @@ TEST_F(ValidationErrorTest, AllowEnumAlias) {
}
TEST_F(ValidationErrorTest, UnusedImportWarning) {
-
pool_.AddUnusedImportTrackFile("bar.proto");
BuildFile(
"name: \"bar.proto\" "
@@ -5075,7 +5227,7 @@ TEST_F(ValidationErrorTest, UnusedImportWarning) {
// }
//
pool_.AddUnusedImportTrackFile("forward.proto");
- BuildFile(
+ BuildFileWithWarnings(
"name: \"forward.proto\""
"dependency: \"base.proto\""
"dependency: \"bar.proto\""
@@ -5085,7 +5237,8 @@ TEST_F(ValidationErrorTest, UnusedImportWarning) {
"message_type {"
" name: \"Forward\""
" field { name:\"base\" number:1 label:LABEL_OPTIONAL type_name:\"Base\" }"
- "}");
+ "}",
+ "forward.proto: bar.proto: OTHER: Import bar.proto but not used.\n");
}
namespace {
@@ -5681,6 +5834,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/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index 2e22ccb1..b325944e 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/duration.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/duration.pb.h"
+#include <google/protobuf/duration.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -111,10 +112,10 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Duration::kSecondsFieldNumber;
const int Duration::kNanosFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Duration::Duration()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto
index 7f172aa6..78bcc74b 100644
--- a/src/google/protobuf/duration.proto
+++ b/src/google/protobuf/duration.proto
@@ -27,15 +27,16 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package google.protobuf;
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "DurationProto";
-option java_package = "com.google.protobuf";
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DurationProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
option objc_class_prefix = "GPB";
// A Duration represents a signed, fixed-length span of time represented
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index 2324d952..bb400476 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -64,9 +64,13 @@
#include <algorithm>
#include <google/protobuf/stubs/hash.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
-#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/descriptor.h>
@@ -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<int> offsets;
- scoped_ptr<const GeneratedMessageReflection> reflection;
+ google::protobuf::scoped_array<int> offsets;
+ google::protobuf::scoped_ptr<const GeneratedMessageReflection> 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 <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/dynamic_message.h>
@@ -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> message(prototype_->New());
+ google::protobuf::scoped_ptr<Message> 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> message(extensions_prototype_->New());
+ google::protobuf::scoped_ptr<Message> 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> message(packed_prototype_->New());
+ google::protobuf::scoped_ptr<Message> 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> message(oneof_prototype_->New());
+ google::protobuf::scoped_ptr<Message> 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> message(prototype_->New());
+ google::protobuf::scoped_ptr<Message> message(prototype_->New());
TestUtil::ReflectionTester reflection_tester(descriptor_);
int initial_space_used = message->SpaceUsed();
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 50cbd9a8..f2eec782 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/empty.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/empty.pb.h"
+#include <google/protobuf/empty.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -79,9 +80,9 @@ void protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto() {
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
"\n\033google/protobuf/empty.proto\022\017google.pr"
- "otobuf\"\007\n\005EmptyBM\n\023com.google.protobufB\n"
- "EmptyProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protobuf."
- "WellKnownTypesb\006proto3", 142);
+ "otobuf\"\007\n\005EmptyBP\n\023com.google.protobufB\n"
+ "EmptyProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Protob"
+ "uf.WellKnownTypesb\006proto3", 145);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/empty.proto", &protobuf_RegisterTypes);
Empty::default_instance_ = new Empty();
@@ -108,8 +109,8 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
-#endif // !_MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Empty::Empty()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -117,6 +118,14 @@ Empty::Empty()
// @@protoc_insertion_point(constructor:google.protobuf.Empty)
}
+Empty::Empty(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.Empty)
+}
+
void Empty::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -140,10 +149,20 @@ Empty::~Empty() {
}
void Empty::SharedDtor() {
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
if (this != default_instance_) {
}
}
+void Empty::ArenaDtor(void* object) {
+ Empty* _this = reinterpret_cast< Empty* >(object);
+ (void)_this;
+}
+void Empty::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void Empty::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -162,11 +181,7 @@ const Empty& Empty::default_instance() {
Empty* Empty::default_instance_ = NULL;
Empty* Empty::New(::google::protobuf::Arena* arena) const {
- Empty* n = new Empty;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<Empty>(arena);
}
void Empty::Clear() {
@@ -255,6 +270,18 @@ bool Empty::IsInitialized() const {
void Empty::Swap(Empty* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ Empty temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void Empty::UnsafeArenaSwap(Empty* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void Empty::InternalSwap(Empty* other) {
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index 20876bea..868009fc 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -53,9 +53,14 @@ class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const Empty& default_instance();
+ void UnsafeArenaSwap(Empty* other);
void Swap(Empty* other);
// implements Message ----------------------------------------------
@@ -82,6 +87,11 @@ class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(Empty* other);
+ protected:
+ explicit Empty(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -101,6 +111,9 @@ class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message {
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
mutable int _cached_size_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto();
diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto
index 9dddc6c5..b96daf28 100644
--- a/src/google/protobuf/empty.proto
+++ b/src/google/protobuf/empty.proto
@@ -27,16 +27,18 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package google.protobuf;
-option java_multiple_files = true;
-option java_outer_classname = "EmptyProto";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option java_package = "com.google.protobuf";
+option java_outer_classname = "EmptyProto";
+option java_multiple_files = true;
option java_generate_equals_and_hash = true;
-option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option objc_class_prefix = "GPB";
+option cc_enable_arenas = true;
// A generic empty message that you can re-use to avoid defining duplicated
// empty messages in your APIs. A typical example is to use it as the request
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 <google/protobuf/stubs/hash.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/io/coded_stream.h>
@@ -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..bca179be 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_;
+LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_primitive_generic_type_traits_once_init_;
class LIBPROTOBUF_EXPORT RepeatedPrimitiveGenericTypeTraits {
private:
@@ -766,7 +765,7 @@ template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Add( \
} \
template<> inline const RepeatedField<TYPE>* \
RepeatedPrimitiveTypeTraits<TYPE>::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_;
+LIBPROTOBUF_EXPORT 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_;
+LIBPROTOBUF_EXPORT 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<typename Type> inline
const typename RepeatedMessageTypeTraits<Type>::RepeatedFieldType*
RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() {
- GoogleOnceInit(
+ ::google::protobuf::GoogleOnceInit(
&repeated_message_generic_type_traits_once_init_,
&RepeatedMessageGenericTypeTraits::InitializeDefaultRepeatedFields);
return reinterpret_cast<const RepeatedFieldType*>(
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/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index d8f4ee91..01a6ce56 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/field_mask.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/field_mask.pb.h"
+#include <google/protobuf/field_mask.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -110,9 +111,9 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int FieldMask::kPathsFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
FieldMask::FieldMask()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto
index 8b21c692..908c8a86 100644
--- a/src/google/protobuf/field_mask.proto
+++ b/src/google/protobuf/field_mask.proto
@@ -27,16 +27,17 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package google.protobuf;
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "FieldMaskProto";
-option java_package = "com.google.protobuf";
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "FieldMaskProto";
+option java_multiple_files = true;
option objc_class_prefix = "GPB";
+option java_generate_equals_and_hash = true;
// `FieldMask` represents a set of symbolic field paths, for example:
//
@@ -69,7 +70,7 @@ option objc_class_prefix = "GPB";
// z: 8
//
// The result will not contain specific values for fields x,y and z
-// (there value will be set to the default, and omitted in proto text
+// (their value will be set to the default, and omitted in proto text
// output):
//
//
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 <google/protobuf/generated_message_reflection.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
#include <google/protobuf/descriptor.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/unittest.pb.h>
@@ -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<Message> released(message.GetReflection()->ReleaseLast(
+ google::protobuf::scoped_ptr<Message> 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<Message> released(message.GetReflection()->ReleaseLast(
+ google::protobuf::scoped_ptr<Message> 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.cc b/src/google/protobuf/io/coded_stream.cc
index 4bcd354f..e3a34d0a 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -629,6 +629,24 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
had_error_ = false;
}
+CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output,
+ bool do_eager_refresh)
+ : output_(output),
+ buffer_(NULL),
+ buffer_size_(0),
+ total_bytes_(0),
+ had_error_(false),
+ aliasing_enabled_(false) {
+ if (do_eager_refresh) {
+ // Eagerly Refresh() so buffer space is immediately available.
+ Refresh();
+ // The Refresh() may have failed. If the client doesn't write any data,
+ // though, don't consider this an error. If the client does write data, then
+ // another Refresh() will be attempted and it will set the error once again.
+ had_error_ = false;
+ }
+}
+
CodedOutputStream::~CodedOutputStream() {
Trim();
}
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index 361c406b..020f20c7 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -109,6 +109,7 @@
#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
+#include <assert.h>
#include <string>
#include <utility>
#ifdef _MSC_VER
@@ -665,6 +666,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
public:
// Create an CodedOutputStream that writes to the given ZeroCopyOutputStream.
explicit CodedOutputStream(ZeroCopyOutputStream* output);
+ CodedOutputStream(ZeroCopyOutputStream* output, bool do_eager_refresh);
// Destroy the CodedOutputStream and position the underlying
// ZeroCopyOutputStream immediately after the last byte written.
@@ -1035,7 +1037,7 @@ inline const uint8* CodedInputStream::ExpectTagFromArray(
inline void CodedInputStream::GetDirectBufferPointerInline(const void** data,
int* size) {
*data = buffer_;
- *size = buffer_end_ - buffer_;
+ *size = static_cast<int>(buffer_end_ - buffer_);
}
inline bool CodedInputStream::ExpectAtEnd() {
@@ -1231,7 +1233,7 @@ inline MessageFactory* CodedInputStream::GetExtensionFactory() {
}
inline int CodedInputStream::BufferSize() const {
- return buffer_end_ - buffer_;
+ return static_cast<int>(buffer_end_ - buffer_);
}
inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
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 <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <vector>
#include <google/protobuf/io/coded_stream.h>
@@ -679,7 +683,7 @@ TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnStack) {
}
TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) {
- scoped_array<uint8> buffer(new uint8[8]);
+ google::protobuf::scoped_array<uint8> 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/strtod.cc b/src/google/protobuf/io/strtod.cc
index 579de9aa..a90bb9a3 100644
--- a/src/google/protobuf/io/strtod.cc
+++ b/src/google/protobuf/io/strtod.cc
@@ -32,6 +32,7 @@
#include <cstdio>
#include <cstring>
+#include <limits>
#include <string>
#include <google/protobuf/stubs/logging.h>
@@ -109,6 +110,16 @@ double NoLocaleStrtod(const char* text, char** original_endptr) {
return result;
}
+float SafeDoubleToFloat(double value) {
+ if (value > std::numeric_limits<float>::max()) {
+ return std::numeric_limits<float>::infinity();
+ } else if (value < -std::numeric_limits<float>::max()) {
+ return -std::numeric_limits<float>::infinity();
+ } else {
+ return static_cast<float>(value);
+ }
+}
+
} // namespace io
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/io/strtod.h b/src/google/protobuf/io/strtod.h
index c2efc8d3..f56e41c8 100644
--- a/src/google/protobuf/io/strtod.h
+++ b/src/google/protobuf/io/strtod.h
@@ -43,6 +43,11 @@ namespace io {
// uses a dot as the decimal separator.
double NoLocaleStrtod(const char* str, char** endptr);
+// Casts a double value to a float value. If the value is outside of the
+// representable range of float, it will be converted to positive or negative
+// infinity.
+float SafeDoubleToFloat(double value);
+
} // namespace io
} // namespace protobuf
diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc
index 7ccd633d..3d57707c 100644
--- a/src/google/protobuf/io/tokenizer.cc
+++ b/src/google/protobuf/io/tokenizer.cc
@@ -375,7 +375,7 @@ void Tokenizer::ConsumeString(char delimiter) {
// Possibly followed by two more octal digits, but these will
// just be consumed by the main loop anyway so we don't need
// to do so explicitly here.
- } else if (TryConsume('x') || TryConsume('X')) {
+ } else if (TryConsume('x')) {
if (!TryConsumeOne<HexDigit>()) {
AddError("Expected hex digits for escape sequence.");
}
diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc
index 6526056a..20d50a2c 100644
--- a/src/google/protobuf/io/tokenizer_unittest.cc
+++ b/src/google/protobuf/io/tokenizer_unittest.cc
@@ -875,6 +875,8 @@ ErrorCase kErrorCases[] = {
// String errors.
{ "'\\l' foo", true,
"0:2: Invalid escape sequence in string literal.\n" },
+ { "'\\X' foo", true,
+ "0:2: Invalid escape sequence in string literal.\n" },
{ "'\\x' foo", true,
"0:3: Expected hex digits for escape sequence.\n" },
{ "'foo", false,
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
index 686e63f2..083beca4 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -157,6 +157,7 @@ StringOutputStream::~StringOutputStream() {
}
bool StringOutputStream::Next(void** data, int* size) {
+ GOOGLE_CHECK_NE(NULL, target_);
int old_size = target_->size();
// Grow the string.
@@ -188,14 +189,44 @@ bool StringOutputStream::Next(void** data, int* size) {
void StringOutputStream::BackUp(int count) {
GOOGLE_CHECK_GE(count, 0);
+ GOOGLE_CHECK_NE(NULL, target_);
GOOGLE_CHECK_LE(count, target_->size());
target_->resize(target_->size() - count);
}
int64 StringOutputStream::ByteCount() const {
+ GOOGLE_CHECK_NE(NULL, target_);
return target_->size();
}
+void StringOutputStream::SetString(string* target) {
+ target_ = target;
+}
+
+// ===================================================================
+
+LazyStringOutputStream::LazyStringOutputStream(
+ ResultCallback<string*>* callback)
+ : StringOutputStream(NULL),
+ callback_(GOOGLE_CHECK_NOTNULL(callback)),
+ string_is_set_(false) {
+}
+
+LazyStringOutputStream::~LazyStringOutputStream() {
+}
+
+bool LazyStringOutputStream::Next(void** data, int* size) {
+ if (!string_is_set_) {
+ SetString(callback_->Run());
+ string_is_set_ = true;
+ }
+ return StringOutputStream::Next(data, size);
+}
+
+int64 LazyStringOutputStream::ByteCount() const {
+ return string_is_set_ ? StringOutputStream::ByteCount() : 0;
+}
+
// ===================================================================
CopyingInputStream::~CopyingInputStream() {}
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..1c397dea 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 <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
#include <iosfwd>
#include <google/protobuf/io/zero_copy_stream.h>
@@ -144,6 +148,9 @@ class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
void BackUp(int count);
int64 ByteCount() const;
+ protected:
+ void SetString(string* target);
+
private:
static const int kMinimumSize = 16;
@@ -152,6 +159,27 @@ class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
};
+// LazyStringOutputStream is a StringOutputStream with lazy acquisition of
+// the output string from a callback. The string is owned externally, and not
+// deleted in the stream destructor.
+class LIBPROTOBUF_EXPORT LazyStringOutputStream : public StringOutputStream {
+ public:
+ // Callback should be permanent (non-self-deleting). Ownership is transferred
+ // to the LazyStringOutputStream.
+ explicit LazyStringOutputStream(ResultCallback<string*>* callback);
+ ~LazyStringOutputStream();
+
+ // implements ZeroCopyOutputStream, overriding StringOutputStream -----------
+ bool Next(void** data, int* size);
+ int64 ByteCount() const;
+
+ private:
+ const scoped_ptr<ResultCallback<string*> > callback_;
+ bool string_is_set_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyStringOutputStream);
+};
+
// Note: There is no StringInputStream. Instead, just create an
// ArrayInputStream as follows:
// ArrayInputStream input(str.data(), str.size());
@@ -235,7 +263,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<uint8> buffer_;
+ google::protobuf::scoped_array<uint8> buffer_;
const int buffer_size_;
// Number of valid bytes currently in the buffer (i.e. the size last
@@ -324,7 +352,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<uint8> buffer_;
+ google::protobuf::scoped_array<uint8> 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 <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <sstream>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -197,7 +201,7 @@ void IoTest::WriteString(ZeroCopyOutputStream* output, const string& str) {
}
void IoTest::ReadString(ZeroCopyInputStream* input, const string& str) {
- scoped_array<char> buffer(new char[str.size() + 1]);
+ google::protobuf::scoped_array<char> 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.h b/src/google/protobuf/map.h
index 8b61573d..dfc62420 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -155,7 +155,7 @@ class LIBPROTOBUF_EXPORT MapKey {
"MapKey::GetUInt32Value");
return val_.uint32_value_;
}
- int32 GetBoolValue() const {
+ bool GetBoolValue() const {
TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL,
"MapKey::GetBoolValue");
return val_.bool_value_;
@@ -188,8 +188,9 @@ class LIBPROTOBUF_EXPORT MapKey {
case FieldDescriptor::CPPTYPE_ENUM:
case FieldDescriptor::CPPTYPE_MESSAGE:
GOOGLE_LOG(FATAL) << "Can't get here.";
- return false;
}
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return false;
}
void CopyFrom(const MapKey& other) {
@@ -273,7 +274,7 @@ class LIBPROTOBUF_EXPORT MapValueRef {
"MapValueRef::SetInt32Value");
*reinterpret_cast<int32*>(data_) = value;
}
- void SetUInt32Value(uint64 value) {
+ void SetUInt32Value(uint32 value) {
TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32,
"MapValueRef::SetUInt32Value");
*reinterpret_cast<uint32*>(data_) = value;
@@ -495,7 +496,7 @@ class Map {
insert(other.begin(), other.end());
}
template <class InputIt>
- explicit Map(const InputIt& first, const InputIt& last)
+ Map(const InputIt& first, const InputIt& last)
: arena_(NULL),
allocator_(arena_),
elements_(0, hasher(), key_equal(), allocator_),
@@ -582,21 +583,22 @@ class Map {
private:
typedef void DestructorSkippable_;
- Arena* arena_;
+ Arena* const arena_;
template <typename X>
friend class MapAllocator;
};
- public:
typedef MapAllocator<std::pair<const Key, MapPair<Key, T>*> > Allocator;
+ typedef hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator>
+ InnerMap;
+ public:
// Iterators
class const_iterator
: public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t,
const value_type*, const value_type&> {
- typedef typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
- Allocator>::const_iterator InnerIt;
+ typedef typename InnerMap::const_iterator InnerIt;
public:
const_iterator() {}
@@ -623,8 +625,7 @@ class Map {
};
class iterator : public std::iterator<std::forward_iterator_tag, value_type> {
- typedef typename hash_map<Key, value_type*, hasher, equal_to<Key>,
- Allocator>::iterator InnerIt;
+ typedef typename InnerMap::iterator InnerIt;
public:
iterator() {}
@@ -740,8 +741,7 @@ class Map {
// Erase
size_type erase(const key_type& key) {
- typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
- Allocator>::iterator it = elements_.find(key);
+ typename InnerMap::iterator it = elements_.find(key);
if (it == elements_.end()) {
return 0;
} else {
@@ -811,7 +811,7 @@ class Map {
Arena* arena_;
Allocator allocator_;
- hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator> elements_;
+ InnerMap elements_;
int default_enum_value_;
friend class ::google::protobuf::Arena;
@@ -850,8 +850,9 @@ struct hash<google::protobuf::MapKey> {
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
GOOGLE_LOG(FATAL) << "Can't get here.";
- return 0;
}
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return 0;
}
bool
operator()(const google::protobuf::MapKey& map_key1,
@@ -873,8 +874,9 @@ struct hash<google::protobuf::MapKey> {
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
GOOGLE_LOG(FATAL) << "Can't get here.";
- return true;
}
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return true;
}
};
GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
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<Key, T>::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<FieldDescriptor::CppType>(that_iter.value_.type_));
SetMapIteratorValue(this_iter);
}
diff --git a/src/google/protobuf/map_lite_test_util.h b/src/google/protobuf/map_lite_test_util.h
index 77b5336f..66dedde5 100644
--- a/src/google/protobuf/map_lite_test_util.h
+++ b/src/google/protobuf/map_lite_test_util.h
@@ -47,7 +47,7 @@ class MapLiteTestUtil {
// Set every field in the message to a default value.
static void SetMapFieldsInitialized(protobuf_unittest::TestMapLite* message);
- // Modify all the map fields of the messsage (which should already have been
+ // Modify all the map fields of the message (which should already have been
// initialized with SetMapFields()).
static void ModifyMapFields(protobuf_unittest::TestMapLite* message);
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<int32, Proto2MapEnumPlusExtra> known_map_field = 101;
map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102;
}
+
+message TestImportEnumMap {
+ map<int32, protobuf_unittest_import.ImportEnumForMap> 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> message(map_prototype_->New());
+ google::protobuf::scoped_ptr<Message> 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> message(map_prototype_->New());
+ google::protobuf::scoped_ptr<Message> 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> message(map_prototype_->New());
+ google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
MapReflectionTester reflection_tester(map_descriptor_);
int initial_space_used = message->SpaceUsed();
diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h
index 107a639d..deaf0f4f 100644
--- a/src/google/protobuf/map_test_util.h
+++ b/src/google/protobuf/map_test_util.h
@@ -49,7 +49,7 @@ class MapTestUtil {
// Set every field in the message to a default value.
static void SetMapFieldsInitialized(unittest::TestMap* message);
- // Modify all the map fields of the messsage (which should already have been
+ // Modify all the map fields of the message (which should already have been
// initialized with SetMapFields()).
static void ModifyMapFields(unittest::TestMap* message);
diff --git a/src/google/protobuf/map_test_util_impl.h b/src/google/protobuf/map_test_util_impl.h
index 7e8757ed..b3ba4e06 100644
--- a/src/google/protobuf/map_test_util_impl.h
+++ b/src/google/protobuf/map_test_util_impl.h
@@ -64,7 +64,7 @@ class MapTestUtilImpl {
template <typename MapMessage>
static void SetMapFieldsInitialized(MapMessage* message);
- // Modify all the map fields of the messsage (which should already have been
+ // Modify all the map fields of the message (which should already have been
// initialized with SetMapFields()).
template <typename EnumType, EnumType enum_value, typename MapMessage>
static void ModifyMapFields(MapMessage* message);
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index 5040e605..f8ad7584 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -272,24 +272,24 @@ MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::ByteSize(
return WireFormatLite::MessageSizeNoVirtual(value);
}
-#define BYTE_SIZE(FieldType, DeclaredType) \
+#define GOOGLE_PROTOBUF_BYTE_SIZE(FieldType, DeclaredType) \
template <typename Type> \
inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \
const MapEntryAccessorType& value) { \
return WireFormatLite::DeclaredType##Size(value); \
}
-BYTE_SIZE(STRING, String)
-BYTE_SIZE(BYTES , Bytes)
-BYTE_SIZE(INT64 , Int64)
-BYTE_SIZE(UINT64, UInt64)
-BYTE_SIZE(INT32 , Int32)
-BYTE_SIZE(UINT32, UInt32)
-BYTE_SIZE(SINT64, SInt64)
-BYTE_SIZE(SINT32, SInt32)
-BYTE_SIZE(ENUM , Enum)
-
-#undef BYTE_SIZE
+GOOGLE_PROTOBUF_BYTE_SIZE(STRING, String)
+GOOGLE_PROTOBUF_BYTE_SIZE(BYTES , Bytes)
+GOOGLE_PROTOBUF_BYTE_SIZE(INT64 , Int64)
+GOOGLE_PROTOBUF_BYTE_SIZE(UINT64, UInt64)
+GOOGLE_PROTOBUF_BYTE_SIZE(INT32 , Int32)
+GOOGLE_PROTOBUF_BYTE_SIZE(UINT32, UInt32)
+GOOGLE_PROTOBUF_BYTE_SIZE(SINT64, SInt64)
+GOOGLE_PROTOBUF_BYTE_SIZE(SINT32, SInt32)
+GOOGLE_PROTOBUF_BYTE_SIZE(ENUM , Enum)
+
+#undef GOOGLE_PROTOBUF_BYTE_SIZE
#define FIXED_BYTE_SIZE(FieldType, DeclaredType) \
template <typename Type> \
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 2f6416d0..032748bd 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -55,7 +55,6 @@
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/singleton.h>
#include <google/protobuf/stubs/stl_util.h>
-#include <google/protobuf/stubs/port.h>
namespace google {
namespace protobuf {
@@ -495,11 +494,19 @@ Message* GenericTypeHandler<Message>::NewFromPrototype(
return prototype->New(arena);
}
template<>
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+GOOGLE_ATTRIBUTE_NOINLINE
+#endif
google::protobuf::Arena* GenericTypeHandler<Message>::GetArena(
Message* value) {
return value->GetArena();
}
template<>
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+GOOGLE_ATTRIBUTE_NOINLINE
+#endif
void* GenericTypeHandler<Message>::GetMaybeArenaPointer(
Message* value) {
return value->GetMaybeArenaPointer();
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/metadata.h b/src/google/protobuf/metadata.h
index fdee150b..219645d3 100644
--- a/src/google/protobuf/metadata.h
+++ b/src/google/protobuf/metadata.h
@@ -56,7 +56,7 @@ namespace internal {
// The tagged pointer uses the LSB to disambiguate cases, and uses bit 0 == 0 to
// indicate an arena pointer and bit 0 == 1 to indicate a UFS+Arena-container
// pointer.
-class LIBPROTOBUF_EXPORT InternalMetadataWithArena {
+class InternalMetadataWithArena {
public:
InternalMetadataWithArena() : ptr_(NULL) {}
explicit InternalMetadataWithArena(Arena* arena)
diff --git a/src/google/protobuf/proto_cast.h b/src/google/protobuf/proto_cast.h
deleted file mode 100644
index dc0e9aca..00000000
--- a/src/google/protobuf/proto_cast.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__
-#define GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__
-
-#include <string>
-
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
-
-// proto_cast<> is used to simulate over-the-wire conversion of one
-// proto message into another. This is primarily useful for unit tests
-// which validate the version-compatibility semantics of protobufs.
-// Usage is similar to C++-style typecasts:
-//
-// OldMessage old_message = /*...*/;
-// NewMessage new_message = proto_cast<NewMessage>(old_message);
-namespace google {
-template<typename NewProto,
- typename OldProto>
-NewProto proto_cast(const OldProto& old_proto) {
- string wire_format;
- GOOGLE_CHECK(old_proto.SerializeToString(&wire_format));
-
- NewProto new_proto;
- GOOGLE_CHECK(new_proto.ParseFromString(wire_format));
- return new_proto;
-}
-
-} // namespace google
-#endif // GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__
diff --git a/src/google/protobuf/proto_cast_test.cc b/src/google/protobuf/proto_cast_test.cc
deleted file mode 100644
index a8f43ae4..00000000
--- a/src/google/protobuf/proto_cast_test.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <google/protobuf/util/proto_cast.h>
-
-#include <google/protobuf/util/unknown_enum_test.pb.h>
-#include <gtest/gtest.h>
-#include <gmock/gmock.h>
-
-namespace google {
-using google::protobuf::util::UpRevision;
-using google::protobuf::util::DownRevision;
-
-namespace {
-
-TEST(ProtoCastTest, V2KnownValue) {
- UpRevision sender;
- sender.set_value(UpRevision::NONDEFAULT_VALUE);
-
- DownRevision receiver = proto_cast<DownRevision>(sender);
- ASSERT_EQ(DownRevision::NONDEFAULT_VALUE, receiver.value());
-}
-
-TEST(ProtoCastTest, V2UnknownValue) {
- UpRevision sender;
- sender.set_value(UpRevision::NEW_VALUE);
-
- DownRevision receiver = proto_cast<DownRevision>(sender);
- ASSERT_EQ(DownRevision::DEFAULT_VALUE, receiver.value());
-}
-
-} // namespace
-} // namespace google
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index b10e7a95..61f3f558 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -208,10 +208,19 @@ class RepeatedField {
// sizeof(*this)
int SpaceUsedExcludingSelf() const;
- // Remove the element referenced by position.
+ // Removes the element referenced by position.
+ //
+ // Returns an iterator to the element immediately following the removed
+ // element.
+ //
+ // Invalidates all iterators at or after the removed element, including end().
iterator erase(const_iterator position);
- // Remove the elements in the range [first, last).
+ // Removes the elements in the range [first, last).
+ //
+ // Returns an iterator to the element immediately following the removed range.
+ //
+ // Invalidates all iterators at or after the removed range, including end().
iterator erase(const_iterator first, const_iterator last);
// Get the Arena on which this RepeatedField stores its elements.
@@ -649,7 +658,7 @@ inline const Message& GenericTypeHandler<Message>::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:
@@ -683,7 +692,7 @@ class LIBPROTOBUF_EXPORT StringTypeHandlerBase {
class StringTypeHandler : public StringTypeHandlerBase {
public:
static int SpaceUsed(const string& value) {
- return sizeof(value) + StringSpaceUsedExcludingSelf(value);
+ return static_cast<int>(sizeof(value)) + StringSpaceUsedExcludingSelf(value);
}
};
@@ -885,10 +894,19 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
// so will trigger a GOOGLE_DCHECK-failure.
Element* ReleaseCleared();
- // Remove the element referenced by position.
+ // Removes the element referenced by position.
+ //
+ // Returns an iterator to the element immediately following the removed
+ // element.
+ //
+ // Invalidates all iterators at or after the removed element, including end().
iterator erase(const_iterator position);
// Removes the elements in the range [first, last).
+ //
+ // Returns an iterator to the element immediately following the removed range.
+ //
+ // Invalidates all iterators at or after the removed range, including end().
iterator erase(const_iterator first, const_iterator last);
// Gets the arena on which this RepeatedPtrField stores its elements.
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index c8397639..f2eb7ae7 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/source_context.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/source_context.pb.h"
+#include <google/protobuf/source_context.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -110,9 +111,9 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int SourceContext::kFileNameFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
SourceContext::SourceContext()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto
index e9a27d65..d76252ca 100644
--- a/src/google/protobuf/source_context.proto
+++ b/src/google/protobuf/source_context.proto
@@ -27,15 +27,16 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package google.protobuf;
-option java_multiple_files = true;
-option java_outer_classname = "SourceContextProto";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option java_package = "com.google.protobuf";
+option java_outer_classname = "SourceContextProto";
+option java_multiple_files = true;
option java_generate_equals_and_hash = true;
-option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option objc_class_prefix = "GPB";
// `SourceContext` represents information about the source of a
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index d5f89122..e020597a 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/struct.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/struct.pb.h"
+#include <google/protobuf/struct.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -212,9 +213,9 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Struct::kFieldsFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Struct::Struct()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -480,14 +481,14 @@ Struct::mutable_fields() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Value::kNullValueFieldNumber;
const int Value::kNumberValueFieldNumber;
const int Value::kStringValueFieldNumber;
const int Value::kBoolValueFieldNumber;
const int Value::kStructValueFieldNumber;
const int Value::kListValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Value::Value()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1218,9 +1219,9 @@ Value::KindCase Value::kind_case() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int ListValue::kValuesFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
ListValue::ListValue()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto
index b3e9e699..8562e2c1 100644
--- a/src/google/protobuf/struct.proto
+++ b/src/google/protobuf/struct.proto
@@ -27,15 +27,16 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package google.protobuf;
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "StructProto";
-option java_package = "com.google.protobuf";
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "StructProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
option objc_class_prefix = "GPB";
diff --git a/src/google/protobuf/stubs/atomicops.h b/src/google/protobuf/stubs/atomicops.h
index 6deab318..cb93227f 100644
--- a/src/google/protobuf/stubs/atomicops.h
+++ b/src/google/protobuf/stubs/atomicops.h
@@ -192,7 +192,7 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
// AIX
#elif defined(GOOGLE_PROTOBUF_OS_AIX)
-#include <google/protobuf/stubs/atomicops_internals_aix.h>
+#include <google/protobuf/stubs/atomicops_internals_power.h>
// Apple.
#elif defined(GOOGLE_PROTOBUF_OS_APPLE)
@@ -210,6 +210,8 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
#include <google/protobuf/stubs/atomicops_internals_arm_qnx.h>
#elif defined(GOOGLE_PROTOBUF_ARCH_MIPS) || defined(GOOGLE_PROTOBUF_ARCH_MIPS64)
#include <google/protobuf/stubs/atomicops_internals_mips_gcc.h>
+#elif defined(GOOGLE_PROTOBUF_ARCH_POWER)
+#include <google/protobuf/stubs/atomicops_internals_power.h>
#elif defined(__native_client__)
#include <google/protobuf/stubs/atomicops_internals_pnacl.h>
#elif (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
diff --git a/src/google/protobuf/stubs/atomicops_internals_aix.h b/src/google/protobuf/stubs/atomicops_internals_power.h
index b8a42f21..b8a42f21 100644
--- a/src/google/protobuf/stubs/atomicops_internals_aix.h
+++ b/src/google/protobuf/stubs/atomicops_internals_power.h
diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h
index c4f9edee..87271c5e 100644
--- a/src/google/protobuf/stubs/callback.h
+++ b/src/google/protobuf/stubs/callback.h
@@ -78,6 +78,18 @@ class LIBPROTOBUF_EXPORT Closure {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
};
+template<typename R>
+class ResultCallback {
+ public:
+ ResultCallback() {}
+ virtual ~ResultCallback() {}
+
+ virtual R Run() = 0;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback);
+};
+
template<typename R, typename A1>
class LIBPROTOBUF_EXPORT ResultCallback1 {
public:
@@ -240,6 +252,50 @@ class MethodClosure2 : public Closure {
Arg2 arg2_;
};
+template<typename R>
+class FunctionResultCallback_0_0 : public ResultCallback<R> {
+ public:
+ typedef R (*FunctionType)();
+
+ FunctionResultCallback_0_0(FunctionType function, bool self_deleting)
+ : function_(function), self_deleting_(self_deleting) {}
+ ~FunctionResultCallback_0_0() {}
+
+ R Run() {
+ bool needs_delete = self_deleting_; // read in case callback deletes
+ R result = function_();
+ if (needs_delete) delete this;
+ return result;
+ }
+
+ private:
+ FunctionType function_;
+ bool self_deleting_;
+};
+
+template<typename R, typename P1>
+class FunctionResultCallback_1_0 : public ResultCallback<R> {
+ public:
+ typedef R (*FunctionType)(P1);
+
+ FunctionResultCallback_1_0(FunctionType function, bool self_deleting,
+ P1 p1)
+ : function_(function), self_deleting_(self_deleting), p1_(p1) {}
+ ~FunctionResultCallback_1_0() {}
+
+ R Run() {
+ bool needs_delete = self_deleting_; // read in case callback deletes
+ R result = function_(p1_);
+ if (needs_delete) delete this;
+ return result;
+ }
+
+ private:
+ FunctionType function_;
+ bool self_deleting_;
+ P1 p1_;
+};
+
template<typename R, typename Arg1>
class FunctionResultCallback_0_1 : public ResultCallback1<R, Arg1> {
public:
@@ -325,8 +381,6 @@ class MethodResultCallback_5_2 : public ResultCallback2<R, A1, A2> {
typename remove_reference<P5>::type p5_;
};
-} // namespace internal
-
// See Closure.
inline Closure* NewCallback(void (*function)()) {
return new internal::FunctionClosure0(function, true);
@@ -410,6 +464,33 @@ inline Closure* NewPermanentCallback(
object, method, false, arg1, arg2);
}
+// See ResultCallback
+template<typename R>
+inline ResultCallback<R>* NewCallback(R (*function)()) {
+ return new internal::FunctionResultCallback_0_0<R>(function, true);
+}
+
+// See ResultCallback
+template<typename R>
+inline ResultCallback<R>* NewPermanentCallback(R (*function)()) {
+ return new internal::FunctionResultCallback_0_0<R>(function, false);
+}
+
+// See ResultCallback
+template<typename R, typename P1>
+inline ResultCallback<R>* NewCallback(R (*function)(P1), P1 p1) {
+ return new internal::FunctionResultCallback_1_0<R, P1>(
+ function, true, p1);
+}
+
+// See ResultCallback
+template<typename R, typename P1>
+inline ResultCallback<R>* NewPermanentCallback(
+ R (*function)(P1), P1 p1) {
+ return new internal::FunctionResultCallback_1_0<R, P1>(
+ function, false, p1);
+}
+
// See ResultCallback1
template<typename R, typename A1>
inline ResultCallback1<R, A1>* NewCallback(R (*function)(A1)) {
@@ -452,6 +533,8 @@ inline ResultCallback2<R, A1, A2>* NewPermanentCallback(
p2, p3, p4, p5);
}
+} // namespace internal
+
// A function which does nothing. Useful for creating no-op callbacks, e.g.:
// Closure* nothing = NewCallback(&DoNothing);
void LIBPROTOBUF_EXPORT DoNothing();
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
index 88e7084f..9c05cac3 100644
--- a/src/google/protobuf/stubs/common.h
+++ b/src/google/protobuf/stubs/common.h
@@ -146,7 +146,7 @@ namespace internal {
LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
inline bool IsStructurallyValidUTF8(const std::string& str) {
- return IsStructurallyValidUTF8(str.data(), str.length());
+ return IsStructurallyValidUTF8(str.data(), static_cast<int>(str.length()));
}
// Returns initial number of bytes of structually valid UTF-8.
diff --git a/src/google/protobuf/stubs/common_unittest.cc b/src/google/protobuf/stubs/common_unittest.cc
index f9e2cfd4..25bae9b0 100644
--- a/src/google/protobuf/stubs/common_unittest.cc
+++ b/src/google/protobuf/stubs/common_unittest.cc
@@ -41,6 +41,8 @@
namespace google {
namespace protobuf {
+using internal::NewCallback;
+using internal::NewPermanentCallback;
namespace {
// TODO(kenton): More tests.
diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h
index c6f210f0..58334322 100755
--- a/src/google/protobuf/stubs/hash.h
+++ b/src/google/protobuf/stubs/hash.h
@@ -41,10 +41,15 @@
#define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1
#define GOOGLE_PROTOBUF_HAVE_HASH_SET 1
-// Use C++11 unordered_{map|set} if available. Otherwise, libc++ always support
-// unordered_{map|set}
-#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X) || \
- defined(_LIBCPP_VERSION)
+// Android
+#if defined(__ANDROID__)
+# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
+# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
+
+// Use C++11 unordered_{map|set} if available.
+#elif ((_LIBCPP_STD_VER >= 11) || \
+ (((__cplusplus >= 201103L) || defined(__GXX_EXPERIMENTAL_CXX0X)) && \
+ (__GLIBCXX__ > 20090421)))
# define GOOGLE_PROTOBUF_HAS_CXX11_HASH
// For XCode >= 4.6: the compiler is clang with libc++.
diff --git a/src/google/protobuf/stubs/int128.cc b/src/google/protobuf/stubs/int128.cc
index 9f4fb824..d80c64f2 100644
--- a/src/google/protobuf/stubs/int128.cc
+++ b/src/google/protobuf/stubs/int128.cc
@@ -188,7 +188,8 @@ std::ostream& operator<<(std::ostream& o, const uint128& b) {
if ((flags & std::ios::adjustfield) == std::ios::left) {
rep.append(width - rep.size(), o.fill());
} else {
- rep.insert(0, width - rep.size(), o.fill());
+ rep.insert(static_cast<std::string::size_type>(0),
+ width - rep.size(), o.fill());
}
}
diff --git a/src/google/protobuf/stubs/once_unittest.cc b/src/google/protobuf/stubs/once_unittest.cc
index cb5a20dd..37def58d 100644
--- a/src/google/protobuf/stubs/once_unittest.cc
+++ b/src/google/protobuf/stubs/once_unittest.cc
@@ -43,6 +43,7 @@
namespace google {
namespace protobuf {
+using internal::NewCallback;
namespace {
class OnceInitTest : public testing::Test {
@@ -127,10 +128,11 @@ class OnceInitTest : public testing::Test {
};
TestThread* RunInitOnceInNewThread() {
- return new TestThread(NewCallback(this, &OnceInitTest::InitOnce));
+ return new TestThread(internal::NewCallback(this, &OnceInitTest::InitOnce));
}
TestThread* RunInitRecursiveOnceInNewThread() {
- return new TestThread(NewCallback(this, &OnceInitTest::InitRecursiveOnce));
+ return new TestThread(
+ internal::NewCallback(this, &OnceInitTest::InitRecursiveOnce));
}
enum State {
diff --git a/src/google/protobuf/stubs/platform_macros.h b/src/google/protobuf/stubs/platform_macros.h
index 55d32759..22b35723 100644
--- a/src/google/protobuf/stubs/platform_macros.h
+++ b/src/google/protobuf/stubs/platform_macros.h
@@ -70,7 +70,7 @@
#else
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
#endif
-#elif defined(_POWER)
+#elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__)
#define GOOGLE_PROTOBUF_ARCH_POWER 1
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
#elif defined(__GNUC__)
@@ -97,6 +97,8 @@ GOOGLE_PROTOBUF_PLATFORM_ERROR
#if TARGET_OS_IPHONE
#define GOOGLE_PROTOBUF_OS_IPHONE
#endif
+#elif defined(__EMSCRIPTEN__)
+#define GOOGLE_PROTOBUF_OS_EMSCRIPTEN
#elif defined(__native_client__)
#define GOOGLE_PROTOBUF_OS_NACL
#elif defined(sun)
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 <string>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/hash.h>
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<StringPiece> {
+ 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..a52d81f8 100644
--- a/src/google/protobuf/stubs/stringpiece_unittest.cc
+++ b/src/google/protobuf/stubs/stringpiece_unittest.cc
@@ -36,6 +36,7 @@
#include <vector>
#include <google/protobuf/testing/googletest.h>
+#include <google/protobuf/stubs/hash.h>
#include <gtest/gtest.h>
namespace google {
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
index 8442f2ce..7ba92e8f 100644
--- a/src/google/protobuf/stubs/strutil.cc
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -524,27 +524,81 @@ int CEscapeInternal(const char* src, int src_len, char* dest,
return used;
}
-int CEscapeString(const char* src, int src_len, char* dest, int dest_len) {
- return CEscapeInternal(src, src_len, dest, dest_len, false, false);
+// Calculates the length of the C-style escaped version of 'src'.
+// Assumes that non-printable characters are escaped using octal sequences, and
+// that UTF-8 bytes are not handled specially.
+static inline size_t CEscapedLength(StringPiece src) {
+ static char c_escaped_len[256] = {
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", '
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9'
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O'
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\'
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o'
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ };
+
+ size_t escaped_len = 0;
+ for (int i = 0; i < src.size(); ++i) {
+ unsigned char c = static_cast<unsigned char>(src[i]);
+ escaped_len += c_escaped_len[c];
+ }
+ return escaped_len;
}
// ----------------------------------------------------------------------
-// CEscape()
-// CHexEscape()
-// Copies 'src' to result, escaping dangerous characters using
-// C-style escape sequences. This is very useful for preparing query
-// flags. 'src' and 'dest' should not overlap. The 'Hex' version
-// hexadecimal rather than octal sequences.
-//
-// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
+// Escapes 'src' using C-style escape sequences, and appends the escaped string
+// to 'dest'. This version is faster than calling CEscapeInternal as it computes
+// the required space using a lookup table, and also does not do any special
+// handling for Hex or UTF-8 characters.
// ----------------------------------------------------------------------
+void CEscapeAndAppend(StringPiece src, string* dest) {
+ size_t escaped_len = CEscapedLength(src);
+ if (escaped_len == src.size()) {
+ dest->append(src.data(), src.size());
+ return;
+ }
+
+ size_t cur_dest_len = dest->size();
+ dest->resize(cur_dest_len + escaped_len);
+ char* append_ptr = &(*dest)[cur_dest_len];
+
+ for (int i = 0; i < src.size(); ++i) {
+ unsigned char c = static_cast<unsigned char>(src[i]);
+ switch (c) {
+ case '\n': *append_ptr++ = '\\'; *append_ptr++ = 'n'; break;
+ case '\r': *append_ptr++ = '\\'; *append_ptr++ = 'r'; break;
+ case '\t': *append_ptr++ = '\\'; *append_ptr++ = 't'; break;
+ case '\"': *append_ptr++ = '\\'; *append_ptr++ = '\"'; break;
+ case '\'': *append_ptr++ = '\\'; *append_ptr++ = '\''; break;
+ case '\\': *append_ptr++ = '\\'; *append_ptr++ = '\\'; break;
+ default:
+ if (!isprint(c)) {
+ *append_ptr++ = '\\';
+ *append_ptr++ = '0' + c / 64;
+ *append_ptr++ = '0' + (c % 64) / 8;
+ *append_ptr++ = '0' + c % 8;
+ } else {
+ *append_ptr++ = c;
+ }
+ break;
+ }
+ }
+}
+
string CEscape(const string& src) {
- const int dest_length = src.size() * 4 + 1; // Maximum possible expansion
- scoped_array<char> dest(new char[dest_length]);
- const int len = CEscapeInternal(src.data(), src.size(),
- dest.get(), dest_length, false, false);
- GOOGLE_DCHECK_GE(len, 0);
- return string(dest.get(), len);
+ string dest;
+ CEscapeAndAppend(src, &dest);
+ return dest;
}
namespace strings {
diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h
index b22066b6..27d47575 100644
--- a/src/google/protobuf/stubs/strutil.h
+++ b/src/google/protobuf/stubs/strutil.h
@@ -314,26 +314,20 @@ LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest,
LIBPROTOBUF_EXPORT string UnescapeCEscapeString(const string& src);
// ----------------------------------------------------------------------
-// CEscapeString()
-// Copies 'src' to 'dest', escaping dangerous characters using
-// C-style escape sequences. This is very useful for preparing query
-// flags. 'src' and 'dest' should not overlap.
-// Returns the number of bytes written to 'dest' (not including the \0)
-// or -1 if there was insufficient space.
+// CEscape()
+// Escapes 'src' using C-style escape sequences and returns the resulting
+// string.
//
-// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
+// Escaped chars: \n, \r, \t, ", ', \, and !isprint().
// ----------------------------------------------------------------------
-LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len,
- char* dest, int dest_len);
+LIBPROTOBUF_EXPORT string CEscape(const string& src);
// ----------------------------------------------------------------------
-// CEscape()
-// More convenient form of CEscapeString: returns result as a "string".
-// This version is slower than CEscapeString() because it does more
-// allocation. However, it is much more convenient to use in
-// non-speed-critical code like logging messages etc.
+// CEscapeAndAppend()
+// Escapes 'src' using C-style escape sequences, and appends the escaped
+// string to 'dest'.
// ----------------------------------------------------------------------
-LIBPROTOBUF_EXPORT string CEscape(const string& src);
+LIBPROTOBUF_EXPORT void CEscapeAndAppend(StringPiece src, string* dest);
namespace strings {
// Like CEscape() but does not escape bytes with the upper bit set.
diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h
index d449c009..1c13a1a7 100644
--- a/src/google/protobuf/test_util.h
+++ b/src/google/protobuf/test_util.h
@@ -65,7 +65,7 @@ class TestUtil {
static void SetOneof2(unittest::TestOneof2* message);
// Use the repeated versions of the set_*() accessors to modify all the
- // repeated fields of the messsage (which should already have been
+ // repeated fields of the message (which should already have been
// initialized with Set*Fields()). Set*Fields() itself only tests
// the add_*() accessors.
static void ModifyRepeatedFields(unittest::TestAllTypes* message);
diff --git a/src/google/protobuf/test_util_lite.h b/src/google/protobuf/test_util_lite.h
index f250c937..47a2269d 100644
--- a/src/google/protobuf/test_util_lite.h
+++ b/src/google/protobuf/test_util_lite.h
@@ -52,7 +52,7 @@ class TestUtilLite {
static void SetPackedExtensions(unittest::TestPackedExtensionsLite* message);
// Use the repeated versions of the set_*() accessors to modify all the
- // repeated fields of the messsage (which should already have been
+ // repeated fields of the message (which should already have been
// initialized with Set*Fields()). Set*Fields() itself only tests
// the add_*() accessors.
static void ModifyRepeatedFields(unittest::TestAllTypesLite* message);
diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc
index b8bd790b..2b9cddef 100644
--- a/src/google/protobuf/testing/googletest.cc
+++ b/src/google/protobuf/testing/googletest.cc
@@ -94,6 +94,13 @@ string TestSourceDir() {
namespace {
string GetTemporaryDirectoryName() {
+ // Tests run under Bazel "should not" use /tmp. Bazel sets this environment
+ // variable for tests to use instead.
+ char *from_environment = getenv("TEST_TMPDIR");
+ if (from_environment != NULL && from_environment[0] != '\0') {
+ return string(from_environment) + "/protobuf_tmpdir";
+ }
+
// tmpnam() is generally not considered safe but we're only using it for
// testing. We cannot use tmpfile() or mkstemp() since we're creating a
// directory.
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 4d8c1f91..b0a5ce63 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -46,6 +46,7 @@
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/io/strtod.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -377,19 +378,19 @@ 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("]"));
+ TryConsume(":"); // ':' is optional between message labels and values.
string serialized_value;
DO(ConsumeAnyValue(full_type_name,
message->GetDescriptor()->file()->pool(),
&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.
}
if (TryConsume("[")) {
// Extension.
@@ -656,7 +657,7 @@ class TextFormat::Parser::ParserImpl {
case FieldDescriptor::CPPTYPE_FLOAT: {
double value;
DO(ConsumeDouble(&value));
- SET_FIELD(Float, static_cast<float>(value));
+ SET_FIELD(Float, io::SafeDoubleToFloat(value));
break;
}
@@ -981,7 +982,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 +995,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;
@@ -1354,7 +1358,10 @@ string TextFormat::FieldValuePrinter::PrintDouble(double val) const {
return SimpleDtoa(val);
}
string TextFormat::FieldValuePrinter::PrintString(const string& val) const {
- return StrCat("\"", CEscape(val), "\"");
+ string printed("\"");
+ CEscapeAndAppend(val, &printed);
+ printed.push_back('\"');
+ return printed;
}
string TextFormat::FieldValuePrinter::PrintBytes(const string& val) const {
return PrintString(val);
@@ -1420,7 +1427,8 @@ TextFormat::Printer::Printer()
use_short_repeated_primitives_(false),
hide_unknown_fields_(false),
print_message_fields_in_index_order_(false),
- expand_any_(false) {
+ expand_any_(false),
+ truncate_string_field_longer_than_(0LL) {
SetUseUtf8StringEscaping(false);
}
@@ -1772,11 +1780,21 @@ void TextFormat::Printer::PrintFieldValue(
? reflection->GetRepeatedStringReference(
message, field, index, &scratch)
: reflection->GetStringReference(message, field, &scratch);
+ int64 size = value.size();
+ if (truncate_string_field_longer_than_ > 0) {
+ size = std::min(truncate_string_field_longer_than_,
+ static_cast<int64>(value.size()));
+ }
+ string truncated_value(value.substr(0, size) + "...<truncated>...");
+ const string* value_to_print = &value;
+ if (size < value.size()) {
+ value_to_print = &truncated_value;
+ }
if (field->type() == FieldDescriptor::TYPE_STRING) {
- generator.Print(printer->PrintString(value));
+ generator.Print(printer->PrintString(*value_to_print));
} else {
GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_BYTES);
- generator.Print(printer->PrintBytes(value));
+ generator.Print(printer->PrintBytes(*value_to_print));
}
break;
}
@@ -1923,14 +1941,10 @@ void TextFormat::Printer::PrintUnknownFields(
} else {
// This field is not parseable as a Message.
// So it is probably just a plain string.
- generator.Print(": \"");
- generator.Print(CEscape(value));
- generator.Print("\"");
- if (single_line_mode_) {
- generator.Print(" ");
- } else {
- generator.Print("\n");
- }
+ string printed(": \"");
+ CEscapeAndAppend(value, &printed);
+ printed.append(single_line_mode_ ? "\" " : "\"\n");
+ generator.Print(printed);
}
break;
}
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index 6717aecd..ef3d4a8f 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -219,6 +219,18 @@ class LIBPROTOBUF_EXPORT TextFormat {
expand_any_ = expand;
}
+ // If non-zero, we truncate all string fields that are longer than this
+ // threshold. This is useful when the proto message has very long strings,
+ // e.g., dump of encoded image file.
+ //
+ // NOTE(hfgong): Setting a non-zero value breaks round-trip safe
+ // property of TextFormat::Printer. That is, from the printed message, we
+ // cannot fully recover the original string field any more.
+ void SetTruncateStringFieldLongerThan(
+ const int64 truncate_string_field_longer_than) {
+ truncate_string_field_longer_than_ = truncate_string_field_longer_than;
+ }
+
// Register a custom field-specific FieldValuePrinter for fields
// with a particular FieldDescriptor.
// Returns "true" if the registration succeeded, or "false", if there is
@@ -286,6 +298,8 @@ class LIBPROTOBUF_EXPORT TextFormat {
bool expand_any_;
+ int64 truncate_string_field_longer_than_;
+
google::protobuf::scoped_ptr<const FieldValuePrinter> default_field_value_printer_;
typedef map<const FieldDescriptor*,
const FieldValuePrinter*> CustomPrinterMap;
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 <math.h>
#include <stdlib.h>
#include <limits>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
@@ -931,7 +935,7 @@ class TextFormatParserTest : public testing::Test {
protected:
void ExpectFailure(const string& input, const string& message, int line,
int col) {
- scoped_ptr<unittest::TestAllTypes> proto(new unittest::TestAllTypes);
+ google::protobuf::scoped_ptr<unittest::TestAllTypes> 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<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+ google::protobuf::scoped_ptr<unittest::TestAllTypes> 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<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+ google::protobuf::scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
const Descriptor* d = message->GetDescriptor();
#define EXPECT_FIELD(name, value, valuestring) \
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 2ee0ec29..c1c4402c 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/timestamp.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/timestamp.pb.h"
+#include <google/protobuf/timestamp.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -82,9 +83,9 @@ void protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto() {
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
"\n\037google/protobuf/timestamp.proto\022\017googl"
"e.protobuf\"+\n\tTimestamp\022\017\n\007seconds\030\001 \001(\003"
- "\022\r\n\005nanos\030\002 \001(\005BQ\n\023com.google.protobufB\016"
- "TimestampProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Proto"
- "buf.WellKnownTypesb\006proto3", 186);
+ "\022\r\n\005nanos\030\002 \001(\005BT\n\023com.google.protobufB\016"
+ "TimestampProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Pr"
+ "otobuf.WellKnownTypesb\006proto3", 189);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/timestamp.proto", &protobuf_RegisterTypes);
Timestamp::default_instance_ = new Timestamp();
@@ -111,10 +112,10 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Timestamp::kSecondsFieldNumber;
const int Timestamp::kNanosFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Timestamp::Timestamp()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -122,6 +123,14 @@ Timestamp::Timestamp()
// @@protoc_insertion_point(constructor:google.protobuf.Timestamp)
}
+Timestamp::Timestamp(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.Timestamp)
+}
+
void Timestamp::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -147,10 +156,20 @@ Timestamp::~Timestamp() {
}
void Timestamp::SharedDtor() {
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
if (this != default_instance_) {
}
}
+void Timestamp::ArenaDtor(void* object) {
+ Timestamp* _this = reinterpret_cast< Timestamp* >(object);
+ (void)_this;
+}
+void Timestamp::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void Timestamp::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -169,11 +188,7 @@ const Timestamp& Timestamp::default_instance() {
Timestamp* Timestamp::default_instance_ = NULL;
Timestamp* Timestamp::New(::google::protobuf::Arena* arena) const {
- Timestamp* n = new Timestamp;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<Timestamp>(arena);
}
void Timestamp::Clear() {
@@ -349,6 +364,18 @@ bool Timestamp::IsInitialized() const {
void Timestamp::Swap(Timestamp* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ Timestamp temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void Timestamp::UnsafeArenaSwap(Timestamp* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void Timestamp::InternalSwap(Timestamp* other) {
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 85fc1242..7bf62597 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -53,9 +53,14 @@ class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const Timestamp& default_instance();
+ void UnsafeArenaSwap(Timestamp* other);
void Swap(Timestamp* other);
// implements Message ----------------------------------------------
@@ -82,6 +87,11 @@ class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(Timestamp* other);
+ protected:
+ explicit Timestamp(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -113,6 +123,9 @@ class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message {
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
::google::protobuf::int64 seconds_;
::google::protobuf::int32 nanos_;
diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto
index 06b60e6f..b51fc3fa 100644
--- a/src/google/protobuf/timestamp.proto
+++ b/src/google/protobuf/timestamp.proto
@@ -27,15 +27,17 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package google.protobuf;
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "TimestampProto";
-option java_package = "com.google.protobuf";
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TimestampProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
option objc_class_prefix = "GPB";
// A Timestamp represents a point in time independent of any time zone
@@ -92,6 +94,7 @@ option objc_class_prefix = "GPB";
// nanos = int((now - seconds) * 10**9)
// timestamp = Timestamp(seconds=seconds, nanos=nanos)
//
+//
message Timestamp {
// Represents seconds of UTC time since Unix epoch
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index 8f993561..7b47b3bd 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/type.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/type.pb.h"
+#include <google/protobuf/type.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -70,7 +71,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _internal_metadata_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _is_default_instance_));
Field_descriptor_ = file->message_type(1);
- static const int Field_offsets_[9] = {
+ static const int Field_offsets_[10] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, kind_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, cardinality_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, number_),
@@ -80,6 +81,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, packed_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, options_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, json_name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, default_value_),
};
Field_reflection_ =
::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
@@ -203,37 +205,37 @@ void protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto() {
"\030\004 \003(\0132\027.google.protobuf.Option\0226\n\016sourc"
"e_context\030\005 \001(\0132\036.google.protobuf.Source"
"Context\022\'\n\006syntax\030\006 \001(\0162\027.google.protobu"
- "f.Syntax\"\276\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl"
+ "f.Syntax\"\325\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl"
"e.protobuf.Field.Kind\0227\n\013cardinality\030\002 \001"
"(\0162\".google.protobuf.Field.Cardinality\022\016"
"\n\006number\030\003 \001(\005\022\014\n\004name\030\004 \001(\t\022\020\n\010type_url"
"\030\006 \001(\t\022\023\n\013oneof_index\030\007 \001(\005\022\016\n\006packed\030\010 "
"\001(\010\022(\n\007options\030\t \003(\0132\027.google.protobuf.O"
- "ption\022\021\n\tjson_name\030\n \001(\t\"\310\002\n\004Kind\022\020\n\014TYP"
- "E_UNKNOWN\020\000\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLO"
- "AT\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_GROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nT"
- "YPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENU"
- "M\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_SINT64\020\022\"t\n\013C"
- "ardinality\022\027\n\023CARDINALITY_UNKNOWN\020\000\022\030\n\024C"
- "ARDINALITY_OPTIONAL\020\001\022\030\n\024CARDINALITY_REQ"
- "UIRED\020\002\022\030\n\024CARDINALITY_REPEATED\020\003\"\316\001\n\004En"
- "um\022\014\n\004name\030\001 \001(\t\022-\n\tenumvalue\030\002 \003(\0132\032.go"
- "ogle.protobuf.EnumValue\022(\n\007options\030\003 \003(\013"
- "2\027.google.protobuf.Option\0226\n\016source_cont"
- "ext\030\004 \001(\0132\036.google.protobuf.SourceContex"
- "t\022\'\n\006syntax\030\005 \001(\0162\027.google.protobuf.Synt"
- "ax\"S\n\tEnumValue\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030"
- "\002 \001(\005\022(\n\007options\030\003 \003(\0132\027.google.protobuf"
- ".Option\";\n\006Option\022\014\n\004name\030\001 \001(\t\022#\n\005value"
- "\030\002 \001(\0132\024.google.protobuf.Any*.\n\006Syntax\022\021"
- "\n\rSYNTAX_PROTO2\020\000\022\021\n\rSYNTAX_PROTO3\020\001BL\n\023"
- "com.google.protobufB\tTypeProtoP\001\240\001\001\242\002\003GP"
- "B\252\002\036Google.Protobuf.WellKnownTypesb\006prot"
- "o3", 1522);
+ "ption\022\021\n\tjson_name\030\n \001(\t\022\025\n\rdefault_valu"
+ "e\030\013 \001(\t\"\310\002\n\004Kind\022\020\n\014TYPE_UNKNOWN\020\000\022\017\n\013TY"
+ "PE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT6"
+ "4\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014"
+ "TYPE_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_GROUP\020\n"
+ "\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TY"
+ "PE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXE"
+ "D32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020"
+ "\021\022\017\n\013TYPE_SINT64\020\022\"t\n\013Cardinality\022\027\n\023CAR"
+ "DINALITY_UNKNOWN\020\000\022\030\n\024CARDINALITY_OPTION"
+ "AL\020\001\022\030\n\024CARDINALITY_REQUIRED\020\002\022\030\n\024CARDIN"
+ "ALITY_REPEATED\020\003\"\316\001\n\004Enum\022\014\n\004name\030\001 \001(\t\022"
+ "-\n\tenumvalue\030\002 \003(\0132\032.google.protobuf.Enu"
+ "mValue\022(\n\007options\030\003 \003(\0132\027.google.protobu"
+ "f.Option\0226\n\016source_context\030\004 \001(\0132\036.googl"
+ "e.protobuf.SourceContext\022\'\n\006syntax\030\005 \001(\016"
+ "2\027.google.protobuf.Syntax\"S\n\tEnumValue\022\014"
+ "\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\022(\n\007options\030"
+ "\003 \003(\0132\027.google.protobuf.Option\";\n\006Option"
+ "\022\014\n\004name\030\001 \001(\t\022#\n\005value\030\002 \001(\0132\024.google.p"
+ "rotobuf.Any*.\n\006Syntax\022\021\n\rSYNTAX_PROTO2\020\000"
+ "\022\021\n\rSYNTAX_PROTO3\020\001BL\n\023com.google.protob"
+ "ufB\tTypeProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protob"
+ "uf.WellKnownTypesb\006proto3", 1545);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/type.proto", &protobuf_RegisterTypes);
Type::default_instance_ = new Type();
@@ -282,14 +284,14 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Type::kNameFieldNumber;
const int Type::kFieldsFieldNumber;
const int Type::kOneofsFieldNumber;
const int Type::kOptionsFieldNumber;
const int Type::kSourceContextFieldNumber;
const int Type::kSyntaxFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Type::Type()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -967,7 +969,7 @@ bool Field_Kind_IsValid(int value) {
}
}
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const Field_Kind Field::TYPE_UNKNOWN;
const Field_Kind Field::TYPE_DOUBLE;
const Field_Kind Field::TYPE_FLOAT;
@@ -990,7 +992,7 @@ const Field_Kind Field::TYPE_SINT64;
const Field_Kind Field::Kind_MIN;
const Field_Kind Field::Kind_MAX;
const int Field::Kind_ARRAYSIZE;
-#endif // _MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
const ::google::protobuf::EnumDescriptor* Field_Cardinality_descriptor() {
protobuf_AssignDescriptorsOnce();
return Field_Cardinality_descriptor_;
@@ -1007,7 +1009,7 @@ bool Field_Cardinality_IsValid(int value) {
}
}
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const Field_Cardinality Field::CARDINALITY_UNKNOWN;
const Field_Cardinality Field::CARDINALITY_OPTIONAL;
const Field_Cardinality Field::CARDINALITY_REQUIRED;
@@ -1015,8 +1017,8 @@ const Field_Cardinality Field::CARDINALITY_REPEATED;
const Field_Cardinality Field::Cardinality_MIN;
const Field_Cardinality Field::Cardinality_MAX;
const int Field::Cardinality_ARRAYSIZE;
-#endif // _MSC_VER
-#ifndef _MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Field::kKindFieldNumber;
const int Field::kCardinalityFieldNumber;
const int Field::kNumberFieldNumber;
@@ -1026,7 +1028,8 @@ const int Field::kOneofIndexFieldNumber;
const int Field::kPackedFieldNumber;
const int Field::kOptionsFieldNumber;
const int Field::kJsonNameFieldNumber;
-#endif // !_MSC_VER
+const int Field::kDefaultValueFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Field::Field()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1058,6 +1061,7 @@ void Field::SharedCtor() {
oneof_index_ = 0;
packed_ = false;
json_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
Field::~Field() {
@@ -1069,6 +1073,7 @@ void Field::SharedDtor() {
name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
json_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
}
}
@@ -1113,6 +1118,7 @@ void Field::Clear() {
type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
packed_ = false;
json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
#undef ZR_HELPER_
#undef ZR_
@@ -1270,6 +1276,23 @@ bool Field::MergePartialFromCodedStream(
} else {
goto handle_unusual;
}
+ if (input->ExpectTag(90)) goto parse_default_value;
+ break;
+ }
+
+ // optional string default_value = 11;
+ case 11: {
+ if (tag == 90) {
+ parse_default_value:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_default_value()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->default_value().data(), this->default_value().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "google.protobuf.Field.default_value"));
+ } else {
+ goto handle_unusual;
+ }
if (input->ExpectAtEnd()) goto success;
break;
}
@@ -1361,6 +1384,16 @@ void Field::SerializeWithCachedSizes(
10, this->json_name(), output);
}
+ // optional string default_value = 11;
+ if (this->default_value().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->default_value().data(), this->default_value().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "google.protobuf.Field.default_value");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 11, this->default_value(), output);
+ }
+
// @@protoc_insertion_point(serialize_end:google.protobuf.Field)
}
@@ -1434,6 +1467,17 @@ void Field::SerializeWithCachedSizes(
10, this->json_name(), target);
}
+ // optional string default_value = 11;
+ if (this->default_value().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->default_value().data(), this->default_value().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "google.protobuf.Field.default_value");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 11, this->default_value(), target);
+ }
+
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Field)
return target;
}
@@ -1493,6 +1537,13 @@ int Field::ByteSize() const {
this->json_name());
}
+ // optional string default_value = 11;
+ if (this->default_value().size() > 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->default_value());
+ }
+
// repeated .google.protobuf.Option options = 9;
total_size += 1 * this->options_size();
for (int i = 0; i < this->options_size(); i++) {
@@ -1549,6 +1600,10 @@ void Field::MergeFrom(const Field& from) {
json_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.json_name_);
}
+ if (from.default_value().size() > 0) {
+
+ default_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.default_value_);
+ }
}
void Field::CopyFrom(const ::google::protobuf::Message& from) {
@@ -1582,6 +1637,7 @@ void Field::InternalSwap(Field* other) {
std::swap(packed_, other->packed_);
options_.UnsafeArenaSwap(&other->options_);
json_name_.Swap(&other->json_name_);
+ default_value_.Swap(&other->default_value_);
_internal_metadata_.Swap(&other->_internal_metadata_);
std::swap(_cached_size_, other->_cached_size_);
}
@@ -1826,17 +1882,60 @@ void Field::clear_json_name() {
// @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name)
}
+// optional string default_value = 11;
+void Field::clear_default_value() {
+ default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Field::default_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value)
+ return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_default_value(const ::std::string& value) {
+
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value)
+}
+ void Field::set_default_value(const char* value) {
+
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.Field.default_value)
+}
+ void Field::set_default_value(const char* value, size_t size) {
+
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.default_value)
+}
+ ::std::string* Field::mutable_default_value() {
+
+ // @@protoc_insertion_point(field_mutable:google.protobuf.Field.default_value)
+ return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Field::release_default_value() {
+
+ return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_allocated_default_value(::std::string* default_value) {
+ if (default_value != NULL) {
+
+ } else {
+
+ }
+ default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value)
+}
+
#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Enum::kNameFieldNumber;
const int Enum::kEnumvalueFieldNumber;
const int Enum::kOptionsFieldNumber;
const int Enum::kSourceContextFieldNumber;
const int Enum::kSyntaxFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Enum::Enum()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2379,11 +2478,11 @@ void Enum::clear_syntax() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int EnumValue::kNameFieldNumber;
const int EnumValue::kNumberFieldNumber;
const int EnumValue::kOptionsFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
EnumValue::EnumValue()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2775,10 +2874,10 @@ EnumValue::options() const {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Option::kNameFieldNumber;
const int Option::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Option::Option()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index deda9213..76fe8a65 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -28,8 +28,8 @@
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_enum_reflection.h>
#include <google/protobuf/unknown_field_set.h>
-#include "google/protobuf/any.pb.h"
-#include "google/protobuf/source_context.pb.h"
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/source_context.pb.h>
// @@protoc_insertion_point(includes)
namespace google {
@@ -471,6 +471,17 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message {
::std::string* release_json_name();
void set_allocated_json_name(::std::string* json_name);
+ // optional string default_value = 11;
+ void clear_default_value();
+ static const int kDefaultValueFieldNumber = 11;
+ const ::std::string& default_value() const;
+ void set_default_value(const ::std::string& value);
+ void set_default_value(const char* value);
+ void set_default_value(const char* value, size_t size);
+ ::std::string* mutable_default_value();
+ ::std::string* release_default_value();
+ void set_allocated_default_value(::std::string* default_value);
+
// @@protoc_insertion_point(class_scope:google.protobuf.Field)
private:
@@ -484,6 +495,7 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message {
::google::protobuf::internal::ArenaStringPtr type_url_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_;
::google::protobuf::internal::ArenaStringPtr json_name_;
+ ::google::protobuf::internal::ArenaStringPtr default_value_;
bool packed_;
mutable int _cached_size_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
@@ -1264,6 +1276,49 @@ inline void Field::set_allocated_json_name(::std::string* json_name) {
// @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name)
}
+// optional string default_value = 11;
+inline void Field::clear_default_value() {
+ default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Field::default_value() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value)
+ return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_default_value(const ::std::string& value) {
+
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value)
+}
+inline void Field::set_default_value(const char* value) {
+
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:google.protobuf.Field.default_value)
+}
+inline void Field::set_default_value(const char* value, size_t size) {
+
+ default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.default_value)
+}
+inline ::std::string* Field::mutable_default_value() {
+
+ // @@protoc_insertion_point(field_mutable:google.protobuf.Field.default_value)
+ return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Field::release_default_value() {
+
+ return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_allocated_default_value(::std::string* default_value) {
+ if (default_value != NULL) {
+
+ } else {
+
+ }
+ default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value)
+}
+
// -------------------------------------------------------------------
// Enum
diff --git a/src/google/protobuf/type.proto b/src/google/protobuf/type.proto
index 4df95762..1c9cf53d 100644
--- a/src/google/protobuf/type.proto
+++ b/src/google/protobuf/type.proto
@@ -27,6 +27,7 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package google.protobuf;
@@ -34,22 +35,22 @@ package google.protobuf;
import "google/protobuf/any.proto";
import "google/protobuf/source_context.proto";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option java_package = "com.google.protobuf";
option java_outer_classname = "TypeProto";
option java_multiple_files = true;
option java_generate_equals_and_hash = true;
-option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option objc_class_prefix = "GPB";
-// A light-weight descriptor for a proto message type.
+// A protocol buffer message type.
message Type {
// The fully qualified message name.
string name = 1;
// The list of fields.
repeated Field fields = 2;
- // The list of oneof definitions.
- repeated string oneofs = 3; // The list of oneofs declared in this Type
- // The proto options.
+ // The list of types appearing in `oneof` definitions in this type.
+ repeated string oneofs = 3;
+ // The protocol buffer options.
repeated Option options = 4;
// The source context.
SourceContext source_context = 5;
@@ -57,9 +58,9 @@ message Type {
Syntax syntax = 6;
}
-// Field represents a single field of a message type.
+// A single field of a message type.
message Field {
- // Kind represents a basic field type.
+ // Basic field types.
enum Kind {
// Field type unknown.
TYPE_UNKNOWN = 0;
@@ -81,7 +82,7 @@ message Field {
TYPE_BOOL = 8;
// Field type string.
TYPE_STRING = 9;
- // Field type group (deprecated proto2 type)
+ // Field type group. Proto2 syntax only, and deprecated.
TYPE_GROUP = 10;
// Field type message.
TYPE_MESSAGE = 11;
@@ -101,38 +102,40 @@ message Field {
TYPE_SINT64 = 18;
};
- // Cardinality represents whether a field is optional, required, or
- // repeated.
+ // Whether a field is optional, required, or repeated.
enum Cardinality {
- // The field cardinality is unknown. Typically an error condition.
+ // For fields with unknown cardinality.
CARDINALITY_UNKNOWN = 0;
// For optional fields.
CARDINALITY_OPTIONAL = 1;
- // For required fields. Not used for proto3.
+ // For required fields. Proto2 syntax only.
CARDINALITY_REQUIRED = 2;
// For repeated fields.
CARDINALITY_REPEATED = 3;
};
- // The field kind.
+ // The field type.
Kind kind = 1;
- // The field cardinality, i.e. optional/required/repeated.
+ // The field cardinality.
Cardinality cardinality = 2;
- // The proto field number.
+ // The field number.
int32 number = 3;
// The field name.
string name = 4;
- // The type URL (without the scheme) when the type is MESSAGE or ENUM,
- // such as `type.googleapis.com/google.protobuf.Empty`.
+ // The field type URL, without the scheme, for message or enumeration
+ // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
string type_url = 6;
- // Index in Type.oneofs. Starts at 1. Zero means no oneof mapping.
+ // The index of the field type in `Type.oneofs`, for message or enumeration
+ // types. The first type has index 1; zero means the type is not in the list.
int32 oneof_index = 7;
// Whether to use alternative packed wire representation.
bool packed = 8;
- // The proto options.
+ // The protocol buffer options.
repeated Option options = 9;
- // The JSON name for this field.
+ // The field JSON name.
string json_name = 10;
+ // The string value of the default value of this field. Proto2 syntax only.
+ string default_value = 11;
}
// Enum type definition.
@@ -141,7 +144,7 @@ message Enum {
string name = 1;
// Enum value definitions.
repeated EnumValue enumvalue = 2;
- // Proto options for the enum type.
+ // Protocol buffer options.
repeated Option options = 3;
// The source context.
SourceContext source_context = 4;
@@ -155,22 +158,23 @@ message EnumValue {
string name = 1;
// Enum value number.
int32 number = 2;
- // Proto options for the enum value.
+ // Protocol buffer options.
repeated Option options = 3;
}
-// Proto option attached to messages/fields/enums etc.
+// A protocol buffer option, which can be attached to a message, field,
+// enumeration, etc.
message Option {
- // Proto option name.
+ // The option's name. For example, `"java_package"`.
string name = 1;
- // Proto option value.
+ // The option's value. For example, `"com.google.protobuf"`.
Any value = 2;
}
-// Syntax specifies the syntax in which a service element was defined.
+// The syntax in which a protocol buffer element is defined.
enum Syntax {
- // Syntax "proto2"
+ // Syntax `proto2`.
SYNTAX_PROTO2 = 0;
- // Syntax "proto3"
+ // Syntax `proto3`.
SYNTAX_PROTO3 = 1;
}
diff --git a/src/google/protobuf/unittest_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto
index d4d6e869..4cc0e362 100644
--- a/src/google/protobuf/unittest_custom_options.proto
+++ b/src/google/protobuf/unittest_custom_options.proto
@@ -392,3 +392,30 @@ message NestedOptionType {
optional int32 nested_extension = 7912573 [(field_opt2) = 1005];
}
}
+
+// Custom message option that has a required enum field.
+// WARNING: this is strongly discouraged!
+message OldOptionType {
+ enum TestEnum {
+ OLD_VALUE = 0;
+ }
+ required TestEnum value = 1;
+}
+
+// Updated version of the custom option above.
+message NewOptionType {
+ enum TestEnum {
+ OLD_VALUE = 0;
+ NEW_VALUE = 1;
+ }
+ required TestEnum value = 1;
+}
+
+extend google.protobuf.MessageOptions {
+ optional OldOptionType required_enum_opt = 106161807;
+}
+
+// Test message using the "required_enum_opt" option defined above.
+message TestMessageWithRequiredEnumOption {
+ option (required_enum_opt) = { value: OLD_VALUE };
+}
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/unittest_well_known_types.proto b/src/google/protobuf/unittest_well_known_types.proto
index 2cb7775c..c9075244 100644
--- a/src/google/protobuf/unittest_well_known_types.proto
+++ b/src/google/protobuf/unittest_well_known_types.proto
@@ -39,6 +39,8 @@ message TestWellKnownTypes {
google.protobuf.BoolValue bool_field = 16;
google.protobuf.StringValue string_field = 17;
google.protobuf.BytesValue bytes_field = 18;
+ // Part of struct, but useful to be able to test separately
+ google.protobuf.Value value_field = 19;
}
// A repeated field for each well-known type.
diff --git a/src/google/protobuf/unknown_enum_impl.h b/src/google/protobuf/unknown_enum_impl.h
deleted file mode 100644
index 7c68ad6c..00000000
--- a/src/google/protobuf/unknown_enum_impl.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__
-#define GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__
-
-#include <stdlib.h>
-
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/bridge/compatibility_mode_support.h>
-
-namespace google {
-namespace protobuf {
-
-// google/protobuf/message.h
-class Message;
-
-namespace util {
-
-// NOTE: You should not call these functions directly. Instead use either
-// HAS_UNKNOWN_ENUM() or GET_UNKNOWN_ENUM(), defined in the public header.
-// The macro-versions operate in a type-safe manner and behave appropriately
-// for the proto version of the message, whereas these versions assume a
-// specific proto version and allow the caller to pass in any arbitrary integer
-// value as a field number.
-//
-// Returns whether the message has unrecognized the enum value for a given
-// field. It also stores the value into the unknown_value parameter if the
-// function returns true and the pointer is not NULL.
-//
-// In proto2, invalid enum values will be treated as unknown fields. This
-// function checks that case.
-bool HasUnknownEnum(const Message& message, int32 field_number,
- int32* unknown_value = NULL);
-// Same as above, but returns all unknown enums.
-bool GetRepeatedEnumUnknowns(const Message& message, int32 field_number,
- vector<int32>* unknown_values = NULL);
-// In proto1, invalue enum values are stored in the same way as valid enum
-// values.
-// TODO(karner): Delete this once the migration to proto2 is complete.
-bool HasUnknownEnumProto1(const Message& message, int32 field_number,
- int32* unknown_value);
-// Same as above, but returns all unknown enums.
-bool GetRepeatedEnumUnknownsProto1(const Message& message, int32 field_number,
- vector<int32>* unknown_values);
-// Invokes the appropriate version based on whether the message is proto1
-// or proto2.
-template <typename T>
-bool HasUnknownEnum_Template(const T& message, int32 field_number,
- int32* unknown_value = NULL) {
- if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
- !internal::is_base_of<ProtocolMessage, T>::value) {
- return HasUnknownEnum(message, field_number, unknown_value);
- } else {
- return HasUnknownEnumProto1(message, field_number, unknown_value);
- }
-}
-// Invokes the appropriate version based on whether the message is proto1
-// or proto2.
-template <typename T>
-bool GetRepeatedEnumUnknowns_Template(
- const T& message, int32 field_number,
- vector<int32>* unknown_values = NULL) {
- if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
- !internal::is_base_of<ProtocolMessage, T>::value) {
- return GetRepeatedEnumUnknowns(message, field_number, unknown_values);
- } else {
- return GetRepeatedEnumUnknownsProto1(message, field_number,
- unknown_values);
- }
-}
-
-// NOTE: You should not call these functions directly. Instead use
-// CLEAR_UNKNOWN_ENUM(), defined in the public header. The macro-versions
-// operate in a type-safe manner and behave appropriately for the proto
-// version of the message, whereas these versions assume a specific proto
-// version and allow the caller to pass in any arbitrary integer value as a
-// field number.
-//
-// Clears the unknown entries of the given field of the message.
-void ClearUnknownEnum(Message* message, int32 field_number);
-// In proto1, clears the field if the value is out of range.
-// TODO(karner): Delete this or make it proto2-only once the migration
-// to proto2 is complete.
-void ClearUnknownEnumProto1(Message* message, int32 field_number);
-template <typename T>
-void ClearUnknownEnum_Template(T* message, int32 field_number) {
- if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
- !internal::is_base_of<ProtocolMessage, T>::value) {
- ClearUnknownEnum(message, field_number);
- } else {
- ClearUnknownEnumProto1(message, field_number);
- }
-}
-
-// NOTE: You should not call these functions directly. Instead use
-// SET_UNKNOWN_ENUM(), defined in the public header. The macro-versions
-// operate in a type-safe manner and behave appropriately for the proto
-// version of the message, whereas these versions assume a specific proto
-// version and allow the caller to pass in any arbitrary integer value as a
-// field number.
-//
-// Sets the given value in the unknown fields of the message.
-void SetUnknownEnum(Message* message, int32 field_number, int32 unknown_value);
-// In proto1, invalue enum values are stored in the same way as valid enum
-// values.
-// TODO(karner): Delete this once the migration to proto2 is complete.
-void SetUnknownEnumProto1(Message* message, int32 field_number,
- int32 unknown_value);
-// Invokes the appropriate version based on whether the message is proto1
-// or proto2.
-template <typename T>
-void SetUnknownEnum_Template(T* message, int32 field_number,
- int32 unknown_value) {
- if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
- !internal::is_base_of<ProtocolMessage, T>::value) {
- SetUnknownEnum(message, field_number, unknown_value);
- } else {
- SetUnknownEnumProto1(message, field_number, unknown_value);
- }
-}
-
-} // namespace util
-} // namespace protobuf
-
-} // namespace google
-#endif // GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__
diff --git a/src/google/protobuf/unknown_enum_test.proto b/src/google/protobuf/unknown_enum_test.proto
deleted file mode 100644
index 3c549cc7..00000000
--- a/src/google/protobuf/unknown_enum_test.proto
+++ /dev/null
@@ -1,62 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Definitions of protos for testing cross-version compatibility. The
-// UpRevision message acts as if it were a newer version of the DownRevision
-// message. That is, UpRevision shares all the same fields as DownRevision,
-// but UpRevision can add fields and add enum values.
-syntax = "proto2";
-
-package google.protobuf.util;
-
-option csharp_namespace = "Google.ProtocolBuffers.TestProtos";
-
-message DownRevision {
- enum Enum {
- DEFAULT_VALUE = 2;
- NONDEFAULT_VALUE = 3;
- }
-
- optional Enum value = 1 [default = DEFAULT_VALUE];
- repeated Enum values = 2;
-}
-
-message UpRevision {
- enum Enum {
- DEFAULT_VALUE = 2;
- NONDEFAULT_VALUE = 3;
- NEW_VALUE = 4;
- NEW_VALUE_2 = 5;
- NEW_VALUE_3 = 6;
- }
-
- optional Enum value = 1 [default = DEFAULT_VALUE];
- repeated Enum values = 2;
-}
diff --git a/src/google/protobuf/util/field_comparator.h b/src/google/protobuf/util/field_comparator.h
index ee676265..8b83c69f 100644
--- a/src/google/protobuf/util/field_comparator.h
+++ b/src/google/protobuf/util/field_comparator.h
@@ -93,7 +93,7 @@ class LIBPROTOBUF_EXPORT FieldComparator {
// Basic implementation of FieldComparator. Supports four modes of floating
// point value comparison: exact, approximate using MathUtil::AlmostEqual
-// method, and arbitrarilly precise using MathUtil::WithinFracionOrMargin.
+// method, and arbitrarilly precise using MathUtil::WithinFractionOrMargin.
class LIBPROTOBUF_EXPORT DefaultFieldComparator : public FieldComparator {
public:
enum FloatComparison {
diff --git a/src/google/protobuf/util/field_comparator_test.cc b/src/google/protobuf/util/field_comparator_test.cc
index 845839ac..23f7d51d 100644
--- a/src/google/protobuf/util/field_comparator_test.cc
+++ b/src/google/protobuf/util/field_comparator_test.cc
@@ -35,6 +35,12 @@
#include <google/protobuf/unittest.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/stubs/mathutil.h>
+// This gtest header is put after mathutil.h intentionally. We have to do
+// this because mathutil.h includes mathlimits.h which requires cmath not
+// being included to compile on some versions of gcc:
+// https://github.com/google/protobuf/blob/818c5eee08840355d70d2f3bdf1a2f17986a5e70/src/google/protobuf/stubs/mathlimits.h#L48
+// and the opensource version gtest.h header includes cmath transitively
+// somehow.
#include <gtest/gtest.h>
namespace google {
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<string> 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<string> 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 <google/protobuf/descriptor.h>
#include <google/protobuf/field_mask.pb.h>
+#include <google/protobuf/stubs/stringpiece.h>
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 <typename T>
- 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 <typename T>
- static void AddPathToFieldMask(const string& path, FieldMask* mask) {
+ static void AddPathToFieldMask(StringPiece path, FieldMask* mask) {
GOOGLE_CHECK(IsValidPath<T>(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/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc
index ea360798..b557429f 100644
--- a/src/google/protobuf/util/internal/datapiece.cc
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -35,8 +35,8 @@
#include <google/protobuf/descriptor.h>
#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/mathutil.h>
#include <google/protobuf/stubs/mathlimits.h>
+#include <google/protobuf/stubs/mathutil.h>
namespace google {
namespace protobuf {
@@ -57,13 +57,8 @@ inline Status InvalidArgument(StringPiece value_str) {
return Status(util::error::INVALID_ARGUMENT, value_str);
}
-// For general conversion between
-// int32, int64, uint32, uint64, double and float
-// except conversion between double and float.
template <typename To, typename From>
-StatusOr<To> NumberConvertAndCheck(From before) {
- if (::google::protobuf::internal::is_same<From, To>::value) return before;
- To after = static_cast<To>(before);
+StatusOr<To> ValidateNumberConversion(To after, From before) {
if (after == before &&
MathUtil::Sign<From>(before) == MathUtil::Sign<To>(after)) {
return after;
@@ -76,6 +71,27 @@ StatusOr<To> NumberConvertAndCheck(From before) {
}
}
+// For general conversion between
+// int32, int64, uint32, uint64, double and float
+// except conversion between double and float.
+template <typename To, typename From>
+StatusOr<To> NumberConvertAndCheck(From before) {
+ if (::google::protobuf::internal::is_same<From, To>::value) return before;
+
+ To after = static_cast<To>(before);
+ return ValidateNumberConversion(after, before);
+}
+
+// For conversion to integer types (int32, int64, uint32, uint64) from floating
+// point types (double, float) only.
+template <typename To, typename From>
+StatusOr<To> FloatingPointToIntConvertAndCheck(From before) {
+ if (::google::protobuf::internal::is_same<From, To>::value) return before;
+
+ To after = static_cast<To>(before);
+ return ValidateNumberConversion(after, before);
+}
+
// For conversion between double and float only.
template <typename To, typename From>
StatusOr<To> FloatingPointConvertAndCheck(From before) {
@@ -96,30 +112,50 @@ StatusOr<To> FloatingPointConvertAndCheck(From before) {
} // namespace
StatusOr<int32> DataPiece::ToInt32() const {
- if (type_ == TYPE_STRING) {
- return StringToNumber<int32>(safe_strto32);
- }
+ if (type_ == TYPE_STRING) return StringToNumber<int32>(safe_strto32);
+
+ if (type_ == TYPE_DOUBLE)
+ return FloatingPointToIntConvertAndCheck<int32, double>(double_);
+
+ if (type_ == TYPE_FLOAT)
+ return FloatingPointToIntConvertAndCheck<int32, float>(float_);
+
return GenericConvert<int32>();
}
StatusOr<uint32> DataPiece::ToUint32() const {
- if (type_ == TYPE_STRING) {
- return StringToNumber<uint32>(safe_strtou32);
- }
+ if (type_ == TYPE_STRING) return StringToNumber<uint32>(safe_strtou32);
+
+ if (type_ == TYPE_DOUBLE)
+ return FloatingPointToIntConvertAndCheck<uint32, double>(double_);
+
+ if (type_ == TYPE_FLOAT)
+ return FloatingPointToIntConvertAndCheck<uint32, float>(float_);
+
return GenericConvert<uint32>();
}
StatusOr<int64> DataPiece::ToInt64() const {
- if (type_ == TYPE_STRING) {
- return StringToNumber<int64>(safe_strto64);
- }
+ if (type_ == TYPE_STRING) return StringToNumber<int64>(safe_strto64);
+
+ if (type_ == TYPE_DOUBLE)
+ return FloatingPointToIntConvertAndCheck<int64, double>(double_);
+
+ if (type_ == TYPE_FLOAT)
+ return FloatingPointToIntConvertAndCheck<int64, float>(float_);
+
return GenericConvert<int64>();
}
StatusOr<uint64> DataPiece::ToUint64() const {
- if (type_ == TYPE_STRING) {
- return StringToNumber<uint64>(safe_strtou64);
- }
+ if (type_ == TYPE_STRING) return StringToNumber<uint64>(safe_strtou64);
+
+ if (type_ == TYPE_DOUBLE)
+ return FloatingPointToIntConvertAndCheck<uint64, double>(double_);
+
+ if (type_ == TYPE_FLOAT)
+ return FloatingPointToIntConvertAndCheck<uint64, float>(float_);
+
return GenericConvert<uint64>();
}
diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h
index 2ab3fa88..f22bfe70 100644
--- a/src/google/protobuf/util/internal/datapiece.h
+++ b/src/google/protobuf/util/internal/datapiece.h
@@ -98,7 +98,8 @@ class LIBPROTOBUF_EXPORT DataPiece {
static DataPiece NullData() { return DataPiece(TYPE_NULL, 0); }
- virtual ~DataPiece() {}
+ virtual ~DataPiece() {
+ }
// Accessors
Type type() const { return type_; }
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc
index 97b248ff..a63e560d 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter.cc
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc
@@ -33,6 +33,7 @@
#include <google/protobuf/stubs/hash.h>
#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/stubs/map_util.h>
namespace google {
@@ -42,13 +43,25 @@ using util::Status;
using util::StatusOr;
namespace converter {
+namespace {
+// Helper function to convert string value to given data type by calling the
+// passed converter function on the DataPiece created from "value" argument.
+// If value is empty or if conversion fails, the default_value is returned.
+template <typename T>
+T ConvertTo(StringPiece value, StatusOr<T> (DataPiece::*converter_fn)() const,
+ T default_value) {
+ if (value.empty()) return default_value;
+ StatusOr<T> result = (DataPiece(value).*converter_fn)();
+ return result.ok() ? result.ValueOrDie() : default_value;
+}
+} // namespace
+
DefaultValueObjectWriter::DefaultValueObjectWriter(
TypeResolver* type_resolver, const google::protobuf::Type& type,
ObjectWriter* ow)
: typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
own_typeinfo_(true),
type_(type),
- disable_normalize_(false),
current_(NULL),
root_(NULL),
ow_(ow) {}
@@ -165,12 +178,6 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
return this;
}
-DefaultValueObjectWriter*
-DefaultValueObjectWriter::DisableCaseNormalizationForNextKey() {
- disable_normalize_ = true;
- return this;
-}
-
DefaultValueObjectWriter::Node::Node(const string& name,
const google::protobuf::Type* type,
NodeKind kind, const DataPiece& data,
@@ -178,7 +185,6 @@ DefaultValueObjectWriter::Node::Node(const string& name,
: name_(name),
type_(type),
kind_(kind),
- disable_normalize_(false),
is_any_(false),
data_(data),
is_placeholder_(is_placeholder) {}
@@ -198,10 +204,6 @@ DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
}
void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
- if (disable_normalize_) {
- ow->DisableCaseNormalizationForNextKey();
- }
-
if (kind_ == PRIMITIVE) {
ObjectWriter::RenderDataPieceTo(data_, name_, ow);
return;
@@ -324,6 +326,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren(
}
}
}
+
if (!is_map &&
field.cardinality() ==
google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
@@ -336,11 +339,11 @@ void DefaultValueObjectWriter::Node::PopulateChildren(
// If the child field is of primitive type, sets its data to the default
// value of its type.
- google::protobuf::scoped_ptr<Node> child(
- new Node(field.json_name(), field_type, kind,
- kind == PRIMITIVE ? CreateDefaultDataPieceForField(field)
- : DataPiece::NullData(),
- true));
+ google::protobuf::scoped_ptr<Node> child(new Node(
+ field.json_name(), field_type, kind,
+ kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo)
+ : DataPiece::NullData(),
+ true));
new_children.push_back(child.release());
}
// Adds all leftover nodes in children_ to the beginning of new_child.
@@ -363,41 +366,68 @@ void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) {
}
}
+DataPiece DefaultValueObjectWriter::FindEnumDefault(
+ const google::protobuf::Field& field, const TypeInfo* typeinfo) {
+ if (!field.default_value().empty()) return DataPiece(field.default_value());
+
+ const google::protobuf::Enum* enum_type =
+ typeinfo->GetEnumByTypeUrl(field.type_url());
+ if (!enum_type) {
+ GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url()
+ << "'";
+ return DataPiece::NullData();
+ }
+ // We treat the first value as the default if none is specified.
+ return enum_type->enumvalue_size() > 0
+ ? DataPiece(enum_type->enumvalue(0).name())
+ : DataPiece::NullData();
+}
+
DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
- const google::protobuf::Field& field) {
+ const google::protobuf::Field& field, const TypeInfo* typeinfo) {
switch (field.kind()) {
case google::protobuf::Field_Kind_TYPE_DOUBLE: {
- return DataPiece(static_cast<double>(0));
+ return DataPiece(ConvertTo<double>(
+ field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
}
case google::protobuf::Field_Kind_TYPE_FLOAT: {
- return DataPiece(static_cast<float>(0));
+ return DataPiece(ConvertTo<float>(
+ field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
}
case google::protobuf::Field_Kind_TYPE_INT64:
case google::protobuf::Field_Kind_TYPE_SINT64:
case google::protobuf::Field_Kind_TYPE_SFIXED64: {
- return DataPiece(static_cast<int64>(0));
+ return DataPiece(ConvertTo<int64>(
+ field.default_value(), &DataPiece::ToInt64, static_cast<int64>(0)));
}
case google::protobuf::Field_Kind_TYPE_UINT64:
case google::protobuf::Field_Kind_TYPE_FIXED64: {
- return DataPiece(static_cast<uint64>(0));
+ return DataPiece(ConvertTo<uint64>(
+ field.default_value(), &DataPiece::ToUint64, static_cast<uint64>(0)));
}
case google::protobuf::Field_Kind_TYPE_INT32:
case google::protobuf::Field_Kind_TYPE_SINT32:
case google::protobuf::Field_Kind_TYPE_SFIXED32: {
- return DataPiece(static_cast<int32>(0));
+ return DataPiece(ConvertTo<int32>(
+ field.default_value(), &DataPiece::ToInt32, static_cast<int32>(0)));
}
case google::protobuf::Field_Kind_TYPE_BOOL: {
- return DataPiece(false);
+ return DataPiece(
+ ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
}
case google::protobuf::Field_Kind_TYPE_STRING: {
- return DataPiece(string());
+ return DataPiece(field.default_value());
}
case google::protobuf::Field_Kind_TYPE_BYTES: {
- return DataPiece("", false);
+ return DataPiece(field.default_value(), false);
}
case google::protobuf::Field_Kind_TYPE_UINT32:
case google::protobuf::Field_Kind_TYPE_FIXED32: {
- return DataPiece(static_cast<uint32>(0));
+ return DataPiece(ConvertTo<uint32>(
+ field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0)));
+ }
+ case google::protobuf::Field_Kind_TYPE_ENUM: {
+ return FindEnumDefault(field, typeinfo);
}
default: { return DataPiece::NullData(); }
}
@@ -408,7 +438,6 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
if (current_ == NULL) {
root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(),
false));
- root_->set_disable_normalize(GetAndResetDisableNormalize());
root_->PopulateChildren(typeinfo_);
current_ = root_.get();
return this;
@@ -428,7 +457,6 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
}
child->set_is_placeholder(false);
- child->set_disable_normalize(GetAndResetDisableNormalize());
if (child->kind() == OBJECT && child->number_of_children() == 0) {
child->PopulateChildren(typeinfo_);
}
@@ -454,21 +482,18 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartList(
if (current_ == NULL) {
root_.reset(
new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), false));
- root_->set_disable_normalize(GetAndResetDisableNormalize());
current_ = root_.get();
return this;
}
MaybePopulateChildrenOfAny(current_);
Node* child = current_->FindChild(name);
if (child == NULL || child->kind() != LIST) {
- GOOGLE_LOG(WARNING) << "Cannot find field '" << name << "'.";
google::protobuf::scoped_ptr<Node> node(
new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false));
child = node.get();
current_->AddChild(node.release());
}
child->set_is_placeholder(false);
- child->set_disable_normalize(GetAndResetDisableNormalize());
stack_.push(current_);
current_ = child;
@@ -526,7 +551,6 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
} else {
child->set_data(data);
}
- child->set_disable_normalize(GetAndResetDisableNormalize());
}
} // namespace converter
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h
index d4547601..695b9dd8 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter.h
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.h
@@ -98,8 +98,6 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
virtual DefaultValueObjectWriter* RenderNull(StringPiece name);
- virtual DefaultValueObjectWriter* DisableCaseNormalizationForNextKey();
-
private:
enum NodeKind {
PRIMITIVE = 0,
@@ -110,7 +108,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);
@@ -149,10 +147,6 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
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; }
@@ -176,8 +170,6 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
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.
@@ -201,16 +193,17 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
// 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;
- }
+ const google::protobuf::Field& field, const TypeInfo* typeinfo);
// Adds or replaces the data_ of a primitive child node.
void RenderDataPiece(StringPiece name, const DataPiece& data);
+ // Returns the default enum value as a DataPiece, or the first enum value if
+ // there is no default. For proto3, where we cannot specify an explicit
+ // default, a zero value will always be returned.
+ static DataPiece FindEnumDefault(const google::protobuf::Field& field,
+ const TypeInfo* typeinfo);
+
// Type information for all the types used in the descriptor. Used to find
// google::protobuf::Type of nested messages/enums.
const TypeInfo* typeinfo_;
@@ -221,8 +214,6 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
// Holds copies of strings passed to RenderString.
vector<string*> 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.
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
index 237d0722..8254c0fa 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
@@ -43,21 +43,19 @@ namespace testing {
using google::protobuf::testing::DefaultValueTest;
-// Tests to cover some basic DefaultValueObjectWriter use cases. More tests are
-// in the marshalling_test.cc and translator_integration_test.cc.
-class DefaultValueObjectWriterTest
+// Base class for setting up required state for running default values tests on
+// different descriptors.
+class BaseDefaultValueObjectWriterTest
: public ::testing::TestWithParam<testing::TypeInfoSource> {
protected:
- DefaultValueObjectWriterTest()
+ explicit BaseDefaultValueObjectWriterTest(const Descriptor* descriptor)
: helper_(GetParam()), mock_(), expects_(&mock_) {
- helper_.ResetTypeInfo(DefaultValueTest::descriptor());
+ helper_.ResetTypeInfo(descriptor);
testing_.reset(helper_.NewDefaultValueWriter(
- string(kTypeServiceBaseUrl) + "/" +
- DefaultValueTest::descriptor()->full_name(),
- &mock_));
+ string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(), &mock_));
}
- virtual ~DefaultValueObjectWriterTest() {}
+ virtual ~BaseDefaultValueObjectWriterTest() {}
TypeInfoTestHelper helper_;
MockObjectWriter mock_;
@@ -65,6 +63,15 @@ class DefaultValueObjectWriterTest
google::protobuf::scoped_ptr<DefaultValueObjectWriter> testing_;
};
+// Tests to cover some basic DefaultValueObjectWriter use cases. More tests are
+// in the marshalling_test.cc and translator_integration_test.cc.
+class DefaultValueObjectWriterTest : public BaseDefaultValueObjectWriterTest {
+ protected:
+ DefaultValueObjectWriterTest()
+ : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) {}
+ virtual ~DefaultValueObjectWriterTest() {}
+};
+
INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
DefaultValueObjectWriterTest,
::testing::Values(
@@ -74,6 +81,8 @@ TEST_P(DefaultValueObjectWriterTest, Empty) {
// Set expectation
expects_.StartObject("")
->RenderDouble("doubleValue", 0.0)
+ ->StartList("repeatedDouble")
+ ->EndList()
->RenderFloat("floatValue", 0.0)
->RenderInt64("int64Value", 0)
->RenderUint64("uint64Value", 0)
@@ -82,6 +91,7 @@ TEST_P(DefaultValueObjectWriterTest, Empty) {
->RenderBool("boolValue", false)
->RenderString("stringValue", "")
->RenderBytes("bytesValue", "")
+ ->RenderString("enumValue", "ENUM_FIRST")
->EndObject();
// Actual testing
@@ -92,6 +102,8 @@ TEST_P(DefaultValueObjectWriterTest, NonDefaultDouble) {
// Set expectation
expects_.StartObject("")
->RenderDouble("doubleValue", 1.0)
+ ->StartList("repeatedDouble")
+ ->EndList()
->RenderFloat("floatValue", 0.0)
->RenderInt64("int64Value", 0)
->RenderUint64("uint64Value", 0)
@@ -99,6 +111,7 @@ TEST_P(DefaultValueObjectWriterTest, NonDefaultDouble) {
->RenderUint32("uint32Value", 0)
->RenderBool("boolValue", false)
->RenderString("stringValue", "")
+ ->RenderString("enumValue", "ENUM_FIRST")
->EndObject();
// Actual testing
@@ -109,6 +122,8 @@ TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) {
// Set expectation
expects_.StartObject("")
->RenderDouble("doubleValue", 1.0)
+ ->StartList("repeatedDouble")
+ ->EndList()
->RenderFloat("floatValue", 0.0)
->RenderInt64("int64Value", 0)
->RenderUint64("uint64Value", 0)
@@ -120,6 +135,7 @@ TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) {
->StartObject("unknownObject")
->RenderString("unknown", "def")
->EndObject()
+ ->RenderString("enumValue", "ENUM_FIRST")
->EndObject();
// Actual testing
@@ -132,6 +148,7 @@ TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) {
->EndObject();
}
+
} // namespace testing
} // namespace converter
} // namespace util
diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h
index 2699684d..3f063936 100644
--- a/src/google/protobuf/util/internal/error_listener.h
+++ b/src/google/protobuf/util/internal/error_listener.h
@@ -31,11 +31,13 @@
#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__
#define GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__
+#include <algorithm>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <string>
+#include <vector>
#include <google/protobuf/stubs/callback.h>
#include <google/protobuf/stubs/common.h>
diff --git a/src/google/protobuf/util/internal/json_escaping.cc b/src/google/protobuf/util/internal/json_escaping.cc
index 36dc8ef9..24bd554e 100644
--- a/src/google/protobuf/util/internal/json_escaping.cc
+++ b/src/google/protobuf/util/internal/json_escaping.cc
@@ -186,7 +186,7 @@ bool ReadCodePoint(StringPiece str, int index,
uint32 *cp, int* num_left, int *num_read) {
if (*num_left == 0) {
// Last read was complete. Start reading a new unicode code point.
- *cp = str[index++];
+ *cp = static_cast<uint8>(str[index++]);
*num_read = 1;
// The length of the code point is determined from reading the first byte.
//
@@ -235,7 +235,7 @@ bool ReadCodePoint(StringPiece str, int index,
*num_read = 0;
}
while (*num_left > 0 && index < str.size()) {
- uint32 ch = str[index++];
+ uint32 ch = static_cast<uint8>(str[index++]);
--(*num_left);
++(*num_read);
*cp = (*cp << 6) | (ch & 0x3f);
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 <google/protobuf/stubs/common.h>
#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/util/internal/json_escaping.h>
-#include <google/protobuf/stubs/mathlimits.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/mathlimits.h>
namespace google {
namespace protobuf {
@@ -116,7 +116,7 @@ JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name,
JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
double value) {
- if (google::protobuf::MathLimits<double>::IsFinite(value)) {
+ if (MathLimits<double>::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<float>::IsFinite(value)) {
+ if (MathLimits<float>::IsFinite(value)) {
return RenderSimple(name, SimpleFtoa(value));
}
diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc
index dcd60601..9d820162 100644
--- a/src/google/protobuf/util/internal/json_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc
@@ -47,8 +47,7 @@ class JsonObjectWriterTest : public ::testing::Test {
JsonObjectWriterTest()
: str_stream_(new StringOutputStream(&output_)),
out_stream_(new CodedOutputStream(str_stream_)),
- ow_(NULL) {
- }
+ ow_(NULL) {}
virtual ~JsonObjectWriterTest() {
delete ow_;
@@ -64,36 +63,34 @@ class JsonObjectWriterTest : public ::testing::Test {
TEST_F(JsonObjectWriterTest, EmptyRootObject) {
ow_ = new JsonObjectWriter("", out_stream_);
- ow_->StartObject("")
- ->EndObject();
+ ow_->StartObject("")->EndObject();
EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount()));
}
TEST_F(JsonObjectWriterTest, EmptyObject) {
ow_ = new JsonObjectWriter("", out_stream_);
ow_->StartObject("")
- ->RenderString("test", "value")
- ->StartObject("empty")
- ->EndObject()
- ->EndObject();
+ ->RenderString("test", "value")
+ ->StartObject("empty")
+ ->EndObject()
+ ->EndObject();
EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}",
output_.substr(0, out_stream_->ByteCount()));
}
TEST_F(JsonObjectWriterTest, EmptyRootList) {
ow_ = new JsonObjectWriter("", out_stream_);
- ow_->StartList("")
- ->EndList();
+ ow_->StartList("")->EndList();
EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount()));
}
TEST_F(JsonObjectWriterTest, EmptyList) {
ow_ = new JsonObjectWriter("", out_stream_);
ow_->StartObject("")
- ->RenderString("test", "value")
- ->StartList("empty")
- ->EndList()
- ->EndObject();
+ ->RenderString("test", "value")
+ ->StartList("empty")
+ ->EndList()
+ ->EndObject();
EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}",
output_.substr(0, out_stream_->ByteCount()));
}
@@ -101,10 +98,10 @@ TEST_F(JsonObjectWriterTest, EmptyList) {
TEST_F(JsonObjectWriterTest, ObjectInObject) {
ow_ = new JsonObjectWriter("", out_stream_);
ow_->StartObject("")
- ->StartObject("nested")
- ->RenderString("field", "value")
- ->EndObject()
- ->EndObject();
+ ->StartObject("nested")
+ ->RenderString("field", "value")
+ ->EndObject()
+ ->EndObject();
EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}",
output_.substr(0, out_stream_->ByteCount()));
}
@@ -112,10 +109,10 @@ TEST_F(JsonObjectWriterTest, ObjectInObject) {
TEST_F(JsonObjectWriterTest, ListInObject) {
ow_ = new JsonObjectWriter("", out_stream_);
ow_->StartObject("")
- ->StartList("nested")
- ->RenderString("", "value")
- ->EndList()
- ->EndObject();
+ ->StartList("nested")
+ ->RenderString("", "value")
+ ->EndList()
+ ->EndObject();
EXPECT_EQ("{\"nested\":[\"value\"]}",
output_.substr(0, out_stream_->ByteCount()));
}
@@ -123,10 +120,10 @@ TEST_F(JsonObjectWriterTest, ListInObject) {
TEST_F(JsonObjectWriterTest, ObjectInList) {
ow_ = new JsonObjectWriter("", out_stream_);
ow_->StartList("")
- ->StartObject("")
- ->RenderString("field", "value")
- ->EndObject()
- ->EndList();
+ ->StartObject("")
+ ->RenderString("field", "value")
+ ->EndObject()
+ ->EndList();
EXPECT_EQ("[{\"field\":\"value\"}]",
output_.substr(0, out_stream_->ByteCount()));
}
@@ -134,10 +131,10 @@ TEST_F(JsonObjectWriterTest, ObjectInList) {
TEST_F(JsonObjectWriterTest, ListInList) {
ow_ = new JsonObjectWriter("", out_stream_);
ow_->StartList("")
- ->StartList("")
- ->RenderString("", "value")
- ->EndList()
- ->EndList();
+ ->StartList("")
+ ->RenderString("", "value")
+ ->EndList()
+ ->EndList();
EXPECT_EQ("[[\"value\"]]", output_.substr(0, out_stream_->ByteCount()));
}
@@ -156,14 +153,18 @@ TEST_F(JsonObjectWriterTest, RenderPrimitives) {
->EndObject();
EXPECT_EQ(
"{\"bool\":true,"
- "\"double\":" + ValueAsString<double>(1.7976931348623157e+308) + ","
- "\"float\":" + ValueAsString<float>(3.4028235e+38) + ","
- "\"int\":-2147483648,"
- "\"long\":\"-9223372036854775808\","
- "\"bytes\":\"YWJyYWNhZGFicmE=\","
- "\"string\":\"string\","
- "\"emptybytes\":\"\","
- "\"emptystring\":\"\"}",
+ "\"double\":" +
+ ValueAsString<double>(std::numeric_limits<double>::max()) +
+ ","
+ "\"float\":" +
+ ValueAsString<float>(std::numeric_limits<float>::max()) +
+ ","
+ "\"int\":-2147483648,"
+ "\"long\":\"-9223372036854775808\","
+ "\"bytes\":\"YWJyYWNhZGFicmE=\","
+ "\"string\":\"string\","
+ "\"emptybytes\":\"\","
+ "\"emptystring\":\"\"}",
output_.substr(0, out_stream_->ByteCount()));
}
@@ -181,81 +182,83 @@ TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) {
TEST_F(JsonObjectWriterTest, PrettyPrintList) {
ow_ = new JsonObjectWriter(" ", out_stream_);
ow_->StartObject("")
- ->StartList("items")
- ->RenderString("", "item1")
- ->RenderString("", "item2")
- ->RenderString("", "item3")
- ->EndList()
- ->StartList("empty")
- ->EndList()
- ->EndObject();
- EXPECT_EQ("{\n"
- " \"items\": [\n"
- " \"item1\",\n"
- " \"item2\",\n"
- " \"item3\"\n"
- " ],\n"
- " \"empty\": []\n"
- "}\n",
- output_.substr(0, out_stream_->ByteCount()));
+ ->StartList("items")
+ ->RenderString("", "item1")
+ ->RenderString("", "item2")
+ ->RenderString("", "item3")
+ ->EndList()
+ ->StartList("empty")
+ ->EndList()
+ ->EndObject();
+ EXPECT_EQ(
+ "{\n"
+ " \"items\": [\n"
+ " \"item1\",\n"
+ " \"item2\",\n"
+ " \"item3\"\n"
+ " ],\n"
+ " \"empty\": []\n"
+ "}\n",
+ output_.substr(0, out_stream_->ByteCount()));
}
TEST_F(JsonObjectWriterTest, PrettyPrintObject) {
ow_ = new JsonObjectWriter(" ", out_stream_);
ow_->StartObject("")
- ->StartObject("items")
- ->RenderString("key1", "item1")
- ->RenderString("key2", "item2")
- ->RenderString("key3", "item3")
- ->EndObject()
- ->StartObject("empty")
- ->EndObject()
- ->EndObject();
- EXPECT_EQ("{\n"
- " \"items\": {\n"
- " \"key1\": \"item1\",\n"
- " \"key2\": \"item2\",\n"
- " \"key3\": \"item3\"\n"
- " },\n"
- " \"empty\": {}\n"
- "}\n",
- output_.substr(0, out_stream_->ByteCount()));
+ ->StartObject("items")
+ ->RenderString("key1", "item1")
+ ->RenderString("key2", "item2")
+ ->RenderString("key3", "item3")
+ ->EndObject()
+ ->StartObject("empty")
+ ->EndObject()
+ ->EndObject();
+ EXPECT_EQ(
+ "{\n"
+ " \"items\": {\n"
+ " \"key1\": \"item1\",\n"
+ " \"key2\": \"item2\",\n"
+ " \"key3\": \"item3\"\n"
+ " },\n"
+ " \"empty\": {}\n"
+ "}\n",
+ output_.substr(0, out_stream_->ByteCount()));
}
TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) {
ow_ = new JsonObjectWriter(" ", out_stream_);
ow_->StartObject("")
- ->StartList("list")
- ->StartObject("")
- ->EndObject()
- ->EndList()
- ->EndObject();
- EXPECT_EQ("{\n"
- " \"list\": [\n"
- " {}\n"
- " ]\n"
- "}\n",
- output_.substr(0, out_stream_->ByteCount()));
+ ->StartList("list")
+ ->StartObject("")
+ ->EndObject()
+ ->EndList()
+ ->EndObject();
+ EXPECT_EQ(
+ "{\n"
+ " \"list\": [\n"
+ " {}\n"
+ " ]\n"
+ "}\n",
+ output_.substr(0, out_stream_->ByteCount()));
}
TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) {
ow_ = new JsonObjectWriter(" ", out_stream_);
ow_->StartObject("")
- ->RenderBool("bool", true)
- ->RenderInt32("int", 42)
- ->EndObject();
- EXPECT_EQ("{\n"
- " \"bool\": true,\n"
- " \"int\": 42\n"
- "}\n",
- output_.substr(0, out_stream_->ByteCount()));
+ ->RenderBool("bool", true)
+ ->RenderInt32("int", 42)
+ ->EndObject();
+ EXPECT_EQ(
+ "{\n"
+ " \"bool\": true,\n"
+ " \"int\": 42\n"
+ "}\n",
+ output_.substr(0, out_stream_->ByteCount()));
}
TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) {
ow_ = new JsonObjectWriter("", out_stream_);
- ow_->StartObject("")
- ->RenderString("string", "'<>&amp;\\\"\r\n")
- ->EndObject();
+ ow_->StartObject("")->RenderString("string", "'<>&amp;\\\"\r\n")->EndObject();
EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&amp;\\\\\\\"\\r\\n\"}",
output_.substr(0, out_stream_->ByteCount()));
}
@@ -263,13 +266,13 @@ TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) {
TEST_F(JsonObjectWriterTest, Stringification) {
ow_ = new JsonObjectWriter("", out_stream_);
ow_->StartObject("")
- ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN())
- ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN())
- ->RenderDouble("double_pos", std::numeric_limits<double>::infinity())
- ->RenderFloat("float_pos", std::numeric_limits<float>::infinity())
- ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity())
- ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity())
- ->EndObject();
+ ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN())
+ ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN())
+ ->RenderDouble("double_pos", std::numeric_limits<double>::infinity())
+ ->RenderFloat("float_pos", std::numeric_limits<float>::infinity())
+ ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity())
+ ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity())
+ ->EndObject();
EXPECT_EQ(
"{\"double_nan\":\"NaN\","
"\"float_nan\":\"NaN\","
diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc
index a7ef7fe2..df916751 100644
--- a/src/google/protobuf/util/internal/json_stream_parser.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -157,10 +157,10 @@ util::Status JsonStreamParser::FinishParse() {
char* coerced = internal::UTF8CoerceToStructurallyValid(leftover_, utf8.get(), ' ');
p_ = json_ = StringPiece(coerced, leftover_.size());
} else {
+ p_ = json_ = leftover_;
if (!internal::IsStructurallyValidUTF8(leftover_)) {
return ReportFailure("Encountered non UTF-8 code points.");
}
- p_ = json_ = leftover_;
}
// Parse the remainder in finishing mode, which reports errors for things like
diff --git a/src/google/protobuf/util/internal/json_stream_parser_test.cc b/src/google/protobuf/util/internal/json_stream_parser_test.cc
index c833ed1f..3414826e 100644
--- a/src/google/protobuf/util/internal/json_stream_parser_test.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc
@@ -348,6 +348,7 @@ TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) {
for (int i = 0; i <= json.length(); ++i) {
DoErrorTest(json, i, "Encountered non UTF-8 code points.");
}
+ DoErrorTest("\xFF{}", 0, "Encountered non UTF-8 code points.");
}
#ifndef _MSC_VER
diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h
index 20bd3627..e695f45e 100644
--- a/src/google/protobuf/util/internal/object_writer.h
+++ b/src/google/protobuf/util/internal/object_writer.h
@@ -101,11 +101,6 @@ class LIBPROTOBUF_EXPORT ObjectWriter {
// Renders a Null value.
virtual ObjectWriter* RenderNull(StringPiece name) = 0;
- // Disables case normalization. Any RenderTYPE call after calling this
- // function will output the name field as-is. No normalization is attempted on
- // it. This setting is reset immediately after the next RenderTYPE is called.
- virtual ObjectWriter* DisableCaseNormalizationForNextKey() { return this; }
-
// Renders a DataPiece object to a ObjectWriter.
static void RenderDataPieceTo(const DataPiece& data, StringPiece name,
ObjectWriter* ow);
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
new file mode 100644
index 00000000..47e0009e
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -0,0 +1,744 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/proto_writer.h>
+
+#include <functional>
+#include <stack>
+
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/statusor.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using google::protobuf::internal::WireFormatLite;
+using google::protobuf::io::CodedOutputStream;
+using util::error::INVALID_ARGUMENT;
+using util::Status;
+using util::StatusOr;
+
+
+ProtoWriter::ProtoWriter(TypeResolver* type_resolver,
+ const google::protobuf::Type& type,
+ strings::ByteSink* output, ErrorListener* listener)
+ : master_type_(type),
+ typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
+ own_typeinfo_(true),
+ done_(false),
+ element_(NULL),
+ size_insert_(),
+ output_(output),
+ buffer_(),
+ adapter_(&buffer_),
+ stream_(new CodedOutputStream(&adapter_)),
+ listener_(listener),
+ invalid_depth_(0),
+ tracker_(new ObjectLocationTracker()) {}
+
+ProtoWriter::ProtoWriter(const TypeInfo* typeinfo,
+ const google::protobuf::Type& type,
+ strings::ByteSink* output, ErrorListener* listener)
+ : master_type_(type),
+ typeinfo_(typeinfo),
+ own_typeinfo_(false),
+ done_(false),
+ element_(NULL),
+ size_insert_(),
+ output_(output),
+ buffer_(),
+ adapter_(&buffer_),
+ stream_(new CodedOutputStream(&adapter_)),
+ listener_(listener),
+ invalid_depth_(0),
+ tracker_(new ObjectLocationTracker()) {}
+
+ProtoWriter::~ProtoWriter() {
+ if (own_typeinfo_) {
+ delete typeinfo_;
+ }
+ if (element_ == NULL) return;
+ // Cleanup explicitly in order to avoid destructor stack overflow when input
+ // is deeply nested.
+ // Cast to BaseElement to avoid doing additional checks (like missing fields)
+ // during pop().
+ google::protobuf::scoped_ptr<BaseElement> element(
+ static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
+ while (element != NULL) {
+ element.reset(element->pop<BaseElement>());
+ }
+}
+
+namespace {
+
+// Writes an INT32 field, including tag to the stream.
+inline Status WriteInt32(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<int32> i32 = data.ToInt32();
+ if (i32.ok()) {
+ WireFormatLite::WriteInt32(field_number, i32.ValueOrDie(), stream);
+ }
+ return i32.status();
+}
+
+// writes an SFIXED32 field, including tag, to the stream.
+inline Status WriteSFixed32(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<int32> i32 = data.ToInt32();
+ if (i32.ok()) {
+ WireFormatLite::WriteSFixed32(field_number, i32.ValueOrDie(), stream);
+ }
+ return i32.status();
+}
+
+// Writes an SINT32 field, including tag, to the stream.
+inline Status WriteSInt32(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<int32> i32 = data.ToInt32();
+ if (i32.ok()) {
+ WireFormatLite::WriteSInt32(field_number, i32.ValueOrDie(), stream);
+ }
+ return i32.status();
+}
+
+// Writes a FIXED32 field, including tag, to the stream.
+inline Status WriteFixed32(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<uint32> u32 = data.ToUint32();
+ if (u32.ok()) {
+ WireFormatLite::WriteFixed32(field_number, u32.ValueOrDie(), stream);
+ }
+ return u32.status();
+}
+
+// Writes a UINT32 field, including tag, to the stream.
+inline Status WriteUInt32(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<uint32> u32 = data.ToUint32();
+ if (u32.ok()) {
+ WireFormatLite::WriteUInt32(field_number, u32.ValueOrDie(), stream);
+ }
+ return u32.status();
+}
+
+// Writes an INT64 field, including tag, to the stream.
+inline Status WriteInt64(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<int64> i64 = data.ToInt64();
+ if (i64.ok()) {
+ WireFormatLite::WriteInt64(field_number, i64.ValueOrDie(), stream);
+ }
+ return i64.status();
+}
+
+// Writes an SFIXED64 field, including tag, to the stream.
+inline Status WriteSFixed64(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<int64> i64 = data.ToInt64();
+ if (i64.ok()) {
+ WireFormatLite::WriteSFixed64(field_number, i64.ValueOrDie(), stream);
+ }
+ return i64.status();
+}
+
+// Writes an SINT64 field, including tag, to the stream.
+inline Status WriteSInt64(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<int64> i64 = data.ToInt64();
+ if (i64.ok()) {
+ WireFormatLite::WriteSInt64(field_number, i64.ValueOrDie(), stream);
+ }
+ return i64.status();
+}
+
+// Writes a FIXED64 field, including tag, to the stream.
+inline Status WriteFixed64(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<uint64> u64 = data.ToUint64();
+ if (u64.ok()) {
+ WireFormatLite::WriteFixed64(field_number, u64.ValueOrDie(), stream);
+ }
+ return u64.status();
+}
+
+// Writes a UINT64 field, including tag, to the stream.
+inline Status WriteUInt64(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<uint64> u64 = data.ToUint64();
+ if (u64.ok()) {
+ WireFormatLite::WriteUInt64(field_number, u64.ValueOrDie(), stream);
+ }
+ return u64.status();
+}
+
+// Writes a DOUBLE field, including tag, to the stream.
+inline Status WriteDouble(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<double> d = data.ToDouble();
+ if (d.ok()) {
+ WireFormatLite::WriteDouble(field_number, d.ValueOrDie(), stream);
+ }
+ return d.status();
+}
+
+// Writes a FLOAT field, including tag, to the stream.
+inline Status WriteFloat(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<float> f = data.ToFloat();
+ if (f.ok()) {
+ WireFormatLite::WriteFloat(field_number, f.ValueOrDie(), stream);
+ }
+ return f.status();
+}
+
+// Writes a BOOL field, including tag, to the stream.
+inline Status WriteBool(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<bool> b = data.ToBool();
+ if (b.ok()) {
+ WireFormatLite::WriteBool(field_number, b.ValueOrDie(), stream);
+ }
+ return b.status();
+}
+
+// Writes a BYTES field, including tag, to the stream.
+inline Status WriteBytes(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<string> c = data.ToBytes();
+ if (c.ok()) {
+ WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream);
+ }
+ return c.status();
+}
+
+// Writes a STRING field, including tag, to the stream.
+inline Status WriteString(int field_number, const DataPiece& data,
+ CodedOutputStream* stream) {
+ StatusOr<string> s = data.ToString();
+ if (s.ok()) {
+ WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream);
+ }
+ return s.status();
+}
+
+// Writes an ENUM field, including tag, to the stream.
+inline Status WriteEnum(int field_number, const DataPiece& data,
+ const google::protobuf::Enum* enum_type,
+ CodedOutputStream* stream) {
+ StatusOr<int> e = data.ToEnum(enum_type);
+ if (e.ok()) {
+ WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream);
+ }
+ return e.status();
+}
+
+// Given a google::protobuf::Type, returns the set of all required fields.
+std::set<const google::protobuf::Field*> GetRequiredFields(
+ const google::protobuf::Type& type) {
+ std::set<const google::protobuf::Field*> required;
+ for (int i = 0; i < type.fields_size(); i++) {
+ const google::protobuf::Field& field = type.fields(i);
+ if (field.cardinality() ==
+ google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
+ required.insert(&field);
+ }
+ }
+ return required;
+}
+
+} // namespace
+
+ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo,
+ const google::protobuf::Type& type,
+ ProtoWriter* enclosing)
+ : BaseElement(NULL),
+ ow_(enclosing),
+ parent_field_(NULL),
+ typeinfo_(typeinfo),
+ type_(type),
+ required_fields_(GetRequiredFields(type)),
+ size_index_(-1),
+ array_index_(-1) {}
+
+ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
+ const google::protobuf::Field* field,
+ const google::protobuf::Type& type,
+ bool is_list)
+ : BaseElement(parent),
+ ow_(this->parent()->ow_),
+ parent_field_(field),
+ typeinfo_(this->parent()->typeinfo_),
+ type_(type),
+ size_index_(
+ !is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE
+ ? ow_->size_insert_.size()
+ : -1),
+ array_index_(is_list ? 0 : -1) {
+ if (!is_list) {
+ if (ow_->IsRepeated(*field)) {
+ // Update array_index_ if it is an explicit list.
+ if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
+ } else {
+ this->parent()->RegisterField(field);
+ }
+
+ if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+ required_fields_ = GetRequiredFields(type_);
+ int start_pos = ow_->stream_->ByteCount();
+ // length of serialized message is the final buffer position minus
+ // starting buffer position, plus length adjustments for size fields
+ // of any nested messages. We start with -start_pos here, so we only
+ // need to add the final buffer position to it at the end.
+ SizeInfo info = {start_pos, -start_pos};
+ ow_->size_insert_.push_back(info);
+ }
+ }
+}
+
+ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() {
+ // Calls the registered error listener for any required field(s) not yet
+ // seen.
+ for (set<const google::protobuf::Field*>::iterator it =
+ required_fields_.begin();
+ it != required_fields_.end(); ++it) {
+ ow_->MissingField((*it)->name());
+ }
+ // Computes the total number of proto bytes used by a message, also adjusts
+ // the size of all parent messages by the length of this size field.
+ // If size_index_ < 0, this is not a message, so no size field is added.
+ if (size_index_ >= 0) {
+ // Add the final buffer position to compute the total length of this
+ // serialized message. The stored value (before this addition) already
+ // contains the total length of the size fields of all nested messages
+ // minus the initial buffer position.
+ ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount();
+ // Calculate the length required to serialize the size field of the
+ // message, and propagate this additional size information upward to
+ // all enclosing messages.
+ int size = ow_->size_insert_[size_index_].size;
+ int length = CodedOutputStream::VarintSize32(size);
+ for (ProtoElement* e = parent(); e != NULL; e = e->parent()) {
+ // Only nested messages have size field, lists do not have size field.
+ if (e->size_index_ >= 0) {
+ ow_->size_insert_[e->size_index_].size += length;
+ }
+ }
+ }
+ return BaseElement::pop<ProtoElement>();
+}
+
+void ProtoWriter::ProtoElement::RegisterField(
+ const google::protobuf::Field* field) {
+ if (!required_fields_.empty() &&
+ field->cardinality() ==
+ google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
+ required_fields_.erase(field);
+ }
+}
+
+string ProtoWriter::ProtoElement::ToString() const {
+ if (parent() == NULL) return "";
+ string loc = parent()->ToString();
+ if (!ow_->IsRepeated(*parent_field_) ||
+ parent()->parent_field_ != parent_field_) {
+ string name = parent_field_->name();
+ int i = 0;
+ while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
+ if (i > 0 && i == name.size()) { // safe field name
+ if (loc.empty()) {
+ loc = name;
+ } else {
+ StrAppend(&loc, ".", name);
+ }
+ } else {
+ StrAppend(&loc, "[\"", CEscape(name), "\"]");
+ }
+ }
+ if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) {
+ StrAppend(&loc, "[", array_index_ - 1, "]");
+ }
+ return loc.empty() ? "." : loc;
+}
+
+bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) {
+ return ContainsKey(oneof_indices_, index);
+}
+
+void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) {
+ InsertIfNotPresent(&oneof_indices_, index);
+}
+
+void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) {
+ listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
+}
+
+void ProtoWriter::InvalidValue(StringPiece type_name, StringPiece value) {
+ listener_->InvalidValue(location(), type_name, value);
+}
+
+void ProtoWriter::MissingField(StringPiece missing_name) {
+ listener_->MissingField(location(), missing_name);
+}
+
+ProtoWriter* ProtoWriter::StartObject(StringPiece name) {
+ // Starting the root message. Create the root ProtoElement and return.
+ if (element_ == NULL) {
+ if (!name.empty()) {
+ InvalidName(name, "Root element should not be named.");
+ }
+ element_.reset(new ProtoElement(typeinfo_, master_type_, this));
+ return this;
+ }
+
+ const google::protobuf::Field* field = NULL;
+ field = BeginNamed(name, false);
+ if (field == NULL) return this;
+
+ // Check to see if this field is a oneof and that no oneof in that group has
+ // already been set.
+ if (!ValidOneof(*field, name)) {
+ ++invalid_depth_;
+ return this;
+ }
+
+ const google::protobuf::Type* type = LookupType(field);
+ if (type == NULL) {
+ ++invalid_depth_;
+ InvalidName(name,
+ StrCat("Missing descriptor for field: ", field->type_url()));
+ return this;
+ }
+
+ WriteTag(*field);
+ element_.reset(new ProtoElement(element_.release(), field, *type, false));
+ return this;
+}
+
+ProtoWriter* ProtoWriter::EndObject() {
+ if (invalid_depth_ > 0) {
+ --invalid_depth_;
+ return this;
+ }
+
+ if (element_ != NULL) {
+ element_.reset(element_->pop());
+ }
+
+
+ // If ending the root element,
+ // then serialize the full message with calculated sizes.
+ if (element_ == NULL) {
+ WriteRootMessage();
+ }
+ return this;
+}
+
+ProtoWriter* ProtoWriter::StartList(StringPiece name) {
+ const google::protobuf::Field* field = BeginNamed(name, true);
+ if (field == NULL) return this;
+
+ if (!ValidOneof(*field, name)) {
+ ++invalid_depth_;
+ return this;
+ }
+
+ const google::protobuf::Type* type = LookupType(field);
+ if (type == NULL) {
+ ++invalid_depth_;
+ InvalidName(name,
+ StrCat("Missing descriptor for field: ", field->type_url()));
+ return this;
+ }
+
+ element_.reset(new ProtoElement(element_.release(), field, *type, true));
+ return this;
+}
+
+ProtoWriter* ProtoWriter::EndList() {
+ if (invalid_depth_ > 0) {
+ --invalid_depth_;
+ } else if (element_ != NULL) {
+ element_.reset(element_->pop());
+ }
+ return this;
+}
+
+ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name,
+ const DataPiece& data) {
+ Status status;
+ if (invalid_depth_ > 0) return this;
+
+ const google::protobuf::Field* field = Lookup(name);
+ if (field == NULL) return this;
+
+ if (!ValidOneof(*field, name)) return this;
+
+ const google::protobuf::Type* type = LookupType(field);
+ if (type == NULL) {
+ InvalidName(name,
+ StrCat("Missing descriptor for field: ", field->type_url()));
+ return this;
+ }
+
+ // Pushing a ProtoElement and then pop it off at the end for 2 purposes:
+ // error location reporting and required field accounting.
+ element_.reset(new ProtoElement(element_.release(), field, *type, false));
+
+ if (field->kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN ||
+ field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+ InvalidValue(field->type_url().empty()
+ ? google::protobuf::Field_Kind_Name(field->kind())
+ : field->type_url(),
+ data.ValueAsStringOrDefault(""));
+ element_.reset(element()->pop());
+ return this;
+ }
+
+ switch (field->kind()) {
+ case google::protobuf::Field_Kind_TYPE_INT32: {
+ status = WriteInt32(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_SFIXED32: {
+ status = WriteSFixed32(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_SINT32: {
+ status = WriteSInt32(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_FIXED32: {
+ status = WriteFixed32(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_UINT32: {
+ status = WriteUInt32(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_INT64: {
+ status = WriteInt64(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_SFIXED64: {
+ status = WriteSFixed64(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_SINT64: {
+ status = WriteSInt64(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_FIXED64: {
+ status = WriteFixed64(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_UINT64: {
+ status = WriteUInt64(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_DOUBLE: {
+ status = WriteDouble(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_FLOAT: {
+ status = WriteFloat(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_BOOL: {
+ status = WriteBool(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_BYTES: {
+ status = WriteBytes(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_STRING: {
+ status = WriteString(field->number(), data, stream_.get());
+ break;
+ }
+ case google::protobuf::Field_Kind_TYPE_ENUM: {
+ status = WriteEnum(field->number(), data,
+ typeinfo_->GetEnumByTypeUrl(field->type_url()),
+ stream_.get());
+ break;
+ }
+ default: // TYPE_GROUP or TYPE_MESSAGE
+ status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie());
+ }
+
+ if (!status.ok()) {
+ InvalidValue(google::protobuf::Field_Kind_Name(field->kind()),
+ status.error_message());
+ }
+
+ element_.reset(element()->pop());
+ return this;
+}
+
+bool ProtoWriter::ValidOneof(const google::protobuf::Field& field,
+ StringPiece unnormalized_name) {
+ if (element_ == NULL) return true;
+
+ if (field.oneof_index() > 0) {
+ if (element_->IsOneofIndexTaken(field.oneof_index())) {
+ InvalidValue(
+ "oneof",
+ StrCat("oneof field '",
+ element_->type().oneofs(field.oneof_index() - 1),
+ "' is already set. Cannot set '", unnormalized_name, "'"));
+ return false;
+ }
+ element_->TakeOneofIndex(field.oneof_index());
+ }
+ return true;
+}
+
+bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) {
+ return field.cardinality() ==
+ google::protobuf::Field_Cardinality_CARDINALITY_REPEATED;
+}
+
+const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name,
+ bool is_list) {
+ if (invalid_depth_ > 0) {
+ ++invalid_depth_;
+ return NULL;
+ }
+ const google::protobuf::Field* field = Lookup(name);
+ if (field == NULL) {
+ ++invalid_depth_;
+ // InvalidName() already called in Lookup().
+ return NULL;
+ }
+ if (is_list && !IsRepeated(*field)) {
+ ++invalid_depth_;
+ InvalidName(name, "Proto field is not repeating, cannot start list.");
+ return NULL;
+ }
+ return field;
+}
+
+const google::protobuf::Field* ProtoWriter::Lookup(
+ StringPiece unnormalized_name) {
+ ProtoElement* e = element();
+ if (e == NULL) {
+ InvalidName(unnormalized_name, "Root element must be a message.");
+ return NULL;
+ }
+ if (unnormalized_name.empty()) {
+ // Objects in repeated field inherit the same field descriptor.
+ if (e->parent_field() == NULL) {
+ InvalidName(unnormalized_name, "Proto fields must have a name.");
+ } else if (!IsRepeated(*e->parent_field())) {
+ InvalidName(unnormalized_name, "Proto fields must have a name.");
+ return NULL;
+ }
+ return e->parent_field();
+ }
+ const google::protobuf::Field* field =
+ typeinfo_->FindField(&e->type(), unnormalized_name);
+ if (field == NULL) InvalidName(unnormalized_name, "Cannot find field.");
+ return field;
+}
+
+const google::protobuf::Type* ProtoWriter::LookupType(
+ const google::protobuf::Field* field) {
+ return ((field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE ||
+ field->kind() == google::protobuf::Field_Kind_TYPE_GROUP)
+ ? typeinfo_->GetTypeByTypeUrl(field->type_url())
+ : &element_->type());
+}
+
+void ProtoWriter::WriteRootMessage() {
+ GOOGLE_DCHECK(!done_);
+ int curr_pos = 0;
+ // Calls the destructor of CodedOutputStream to remove any uninitialized
+ // memory from the Cord before we read it.
+ stream_.reset(NULL);
+ const void* data;
+ int length;
+ google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size());
+ while (input_stream.Next(&data, &length)) {
+ if (length == 0) continue;
+ int num_bytes = length;
+ // Write up to where we need to insert the size field.
+ // The number of bytes we may write is the smaller of:
+ // - the current fragment size
+ // - the distance to the next position where a size field needs to be
+ // inserted.
+ if (!size_insert_.empty() &&
+ size_insert_.front().pos - curr_pos < num_bytes) {
+ num_bytes = size_insert_.front().pos - curr_pos;
+ }
+ output_->Append(static_cast<const char*>(data), num_bytes);
+ if (num_bytes < length) {
+ input_stream.BackUp(length - num_bytes);
+ }
+ curr_pos += num_bytes;
+ // Insert the size field.
+ // size_insert_.front(): the next <index, size> pair to be written.
+ // size_insert_.front().pos: position of the size field.
+ // size_insert_.front().size: the size (integer) to be inserted.
+ if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) {
+ // Varint32 occupies at most 10 bytes.
+ uint8 insert_buffer[10];
+ uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray(
+ size_insert_.front().size, insert_buffer);
+ output_->Append(reinterpret_cast<const char*>(insert_buffer),
+ insert_buffer_pos - insert_buffer);
+ size_insert_.pop_front();
+ }
+ }
+ output_->Flush();
+ stream_.reset(new CodedOutputStream(&adapter_));
+ done_ = true;
+}
+
+void ProtoWriter::WriteTag(const google::protobuf::Field& field) {
+ WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
+ static_cast<WireFormatLite::FieldType>(field.kind()));
+ stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
+}
+
+
+} // namespace converter
+} // namespace util
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h
new file mode 100644
index 00000000..e631e56f
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -0,0 +1,315 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
+
+#include <deque>
+#include <google/protobuf/stubs/hash.h>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/internal/datapiece.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/bytestream.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class CodedOutputStream;
+} // namespace io
+} // namespace protobuf
+
+
+namespace protobuf {
+class Type;
+class Field;
+} // namespace protobuf
+
+
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class ObjectLocationTracker;
+
+// An ObjectWriter that can write protobuf bytes directly from writer events.
+// This class does not support special types like Struct or Map. However, since
+// this class supports raw protobuf, it can be used to provide support for
+// special types by inheriting from it or by wrapping it.
+//
+// It also supports streaming.
+class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter {
+ public:
+// Constructor. Does not take ownership of any parameter passed in.
+ ProtoWriter(TypeResolver* type_resolver, const google::protobuf::Type& type,
+ strings::ByteSink* output, ErrorListener* listener);
+ virtual ~ProtoWriter();
+
+ // ObjectWriter methods.
+ virtual ProtoWriter* StartObject(StringPiece name);
+ virtual ProtoWriter* EndObject();
+ virtual ProtoWriter* StartList(StringPiece name);
+ virtual ProtoWriter* EndList();
+ virtual ProtoWriter* RenderBool(StringPiece name, bool value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoWriter* RenderInt32(StringPiece name, int32 value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoWriter* RenderUint32(StringPiece name, uint32 value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoWriter* RenderInt64(StringPiece name, int64 value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoWriter* RenderUint64(StringPiece name, uint64 value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoWriter* RenderDouble(StringPiece name, double value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoWriter* RenderFloat(StringPiece name, float value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoWriter* RenderString(StringPiece name, StringPiece value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) {
+ return RenderDataPiece(name, DataPiece(value, false));
+ }
+ virtual ProtoWriter* RenderNull(StringPiece name) {
+ return RenderDataPiece(name, DataPiece::NullData());
+ }
+
+ // Renders a DataPiece 'value' into a field whose wire type is determined
+ // from the given field 'name'.
+ virtual ProtoWriter* RenderDataPiece(StringPiece name,
+ const DataPiece& value);
+
+ // Returns the location tracker to use for tracking locations for errors.
+ const LocationTrackerInterface& location() {
+ return element_ != NULL ? *element_ : *tracker_;
+ }
+
+ // When true, we finished writing to output a complete message.
+ bool done() const { return done_; }
+
+ // Returns the proto stream object.
+ google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); }
+
+ // Getters and mutators of invalid_depth_.
+ void IncrementInvalidDepth() { ++invalid_depth_; }
+ void DecrementInvalidDepth() { --invalid_depth_; }
+ int invalid_depth() { return invalid_depth_; }
+
+ ErrorListener* listener() { return listener_; }
+
+ const TypeInfo* typeinfo() { return typeinfo_; }
+
+ protected:
+ class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface {
+ public:
+ // Constructor for the root element. No parent nor field.
+ ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type,
+ ProtoWriter* enclosing);
+
+ // Constructor for a field of an element.
+ ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
+ const google::protobuf::Type& type, bool is_list);
+
+ virtual ~ProtoElement() {}
+
+ // Called just before the destructor for clean up:
+ // - reports any missing required fields
+ // - computes the space needed by the size field, and augment the
+ // length of all parent messages by this additional space.
+ // - releases and returns the parent pointer.
+ ProtoElement* pop();
+
+ // Accessors
+ // parent_field() may be NULL if we are at root.
+ const google::protobuf::Field* parent_field() const {
+ return parent_field_;
+ }
+ const google::protobuf::Type& type() const { return type_; }
+
+ // Registers field for accounting required fields.
+ void RegisterField(const google::protobuf::Field* field);
+
+ // To report location on error messages.
+ virtual string ToString() const;
+
+ virtual ProtoElement* parent() const {
+ return static_cast<ProtoElement*>(BaseElement::parent());
+ }
+
+ // Returns true if the index is already taken by a preceeding oneof input.
+ bool IsOneofIndexTaken(int32 index);
+
+ // Marks the oneof 'index' as taken. Future inputs to this oneof will
+ // generate an error.
+ void TakeOneofIndex(int32 index);
+
+ private:
+ // Used for access to variables of the enclosing instance of
+ // ProtoWriter.
+ ProtoWriter* ow_;
+
+ // Describes the element as a field in the parent message.
+ // parent_field_ is NULL if and only if this element is the root element.
+ const google::protobuf::Field* parent_field_;
+
+ // TypeInfo to lookup types.
+ const TypeInfo* typeinfo_;
+
+ // Additional variables if this element is a message:
+ // (Root element is always a message).
+ // type_ : the type of this element.
+ // required_fields_ : set of required fields.
+ // size_index_ : index into ProtoWriter::size_insert_
+ // for later insertion of serialized message length.
+ const google::protobuf::Type& type_;
+ std::set<const google::protobuf::Field*> required_fields_;
+ const int size_index_;
+
+ // Tracks position in repeated fields, needed for LocationTrackerInterface.
+ int array_index_;
+
+ // Set of oneof indices already seen for the type_. Used to validate
+ // incoming messages so no more than one oneof is set.
+ hash_set<int32> oneof_indices_;
+
+ GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
+ };
+
+ // Container for inserting 'size' information at the 'pos' position.
+ struct SizeInfo {
+ const int pos;
+ int size;
+ };
+
+ ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type,
+ strings::ByteSink* output, ErrorListener* listener);
+
+ virtual ProtoElement* element() { return element_.get(); }
+
+ // Helper methods for calling ErrorListener. See error_listener.h.
+ void InvalidName(StringPiece unknown_name, StringPiece message);
+ void InvalidValue(StringPiece type_name, StringPiece value);
+ void MissingField(StringPiece missing_name);
+
+ // Common code for BeginObject() and BeginList() that does invalid_depth_
+ // bookkeeping associated with name lookup.
+ const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list);
+
+ // Lookup the field in the current element. Looks in the base descriptor
+ // and in any extension. This will report an error if the field cannot be
+ // found or if multiple matching extensions are found.
+ const google::protobuf::Field* Lookup(StringPiece name);
+
+ // Lookup the field type in the type descriptor. Returns NULL if the type
+ // is not known.
+ const google::protobuf::Type* LookupType(
+ const google::protobuf::Field* field);
+
+ // Write serialized output to the final output ByteSink, inserting all
+ // the size information for nested messages that are missing from the
+ // intermediate Cord buffer.
+ void WriteRootMessage();
+
+ // Helper method to write proto tags based on the given field.
+ void WriteTag(const google::protobuf::Field& field);
+
+
+ // Returns true if the field for type_ can be set as a oneof. If field is not
+ // a oneof type, this function does nothing and returns true.
+ // If another field for this oneof is already set, this function returns
+ // false. It also calls the appropriate error callback.
+ // unnormalized_name is used for error string.
+ bool ValidOneof(const google::protobuf::Field& field,
+ StringPiece unnormalized_name);
+
+ // Returns true if the field is repeated.
+ bool IsRepeated(const google::protobuf::Field& field);
+
+ private:
+ // Variables for describing the structure of the input tree:
+ // master_type_: descriptor for the whole protobuf message.
+ // typeinfo_ : the TypeInfo object to lookup types.
+ const google::protobuf::Type& master_type_;
+ const TypeInfo* typeinfo_;
+ // Whether we own the typeinfo_ object.
+ bool own_typeinfo_;
+
+ // Indicates whether we finished writing root message completely.
+ bool done_;
+
+ // Variable for internal state processing:
+ // element_ : the current element.
+ // size_insert_: sizes of nested messages.
+ // pos - position to insert the size field.
+ // size - size value to be inserted.
+ google::protobuf::scoped_ptr<ProtoElement> element_;
+ std::deque<SizeInfo> size_insert_;
+
+ // Variables for output generation:
+ // output_ : pointer to an external ByteSink for final user-visible output.
+ // buffer_ : buffer holding partial message before being ready for output_.
+ // adapter_ : internal adapter between CodedOutputStream and buffer_.
+ // stream_ : wrapper for writing tags and other encodings in wire format.
+ strings::ByteSink* output_;
+ string buffer_;
+ google::protobuf::io::StringOutputStream adapter_;
+ google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_;
+
+ // Variables for error tracking and reporting:
+ // listener_ : a place to report any errors found.
+ // invalid_depth_: number of enclosing invalid nested messages.
+ // tracker_ : the root location tracker interface.
+ ErrorListener* listener_;
+ int invalid_depth_;
+ google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_;
+
+ GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter);
+};
+
+} // namespace converter
+} // namespace util
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 996e1f8c..034d616f 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -47,7 +47,6 @@
#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h>
-#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/status_macros.h>
@@ -140,10 +139,11 @@ 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);
- }
+
+ const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
+ if (type_renderer != NULL) {
+ return (*type_renderer)(this, type, name, ow);
+ }
const google::protobuf::Field* field = NULL;
string field_name;
@@ -171,7 +171,9 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
if (field->cardinality() ==
google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
- if (IsMap(*field)) {
+ bool check_maps = true;
+
+ if (check_maps && IsMap(*field)) {
ow->StartObject(field_name);
ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow));
ow->EndObject();
@@ -218,48 +220,32 @@ StatusOr<uint32> ProtoStreamObjectSource::RenderMap(
const google::protobuf::Type* field_type =
typeinfo_->GetTypeByTypeUrl(field->type_url());
uint32 tag_to_return = 0;
- if (IsPackable(*field) &&
- list_tag ==
- WireFormatLite::MakeTag(field->number(),
- WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
- RETURN_IF_ERROR(RenderPackedMapEntry(field_type, ow));
- tag_to_return = stream_->ReadTag();
- } else {
- do {
- RETURN_IF_ERROR(RenderMapEntry(field_type, ow));
- } while ((tag_to_return = stream_->ReadTag()) == list_tag);
- }
- return tag_to_return;
-}
-
-Status ProtoStreamObjectSource::RenderMapEntry(
- const google::protobuf::Type* type, ObjectWriter* ow) const {
- uint32 buffer32;
- stream_->ReadVarint32(&buffer32); // message length
- int old_limit = stream_->PushLimit(buffer32);
- string map_key;
- for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
- const google::protobuf::Field* field = FindAndVerifyField(*type, tag);
- if (field == NULL) {
- WireFormat::SkipField(stream_, tag, NULL);
- continue;
- }
- // Map field numbers are key = 1 and value = 2
- if (field->number() == 1) {
- map_key = ReadFieldValueAsString(*field);
- } else if (field->number() == 2) {
- if (map_key.empty()) {
- return Status(util::error::INTERNAL, "Map key must be non-empty");
+ do {
+ // Render map entry message type.
+ uint32 buffer32;
+ stream_->ReadVarint32(&buffer32); // message length
+ int old_limit = stream_->PushLimit(buffer32);
+ string map_key;
+ for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
+ const google::protobuf::Field* field =
+ FindAndVerifyField(*field_type, tag);
+ if (field == NULL) {
+ WireFormat::SkipField(stream_, tag, NULL);
+ continue;
+ }
+ // Map field numbers are key = 1 and value = 2
+ if (field->number() == 1) {
+ map_key = ReadFieldValueAsString(*field);
+ } else if (field->number() == 2) {
+ if (map_key.empty()) {
+ return Status(util::error::INTERNAL, "Map key must be non-empty");
+ }
+ RETURN_IF_ERROR(RenderField(field, map_key, ow));
}
- // Disable case normalization for map keys as they are just data. We
- // retain them intact.
- ow->DisableCaseNormalizationForNextKey();
- RETURN_IF_ERROR(RenderField(field, map_key, ow));
}
- }
- stream_->PopLimit(old_limit);
-
- return Status::OK;
+ stream_->PopLimit(old_limit);
+ } while ((tag_to_return = stream_->ReadTag()) == list_tag);
+ return tag_to_return;
}
Status ProtoStreamObjectSource::RenderPacked(
@@ -274,18 +260,6 @@ Status ProtoStreamObjectSource::RenderPacked(
return Status::OK;
}
-Status ProtoStreamObjectSource::RenderPackedMapEntry(
- const google::protobuf::Type* type, ObjectWriter* ow) const {
- uint32 length;
- stream_->ReadVarint32(&length);
- int old_limit = stream_->PushLimit(length);
- while (stream_->BytesUntilLimit() > 0) {
- RETURN_IF_ERROR(RenderMapEntry(type, ow));
- }
- stream_->PopLimit(old_limit);
- return Status::OK;
-}
-
Status ProtoStreamObjectSource::RenderTimestamp(
const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
StringPiece field_name, ObjectWriter* ow) {
@@ -332,10 +306,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;
@@ -602,10 +575,10 @@ Status ProtoStreamObjectSource::RenderAny(const ProtoStreamObjectSource* os,
// nested_type cannot be null at this time.
const google::protobuf::Type* nested_type = resolved_type.ValueOrDie();
- // We know the type so we can render it. Recursively parse the nested stream
- // using a nested ProtoStreamObjectSource using our nested type information.
google::protobuf::io::ArrayInputStream zero_copy_stream(value.data(), value.size());
google::protobuf::io::CodedInputStream in_stream(&zero_copy_stream);
+ // We know the type so we can render it. Recursively parse the nested stream
+ // using a nested ProtoStreamObjectSource using our nested type information.
ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type);
// We manually call start and end object here so we can inject the @type.
@@ -648,6 +621,7 @@ Status ProtoStreamObjectSource::RenderFieldMask(
return Status::OK;
}
+
hash_map<string, ProtoStreamObjectSource::TypeRenderer>*
ProtoStreamObjectSource::renderers_ = NULL;
GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_);
@@ -670,13 +644,15 @@ 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.Struct"] =
+ &ProtoStreamObjectSource::RenderStruct;
(*renderers_)["google.protobuf.Value"] =
&ProtoStreamObjectSource::RenderStructValue;
(*renderers_)["google.protobuf.ListValue"] =
@@ -701,87 +677,118 @@ ProtoStreamObjectSource::FindTypeRenderer(const string& type_url) {
Status ProtoStreamObjectSource::RenderField(
const google::protobuf::Field* field, StringPiece field_name,
ObjectWriter* ow) const {
+ // Short-circuit message types as it tends to call WriteMessage recursively
+ // and ends up using a lot of stack space. Keep the stack usage of this
+ // message small in order to preserve stack space and not crash.
+ if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+ uint32 buffer32;
+ stream_->ReadVarint32(&buffer32); // message length
+ int old_limit = stream_->PushLimit(buffer32);
+ // Get the nested message type for this field.
+ const google::protobuf::Type* type =
+ typeinfo_->GetTypeByTypeUrl(field->type_url());
+ if (type == NULL) {
+ return Status(util::error::INTERNAL,
+ StrCat("Invalid configuration. Could not find the type: ",
+ field->type_url()));
+ }
+
+ // Short-circuit any special type rendering to save call-stack space.
+ const TypeRenderer* type_renderer = FindTypeRenderer(type->name());
+
+ bool use_type_renderer = type_renderer != NULL;
+
+ if (use_type_renderer) {
+ RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow));
+ } else {
+ RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
+ }
+ if (!stream_->ConsumedEntireMessage()) {
+ return Status(util::error::INVALID_ARGUMENT,
+ "Nested protocol message not parsed in its entirety.");
+ }
+ stream_->PopLimit(old_limit);
+ } else {
+ // Render all other non-message types.
+ return RenderNonMessageField(field, field_name, ow);
+ }
+ return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderNonMessageField(
+ const google::protobuf::Field* field, StringPiece field_name,
+ ObjectWriter* ow) const {
+ // Temporary buffers of different types.
+ uint32 buffer32;
+ uint64 buffer64;
+ string strbuffer;
switch (field->kind()) {
case google::protobuf::Field_Kind_TYPE_BOOL: {
- uint64 buffer64;
stream_->ReadVarint64(&buffer64);
ow->RenderBool(field_name, buffer64 != 0);
break;
}
case google::protobuf::Field_Kind_TYPE_INT32: {
- uint32 buffer32;
stream_->ReadVarint32(&buffer32);
ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
break;
}
case google::protobuf::Field_Kind_TYPE_INT64: {
- uint64 buffer64;
stream_->ReadVarint64(&buffer64);
ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
break;
}
case google::protobuf::Field_Kind_TYPE_UINT32: {
- uint32 buffer32;
stream_->ReadVarint32(&buffer32);
ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
break;
}
case google::protobuf::Field_Kind_TYPE_UINT64: {
- uint64 buffer64;
stream_->ReadVarint64(&buffer64);
ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
break;
}
case google::protobuf::Field_Kind_TYPE_SINT32: {
- uint32 buffer32;
stream_->ReadVarint32(&buffer32);
ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32));
break;
}
case google::protobuf::Field_Kind_TYPE_SINT64: {
- uint64 buffer64;
stream_->ReadVarint64(&buffer64);
ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64));
break;
}
case google::protobuf::Field_Kind_TYPE_SFIXED32: {
- uint32 buffer32;
stream_->ReadLittleEndian32(&buffer32);
ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
break;
}
case google::protobuf::Field_Kind_TYPE_SFIXED64: {
- uint64 buffer64;
stream_->ReadLittleEndian64(&buffer64);
ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
break;
}
case google::protobuf::Field_Kind_TYPE_FIXED32: {
- uint32 buffer32;
stream_->ReadLittleEndian32(&buffer32);
ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
break;
}
case google::protobuf::Field_Kind_TYPE_FIXED64: {
- uint64 buffer64;
stream_->ReadLittleEndian64(&buffer64);
ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
break;
}
case google::protobuf::Field_Kind_TYPE_FLOAT: {
- uint32 buffer32;
stream_->ReadLittleEndian32(&buffer32);
ow->RenderFloat(field_name, bit_cast<float>(buffer32));
break;
}
case google::protobuf::Field_Kind_TYPE_DOUBLE: {
- uint64 buffer64;
stream_->ReadLittleEndian64(&buffer64);
ow->RenderDouble(field_name, bit_cast<double>(buffer64));
break;
}
case google::protobuf::Field_Kind_TYPE_ENUM: {
- uint32 buffer32;
stream_->ReadVarint32(&buffer32);
// If the field represents an explicit NULL value, render null.
@@ -803,44 +810,20 @@ Status ProtoStreamObjectSource::RenderField(
ow->RenderString(field_name, enum_value->name());
}
} else {
- GOOGLE_LOG(INFO) << "Unkown enum skipped: " << field->type_url();
+ GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url();
}
break;
}
case google::protobuf::Field_Kind_TYPE_STRING: {
- uint32 buffer32;
- string str;
stream_->ReadVarint32(&buffer32); // string size.
- stream_->ReadString(&str, buffer32);
- ow->RenderString(field_name, str);
+ stream_->ReadString(&strbuffer, buffer32);
+ ow->RenderString(field_name, strbuffer);
break;
}
case google::protobuf::Field_Kind_TYPE_BYTES: {
- uint32 buffer32;
stream_->ReadVarint32(&buffer32); // bytes size.
- string value;
- stream_->ReadString(&value, buffer32);
- ow->RenderBytes(field_name, value);
- break;
- }
- case google::protobuf::Field_Kind_TYPE_MESSAGE: {
- uint32 buffer32;
- stream_->ReadVarint32(&buffer32); // message length
- int old_limit = stream_->PushLimit(buffer32);
- // Get the nested message type for this field.
- const google::protobuf::Type* type =
- typeinfo_->GetTypeByTypeUrl(field->type_url());
- if (type == NULL) {
- return Status(util::error::INTERNAL,
- 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,
- "Nested protocol message not parsed in its entirety.");
- }
- stream_->PopLimit(old_limit);
+ stream_->ReadString(&strbuffer, buffer32);
+ ow->RenderBytes(field_name, strbuffer);
break;
}
default:
@@ -988,7 +971,7 @@ std::pair<int64, int32> 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..78defa1d 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -122,20 +122,12 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
StringPiece name, uint32 list_tag,
ObjectWriter* ow) const;
- // Renders an entry in a map, advancing stream pointers appropriately.
- util::Status RenderMapEntry(const google::protobuf::Type* type,
- ObjectWriter* ow) const;
-
// Renders a packed repeating field. A packed field is stored as:
// {tag length item1 item2 item3} instead of the less efficient
// {tag item1 tag item2 tag item3}.
util::Status RenderPacked(const google::protobuf::Field* field,
ObjectWriter* ow) const;
- // Equivalent of RenderPacked, but for map entries.
- util::Status RenderPackedMapEntry(const google::protobuf::Type* type,
- ObjectWriter* ow) const;
-
// Renders a google.protobuf.Timestamp value to ObjectWriter
static util::Status RenderTimestamp(const ProtoStreamObjectSource* os,
const google::protobuf::Type& type,
@@ -188,8 +180,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 +202,13 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
util::Status RenderField(const google::protobuf::Field* field,
StringPiece field_name, ObjectWriter* ow) const;
+ // Same as above but renders all non-message field types. Callers don't call
+ // this function directly. They just use RenderField.
+ util::Status RenderNonMessageField(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).
@@ -238,6 +236,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
// google::protobuf::Type of the message source.
const google::protobuf::Type& type_;
+
GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
};
diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
index f6e5ee7a..561f6763 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
@@ -327,9 +327,16 @@ TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) {
DoTest(primitive, Primitive::descriptor());
}
+TEST_P(ProtostreamObjectSourceTest, CustomJsonName) {
+ Author author;
+ author.set_id(12345);
+
+ ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject();
+ DoTest(author, Author::descriptor());
+}
+
TEST_P(ProtostreamObjectSourceTest, NestedMessage) {
Author* author = new Author();
- author->set_id(101L);
author->set_name("Tolstoy");
Book book;
book.set_title("My Book");
@@ -338,7 +345,6 @@ TEST_P(ProtostreamObjectSourceTest, NestedMessage) {
ow_.StartObject("")
->RenderString("title", "My Book")
->StartObject("author")
- ->RenderUint64("id", bit_cast<uint64>(101LL))
->RenderString("name", "Tolstoy")
->EndObject()
->EndObject();
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index a935ac39..786bf0be 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -33,13 +33,13 @@
#include <functional>
#include <stack>
+#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/time.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/util/internal/field_mask_utility.h>
#include <google/protobuf/util/internal/object_location_tracker.h>
#include <google/protobuf/util/internal/constants.h>
#include <google/protobuf/util/internal/utility.h>
-#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/statusor.h>
@@ -51,7 +51,6 @@ namespace util {
namespace converter {
using google::protobuf::internal::WireFormatLite;
-using google::protobuf::io::CodedOutputStream;
using util::error::INVALID_ARGUMENT;
using util::Status;
using util::StatusOr;
@@ -60,230 +59,31 @@ using util::StatusOr;
ProtoStreamObjectWriter::ProtoStreamObjectWriter(
TypeResolver* type_resolver, const google::protobuf::Type& type,
strings::ByteSink* output, ErrorListener* listener)
- : master_type_(type),
- typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
- own_typeinfo_(true),
- done_(false),
- element_(NULL),
- size_insert_(),
- output_(output),
- buffer_(),
- adapter_(&buffer_),
- stream_(new CodedOutputStream(&adapter_)),
- listener_(listener),
- invalid_depth_(0),
- tracker_(new ObjectLocationTracker()) {}
+ : ProtoWriter(type_resolver, type, output, listener),
+ master_type_(type),
+ current_(NULL) {}
ProtoStreamObjectWriter::ProtoStreamObjectWriter(
const TypeInfo* typeinfo, const google::protobuf::Type& type,
strings::ByteSink* output, ErrorListener* listener)
- : master_type_(type),
- typeinfo_(typeinfo),
- own_typeinfo_(false),
- done_(false),
- element_(NULL),
- size_insert_(),
- output_(output),
- buffer_(),
- adapter_(&buffer_),
- stream_(new CodedOutputStream(&adapter_)),
- listener_(listener),
- invalid_depth_(0),
- tracker_(new ObjectLocationTracker()) {}
+ : ProtoWriter(typeinfo, type, output, listener),
+ master_type_(type),
+ current_(NULL) {}
ProtoStreamObjectWriter::~ProtoStreamObjectWriter() {
- if (own_typeinfo_) {
- delete typeinfo_;
- }
- if (element_ == NULL) return;
+ if (current_ == NULL) return;
// Cleanup explicitly in order to avoid destructor stack overflow when input
// is deeply nested.
// Cast to BaseElement to avoid doing additional checks (like missing fields)
// during pop().
google::protobuf::scoped_ptr<BaseElement> element(
- static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
+ static_cast<BaseElement*>(current_.get())->pop<BaseElement>());
while (element != NULL) {
element.reset(element->pop<BaseElement>());
}
}
namespace {
-
-// Writes an INT32 field, including tag to the stream.
-inline Status WriteInt32(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<int32> i32 = data.ToInt32();
- if (i32.ok()) {
- WireFormatLite::WriteInt32(field_number, i32.ValueOrDie(), stream);
- }
- return i32.status();
-}
-
-// writes an SFIXED32 field, including tag, to the stream.
-inline Status WriteSFixed32(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<int32> i32 = data.ToInt32();
- if (i32.ok()) {
- WireFormatLite::WriteSFixed32(field_number, i32.ValueOrDie(), stream);
- }
- return i32.status();
-}
-
-// Writes an SINT32 field, including tag, to the stream.
-inline Status WriteSInt32(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<int32> i32 = data.ToInt32();
- if (i32.ok()) {
- WireFormatLite::WriteSInt32(field_number, i32.ValueOrDie(), stream);
- }
- return i32.status();
-}
-
-// Writes a FIXED32 field, including tag, to the stream.
-inline Status WriteFixed32(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<uint32> u32 = data.ToUint32();
- if (u32.ok()) {
- WireFormatLite::WriteFixed32(field_number, u32.ValueOrDie(), stream);
- }
- return u32.status();
-}
-
-// Writes a UINT32 field, including tag, to the stream.
-inline Status WriteUInt32(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<uint32> u32 = data.ToUint32();
- if (u32.ok()) {
- WireFormatLite::WriteUInt32(field_number, u32.ValueOrDie(), stream);
- }
- return u32.status();
-}
-
-// Writes an INT64 field, including tag, to the stream.
-inline Status WriteInt64(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<int64> i64 = data.ToInt64();
- if (i64.ok()) {
- WireFormatLite::WriteInt64(field_number, i64.ValueOrDie(), stream);
- }
- return i64.status();
-}
-
-// Writes an SFIXED64 field, including tag, to the stream.
-inline Status WriteSFixed64(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<int64> i64 = data.ToInt64();
- if (i64.ok()) {
- WireFormatLite::WriteSFixed64(field_number, i64.ValueOrDie(), stream);
- }
- return i64.status();
-}
-
-// Writes an SINT64 field, including tag, to the stream.
-inline Status WriteSInt64(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<int64> i64 = data.ToInt64();
- if (i64.ok()) {
- WireFormatLite::WriteSInt64(field_number, i64.ValueOrDie(), stream);
- }
- return i64.status();
-}
-
-// Writes a FIXED64 field, including tag, to the stream.
-inline Status WriteFixed64(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<uint64> u64 = data.ToUint64();
- if (u64.ok()) {
- WireFormatLite::WriteFixed64(field_number, u64.ValueOrDie(), stream);
- }
- return u64.status();
-}
-
-// Writes a UINT64 field, including tag, to the stream.
-inline Status WriteUInt64(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<uint64> u64 = data.ToUint64();
- if (u64.ok()) {
- WireFormatLite::WriteUInt64(field_number, u64.ValueOrDie(), stream);
- }
- return u64.status();
-}
-
-// Writes a DOUBLE field, including tag, to the stream.
-inline Status WriteDouble(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<double> d = data.ToDouble();
- if (d.ok()) {
- WireFormatLite::WriteDouble(field_number, d.ValueOrDie(), stream);
- }
- return d.status();
-}
-
-// Writes a FLOAT field, including tag, to the stream.
-inline Status WriteFloat(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<float> f = data.ToFloat();
- if (f.ok()) {
- WireFormatLite::WriteFloat(field_number, f.ValueOrDie(), stream);
- }
- return f.status();
-}
-
-// Writes a BOOL field, including tag, to the stream.
-inline Status WriteBool(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<bool> b = data.ToBool();
- if (b.ok()) {
- WireFormatLite::WriteBool(field_number, b.ValueOrDie(), stream);
- }
- return b.status();
-}
-
-// Writes a BYTES field, including tag, to the stream.
-inline Status WriteBytes(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<string> c = data.ToBytes();
- if (c.ok()) {
- WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream);
- }
- return c.status();
-}
-
-// Writes a STRING field, including tag, to the stream.
-inline Status WriteString(int field_number, const DataPiece& data,
- CodedOutputStream* stream) {
- StatusOr<string> s = data.ToString();
- if (s.ok()) {
- WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream);
- }
- return s.status();
-}
-
-// Writes an ENUM field, including tag, to the stream.
-inline Status WriteEnum(int field_number, const DataPiece& data,
- const google::protobuf::Enum* enum_type,
- CodedOutputStream* stream) {
- StatusOr<int> e = data.ToEnum(enum_type);
- if (e.ok()) {
- WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream);
- }
- return e.status();
-}
-
-// Given a google::protobuf::Type, returns the set of all required fields.
-std::set<const google::protobuf::Field*> GetRequiredFields(
- const google::protobuf::Type& type) {
- std::set<const google::protobuf::Field*> required;
- for (int i = 0; i < type.fields_size(); i++) {
- const google::protobuf::Field& field = type.fields(i);
- if (field.cardinality() ==
- google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
- required.insert(&field);
- }
- }
- return required;
-}
-
// Utility method to split a string representation of Timestamp or Duration and
// return the parts.
void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds,
@@ -298,6 +98,78 @@ void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds,
}
}
+Status GetNanosFromStringPiece(StringPiece s_nanos,
+ const char* parse_failure_message,
+ const char* exceeded_limit_message,
+ int32* nanos) {
+ *nanos = 0;
+
+ // Count the number of leading 0s and consume them.
+ int num_leading_zeros = 0;
+ while (s_nanos.Consume("0")) {
+ num_leading_zeros++;
+ }
+ int32 i_nanos = 0;
+ // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to
+ // "0." + s_nanos.ToString() seconds. An int32 is used for the
+ // conversion to 'nanos', rather than a double, so that there is no
+ // loss of precision.
+ if (!s_nanos.empty() && !safe_strto32(s_nanos.ToString(), &i_nanos)) {
+ return Status(INVALID_ARGUMENT, parse_failure_message);
+ }
+ if (i_nanos > kNanosPerSecond || i_nanos < 0) {
+ return Status(INVALID_ARGUMENT, exceeded_limit_message);
+ }
+ // s_nanos should only have digits. No whitespace.
+ if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
+ return Status(INVALID_ARGUMENT, parse_failure_message);
+ }
+
+ if (i_nanos > 0) {
+ // 'scale' is the number of digits to the right of the decimal
+ // point in "0." + s_nanos.ToString()
+ int32 scale = num_leading_zeros + s_nanos.size();
+ // 'conversion' converts i_nanos into nanoseconds.
+ // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale))
+ // For efficiency, we precompute the conversion factor.
+ int32 conversion = 0;
+ switch (scale) {
+ case 1:
+ conversion = 100000000;
+ break;
+ case 2:
+ conversion = 10000000;
+ break;
+ case 3:
+ conversion = 1000000;
+ break;
+ case 4:
+ conversion = 100000;
+ break;
+ case 5:
+ conversion = 10000;
+ break;
+ case 6:
+ conversion = 1000;
+ break;
+ case 7:
+ conversion = 100;
+ break;
+ case 8:
+ conversion = 10;
+ break;
+ case 9:
+ conversion = 1;
+ break;
+ default:
+ return Status(INVALID_ARGUMENT, exceeded_limit_message);
+ }
+ *nanos = i_nanos * conversion;
+ }
+
+ return Status::OK;
+}
+
} // namespace
ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent)
@@ -397,8 +269,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);
}
@@ -421,7 +293,7 @@ void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
}
// Resolve the type url, and report an error if we failed to resolve it.
StatusOr<const google::protobuf::Type*> resolved_type =
- parent_->typeinfo_->ResolveTypeUrl(type_url_);
+ parent_->typeinfo()->ResolveTypeUrl(type_url_);
if (!resolved_type.ok()) {
parent_->InvalidValue("Any", resolved_type.status().error_message());
invalid_ = true;
@@ -440,8 +312,8 @@ void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
// Create our object writer and initialize it with the first StartObject
// call.
- ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo_, *type, &output_,
- parent_->listener_));
+ ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
+ parent_->listener()));
ow_->StartObject("");
}
@@ -453,588 +325,431 @@ void ProtoStreamObjectWriter::AnyWriter::WriteAny() {
}
// Render the type_url and value fields directly to the stream.
// type_url has tag 1 and value has tag 2.
- WireFormatLite::WriteString(1, type_url_, parent_->stream_.get());
+ WireFormatLite::WriteString(1, type_url_, parent_->stream());
if (!data_.empty()) {
- WireFormatLite::WriteBytes(2, data_, parent_->stream_.get());
+ WireFormatLite::WriteBytes(2, data_, parent_->stream());
}
}
-ProtoStreamObjectWriter::ProtoElement::ProtoElement(
- const TypeInfo* typeinfo, const google::protobuf::Type& type,
- ProtoStreamObjectWriter* enclosing)
+ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
+ ItemType item_type, bool is_placeholder,
+ bool is_list)
: BaseElement(NULL),
ow_(enclosing),
any_(),
- field_(NULL),
- typeinfo_(typeinfo),
- type_(type),
- required_fields_(GetRequiredFields(type)),
- is_repeated_type_(false),
- size_index_(-1),
- array_index_(-1),
- element_type_(GetElementType(type_)) {
- if (element_type_ == ANY) {
+ item_type_(item_type),
+ is_placeholder_(is_placeholder),
+ is_list_(is_list) {
+ if (item_type_ == ANY) {
any_.reset(new AnyWriter(ow_));
}
}
-ProtoStreamObjectWriter::ProtoElement::ProtoElement(
- ProtoStreamObjectWriter::ProtoElement* parent,
- const google::protobuf::Field* field, const google::protobuf::Type& type,
- ElementType element_type)
+ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
+ ItemType item_type, bool is_placeholder,
+ bool is_list)
: BaseElement(parent),
ow_(this->parent()->ow_),
any_(),
- field_(field),
- typeinfo_(this->parent()->typeinfo_),
- type_(type),
- is_repeated_type_(element_type == ProtoElement::LIST ||
- element_type == ProtoElement::STRUCT_LIST ||
- element_type == ProtoElement::MAP ||
- element_type == ProtoElement::STRUCT_MAP),
- size_index_(!is_repeated_type_ &&
- field->kind() ==
- google::protobuf::Field_Kind_TYPE_MESSAGE
- ? ow_->size_insert_.size()
- : -1),
- array_index_(is_repeated_type_ ? 0 : -1),
- element_type_(element_type) {
- if (!is_repeated_type_) {
- if (field->cardinality() ==
- google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
- // Update array_index_ if it is an explicit list.
- if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
- } else {
- this->parent()->RegisterField(field);
- }
- if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
- required_fields_ = GetRequiredFields(type_);
- int start_pos = ow_->stream_->ByteCount();
- // length of serialized message is the final buffer position minus
- // starting buffer position, plus length adjustments for size fields
- // of any nested messages. We start with -start_pos here, so we only
- // need to add the final buffer position to it at the end.
- SizeInfo info = {start_pos, -start_pos};
- ow_->size_insert_.push_back(info);
- }
- }
- if (element_type == ANY) {
+ item_type_(item_type),
+ is_placeholder_(is_placeholder),
+ is_list_(is_list) {
+ if (item_type == ANY) {
any_.reset(new AnyWriter(ow_));
}
}
-ProtoStreamObjectWriter::ProtoElement*
-ProtoStreamObjectWriter::ProtoElement::pop() {
- // Calls the registered error listener for any required field(s) not yet
- // seen.
- for (set<const google::protobuf::Field*>::iterator it =
- required_fields_.begin();
- it != required_fields_.end(); ++it) {
- ow_->MissingField((*it)->name());
- }
- // Computes the total number of proto bytes used by a message, also adjusts
- // the size of all parent messages by the length of this size field.
- // If size_index_ < 0, this is not a message, so no size field is added.
- if (size_index_ >= 0) {
- // Add the final buffer position to compute the total length of this
- // serialized message. The stored value (before this addition) already
- // contains the total length of the size fields of all nested messages
- // minus the initial buffer position.
- ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount();
- // Calculate the length required to serialize the size field of the
- // message, and propagate this additional size information upward to
- // all enclosing messages.
- int size = ow_->size_insert_[size_index_].size;
- int length = CodedOutputStream::VarintSize32(size);
- for (ProtoElement* e = parent(); e != NULL; e = e->parent()) {
- // Only nested messages have size field, lists do not have size field.
- if (e->size_index_ >= 0) {
- ow_->size_insert_[e->size_index_].size += length;
- }
- }
- }
- return BaseElement::pop<ProtoElement>();
-}
-
-void ProtoStreamObjectWriter::ProtoElement::RegisterField(
- const google::protobuf::Field* field) {
- if (!required_fields_.empty() &&
- field->cardinality() ==
- google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
- required_fields_.erase(field);
- }
-}
-
-string ProtoStreamObjectWriter::ProtoElement::ToString() const {
- if (parent() == NULL) return "";
- string loc = parent()->ToString();
- if (field_->cardinality() !=
- google::protobuf::Field_Cardinality_CARDINALITY_REPEATED ||
- parent()->field_ != field_) {
- string name = field_->name();
- int i = 0;
- while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
- if (i > 0 && i == name.size()) { // safe field name
- if (loc.empty()) {
- loc = name;
- } else {
- StrAppend(&loc, ".", name);
- }
- } else {
- StrAppend(&loc, "[\"", CEscape(name), "\"]");
- }
- }
- if (field_->cardinality() ==
- google::protobuf::Field_Cardinality_CARDINALITY_REPEATED &&
- array_index_ > 0) {
- StrAppend(&loc, "[", array_index_ - 1, "]");
- }
- return loc.empty() ? "." : loc;
-}
-
-bool ProtoStreamObjectWriter::ProtoElement::OneofIndexTaken(int32 index) {
- return ContainsKey(oneof_indices_, index);
-}
-
-void ProtoStreamObjectWriter::ProtoElement::TakeOneofIndex(int32 index) {
- InsertIfNotPresent(&oneof_indices_, index);
-}
-
-inline void ProtoStreamObjectWriter::InvalidName(StringPiece unknown_name,
- StringPiece message) {
- listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
-}
-
-inline void ProtoStreamObjectWriter::InvalidValue(StringPiece type_name,
- StringPiece value) {
- listener_->InvalidValue(location(), type_name, value);
-}
-
-inline void ProtoStreamObjectWriter::MissingField(StringPiece missing_name) {
- listener_->MissingField(location(), missing_name);
+bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
+ StringPiece map_key) {
+ return InsertIfNotPresent(&map_keys_, map_key.ToString());
}
ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
StringPiece name) {
- // Starting the root message. Create the root ProtoElement and return.
- if (element_ == NULL) {
- if (!name.empty()) {
- InvalidName(name, "Root element should not be named.");
- }
- element_.reset(new ProtoElement(typeinfo_, master_type_, this));
+ if (invalid_depth() > 0) {
+ IncrementInvalidDepth();
+ return this;
+ }
+
+ // Starting the root message. Create the root Item and return.
+ // ANY message type does not need special handling, just set the ItemType
+ // to ANY.
+ if (current_ == NULL) {
+ ProtoWriter::StartObject(name);
+ current_.reset(new Item(
+ this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE,
+ false, false));
// If master type is a special type that needs extra values to be written to
// stream, we write those values.
if (master_type_.name() == kStructType) {
- StartStruct(NULL);
- } else if (master_type_.name() == kStructValueType) {
- // We got a StartObject call with google.protobuf.Value field. This means
- // we are starting an object within google.protobuf.Value type. The only
+ // Struct has a map<string, Value> field called "fields".
+ // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
+ // "fields": [
+ Push("fields", Item::MAP, true, true);
+ return this;
+ }
+
+ if (master_type_.name() == kStructValueType) {
+ // We got a StartObject call with google.protobuf.Value field. The only
// object within that type is a struct type. So start a struct.
- const google::protobuf::Field* field = StartStructValueInStruct(NULL);
- StartStruct(field);
+ //
+ // The struct field in Value type is named "struct_value"
+ // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
+ // Also start the map field "fields" within the struct.
+ // "struct_value": {
+ // "fields": [
+ Push("struct_value", Item::MESSAGE, true, false);
+ Push("fields", Item::MAP, true, true);
+ return this;
}
- return this;
- }
- const google::protobuf::Field* field = NULL;
- if (element_ != NULL && element_->IsAny()) {
- element_->any()->StartObject(name);
- return this;
- } else if (element_ != NULL &&
- (element_->IsMap() || element_->IsStructMap())) {
- field = StartMapEntry(name);
- if (element_->IsStructMapEntry()) {
- // If the top element is a map entry, this means we are starting another
- // struct within a struct.
- field = StartStructValueInStruct(field);
+ if (master_type_.name() == kStructListValueType) {
+ InvalidValue(kStructListValueType,
+ "Cannot start root message with ListValue.");
}
- } else if (element_ != NULL && element_->IsStructList()) {
- // If the top element is a list, then we are starting a list field within a
- // struct.
- field = Lookup(name);
- field = StartStructValueInStruct(field);
- } else {
- field = BeginNamed(name, false);
- }
- if (field == NULL) {
- return this;
- }
- const google::protobuf::Type* type = LookupType(field);
- if (type == NULL) {
- ++invalid_depth_;
- InvalidName(name,
- StrCat("Missing descriptor for field: ", field->type_url()));
return this;
}
- // Check to see if this field is a oneof and that no oneof in that group has
- // already been set.
- if (!ValidOneof(*field, name)) {
- ++invalid_depth_;
+ // Send all ANY events to AnyWriter.
+ if (current_->IsAny()) {
+ current_->any()->StartObject(name);
return this;
}
- if (field->type_url() == GetFullTypeWithUrl(kStructType)) {
- // Start a struct object.
- StartStruct(field);
- } else if (field->type_url() == GetFullTypeWithUrl(kStructValueType)) {
- // We got a StartObject call with google.protobuf.Value field. This means we
- // are starting an object within google.protobuf.Value type. The only object
- // within that type is a struct type. So start a struct.
- field = StartStructValueInStruct(field);
- StartStruct(field);
- } else if (field->type_url() == GetFullTypeWithUrl(kAnyType)) {
- // Begin an Any. We can't do the real work till we get the @type field.
- WriteTag(*field);
- element_.reset(
- new ProtoElement(element_.release(), field, *type, ProtoElement::ANY));
- } else if (IsMap(*field)) {
- // Begin a map.
- // A map is triggered by a StartObject() call if the current field has a map
- // type. Map values are written to proto in a manner detailed in comments
- // above StartMapEntry() function.
- element_.reset(
- new ProtoElement(element_.release(), field, *type, ProtoElement::MAP));
- } else {
- WriteTag(*field);
- element_.reset(new ProtoElement(element_.release(), field, *type,
- ProtoElement::MESSAGE));
- }
- return this;
-}
-
-// Proto3 maps are represented on the wire as a message with
-// "key" and a "value".
-//
-// For example, the syntax:
-// map<key_type, value_type> map_field = N;
-//
-// is represented as:
-// message MapFieldEntry {
-// option map_entry = true; // marks the map construct in the descriptor
-//
-// key_type key = 1;
-// value_type value = 2;
-// }
-// repeated MapFieldEntry map_field = N;
-//
-// See go/proto3-maps for more information.
-const google::protobuf::Field* ProtoStreamObjectWriter::StartMapEntry(
- StringPiece name) {
- // top of stack is already a map field
- const google::protobuf::Field* field = element_->field();
- const google::protobuf::Type& type = element_->type();
- // If we come from a regular map, use MAP_ENTRY or if we come from a struct,
- // use STRUCT_MAP_ENTRY. These values are used later in StartObject/StartList
- // or RenderDataPiece for making appropriate decisions.
- ProtoElement::ElementType element_type = element_->IsStructMap()
- ? ProtoElement::STRUCT_MAP_ENTRY
- : ProtoElement::MAP_ENTRY;
- WriteTag(*field);
- element_.reset(
- new ProtoElement(element_.release(), field, type, element_type));
- RenderDataPiece("key", DataPiece(name));
- return BeginNamed("value", false);
-}
+ // If we are within a map, we render name as keys and send StartObject to the
+ // value field.
+ if (current_->IsMap()) {
+ if (!ValidMapKey(name)) {
+ IncrementInvalidDepth();
+ return this;
+ }
-// Starts a google.protobuf.Struct.
-// 'field' represents a field in a message of type google.protobuf.Struct. A
-// struct contains a map with name 'fields'. This function starts this map as
-// well.
-// When 'field' is NULL, it means that the top level message is of struct
-// type.
-void ProtoStreamObjectWriter::StartStruct(
- const google::protobuf::Field* field) {
- const google::protobuf::Type* type = NULL;
- if (field) {
- type = LookupType(field);
- WriteTag(*field);
- element_.reset(new ProtoElement(element_.release(), field, *type,
- ProtoElement::STRUCT));
- }
- const google::protobuf::Field* struct_field = BeginNamed("fields", false);
+ // Map is a repeated field of message type with a "key" and a "value" field.
+ // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps
+ // message MapFieldEntry {
+ // key_type key = 1;
+ // value_type value = 2;
+ // }
+ //
+ // repeated MapFieldEntry map_field = N;
+ //
+ // That means, we render the following element within a list (hence no
+ // name):
+ // { "key": "<name>", "value": {
+ Push("", Item::MESSAGE, false, false);
+ ProtoWriter::RenderDataPiece("key", DataPiece(name));
+ Push("value", Item::MESSAGE, true, false);
+
+ // Make sure we are valid so far after starting map fields.
+ if (invalid_depth() > 0) return this;
+
+ // If top of stack is g.p.Struct type, start the struct the map field within
+ // it.
+ if (element() != NULL && IsStruct(*element()->parent_field())) {
+ // Render "fields": [
+ Push("fields", Item::MAP, true, true);
+ return this;
+ }
- if (!struct_field) {
- // It is a programmatic error if this happens. Log an error.
- GOOGLE_LOG(ERROR) << "Invalid internal state. Cannot find 'fields' within "
- << (field ? field->type_url() : "google.protobuf.Struct");
- return;
+ // If top of stack is g.p.Value type, start the Struct within it.
+ if (element() != NULL && IsStructValue(*element()->parent_field())) {
+ // Render
+ // "struct_value": {
+ // "fields": [
+ Push("struct_value", Item::MESSAGE, true, false);
+ Push("fields", Item::MAP, true, true);
+ }
+ return this;
}
- type = LookupType(struct_field);
- element_.reset(new ProtoElement(element_.release(), struct_field, *type,
- ProtoElement::STRUCT_MAP));
-}
+ const google::protobuf::Field* field = BeginNamed(name, false);
+ if (field == NULL) return this;
-// Starts a "struct_value" within struct.proto's google.protobuf.Value type.
-// 'field' should be of the type google.protobuf.Value.
-// Returns the field identifying "struct_value" within the given field.
-//
-// If field is NULL, then we are starting struct_value at the top-level, in
-// this case skip writing any tag information for the passed field.
-const google::protobuf::Field*
-ProtoStreamObjectWriter::StartStructValueInStruct(
- const google::protobuf::Field* field) {
- if (field) {
- const google::protobuf::Type* type = LookupType(field);
- WriteTag(*field);
- element_.reset(new ProtoElement(element_.release(), field, *type,
- ProtoElement::STRUCT_VALUE));
- }
- return BeginNamed("struct_value", false);
-}
-
-// Starts a "list_value" within struct.proto's google.protobuf.Value type.
-// 'field' should be of the type google.protobuf.Value.
-// Returns the field identifying "list_value" within the given field.
-//
-// If field is NULL, then we are starting list_value at the top-level, in
-// this case skip writing any tag information for the passed field.
-const google::protobuf::Field* ProtoStreamObjectWriter::StartListValueInStruct(
- const google::protobuf::Field* field) {
- if (field) {
- const google::protobuf::Type* type = LookupType(field);
- WriteTag(*field);
- element_.reset(new ProtoElement(element_.release(), field, *type,
- ProtoElement::STRUCT_VALUE));
+ if (IsStruct(*field)) {
+ // Start a struct object.
+ // Render
+ // "<name>": {
+ // "fields": {
+ Push(name, Item::MESSAGE, false, false);
+ Push("fields", Item::MAP, true, true);
+ return this;
}
- const google::protobuf::Field* list_value = BeginNamed("list_value", false);
- if (!list_value) {
- // It is a programmatic error if this happens. Log an error.
- GOOGLE_LOG(ERROR) << "Invalid internal state. Cannot find 'list_value' within "
- << (field ? field->type_url() : "google.protobuf.Value");
- return field;
+ if (IsStructValue(*field)) {
+ // We got a StartObject call with google.protobuf.Value field. The only
+ // object within that type is a struct type. So start a struct.
+ // Render
+ // "<name>": {
+ // "struct_value": {
+ // "fields": {
+ Push(name, Item::MESSAGE, false, false);
+ Push("struct_value", Item::MESSAGE, true, false);
+ Push("fields", Item::MAP, true, true);
+ return this;
}
- return StartRepeatedValuesInListValue(list_value);
-}
-
-// Starts the repeated "values" field in struct.proto's
-// google.protobuf.ListValue type. 'field' should be of type
-// google.protobuf.ListValue.
-//
-// If field is NULL, then we are starting ListValue at the top-level, in
-// this case skip writing any tag information for the passed field.
-const google::protobuf::Field*
-ProtoStreamObjectWriter::StartRepeatedValuesInListValue(
- const google::protobuf::Field* field) {
- if (field) {
- const google::protobuf::Type* type = LookupType(field);
- WriteTag(*field);
- element_.reset(new ProtoElement(element_.release(), field, *type,
- ProtoElement::STRUCT_LIST_VALUE));
+ if (IsMap(*field)) {
+ // Begin a map. A map is triggered by a StartObject() call if the current
+ // field has a map type.
+ // A map type is always repeated, hence set is_list to true.
+ // Render
+ // "<name>": [
+ Push(name, Item::MAP, false, true);
+ return this;
}
- return BeginNamed("values", true);
-}
-void ProtoStreamObjectWriter::SkipElements() {
- if (element_ == NULL) return;
-
- ProtoElement::ElementType element_type = element_->element_type();
- while (element_type == ProtoElement::STRUCT ||
- element_type == ProtoElement::STRUCT_LIST_VALUE ||
- element_type == ProtoElement::STRUCT_VALUE ||
- element_type == ProtoElement::STRUCT_MAP_ENTRY ||
- element_type == ProtoElement::MAP_ENTRY) {
- element_.reset(element_->pop());
- element_type =
- element_ != NULL ? element_->element_type() : ProtoElement::MESSAGE;
- }
+ // A regular message type. Pass it directly to ProtoWriter.
+ // Render
+ // "<name>": {
+ Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
+ return this;
}
ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
- if (invalid_depth_ > 0) {
- --invalid_depth_;
+ if (invalid_depth() > 0) {
+ DecrementInvalidDepth();
return this;
}
- if (element_ != NULL && element_->IsAny()) {
- if (element_->any()->EndObject()) {
- return this;
- }
- }
- if (element_ != NULL) {
- element_.reset(element_->pop());
- }
- // Skip sentinel elements added to keep track of new proto3 types - map,
- // struct.
- SkipElements();
+ if (current_ == NULL) return this;
- // If ending the root element,
- // then serialize the full message with calculated sizes.
- if (element_ == NULL) {
- WriteRootMessage();
+ if (current_->IsAny()) {
+ if (current_->any()->EndObject()) return this;
}
+
+ Pop();
+
return this;
}
ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
- const google::protobuf::Field* field = NULL;
+ if (invalid_depth() > 0) {
+ IncrementInvalidDepth();
+ return this;
+ }
+
// Since we cannot have a top-level repeated item in protobuf, the only way
- // element_ can be null when here is when we start a top-level list
- // google.protobuf.ListValue.
- if (element_ == NULL) {
+ // this is valid is if we start a special type google.protobuf.ListValue or
+ // google.protobuf.Value.
+ if (current_ == NULL) {
if (!name.empty()) {
InvalidName(name, "Root element should not be named.");
+ IncrementInvalidDepth();
+ return this;
}
- element_.reset(new ProtoElement(typeinfo_, master_type_, this));
// If master type is a special type that needs extra values to be written to
// stream, we write those values.
if (master_type_.name() == kStructValueType) {
// We got a StartList with google.protobuf.Value master type. This means
// we have to start the "list_value" within google.protobuf.Value.
- field = StartListValueInStruct(NULL);
- } else if (master_type_.name() == kStructListValueType) {
+ //
+ // See
+ // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
+ //
+ // Render
+ // "<name>": {
+ // "list_value": {
+ // "values": [ // Start this list.
+ ProtoWriter::StartObject(name);
+ current_.reset(new Item(this, Item::MESSAGE, false, false));
+ Push("list_value", Item::MESSAGE, true, false);
+ Push("values", Item::MESSAGE, true, true);
+ return this;
+ }
+
+ if (master_type_.name() == kStructListValueType) {
// We got a StartList with google.protobuf.ListValue master type. This
// means we have to start the "values" within google.protobuf.ListValue.
- field = StartRepeatedValuesInListValue(NULL);
+ //
+ // Render
+ // "<name>": {
+ // "values": [ // Start this list.
+ ProtoWriter::StartObject(name);
+ current_.reset(new Item(this, Item::MESSAGE, false, false));
+ Push("values", Item::MESSAGE, true, true);
+ return this;
}
- // field is NULL when master_type_ is anything other than
- // google.protobuf.Value or google.protobuf.ListValue.
- if (field) {
- const google::protobuf::Type* type = LookupType(field);
- element_.reset(new ProtoElement(element_.release(), field, *type,
- ProtoElement::STRUCT_LIST));
- }
+ // Send the event to ProtoWriter so proper errors can be reported.
+ //
+ // Render a regular list:
+ // "<name>": [
+ ProtoWriter::StartList(name);
+ current_.reset(new Item(this, Item::MESSAGE, false, true));
return this;
}
- if (element_->IsAny()) {
- element_->any()->StartList(name);
+ if (current_->IsAny()) {
+ current_->any()->StartList(name);
return this;
}
- // The type of element we push to stack.
- ProtoElement::ElementType element_type = ProtoElement::LIST;
-
- // 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()) {
- field = StartMapEntry(name);
- if (field == NULL) return this;
-
- if (element_->IsStructMapEntry()) {
- // If the top element is a map entry, this means we are starting a list
- // within a struct or a map.
- // An example sequence of calls would be
- // StartObject -> StartList
- field = StartListValueInStruct(field);
- if (field == NULL) return this;
+
+ // If the top of stack is a map, we are starting a list value within a map.
+ // Since map does not allow repeated values, this can only happen when the map
+ // value is of a special type that renders a list in JSON. These can be one
+ // of 3 cases:
+ // i. We are rendering a list value within google.protobuf.Struct
+ // ii. We are rendering a list value within google.protobuf.Value
+ // iii. We are rendering a list value with type google.protobuf.ListValue.
+ if (current_->IsMap()) {
+ if (!ValidMapKey(name)) {
+ IncrementInvalidDepth();
+ return this;
}
- element_type = ProtoElement::STRUCT_LIST;
- } else if (element_->IsStructList()) {
- // If the top element is a STRUCT_LIST, this means we are starting a list
- // within the current list (inside a struct).
- // An example call sequence would be
- // StartObject -> StartList -> StartList
- // with StartObject starting a struct.
+ // Start the repeated map entry object.
+ // Render
+ // { "key": "<name>", "value": {
+ Push("", Item::MESSAGE, false, false);
+ ProtoWriter::RenderDataPiece("key", DataPiece(name));
+ Push("value", Item::MESSAGE, true, false);
+
+ // Make sure we are valid after pushing all above items.
+ if (invalid_depth() > 0) return this;
+
+ // case i and ii above. Start "list_value" field within g.p.Value
+ if (element() != NULL && element()->parent_field() != NULL) {
+ // Render
+ // "list_value": {
+ // "values": [ // Start this list
+ if (IsStructValue(*element()->parent_field())) {
+ Push("list_value", Item::MESSAGE, true, false);
+ Push("values", Item::MESSAGE, true, true);
+ return this;
+ }
- // Lookup the last list type in element stack as we are adding an element of
- // the same type.
- field = Lookup(name);
- if (field == NULL) return this;
+ // Render
+ // "values": [
+ if (IsStructListValue(*element()->parent_field())) {
+ // case iii above. Bind directly to g.p.ListValue
+ Push("values", Item::MESSAGE, true, true);
+ return this;
+ }
+ }
- field = StartListValueInStruct(field);
- if (field == NULL) return this;
+ // Report an error.
+ InvalidValue("Map", StrCat("Cannot have repeated items ('", name,
+ "') within a map."));
+ return this;
+ }
- element_type = ProtoElement::STRUCT_LIST;
- } else {
- // Lookup field corresponding to 'name'. If it is a google.protobuf.Value
- // or google.protobuf.ListValue type, then StartList is a valid call, start
- // this list.
- // We cannot use Lookup() here as it will produce InvalidName() error if the
- // field is not found. We do not want to error here as it would cause us to
- // report errors twice, once here and again later in BeginNamed() call.
- // Also we ignore if the field is not found here as it is caught later.
- field = typeinfo_->FindField(&element_->type(), name);
-
- // Only check for oneof collisions on the first StartList call. We identify
- // the first call with !name.empty() check. Subsequent list element calls
- // will not have the name filled.
- if (!name.empty() && field && !ValidOneof(*field, name)) {
- ++invalid_depth_;
- return this;
+ // When name is empty and stack is not empty, we are rendering an item within
+ // a list.
+ if (name.empty()) {
+ if (element() != NULL && element()->parent_field() != NULL) {
+ if (IsStructValue(*element()->parent_field())) {
+ // Since it is g.p.Value, we bind directly to the list_value.
+ // Render
+ // { // g.p.Value item within the list
+ // "list_value": {
+ // "values": [
+ Push("", Item::MESSAGE, false, false);
+ Push("list_value", Item::MESSAGE, true, false);
+ Push("values", Item::MESSAGE, true, true);
+ return this;
+ }
+
+ if (IsStructListValue(*element()->parent_field())) {
+ // Since it is g.p.ListValue, we bind to it directly.
+ // Render
+ // { // g.p.ListValue item within the list
+ // "values": [
+ Push("", Item::MESSAGE, false, false);
+ Push("values", Item::MESSAGE, true, true);
+ return this;
+ }
}
- // It is an error to try to bind to map, which behind the scenes is a list.
- if (field && IsMap(*field)) {
- // Push field to stack for error location tracking & reporting.
- element_.reset(new ProtoElement(element_.release(), field,
- *LookupType(field),
- ProtoElement::MESSAGE));
- InvalidValue("Map", "Cannot bind a list to map.");
- ++invalid_depth_;
- element_->pop();
+ // Pass the event to underlying ProtoWriter.
+ Push(name, Item::MESSAGE, false, true);
+ return this;
+ }
+
+ // name is not empty
+ const google::protobuf::Field* field = Lookup(name);
+ if (field == NULL) {
+ IncrementInvalidDepth();
+ return this;
+ }
+
+ if (IsStructValue(*field)) {
+ // If g.p.Value is repeated, start that list. Otherwise, start the
+ // "list_value" within it.
+ if (IsRepeated(*field)) {
+ // Render it just like a regular repeated field.
+ // "<name>": [
+ Push(name, Item::MESSAGE, false, true);
return this;
}
- if (field && field->type_url() == GetFullTypeWithUrl(kStructValueType)) {
- // There are 2 cases possible:
- // a. g.p.Value is repeated
- // b. g.p.Value is not repeated
- //
- // For case (a), the StartList should bind to the repeated g.p.Value.
- // For case (b), the StartList should bind to g.p.ListValue within the
- // g.p.Value.
- //
- // This means, for case (a), we treat it just like any other repeated
- // message, except we would apply an appropriate element_type so future
- // Start or Render calls are routed appropriately.
- if (field->cardinality() !=
- google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
- field = StartListValueInStruct(field);
- }
- element_type = ProtoElement::STRUCT_LIST;
- } else if (field &&
- field->type_url() == GetFullTypeWithUrl(kStructListValueType)) {
- // We got a StartList with google.protobuf.ListValue master type. This
- // means we have to start the "values" within google.protobuf.ListValue.
- field = StartRepeatedValuesInListValue(field);
- } else {
- // If no special types are to be bound, fall back to normal processing of
- // StartList.
- field = BeginNamed(name, true);
+ // Start the "list_value" field.
+ // Render
+ // "<name>": {
+ // "list_value": {
+ // "values": [
+ Push(name, Item::MESSAGE, false, false);
+ Push("list_value", Item::MESSAGE, true, false);
+ Push("values", Item::MESSAGE, true, true);
+ return this;
+ }
+
+ if (IsStructListValue(*field)) {
+ // If g.p.ListValue is repeated, start that list. Otherwise, start the
+ // "values" within it.
+ if (IsRepeated(*field)) {
+ // Render it just like a regular repeated field.
+ // "<name>": [
+ Push(name, Item::MESSAGE, false, true);
+ return this;
}
- if (field == NULL) return this;
+
+ // Start the "values" field within g.p.ListValue.
+ // Render
+ // "<name>": {
+ // "values": [
+ Push(name, Item::MESSAGE, false, false);
+ Push("values", Item::MESSAGE, true, true);
+ return this;
}
- const google::protobuf::Type* type = LookupType(field);
- if (type == NULL) {
- ++invalid_depth_;
- InvalidName(name,
- StrCat("Missing descriptor for field: ", field->type_url()));
+ // If we are here, the field should be repeated. Report an error otherwise.
+ if (!IsRepeated(*field)) {
+ IncrementInvalidDepth();
+ InvalidName(name, "Proto field is not repeating, cannot start list.");
return this;
}
- element_.reset(
- new ProtoElement(element_.release(), field, *type, element_type));
+ if (IsMap(*field)) {
+ InvalidValue("Map",
+ StrCat("Cannot bind a list to map for field '", name, "'."));
+ IncrementInvalidDepth();
+ return this;
+ }
+
+ // Pass the event to ProtoWriter.
+ // Render
+ // "<name>": [
+ Push(name, Item::MESSAGE, false, true);
return this;
}
ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() {
- if (invalid_depth_ > 0) {
- --invalid_depth_;
- } else if (element_ != NULL) {
- if (element_->IsAny()) {
- element_->any()->EndList();
- } else {
- element_.reset(element_->pop());
- // Skip sentinel elements added to keep track of new proto3 types - map,
- // struct.
- SkipElements();
- }
+ if (invalid_depth() > 0) {
+ DecrementInvalidDepth();
+ return this;
}
- // When element_ is NULL, we have reached the root message type. Write out
- // the bytes.
- if (element_ == NULL) {
- WriteRootMessage();
+ if (current_ == NULL) return this;
+
+ if (current_->IsAny()) {
+ current_->any()->EndList();
+ return this;
}
+
+ Pop();
return this;
}
@@ -1067,7 +782,7 @@ Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow,
"null values are supported.");
}
}
- ow->RenderDataPiece(struct_field_name, data);
+ ow->ProtoWriter::RenderDataPiece(struct_field_name, data);
return Status::OK;
}
@@ -1089,15 +804,15 @@ Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow,
}
- ow->RenderDataPiece("seconds", DataPiece(seconds));
- ow->RenderDataPiece("nanos", DataPiece(nanos));
+ ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+ ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
return Status::OK;
}
static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
StringPiece path) {
- ow->RenderDataPiece("paths",
- DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase)));
+ ow->ProtoWriter::RenderDataPiece(
+ "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase)));
return Status::OK;
}
@@ -1113,7 +828,7 @@ Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
// conversions as much as possible. Because ToSnakeCase sometimes returns the
// wrong value.
google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback(
- NewPermanentCallback(&RenderOneFieldPath, ow));
+ google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow));
return DecodeCompactFieldMaskPaths(data.str(), callback.get());
}
@@ -1146,223 +861,133 @@ Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
"Invalid duration format, failed to parse seconds");
}
- double d_nanos = 0;
- if (!safe_strtod("0." + s_nanos.ToString(), &d_nanos)) {
- return Status(INVALID_ARGUMENT,
- "Invalid duration format, failed to parse nanos seconds");
+ int32 nanos = 0;
+ Status nanos_status = GetNanosFromStringPiece(
+ s_nanos, "Invalid duration format, failed to parse nano seconds",
+ "Duration value exceeds limits", &nanos);
+ if (!nanos_status.ok()) {
+ return nanos_status;
}
+ nanos = sign * nanos;
- int32 nanos = sign * static_cast<int32>(d_nanos * kNanosPerSecond);
int64 seconds = sign * unsigned_seconds;
-
if (seconds > kMaxSeconds || seconds < kMinSeconds ||
nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
return Status(INVALID_ARGUMENT, "Duration value exceeds limits");
}
- ow->RenderDataPiece("seconds", DataPiece(seconds));
- ow->RenderDataPiece("nanos", DataPiece(nanos));
+ ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+ ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
return Status::OK;
}
Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
const DataPiece& data) {
- ow->RenderDataPiece("value", data);
+ ow->ProtoWriter::RenderDataPiece("value", data);
return Status::OK;
}
ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
StringPiece name, const DataPiece& data) {
Status status;
- if (invalid_depth_ > 0) return this;
- if (element_ != NULL && element_->IsAny()) {
- element_->any()->RenderDataPiece(name, data);
+ if (invalid_depth() > 0) return this;
+
+ if (current_ == NULL) {
+ const TypeRenderer* type_renderer =
+ FindTypeRenderer(GetFullTypeWithUrl(master_type_.name()));
+ if (type_renderer == NULL) {
+ InvalidName(name, "Root element must be a message.");
+ return this;
+ }
+ // Render the special type.
+ // "<name>": {
+ // ... Render special type ...
+ // }
+ ProtoWriter::StartObject(name);
+ status = (*type_renderer)(this, data);
+ if (!status.ok()) {
+ InvalidValue(master_type_.name(),
+ StrCat("Field '", name, "', ", status.error_message()));
+ }
+ ProtoWriter::EndObject();
+ return this;
+ }
+
+ if (current_->IsAny()) {
+ current_->any()->RenderDataPiece(name, data);
return this;
}
const google::protobuf::Field* field = NULL;
- string type_url;
- bool is_map_entry = false;
- // We are at the root when element_ == NULL.
- if (element_ == NULL) {
- type_url = GetFullTypeWithUrl(master_type_.name());
- } else {
- if (element_->IsMap() || element_->IsStructMap()) {
- is_map_entry = true;
- field = StartMapEntry(name);
- } else {
- field = Lookup(name);
- }
+ if (current_->IsMap()) {
+ if (!ValidMapKey(name)) return this;
+
+ // Render an item in repeated map list.
+ // { "key": "<name>", "value":
+ Push("", Item::MESSAGE, false, false);
+ ProtoWriter::RenderDataPiece("key", DataPiece(name));
+ field = Lookup("value");
if (field == NULL) {
+ GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
+ return this;
+ }
+
+ const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
+ if (type_renderer != NULL) {
+ // Map's value type is a special type. Render it like a message:
+ // "value": {
+ // ... Render special type ...
+ // }
+ Push("value", Item::MESSAGE, true, false);
+ status = (*type_renderer)(this, data);
+ if (!status.ok()) {
+ InvalidValue(field->type_url(),
+ StrCat("Field '", name, "', ", status.error_message()));
+ }
+ Pop();
return this;
}
- // Check to see if this field is a oneof and that no oneof in that group has
- // already been set.
- if (!ValidOneof(*field, name)) return this;
+ // If we are rendering explicit null values and the backend proto field is
+ // not of the google.protobuf.NullType type, we do nothing.
+ if (data.type() == DataPiece::TYPE_NULL &&
+ field->type_url() != kStructNullValueTypeUrl) {
+ return this;
+ }
- type_url = field->type_url();
+ // Render the map value as a primitive type.
+ ProtoWriter::RenderDataPiece("value", data);
+ Pop();
+ return this;
}
- // Check if there are any well known type renderers available for type_url.
- const TypeRenderer* type_renderer = FindTypeRenderer(type_url);
+ field = Lookup(name);
+ if (field == NULL) return this;
+
+ // Check if the field is of special type. Render it accordingly if so.
+ const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
if (type_renderer != NULL) {
- // Push the current element to stack so lookups in type_renderer will
- // find the fields. We do an EndObject soon after, which pops this. This is
- // safe because all well-known types are messages.
- if (element_ == NULL) {
- element_.reset(new ProtoElement(typeinfo_, master_type_, this));
- } else {
- if (field) {
- WriteTag(*field);
- const google::protobuf::Type* type = LookupType(field);
- element_.reset(new ProtoElement(element_.release(), field, *type,
- ProtoElement::MESSAGE));
- }
- }
+ Push(name, Item::MESSAGE, false, false);
status = (*type_renderer)(this, data);
if (!status.ok()) {
- InvalidValue(type_url,
+ InvalidValue(field->type_url(),
StrCat("Field '", name, "', ", status.error_message()));
}
- EndObject();
- return this;
- } else if (element_ == NULL) { // no message type found at root
- element_.reset(new ProtoElement(typeinfo_, master_type_, this));
- InvalidName(name, "Root element must be a message.");
+ Pop();
return this;
}
- if (field == NULL) {
- return this;
- }
- const google::protobuf::Type* type = LookupType(field);
- if (type == NULL) {
- InvalidName(name,
- StrCat("Missing descriptor for field: ", field->type_url()));
+ // If we are rendering explicit null values and the backend proto field is
+ // not of the google.protobuf.NullType type, we do nothing.
+ if (data.type() == DataPiece::TYPE_NULL &&
+ field->type_url() != kStructNullValueTypeUrl) {
return this;
}
- // Whether we should pop at the end. Set to true if the data field is a
- // message type, which can happen in case of struct values.
- bool should_pop = false;
-
- RenderSimpleDataPiece(*field, *type, data);
-
- if (should_pop && element_ != NULL) {
- element_.reset(element_->pop());
- }
-
- if (is_map_entry) {
- // Ending map is the same as ending an object.
- EndObject();
- }
+ ProtoWriter::RenderDataPiece(name, data);
return this;
}
-void ProtoStreamObjectWriter::RenderSimpleDataPiece(
- const google::protobuf::Field& field, const google::protobuf::Type& type,
- const DataPiece& data) {
- // If we are rendering explicit null values and the backend proto field is not
- // of the google.protobuf.NullType type, we do nothing.
- if (data.type() == DataPiece::TYPE_NULL &&
- field.type_url() != kStructNullValueTypeUrl) {
- return;
- }
-
- // Pushing a ProtoElement and then pop it off at the end for 2 purposes:
- // error location reporting and required field accounting.
- element_.reset(new ProtoElement(element_.release(), &field, type,
- ProtoElement::MESSAGE));
-
- // Make sure that field represents a simple data type.
- if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN ||
- field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
- InvalidValue(field.type_url().empty()
- ? google::protobuf::Field_Kind_Name(field.kind())
- : field.type_url(),
- data.ValueAsStringOrDefault(""));
- return;
- }
-
- Status status;
- switch (field.kind()) {
- case google::protobuf::Field_Kind_TYPE_INT32: {
- status = WriteInt32(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_SFIXED32: {
- status = WriteSFixed32(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_SINT32: {
- status = WriteSInt32(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_FIXED32: {
- status = WriteFixed32(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_UINT32: {
- status = WriteUInt32(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_INT64: {
- status = WriteInt64(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_SFIXED64: {
- status = WriteSFixed64(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_SINT64: {
- status = WriteSInt64(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_FIXED64: {
- status = WriteFixed64(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_UINT64: {
- status = WriteUInt64(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_DOUBLE: {
- status = WriteDouble(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_FLOAT: {
- status = WriteFloat(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_BOOL: {
- status = WriteBool(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_BYTES: {
- status = WriteBytes(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_STRING: {
- status = WriteString(field.number(), data, stream_.get());
- break;
- }
- case google::protobuf::Field_Kind_TYPE_ENUM: {
- status = WriteEnum(field.number(), data,
- typeinfo_->GetEnumByTypeUrl(field.type_url()),
- stream_.get());
- break;
- }
- default: // TYPE_GROUP or TYPE_MESSAGE
- status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie());
- }
- if (!status.ok()) {
- InvalidValue(google::protobuf::Field_Kind_Name(field.kind()),
- status.error_message());
- }
- element_.reset(element_->pop());
-}
-
// Map of functions that are responsible for rendering well known type
// represented by the key.
hash_map<string, ProtoStreamObjectWriter::TypeRenderer>*
@@ -1429,167 +1054,43 @@ ProtoStreamObjectWriter::FindTypeRenderer(const string& type_url) {
return FindOrNull(*renderers_, type_url);
}
-ProtoStreamObjectWriter::ProtoElement::ElementType
-ProtoStreamObjectWriter::GetElementType(const google::protobuf::Type& type) {
- if (type.name() == kAnyType) {
- return ProtoElement::ANY;
- } else if (type.name() == kStructType) {
- return ProtoElement::STRUCT;
- } else if (type.name() == kStructValueType) {
- return ProtoElement::STRUCT_VALUE;
- } else if (type.name() == kStructListValueType) {
- return ProtoElement::STRUCT_LIST_VALUE;
- } else {
- return ProtoElement::MESSAGE;
- }
-}
+bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
+ if (current_ == NULL) return true;
-bool ProtoStreamObjectWriter::ValidOneof(const google::protobuf::Field& field,
- StringPiece unnormalized_name) {
- if (element_ == NULL) return true;
-
- if (field.oneof_index() > 0) {
- if (element_->OneofIndexTaken(field.oneof_index())) {
- InvalidValue(
- "oneof",
- StrCat("oneof field '",
- element_->type().oneofs(field.oneof_index() - 1),
- "' is already set. Cannot set '", unnormalized_name, "'"));
- return false;
- }
- element_->TakeOneofIndex(field.oneof_index());
+ if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) {
+ listener()->InvalidName(
+ location(), 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) {
- ++invalid_depth_;
- return NULL;
- }
- const google::protobuf::Field* field = Lookup(name);
- if (field == NULL) {
- ++invalid_depth_;
- // InvalidName() already called in Lookup().
- return NULL;
- }
- if (is_list &&
- field->cardinality() !=
- google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
- ++invalid_depth_;
- InvalidName(name, "Proto field is not repeating, cannot start list.");
- return NULL;
- }
- return field;
-}
+void ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type,
+ bool is_placeholder, bool is_list) {
+ is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name);
-const google::protobuf::Field* ProtoStreamObjectWriter::Lookup(
- StringPiece unnormalized_name) {
- ProtoElement* e = element();
- if (e == NULL) {
- InvalidName(unnormalized_name, "Root element must be a message.");
- return NULL;
- }
- if (unnormalized_name.empty()) {
- // Objects in repeated field inherit the same field descriptor.
- if (e->field() == NULL) {
- InvalidName(unnormalized_name, "Proto fields must have a name.");
- } else if (e->field()->cardinality() !=
- google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
- InvalidName(unnormalized_name, "Proto fields must have a name.");
- return NULL;
- }
- return e->field();
- }
- const google::protobuf::Field* field =
- typeinfo_->FindField(&e->type(), unnormalized_name);
- if (field == NULL) InvalidName(unnormalized_name, "Cannot find field.");
- return field;
+ // invalid_depth == 0 means it is a successful StartObject or StartList.
+ if (invalid_depth() == 0)
+ current_.reset(
+ new Item(current_.release(), item_type, is_placeholder, is_list));
}
-const google::protobuf::Type* ProtoStreamObjectWriter::LookupType(
- const google::protobuf::Field* field) {
- return (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE
- ? typeinfo_->GetTypeByTypeUrl(field->type_url())
- : &element_->type());
-}
-
-// Looks up the oneof struct field based on the data type.
-StatusOr<const google::protobuf::Field*>
-ProtoStreamObjectWriter::LookupStructField(DataPiece::Type type) {
- const google::protobuf::Field* field = NULL;
- switch (type) {
- // Our JSON parser parses numbers as either int64, uint64, or double.
- case DataPiece::TYPE_INT64:
- case DataPiece::TYPE_UINT64:
- case DataPiece::TYPE_DOUBLE: {
- field = Lookup("number_value");
- break;
- }
- case DataPiece::TYPE_STRING: {
- field = Lookup("string_value");
- break;
- }
- case DataPiece::TYPE_BOOL: {
- field = Lookup("bool_value");
- break;
- }
- case DataPiece::TYPE_NULL: {
- field = Lookup("null_value");
- break;
- }
- default: { return Status(INVALID_ARGUMENT, "Invalid struct data type"); }
+void ProtoStreamObjectWriter::Pop() {
+ // Pop all placeholder items sending StartObject or StartList events to
+ // ProtoWriter according to is_list value.
+ while (current_ != NULL && current_->is_placeholder()) {
+ PopOneElement();
}
- if (field == NULL) {
- return Status(INVALID_ARGUMENT, "Could not lookup struct field");
+ if (current_ != NULL) {
+ PopOneElement();
}
- return field;
}
-void ProtoStreamObjectWriter::WriteRootMessage() {
- GOOGLE_DCHECK(!done_);
- int curr_pos = 0;
- // Calls the destructor of CodedOutputStream to remove any uninitialized
- // memory from the Cord before we read it.
- stream_.reset(NULL);
- const void* data;
- int length;
- google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size());
- while (input_stream.Next(&data, &length)) {
- if (length == 0) continue;
- int num_bytes = length;
- // Write up to where we need to insert the size field.
- // The number of bytes we may write is the smaller of:
- // - the current fragment size
- // - the distance to the next position where a size field needs to be
- // inserted.
- if (!size_insert_.empty() &&
- size_insert_.front().pos - curr_pos < num_bytes) {
- num_bytes = size_insert_.front().pos - curr_pos;
- }
- output_->Append(static_cast<const char*>(data), num_bytes);
- if (num_bytes < length) {
- input_stream.BackUp(length - num_bytes);
- }
- curr_pos += num_bytes;
- // Insert the size field.
- // size_insert_.front(): the next <index, size> pair to be written.
- // size_insert_.front().pos: position of the size field.
- // size_insert_.front().size: the size (integer) to be inserted.
- if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) {
- // Varint32 occupies at most 10 bytes.
- uint8 insert_buffer[10];
- uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray(
- size_insert_.front().size, insert_buffer);
- output_->Append(reinterpret_cast<const char*>(insert_buffer),
- insert_buffer_pos - insert_buffer);
- size_insert_.pop_front();
- }
- }
- output_->Flush();
- stream_.reset(new CodedOutputStream(&adapter_));
- done_ = true;
+void ProtoStreamObjectWriter::PopOneElement() {
+ current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject();
+ current_.reset(current_->pop<Item>());
}
bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
@@ -1600,7 +1101,7 @@ bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
return false;
}
const google::protobuf::Type* field_type =
- typeinfo_->GetTypeByTypeUrl(field.type_url());
+ typeinfo()->GetTypeByTypeUrl(field.type_url());
// TODO(xiaofeng): Unify option names.
return GetBoolOptionOrDefault(field_type->options(),
@@ -1608,10 +1109,22 @@ bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
GetBoolOptionOrDefault(field_type->options(), "map_entry", false);
}
-void ProtoStreamObjectWriter::WriteTag(const google::protobuf::Field& field) {
- WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
- static_cast<WireFormatLite::FieldType>(field.kind()));
- stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
+bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
+ return GetTypeWithoutUrl(field.type_url()) == kAnyType;
+}
+
+bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) {
+ return GetTypeWithoutUrl(field.type_url()) == kStructType;
+}
+
+bool ProtoStreamObjectWriter::IsStructValue(
+ const google::protobuf::Field& field) {
+ return GetTypeWithoutUrl(field.type_url()) == kStructValueType;
+}
+
+bool ProtoStreamObjectWriter::IsStructListValue(
+ const google::protobuf::Field& field) {
+ return GetTypeWithoutUrl(field.type_url()) == kStructListValueType;
}
} // namespace converter
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
index 8f49120b..08ac6e33 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.h
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -42,6 +42,7 @@
#include <google/protobuf/util/internal/type_info.h>
#include <google/protobuf/util/internal/datapiece.h>
#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/proto_writer.h>
#include <google/protobuf/util/internal/structured_objectwriter.h>
#include <google/protobuf/util/type_resolver.h>
#include <google/protobuf/stubs/bytestream.h>
@@ -67,9 +68,11 @@ namespace converter {
class ObjectLocationTracker;
// An ObjectWriter that can write protobuf bytes directly from writer events.
+// This class supports all special types like Struct and Map. It uses
+// the ProtoWriter class to write raw proto bytes.
//
// It also supports streaming.
-class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter {
+class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
public:
// Constructor. Does not take ownership of any parameter passed in.
ProtoStreamObjectWriter(TypeResolver* type_resolver,
@@ -82,56 +85,13 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
virtual ProtoStreamObjectWriter* EndObject();
virtual ProtoStreamObjectWriter* StartList(StringPiece name);
virtual ProtoStreamObjectWriter* EndList();
- virtual ProtoStreamObjectWriter* RenderBool(StringPiece name, bool value) {
- return RenderDataPiece(name, DataPiece(value));
- }
- virtual ProtoStreamObjectWriter* RenderInt32(StringPiece name, int32 value) {
- return RenderDataPiece(name, DataPiece(value));
- }
- virtual ProtoStreamObjectWriter* RenderUint32(StringPiece name,
- uint32 value) {
- return RenderDataPiece(name, DataPiece(value));
- }
- virtual ProtoStreamObjectWriter* RenderInt64(StringPiece name, int64 value) {
- return RenderDataPiece(name, DataPiece(value));
- }
- virtual ProtoStreamObjectWriter* RenderUint64(StringPiece name,
- uint64 value) {
- return RenderDataPiece(name, DataPiece(value));
- }
- virtual ProtoStreamObjectWriter* RenderDouble(StringPiece name,
- double value) {
- return RenderDataPiece(name, DataPiece(value));
- }
- virtual ProtoStreamObjectWriter* RenderFloat(StringPiece name, float value) {
- return RenderDataPiece(name, DataPiece(value));
- }
- virtual ProtoStreamObjectWriter* RenderString(StringPiece name,
- StringPiece value) {
- return RenderDataPiece(name, DataPiece(value));
- }
- virtual ProtoStreamObjectWriter* RenderBytes(StringPiece name,
- StringPiece value) {
- return RenderDataPiece(name, DataPiece(value, false));
- }
- virtual ProtoStreamObjectWriter* RenderNull(StringPiece name) {
- return RenderDataPiece(name, DataPiece::NullData());
- }
// Renders a DataPiece 'value' into a field whose wire type is determined
// from the given field 'name'.
- ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
- const DataPiece& value);
+ virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
+ const DataPiece& value);
- // Returns the location tracker to use for tracking locations for errors.
- const LocationTrackerInterface& location() {
- return element_ != NULL ? *element_ : *tracker_;
- }
-
- // When true, we finished writing to output a complete message.
- bool done() const { return done_; }
-
- private:
+ protected:
// Function that renders a well known type with modified behavior.
typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
const DataPiece&);
@@ -192,72 +152,46 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
bool has_injected_value_message_;
};
- class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface {
+ // Represents an item in a stack of items used to keep state between
+ // ObjectWrier events.
+ class LIBPROTOBUF_EXPORT Item : public BaseElement {
public:
- // Indicates the type of element. Special types like LIST, MAP, MAP_ENTRY,
- // STRUCT etc. are used to deduce other information based on their position
- // on the stack of elements.
- enum ElementType {
- MESSAGE, // Simple message
- LIST, // List/repeated element
- MAP, // Proto3 map type
- MAP_ENTRY, // Proto3 map message type, with 'key' and 'value' fields
- ANY, // Proto3 Any type
- STRUCT, // Proto3 struct type
- STRUCT_VALUE, // Struct's Value message type
- STRUCT_LIST, // List type indicator within a struct
- STRUCT_LIST_VALUE, // Struct Value's ListValue message type
- STRUCT_MAP, // Struct within a struct type
- STRUCT_MAP_ENTRY // Struct map's entry type with 'key' and 'value'
- // fields
+ // Indicates the type of item.
+ enum ItemType {
+ MESSAGE, // Simple message
+ MAP, // Proto3 map type
+ ANY, // Proto3 Any type
};
- // Constructor for the root element. No parent nor field.
- ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type,
- ProtoStreamObjectWriter* enclosing);
+ // Constructor for the root item.
+ Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
+ bool is_placeholder, bool is_list);
- // Constructor for a field of an element.
- ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
- const google::protobuf::Type& type, ElementType element_type);
+ // Constructor for a field of a message.
+ Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
- virtual ~ProtoElement() {}
-
- // Called just before the destructor for clean up:
- // - reports any missing required fields
- // - computes the space needed by the size field, and augment the
- // length of all parent messages by this additional space.
- // - releases and returns the parent pointer.
- ProtoElement* pop();
-
- // Accessors
- const google::protobuf::Field* field() const { return field_; }
- const google::protobuf::Type& type() const { return type_; }
+ virtual ~Item() {}
// These functions return true if the element type is corresponding to the
// type in function name.
- bool IsMap() { return element_type_ == MAP; }
- bool IsStructMap() { return element_type_ == STRUCT_MAP; }
- bool IsStructMapEntry() { return element_type_ == STRUCT_MAP_ENTRY; }
- bool IsStructList() { return element_type_ == STRUCT_LIST; }
- bool IsAny() { return element_type_ == ANY; }
-
- ElementType element_type() { return element_type_; }
-
- void RegisterField(const google::protobuf::Field* field);
- virtual string ToString() const;
+ bool IsMap() { return item_type_ == MAP; }
+ bool IsAny() { return item_type_ == ANY; }
AnyWriter* any() const { return any_.get(); }
- virtual ProtoElement* parent() const {
- return static_cast<ProtoElement*>(BaseElement::parent());
+ virtual Item* parent() const {
+ return static_cast<Item*>(BaseElement::parent());
}
- // Returns true if the index is already taken by a preceeding oneof input.
- bool OneofIndexTaken(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);
- // Marks the oneof 'index' as taken. Future inputs to this oneof will
- // generate an error.
- void TakeOneofIndex(int32 index);
+ bool is_placeholder() const { return is_placeholder_; }
+ bool is_list() const { return is_list_; }
private:
// Used for access to variables of the enclosing instance of
@@ -267,121 +201,42 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
// A writer for Any objects, handles all Any-related nonsense.
google::protobuf::scoped_ptr<AnyWriter> any_;
- // Describes the element as a field in the parent message.
- // field_ is NULL if and only if this element is the root element.
- const google::protobuf::Field* field_;
-
- // TypeInfo to lookup types.
- const TypeInfo* typeinfo_;
-
- // Additional variables if this element is a message:
- // (Root element is always a message).
- // descriptor_ : describes allowed fields in the message.
- // required_fields_: set of required fields.
- // is_repeated_type_ : true if the element is of type list or map.
- // size_index_ : index into ProtoStreamObjectWriter::size_insert_
- // for later insertion of serialized message length.
- const google::protobuf::Type& type_;
- std::set<const google::protobuf::Field*> required_fields_;
- const bool is_repeated_type_;
- const int size_index_;
-
- // Tracks position in repeated fields, needed for LocationTrackerInterface.
- int array_index_;
-
// The type of this element, see enum for permissible types.
- ElementType element_type_;
+ ItemType item_type_;
- // Set of oneof indices already seen for the type_. Used to validate
- // incoming messages so no more than one oneof is set.
- hash_set<int32> 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<string> map_keys_;
- GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
- };
+ // Conveys whether this Item is a placeholder or not. Placeholder items are
+ // pushed to stack to account for special types.
+ bool is_placeholder_;
- // Container for inserting 'size' information at the 'pos' position.
- struct SizeInfo {
- const int pos;
- int size;
+ // Conveys whether this Item is a list or not. This is used to send
+ // StartList or EndList calls to underlying ObjectWriter.
+ bool is_list_;
+
+ GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
};
ProtoStreamObjectWriter(const TypeInfo* typeinfo,
const google::protobuf::Type& type,
strings::ByteSink* output, ErrorListener* listener);
- ProtoElement* element() { return element_.get(); }
-
- // Helper methods for calling ErrorListener. See error_listener.h.
- void InvalidName(StringPiece unknown_name, StringPiece message);
- void InvalidValue(StringPiece type_name, StringPiece value);
- void MissingField(StringPiece missing_name);
-
- // Common code for BeginObject() and BeginList() that does invalid_depth_
- // bookkeeping associated with name lookup.
- const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list);
-
- // Lookup the field in the current element. Looks in the base descriptor
- // and in any extension. This will report an error if the field cannot be
- // found or if multiple matching extensions are found.
- const google::protobuf::Field* Lookup(StringPiece name);
-
- // Lookup the field type in the type descriptor. Returns NULL if the type
- // is not known.
- const google::protobuf::Type* LookupType(
- const google::protobuf::Field* field);
-
- // Looks up the oneof struct Value field depending on the type.
- // On failure to find, it returns an appropriate error.
- util::StatusOr<const google::protobuf::Field*> LookupStructField(
- DataPiece::Type type);
-
- // Starts an entry in map. This will be called after placing map element at
- // the top of the stack. Uses this information to write map entries.
- const google::protobuf::Field* StartMapEntry(StringPiece name);
-
- // Starts a google.protobuf.Struct.
- // 'field' is of type google.protobuf.Struct.
- // If field is NULL, it indicates that the top-level message is a struct
- // type.
- void StartStruct(const google::protobuf::Field* field);
-
- // Starts another struct within a struct.
- // 'field' is of type google.protobuf.Value (see struct.proto).
- const google::protobuf::Field* StartStructValueInStruct(
- const google::protobuf::Field* field);
-
- // Starts a list within a struct.
- // 'field' is of type google.protobuf.ListValue (see struct.proto).
- const google::protobuf::Field* StartListValueInStruct(
- const google::protobuf::Field* field);
-
- // Starts the repeated "values" field in struct.proto's
- // google.protobuf.ListValue type. 'field' should be of type
- // google.protobuf.ListValue.
- const google::protobuf::Field* StartRepeatedValuesInListValue(
- const google::protobuf::Field* field);
-
- // Pops sentinel elements off the stack.
- void SkipElements();
-
- // Write serialized output to the final output ByteSink, inserting all
- // the size information for nested messages that are missing from the
- // intermediate Cord buffer.
- void WriteRootMessage();
-
// Returns true if the field is a map.
bool IsMap(const google::protobuf::Field& field);
// Returns true if the field is an any.
bool IsAny(const google::protobuf::Field& field);
- // Helper method to write proto tags based on the given field.
- void WriteTag(const google::protobuf::Field& field);
+ // Returns true if the field is google.protobuf.Struct.
+ bool IsStruct(const google::protobuf::Field& field);
+
+ // Returns true if the field is google.protobuf.Value.
+ bool IsStructValue(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,
- const DataPiece& data);
+ // Returns true if the field is google.protobuf.ListValue.
+ bool IsStructListValue(const google::protobuf::Field& field);
// Renders google.protobuf.Value in struct.proto. It picks the right oneof
// type based on value's type.
@@ -405,61 +260,46 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
const DataPiece& value);
- // Helper functions to create the map and find functions responsible for
- // rendering well known types, keyed by type URL.
- static hash_map<string, TypeRenderer>* renderers_;
static void InitRendererMap();
static void DeleteRendererMap();
static TypeRenderer* FindTypeRenderer(const string& type_url);
- // Returns the ProtoElement::ElementType for the given Type.
- static ProtoElement::ElementType GetElementType(
- const google::protobuf::Type& type);
+ // 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 (current_)
+ // 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);
+
+ // Pushes an item on to the stack. Also calls either StartObject or StartList
+ // on the underlying ObjectWriter depending on whether is_list is false or
+ // not.
+ // is_placeholder conveys whether the item is a placeholder item or not.
+ // Placeholder items are pushed when adding auxillary types' StartObject or
+ // StartList calls.
+ void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder,
+ bool is_list);
+
+ // Pops items from the stack. All placeholder items are popped until a
+ // non-placeholder item is found.
+ void Pop();
+
+ // Pops one element from the stack. Calls EndObject() or EndList() on the
+ // underlying ObjectWriter depending on the value of is_list_.
+ void PopOneElement();
- // Returns true if the field for type_ can be set as a oneof. If field is not
- // a oneof type, this function does nothing and returns true.
- // If another field for this oneof is already set, this function returns
- // false. It also calls the appropriate error callback.
- // unnormalized_name is used for error string.
- bool ValidOneof(const google::protobuf::Field& field,
- StringPiece unnormalized_name);
+ private:
+ // Helper functions to create the map and find functions responsible for
+ // rendering well known types, keyed by type URL.
+ static hash_map<string, TypeRenderer>* renderers_;
// Variables for describing the structure of the input tree:
// master_type_: descriptor for the whole protobuf message.
- // typeinfo_ : the TypeInfo object to lookup types.
const google::protobuf::Type& master_type_;
- const TypeInfo* typeinfo_;
- // Whether we own the typeinfo_ object.
- bool own_typeinfo_;
-
- // Indicates whether we finished writing root message completely.
- bool done_;
-
- // Variable for internal state processing:
- // element_ : the current element.
- // size_insert_: sizes of nested messages.
- // pos - position to insert the size field.
- // size - size value to be inserted.
- google::protobuf::scoped_ptr<ProtoElement> element_;
- std::deque<SizeInfo> size_insert_;
-
- // Variables for output generation:
- // output_ : pointer to an external ByteSink for final user-visible output.
- // buffer_ : buffer holding partial message before being ready for output_.
- // adapter_ : internal adapter between CodedOutputStream and Cord buffer_.
- // stream_ : wrapper for writing tags and other encodings in wire format.
- strings::ByteSink* output_;
- string buffer_;
- google::protobuf::io::StringOutputStream adapter_;
- google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_;
-
- // Variables for error tracking and reporting:
- // listener_ : a place to report any errors found.
- // invalid_depth_: number of enclosing invalid nested messages.
- // tracker_ : the root location tracker interface.
- ErrorListener* listener_;
- int invalid_depth_;
- google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_;
+
+ // The current element, variable for internal state processing.
+ google::protobuf::scoped_ptr<Item> current_;
GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
};
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
index 96e5ccfb..5f9ffb95 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 <google/protobuf/util/internal/testdata/field_mask.pb.h>
#include <google/protobuf/util/internal/type_info_test_helper.h>
#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/message_differencer.h>
#include <google/protobuf/stubs/bytestream.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/util/internal/testdata/anys.pb.h>
@@ -139,7 +140,9 @@ class BaseProtoStreamObjectWriterTest
google::protobuf::scoped_ptr<Message> 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); }
@@ -156,7 +159,12 @@ class BaseProtoStreamObjectWriterTest
MATCHER_P(HasObjectLocation, expected,
"Verifies the expected object location") {
- string actual = std::tr1::get<0>(arg).ToString();
+ string actual;
+#if __cplusplus >= 201103L
+ actual = std::get<0>(arg).ToString();
+#else
+ actual = std::tr1::get<0>(arg).ToString();
+#endif
if (actual.compare(expected) == 0) return true;
*result_listener << "actual location is: " << actual;
return false;
@@ -233,6 +241,21 @@ TEST_P(ProtoStreamObjectWriterTest, SimpleMessage) {
CheckOutput(book);
}
+TEST_P(ProtoStreamObjectWriterTest, CustomJsonName) {
+ Book book;
+ Author* robert = book.mutable_author();
+ robert->set_id(12345);
+ robert->set_name("robert");
+
+ ow_->StartObject("")
+ ->StartObject("author")
+ ->RenderUint64("@id", 12345)
+ ->RenderString("name", "robert")
+ ->EndObject()
+ ->EndObject();
+ CheckOutput(book);
+}
+
TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) {
Primitive full;
full.set_fix32(101);
@@ -788,10 +811,6 @@ TEST_P(ProtoStreamObjectWriterTest, RootNamedList) {
InvalidName(_, StringPiece("oops"),
StringPiece("Root element should not be named.")))
.With(Args<0>(HasObjectLocation("")));
- EXPECT_CALL(listener_,
- InvalidName(_, StringPiece(""),
- StringPiece("Proto fields must have a name.")))
- .With(Args<0>(HasObjectLocation("")));
ow_->StartList("oops")->RenderString("", "item")->EndList();
CheckOutput(empty, 0);
}
@@ -851,15 +870,31 @@ class ProtoStreamObjectWriterTimestampDurationTest
}
};
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+ ProtoStreamObjectWriterTimestampDurationTest,
+ ::testing::Values(
+ testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) {
+ TimestampDuration timestamp;
+ google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+ ts->set_seconds(1448249855);
+ ts->set_nanos(33155000);
+
+ ow_->StartObject("")
+ ->RenderString("ts", "2015-11-23T03:37:35.033155Z")
+ ->EndObject();
+ CheckOutput(timestamp);
+}
+
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 +905,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 +918,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 +936,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")
@@ -910,9 +945,66 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) {
CheckOutput(timestamp);
}
-// TODO(skarvaje): Write a test for nanos that exceed limit. Currently, it is
-// not possible to construct a test case where nanos exceed limit because of
-// floating point arithmetic.
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError5) {
+ TimestampDuration timestamp;
+
+ EXPECT_CALL(
+ listener_,
+ InvalidValue(_,
+ StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+ StringPiece("Field 'ts', Invalid time format: "
+ "2015-11-23T03:37:35.033155 Z")));
+
+ ow_->StartObject("")
+ // Whitespace in the Timestamp nanos is not allowed.
+ ->RenderString("ts", "2015-11-23T03:37:35.033155 Z")
+ ->EndObject();
+ CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError6) {
+ TimestampDuration timestamp;
+
+ EXPECT_CALL(
+ listener_,
+ InvalidValue(_,
+ StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+ StringPiece("Field 'ts', Invalid time format: "
+ "2015-11-23T03:37:35.033155 1234Z")));
+
+ ow_->StartObject("")
+ // Whitespace in the Timestamp nanos is not allowed.
+ ->RenderString("ts", "2015-11-23T03:37:35.033155 1234Z")
+ ->EndObject();
+ CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError7) {
+ TimestampDuration timestamp;
+
+ EXPECT_CALL(
+ listener_,
+ InvalidValue(_,
+ StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+ StringPiece("Field 'ts', Invalid time format: "
+ "2015-11-23T03:37:35.033abc155Z")));
+
+ ow_->StartObject("")
+ // Non-numeric characters in the Timestamp nanos is not allowed.
+ ->RenderString("ts", "2015-11-23T03:37:35.033abc155Z")
+ ->EndObject();
+ CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseDuration) {
+ TimestampDuration duration;
+ google::protobuf::Duration* dur = duration.mutable_dur();
+ dur->set_seconds(1448216930);
+ dur->set_nanos(132262000);
+
+ ow_->StartObject("")->RenderString("dur", "1448216930.132262s")->EndObject();
+ CheckOutput(duration);
+}
TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError1) {
TimestampDuration duration;
@@ -950,7 +1042,7 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError3) {
InvalidValue(
_, StringPiece("type.googleapis.com/google.protobuf.Duration"),
StringPiece("Field 'dur', Invalid duration format, failed to "
- "parse nanos seconds")));
+ "parse nano seconds")));
ow_->StartObject("")->RenderString("dur", "123.DEFs")->EndObject();
CheckOutput(duration);
@@ -969,6 +1061,19 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError4) {
CheckOutput(duration);
}
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError5) {
+ TimestampDuration duration;
+
+ EXPECT_CALL(
+ listener_,
+ InvalidValue(_,
+ StringPiece("type.googleapis.com/google.protobuf.Duration"),
+ StringPiece("Field 'dur', Duration value exceeds limits")));
+
+ ow_->StartObject("")->RenderString("dur", "0.1000000001s")->EndObject();
+ CheckOutput(duration);
+}
+
TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
MismatchedTimestampTypeInput) {
TimestampDuration timestamp;
@@ -1008,6 +1113,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,18 +1156,69 @@ TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) {
CheckOutput(struct_type);
}
+TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) {
+ EXPECT_CALL(
+ listener_,
+ InvalidName(_, StringPiece("gBike"),
+ StringPiece("Repeated map key: 'gBike' is already set.")));
+ ow_->StartObject("")
+ ->StartObject("object")
+ ->RenderString("gBike", "v1")
+ ->RenderString("gBike", "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_,
- InvalidValue(_, StringPiece("Map"),
- StringPiece("Cannot bind a list to map.")))
- .With(Args<0>(HasObjectLocation("map_input")));
+ EXPECT_CALL(
+ listener_,
+ InvalidValue(
+ _, StringPiece("Map"),
+ StringPiece("Cannot bind a list to map for field 'map_input'.")));
ow_->StartObject("")
->StartList("map_input")
->RenderString("a", "b")
@@ -1066,17 +1227,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<const Descriptor*> 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 +1300,6 @@ TEST_P(ProtoStreamObjectWriterAnyTest, RecursiveAny) {
->EndObject()
->EndObject()
->EndObject();
-
- CheckOutput(out, 115);
}
TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) {
@@ -1155,8 +1334,6 @@ TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) {
->EndObject()
->EndObject()
->EndObject();
-
- CheckOutput(out, 159);
}
TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) {
@@ -1263,6 +1440,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 +1468,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");
@@ -1486,13 +1685,17 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustBeEscapedCorrectly) {
TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyCanContainAnyChars) {
FieldMaskTest expected;
expected.mutable_single_mask()->add_paths(
- "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War孙天涌,./?><\\\\\"]");
+ // \xE5\xAD\x99 is the UTF-8 byte sequence for chinese character å­™.
+ // We cannot embed non-ASCII characters in the code directly because
+ // some windows compilers will try to interpret them using the system's
+ // current encoding and end up with invalid UTF-8 byte sequence.
+ "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"]");
expected.mutable_single_mask()->add_paths("path.to.map[\"key2\"]");
ow_->StartObject("");
ow_->RenderString(
"single_mask",
- "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War孙天涌,./?><\\\\\"],"
+ "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"],"
"path.to.map[\"key2\"]");
ow_->EndObject();
@@ -1683,6 +1886,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/snake2camel_objectwriter.h b/src/google/protobuf/util/internal/snake2camel_objectwriter.h
deleted file mode 100644
index 9b4ab8a3..00000000
--- a/src/google/protobuf/util/internal/snake2camel_objectwriter.h
+++ /dev/null
@@ -1,165 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_SNAKE2CAMEL_OBJECTWRITER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_SNAKE2CAMEL_OBJECTWRITER_H__
-
-#include <string>
-
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/stringpiece.h>
-#include <google/protobuf/util/internal/object_writer.h>
-#include <google/protobuf/util/internal/utility.h>
-
-namespace google {
-namespace protobuf {
-namespace util {
-namespace converter {
-
-// Snake2CamelObjectWriter is an ObjectWriter than translates each field name
-// from snake_case to camelCase. Typical usage is:
-// ProtoStreamObjectSource psos(...);
-// JsonObjectWriter jow(...);
-// Snake2CamelObjectWriter snake_to_camel(&jow);
-// psos.writeTo(&snake_to_camel);
-class Snake2CamelObjectWriter : public ObjectWriter {
- public:
- explicit Snake2CamelObjectWriter(ObjectWriter* ow)
- : ow_(ow), normalize_case_(true) {}
- virtual ~Snake2CamelObjectWriter() {}
-
- // ObjectWriter methods.
- virtual Snake2CamelObjectWriter* StartObject(StringPiece name) {
- ow_->StartObject(name);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* EndObject() {
- ow_->EndObject();
- return this;
- }
-
- virtual Snake2CamelObjectWriter* StartList(StringPiece name) {
- ow_->StartList(name);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* EndList() {
- ow_->EndList();
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderBool(StringPiece name, bool value) {
- ow_->RenderBool(name, value);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderInt32(StringPiece name, int32 value) {
- ow_->RenderInt32(name, value);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderUint32(StringPiece name,
- uint32 value) {
- ow_->RenderUint32(name, value);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderInt64(StringPiece name, int64 value) {
- ow_->RenderInt64(name, value);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderUint64(StringPiece name,
- uint64 value) {
- ow_->RenderUint64(name, value);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderDouble(StringPiece name,
- double value) {
- ow_->RenderDouble(name, value);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderFloat(StringPiece name, float value) {
- ow_->RenderFloat(name, value);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderString(StringPiece name,
- StringPiece value) {
- ow_->RenderString(name, value);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderBytes(StringPiece name,
- StringPiece value) {
- ow_->RenderBytes(name, value);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* RenderNull(StringPiece name) {
- ow_->RenderNull(name);
- return this;
- }
-
- virtual Snake2CamelObjectWriter* DisableCaseNormalizationForNextKey() {
- normalize_case_ = false;
- return this;
- }
-
- private:
- ObjectWriter* ow_;
- bool normalize_case_;
-
- bool ShouldNormalizeCase(StringPiece name) {
- if (normalize_case_) {
- return !IsCamel(name);
- } else {
- normalize_case_ = true;
- return false;
- }
- }
-
- bool IsCamel(StringPiece name) {
- return name.empty() || (ascii_islower(name[0]) && !name.contains("_"));
- }
-
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Snake2CamelObjectWriter);
-};
-
-} // namespace converter
-} // namespace util
-} // namespace protobuf
-
-} // namespace google
-#endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_SNAKE2CAMEL_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto
index 6e2f109b..82b81760 100644
--- a/src/google/protobuf/util/internal/testdata/books.proto
+++ b/src/google/protobuf/util/internal/testdata/books.proto
@@ -66,7 +66,7 @@ message Publisher {
// An author of a book
message Author {
- optional uint64 id = 1;
+ optional uint64 id = 1 [json_name = "@id"];
optional string name = 2;
repeated string pseudonym = 3;
optional bool alive = 4;
diff --git a/src/google/protobuf/util/internal/testdata/default_value.proto b/src/google/protobuf/util/internal/testdata/default_value.proto
index ebbdf6ab..cccc741c 100644
--- a/src/google/protobuf/util/internal/testdata/default_value.proto
+++ b/src/google/protobuf/util/internal/testdata/default_value.proto
@@ -75,9 +75,10 @@ message DefaultValueTestCases {
IntToStringMap int_to_string = 403;
MixedMap mixed1 = 404;
MixedMap2 mixed2 = 405;
- MessageMap map_of_objects = 406;
- MixedMap mixed_empty = 407;
- MessageMap message_map_empty = 408;
+ MixedMap2 empty_mixed2 = 406;
+ MessageMap map_of_objects = 407;
+ MixedMap mixed_empty = 408;
+ MessageMap message_map_empty = 409;
DoubleValueMessage double_value = 501;
DoubleValueMessage double_value_default = 502;
}
diff --git a/src/google/protobuf/util/internal/testdata/default_value_test.proto b/src/google/protobuf/util/internal/testdata/default_value_test.proto
index 21b85e6d..93288341 100644
--- a/src/google/protobuf/util/internal/testdata/default_value_test.proto
+++ b/src/google/protobuf/util/internal/testdata/default_value_test.proto
@@ -43,4 +43,11 @@ message DefaultValueTest {
bool bool_value = 13;
string string_value = 15;
bytes bytes_value = 17 [ctype = CORD];
+
+ enum EnumDefault {
+ ENUM_FIRST = 0;
+ ENUM_SECOND = 1;
+ ENUM_THIRD = 2;
+ }
+ EnumDefault enum_value = 18;
}
diff --git a/src/google/protobuf/util/internal/type_info.cc b/src/google/protobuf/util/internal/type_info.cc
index a45a76e3..00a8ee7a 100644
--- a/src/google/protobuf/util/internal/type_info.cc
+++ b/src/google/protobuf/util/internal/type_info.cc
@@ -136,8 +136,7 @@ class TypeInfoForTypeResolver : public TypeInfo {
for (int i = 0; i < type->fields_size(); ++i) {
const google::protobuf::Field& field = type->fields(i);
StringPiece name = field.name();
- StringPiece camel_case_name =
- *string_storage_.insert(ToCamelCase(name)).first;
+ StringPiece camel_case_name = field.json_name();
const StringPiece* existing = InsertOrReturnExisting(
&camel_case_name_table_, camel_case_name, name);
if (existing && *existing != name) {
diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc
index 5d7dcc87..1ddf2487 100644
--- a/src/google/protobuf/util/internal/utility.cc
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -49,7 +49,8 @@ namespace converter {
namespace {
const StringPiece SkipWhiteSpace(StringPiece str) {
StringPiece::size_type i;
- for (i = 0; i < str.size() && isspace(str[i]); ++i) {}
+ for (i = 0; i < str.size() && isspace(str[i]); ++i) {
+ }
GOOGLE_DCHECK(i == str.size() || !isspace(str[i]));
return StringPiece(str, i);
}
@@ -160,6 +161,19 @@ const google::protobuf::Field* FindFieldInTypeOrNull(
return NULL;
}
+const google::protobuf::Field* FindJsonFieldInTypeOrNull(
+ const google::protobuf::Type* type, StringPiece json_name) {
+ if (type != NULL) {
+ for (int i = 0; i < type->fields_size(); ++i) {
+ const google::protobuf::Field& field = type->fields(i);
+ if (field.json_name() == json_name) {
+ return &field;
+ }
+ }
+ }
+ return NULL;
+}
+
const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
const google::protobuf::Enum* enum_type, StringPiece enum_name) {
if (enum_type != NULL) {
@@ -298,29 +312,41 @@ 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<double>::IsPosInf(value)) return "Infinity";
- if (google::protobuf::MathLimits<double>::IsNegInf(value)) return "-Infinity";
- if (google::protobuf::MathLimits<double>::IsNaN(value)) return "NaN";
+ if (MathLimits<double>::IsPosInf(value)) return "Infinity";
+ if (MathLimits<double>::IsNegInf(value)) return "-Infinity";
+ if (MathLimits<double>::IsNaN(value)) return "NaN";
return SimpleDtoa(value);
}
string FloatAsString(float value) {
- if (google::protobuf::MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
+ if (MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
return DoubleAsString(value);
}
-bool SafeStrToFloat(StringPiece str, float *value) {
+bool SafeStrToFloat(StringPiece str, float* value) {
double double_value;
if (!safe_strtod(str, &double_value)) {
return false;
}
- *value = static_cast<float>(double_value);
- if (google::protobuf::MathLimits<float>::IsInf(*value)) {
+ if (MathLimits<double>::IsInf(double_value) ||
+ MathLimits<double>::IsNaN(double_value))
+ return false;
+
+ // Fail if the value is not representable in float.
+ if (double_value > std::numeric_limits<float>::max() ||
+ double_value < -std::numeric_limits<float>::max()) {
return false;
}
+
+ *value = static_cast<float>(double_value);
return true;
}
diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h
index 87f7602a..33df8eda 100644
--- a/src/google/protobuf/util/internal/utility.h
+++ b/src/google/protobuf/util/internal/utility.h
@@ -127,6 +127,11 @@ const google::protobuf::Option* FindOptionOrNull(
const google::protobuf::Field* FindFieldInTypeOrNull(
const google::protobuf::Type* type, StringPiece field_name);
+// Similar to FindFieldInTypeOrNull, but this looks up fields with given
+// json_name.
+const google::protobuf::Field* FindJsonFieldInTypeOrNull(
+ const google::protobuf::Type* type, StringPiece json_name);
+
// Finds and returns the EnumValue identified by enum_name in the passed tech
// Enum object. Returns NULL if none found.
const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
@@ -138,9 +143,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 +159,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..a1e24c18 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, int32> string_map = 6;
}
+message TestNestedMap {
+ map<bool, int32> bool_map = 1;
+ map<int32, int32> int32_map = 2;
+ map<int64, int32> int64_map = 3;
+ map<uint32, int32> uint32_map = 4;
+ map<uint64, int32> uint64_map = 5;
+ map<string, int32> string_map = 6;
+ map<string, TestNestedMap> map_map = 7;
+}
+
message TestWrapper {
google.protobuf.BoolValue bool_value = 1;
google.protobuf.Int32Value int32_value = 2;
@@ -155,3 +165,12 @@ message TestListValue {
google.protobuf.ListValue value = 1;
repeated google.protobuf.ListValue repeated_value = 2;
}
+
+message TestBoolValue {
+ bool bool_value = 1;
+ map<bool, int32> bool_map = 2;
+}
+
+message TestCustomJsonName {
+ int32 value = 1 [json_name = "@value"];
+}
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 <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/util/internal/default_value_objectwriter.h>
-#include <google/protobuf/util/internal/snake2camel_objectwriter.h>
#include <google/protobuf/util/internal/error_listener.h>
#include <google/protobuf/util/internal/json_objectwriter.h>
#include <google/protobuf/util/internal/json_stream_parser.h>
@@ -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/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
index f4dc3562..da68495f 100644
--- a/src/google/protobuf/util/json_util_test.cc
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -163,7 +163,7 @@ typedef pair<char*, int> Segment;
class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream {
public:
explicit SegmentedZeroCopyOutputStream(list<Segment> segments)
- : segments_(segments), last_segment_(NULL, 0), byte_count_(0) {}
+ : segments_(segments), last_segment_(static_cast<char*>(NULL), 0), byte_count_(0) {}
virtual bool Next(void** buffer, int* length) {
if (segments_.empty()) {
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index d709da57..0f879dc7 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -238,9 +238,25 @@ void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
GOOGLE_CHECK(key_comparator == NULL)
<< "Cannot treat this repeated field as both Map and Set for"
<< " comparison. Field name is: " << field->full_name();
+ GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
+ << "Cannot treat the same field as both SET and LIST. Field name is: "
+ << field->full_name();
set_fields_.insert(field);
}
+void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
+ GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
+ << field->full_name();
+ const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
+ GOOGLE_CHECK(key_comparator == NULL)
+ << "Cannot treat this repeated field as both Map and Set for"
+ << " comparison. Field name is: " << field->full_name();
+ GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
+ << "Cannot treat the same field as both SET and LIST. Field name is: "
+ << field->full_name();
+ list_fields_.insert(field);
+}
+
void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
const FieldDescriptor* key) {
GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
@@ -255,6 +271,9 @@ void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
<< "Cannot treat this repeated field as both Map and Set for "
<< "comparison.";
+ GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
+ << "Cannot treat this repeated field as both Map and List for "
+ << "comparison.";
MapKeyComparator* key_comparator =
new MultipleFieldsMapKeyComparator(this, key);
owned_key_comparators_.push_back(key_comparator);
@@ -920,7 +939,8 @@ bool MessageDifferencer::CheckPathChanged(
bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
if (!field->is_repeated()) return false;
if (field->is_map()) return true;
- if (repeated_field_comparison_ == AS_SET) return true;
+ if (repeated_field_comparison_ == AS_SET)
+ return list_fields_.find(field) == list_fields_.end();
return (set_fields_.find(field) != set_fields_.end());
}
@@ -946,6 +966,18 @@ bool MessageDifferencer::IsIgnored(
return false;
}
+bool MessageDifferencer::IsUnknownFieldIgnored(
+ const Message& message1, const Message& message2,
+ const SpecificField& field, const vector<SpecificField>& 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 +1159,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 +1183,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) {
@@ -1341,9 +1383,11 @@ bool MessageDifferencer::MatchRepeatedFieldIndices(
// doesn't neccessarily imply Compare(b, c). Therefore a naive greedy
// algorithm will fail to find a maximum matching.
// Here we use the argumenting path algorithm.
- MaximumMatcher::NodeMatchCallback* callback = NewPermanentCallback(
- this, &MessageDifferencer::IsMatch, repeated_field, key_comparator,
- &message1, &message2, parent_fields);
+ MaximumMatcher::NodeMatchCallback* callback =
+ google::protobuf::internal::NewPermanentCallback(
+ this, &MessageDifferencer::IsMatch,
+ repeated_field, key_comparator,
+ &message1, &message2, parent_fields);
MaximumMatcher matcher(count1, count2, callback, match_list1,
match_list2);
// If diff info is not needed, we should end the matching process as
@@ -1625,6 +1669,18 @@ void MessageDifferencer::StreamReporter::ReportIgnored(
printer_->Print("\n"); // Print for newlines.
}
+void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored(
+ const Message& message1, const Message& message2,
+ const vector<SpecificField>& 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..3ea74e67 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<SpecificField>& 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<SpecificField>& field_path) {}
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reporter);
};
@@ -317,6 +324,16 @@ class LIBPROTOBUF_EXPORT MessageDifferencer {
const Message& message2,
const FieldDescriptor* field,
const vector<SpecificField>& 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<SpecificField>& parent_fields) {
+ return false;
+ }
};
// To add a Reporter, construct default here, then use ReportDifferencesTo or
@@ -380,9 +397,16 @@ class LIBPROTOBUF_EXPORT MessageDifferencer {
// + n^3) in which n^3 is the time complexity of the maximum matching
// algorithm.
//
- // REQUIRES: field->is_repeated()
+ // REQUIRES: field->is_repeated() and field not registered with TreatAsList
void TreatAsSet(const FieldDescriptor* field);
+ // The elements of the given repeated field will be treated as a list for
+ // diffing purposes, so different orderings of the same elements will NOT be
+ // considered equal.
+ //
+ // REQUIRED: field->is_repeated() and field not registered with TreatAsSet
+ void TreatAsList(const FieldDescriptor* field);
+
// The elements of the given repeated field will be treated as a map for
// diffing purposes, with |key| being the map key. Thus, elements with the
// same key will be compared even if they do not appear at the same index.
@@ -583,6 +607,10 @@ class LIBPROTOBUF_EXPORT MessageDifferencer {
const Message& message2,
const vector<SpecificField>& field_path);
+ virtual void ReportUnknownFieldIgnored(
+ const Message& message1, const Message& message2,
+ const vector<SpecificField>& field_path);
+
protected:
// Prints the specified path of fields to the buffer.
virtual void PrintPath(const vector<SpecificField>& field_path,
@@ -722,6 +750,12 @@ class LIBPROTOBUF_EXPORT MessageDifferencer {
const FieldDescriptor* field,
const vector<SpecificField>& 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<SpecificField>& 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);
@@ -764,6 +798,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer {
RepeatedFieldComparison repeated_field_comparison_;
FieldSet set_fields_;
+ FieldSet list_fields_;
// Keeps track of MapKeyComparators that are created within
// MessageDifferencer. These MapKeyComparators should be deleted
// before MessageDifferencer is destroyed.
diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc
index 701b94ae..a867c881 100755
--- a/src/google/protobuf/util/message_differencer_unittest.cc
+++ b/src/google/protobuf/util/message_differencer_unittest.cc
@@ -1103,12 +1103,19 @@ TEST(MessageDifferencerTest, RepeatedFieldSetTest_Combination) {
msg1.add_rw("change"); msg2.add_rw("change");
// Compare
- util::MessageDifferencer differencer;
- differencer.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"),
- item->GetDescriptor()->FindFieldByName("a"));
- differencer.TreatAsSet(msg1.GetDescriptor()->FindFieldByName("rv"));
- differencer.TreatAsSet(item->GetDescriptor()->FindFieldByName("ra"));
- EXPECT_TRUE(differencer.Compare(msg1, msg2));
+ util::MessageDifferencer differencer1;
+ differencer1.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"),
+ item->GetDescriptor()->FindFieldByName("a"));
+ differencer1.TreatAsSet(msg1.GetDescriptor()->FindFieldByName("rv"));
+ differencer1.TreatAsSet(item->GetDescriptor()->FindFieldByName("ra"));
+ EXPECT_TRUE(differencer1.Compare(msg1, msg2));
+
+ util::MessageDifferencer differencer2;
+ differencer2.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"),
+ item->GetDescriptor()->FindFieldByName("a"));
+ differencer2.set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+ differencer2.TreatAsList(msg1.GetDescriptor()->FindFieldByName("rw"));
+ EXPECT_TRUE(differencer2.Compare(msg1, msg2));
}
TEST(MessageDifferencerTest, RepeatedFieldMapTest_Partial) {
@@ -1168,6 +1175,11 @@ TEST(MessageDifferencerTest, RepeatedFieldSetTest_Duplicates) {
differencer.TreatAsSet(GetFieldDescriptor(a, "rv"));
EXPECT_TRUE(differencer.Compare(b, a));
EXPECT_FALSE(differencer.Compare(c, a));
+
+ util::MessageDifferencer differencer1;
+ differencer1.set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+ EXPECT_TRUE(differencer1.Compare(b, a));
+ EXPECT_FALSE(differencer1.Compare(c, a));
}
TEST(MessageDifferencerTest, RepeatedFieldSetTest_PartialSimple) {
@@ -1442,11 +1454,10 @@ static const char* const kIgnoredFields[] = {"rm.b", "rm.m.b"};
class TestIgnorer : public util::MessageDifferencer::IgnoreCriteria {
public:
- bool IsIgnored(
+ virtual bool IsIgnored(
const Message& message1, const Message& message2,
const FieldDescriptor* field,
- const vector<util::MessageDifferencer::SpecificField>& parent_fields)
- override {
+ const vector<util::MessageDifferencer::SpecificField>& parent_fields) {
string name = "";
for (int i = 0; i < parent_fields.size(); ++i) {
name += parent_fields[i].field->name() + ".";
@@ -1488,8 +1499,10 @@ TEST(MessageDifferencerTest, TreatRepeatedFieldAsMapWithIgnoredKeyFields) {
class ValueProductMapKeyComparator
: public util::MessageDifferencer::MapKeyComparator {
public:
- virtual bool IsMatch(const Message &message1,
- const Message &message2) const {
+ typedef util::MessageDifferencer::SpecificField SpecificField;
+ virtual bool IsMatch(
+ const Message &message1, const Message &message2,
+ const vector<SpecificField>& parent_fields) const {
const Reflection* reflection1 = message1.GetReflection();
const Reflection* reflection2 = message2.GetReflection();
// FieldDescriptor for item.ra
@@ -2803,15 +2816,20 @@ class MatchingTest : public testing::Test {
const Message& msg1, const Message& msg2,
bool result) {
string output;
- io::StringOutputStream output_stream(&output);
- MessageDifferencer::StreamReporter reporter(&output_stream);
- reporter.set_report_modified_aggregates(true);
- differencer->set_report_matches(true);
- differencer->ReportDifferencesTo(&reporter);
- if (result) {
- EXPECT_TRUE(differencer->Compare(msg1, msg2));
- } else {
- EXPECT_FALSE(differencer->Compare(msg1, msg2));
+ {
+ // Before we return the "output" string, we must make sure the
+ // StreamReporter is destructored because its destructor will
+ // flush the stream.
+ io::StringOutputStream output_stream(&output);
+ MessageDifferencer::StreamReporter reporter(&output_stream);
+ reporter.set_report_modified_aggregates(true);
+ differencer->set_report_matches(true);
+ differencer->ReportDifferencesTo(&reporter);
+ if (result) {
+ EXPECT_TRUE(differencer->Compare(msg1, msg2));
+ } else {
+ EXPECT_FALSE(differencer->Compare(msg1, msg2));
+ }
}
return output;
}
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 <google/protobuf/duration.pb.h>
-#include <google/protobuf/stubs/port.h>
#include <google/protobuf/timestamp.pb.h>
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..96393903 100644
--- a/src/google/protobuf/util/type_resolver_util.cc
+++ b/src/google/protobuf/util/type_resolver_util.cc
@@ -34,6 +34,7 @@
#include <google/protobuf/wrappers.pb.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/util/type_resolver.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/status.h>
@@ -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_, "/<typename>', 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_, "/<typename>', 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,10 @@ 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(descriptor->json_name());
+ if (descriptor->has_default_value()) {
+ field->set_default_value(DefaultValueAsString(descriptor));
+ }
if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
field->set_type_url(GetTypeUrl(descriptor->message_type()));
} else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
@@ -221,8 +186,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());
@@ -239,14 +203,54 @@ class DescriptorPoolTypeResolver : public TypeResolver {
return url_prefix_ + "/" + descriptor->full_name();
}
+ string DefaultValueAsString(const FieldDescriptor* descriptor) {
+ switch (descriptor->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return SimpleItoa(descriptor->default_value_int32());
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ return SimpleItoa(descriptor->default_value_int64());
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return SimpleItoa(descriptor->default_value_uint32());
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return SimpleItoa(descriptor->default_value_uint64());
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return SimpleFtoa(descriptor->default_value_float());
+ break;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return SimpleDtoa(descriptor->default_value_double());
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return descriptor->default_value_bool() ? "true" : "false";
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+ return CEscape(descriptor->default_value_string());
+ } else {
+ return descriptor->default_value_string();
+ }
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return descriptor->default_value_enum()->name();
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ GOOGLE_LOG(DFATAL) << "Messages can't have default values!";
+ break;
+ }
+ return "";
+ }
+
string url_prefix_;
const DescriptorPool* pool_;
};
} // 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);
}
diff --git a/src/google/protobuf/util/type_resolver_util_test.cc b/src/google/protobuf/util/type_resolver_util_test.cc
index 74b2d0da..8a0bf652 100644
--- a/src/google/protobuf/util/type_resolver_util_test.cc
+++ b/src/google/protobuf/util/type_resolver_util_test.cc
@@ -43,6 +43,7 @@
#include <google/protobuf/map_unittest.pb.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/util/json_format_proto3.pb.h>
#include <google/protobuf/util/type_resolver.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
@@ -332,6 +333,19 @@ TEST_F(DescriptorPoolTypeResolverTest, TestEnum) {
EnumHasValue(type, "NEG", -1);
}
+TEST_F(DescriptorPoolTypeResolverTest, TestJsonName) {
+ Type type;
+ ASSERT_TRUE(resolver_->ResolveMessageType(
+ GetTypeUrl<protobuf_unittest::TestAllTypes>(), &type)
+ .ok());
+ EXPECT_EQ("optionalInt32", FindField(type, "optional_int32")->json_name());
+
+ ASSERT_TRUE(resolver_->ResolveMessageType(
+ GetTypeUrl<proto3::TestCustomJsonName>(), &type)
+ .ok());
+ EXPECT_EQ("@value", FindField(type, "value")->json_name());
+}
+
} // namespace
} // namespace util
} // namespace protobuf
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index 847e3500..7f1093c8 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -49,8 +49,10 @@ namespace google {
namespace protobuf {
namespace internal {
-#ifndef _MSC_VER // MSVC doesn't like definitions of inline constants, GCC
- // requires them.
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+// Old version of MSVC doesn't like definitions of inline constants, GCC
+// requires them.
const int WireFormatLite::kMessageSetItemStartTag;
const int WireFormatLite::kMessageSetItemEndTag;
const int WireFormatLite::kMessageSetTypeIdTag;
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index 991c3d04..b1c477d1 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -835,12 +835,14 @@ inline int WireFormatLite::EnumSize(int value) {
}
inline int WireFormatLite::StringSize(const string& value) {
- return io::CodedOutputStream::VarintSize32(value.size()) +
- value.size();
+ return static_cast<int>(
+ io::CodedOutputStream::VarintSize32(static_cast<uint32>(value.size())) +
+ value.size());
}
inline int WireFormatLite::BytesSize(const string& value) {
- return io::CodedOutputStream::VarintSize32(value.size()) +
- value.size();
+ return static_cast<int>(
+ io::CodedOutputStream::VarintSize32(static_cast<uint32>(value.size())) +
+ value.size());
}
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index b2a7e970..212dd219 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -2,11 +2,12 @@
// source: google/protobuf/wrappers.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/wrappers.pb.h"
+#include <google/protobuf/wrappers.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -262,10 +263,10 @@ void protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto() {
"e\030\001 \001(\004\"\033\n\nInt32Value\022\r\n\005value\030\001 \001(\005\"\034\n\013"
"UInt32Value\022\r\n\005value\030\001 \001(\r\"\032\n\tBoolValue\022"
"\r\n\005value\030\001 \001(\010\"\034\n\013StringValue\022\r\n\005value\030\001"
- " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014BP\n\023com"
- ".google.protobufB\rWrappersProtoP\001\240\001\001\242\002\003G"
- "PB\252\002\036Google.Protobuf.WellKnownTypesb\006pro"
- "to3", 403);
+ " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014BS\n\023com"
+ ".google.protobufB\rWrappersProtoP\001\240\001\001\370\001\001\242"
+ "\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006"
+ "proto3", 406);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/wrappers.proto", &protobuf_RegisterTypes);
DoubleValue::default_instance_ = new DoubleValue();
@@ -308,9 +309,9 @@ static void MergeFromFail(int line) {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int DoubleValue::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
DoubleValue::DoubleValue()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -318,6 +319,14 @@ DoubleValue::DoubleValue()
// @@protoc_insertion_point(constructor:google.protobuf.DoubleValue)
}
+DoubleValue::DoubleValue(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.DoubleValue)
+}
+
void DoubleValue::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -342,10 +351,20 @@ DoubleValue::~DoubleValue() {
}
void DoubleValue::SharedDtor() {
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
if (this != default_instance_) {
}
}
+void DoubleValue::ArenaDtor(void* object) {
+ DoubleValue* _this = reinterpret_cast< DoubleValue* >(object);
+ (void)_this;
+}
+void DoubleValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void DoubleValue::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -364,11 +383,7 @@ const DoubleValue& DoubleValue::default_instance() {
DoubleValue* DoubleValue::default_instance_ = NULL;
DoubleValue* DoubleValue::New(::google::protobuf::Arena* arena) const {
- DoubleValue* n = new DoubleValue;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<DoubleValue>(arena);
}
void DoubleValue::Clear() {
@@ -495,6 +510,18 @@ bool DoubleValue::IsInitialized() const {
void DoubleValue::Swap(DoubleValue* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ DoubleValue temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void DoubleValue::UnsafeArenaSwap(DoubleValue* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void DoubleValue::InternalSwap(DoubleValue* other) {
@@ -532,9 +559,9 @@ void DoubleValue::clear_value() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int FloatValue::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
FloatValue::FloatValue()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -542,6 +569,14 @@ FloatValue::FloatValue()
// @@protoc_insertion_point(constructor:google.protobuf.FloatValue)
}
+FloatValue::FloatValue(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.FloatValue)
+}
+
void FloatValue::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -566,10 +601,20 @@ FloatValue::~FloatValue() {
}
void FloatValue::SharedDtor() {
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
if (this != default_instance_) {
}
}
+void FloatValue::ArenaDtor(void* object) {
+ FloatValue* _this = reinterpret_cast< FloatValue* >(object);
+ (void)_this;
+}
+void FloatValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void FloatValue::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -588,11 +633,7 @@ const FloatValue& FloatValue::default_instance() {
FloatValue* FloatValue::default_instance_ = NULL;
FloatValue* FloatValue::New(::google::protobuf::Arena* arena) const {
- FloatValue* n = new FloatValue;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<FloatValue>(arena);
}
void FloatValue::Clear() {
@@ -719,6 +760,18 @@ bool FloatValue::IsInitialized() const {
void FloatValue::Swap(FloatValue* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ FloatValue temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void FloatValue::UnsafeArenaSwap(FloatValue* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void FloatValue::InternalSwap(FloatValue* other) {
@@ -756,9 +809,9 @@ void FloatValue::clear_value() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Int64Value::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Int64Value::Int64Value()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -766,6 +819,14 @@ Int64Value::Int64Value()
// @@protoc_insertion_point(constructor:google.protobuf.Int64Value)
}
+Int64Value::Int64Value(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.Int64Value)
+}
+
void Int64Value::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -790,10 +851,20 @@ Int64Value::~Int64Value() {
}
void Int64Value::SharedDtor() {
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
if (this != default_instance_) {
}
}
+void Int64Value::ArenaDtor(void* object) {
+ Int64Value* _this = reinterpret_cast< Int64Value* >(object);
+ (void)_this;
+}
+void Int64Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void Int64Value::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -812,11 +883,7 @@ const Int64Value& Int64Value::default_instance() {
Int64Value* Int64Value::default_instance_ = NULL;
Int64Value* Int64Value::New(::google::protobuf::Arena* arena) const {
- Int64Value* n = new Int64Value;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<Int64Value>(arena);
}
void Int64Value::Clear() {
@@ -945,6 +1012,18 @@ bool Int64Value::IsInitialized() const {
void Int64Value::Swap(Int64Value* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ Int64Value temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void Int64Value::UnsafeArenaSwap(Int64Value* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void Int64Value::InternalSwap(Int64Value* other) {
@@ -982,9 +1061,9 @@ void Int64Value::clear_value() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int UInt64Value::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
UInt64Value::UInt64Value()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -992,6 +1071,14 @@ UInt64Value::UInt64Value()
// @@protoc_insertion_point(constructor:google.protobuf.UInt64Value)
}
+UInt64Value::UInt64Value(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt64Value)
+}
+
void UInt64Value::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -1016,10 +1103,20 @@ UInt64Value::~UInt64Value() {
}
void UInt64Value::SharedDtor() {
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
if (this != default_instance_) {
}
}
+void UInt64Value::ArenaDtor(void* object) {
+ UInt64Value* _this = reinterpret_cast< UInt64Value* >(object);
+ (void)_this;
+}
+void UInt64Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void UInt64Value::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -1038,11 +1135,7 @@ const UInt64Value& UInt64Value::default_instance() {
UInt64Value* UInt64Value::default_instance_ = NULL;
UInt64Value* UInt64Value::New(::google::protobuf::Arena* arena) const {
- UInt64Value* n = new UInt64Value;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<UInt64Value>(arena);
}
void UInt64Value::Clear() {
@@ -1171,6 +1264,18 @@ bool UInt64Value::IsInitialized() const {
void UInt64Value::Swap(UInt64Value* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ UInt64Value temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void UInt64Value::UnsafeArenaSwap(UInt64Value* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void UInt64Value::InternalSwap(UInt64Value* other) {
@@ -1208,9 +1313,9 @@ void UInt64Value::clear_value() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Int32Value::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Int32Value::Int32Value()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1218,6 +1323,14 @@ Int32Value::Int32Value()
// @@protoc_insertion_point(constructor:google.protobuf.Int32Value)
}
+Int32Value::Int32Value(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.Int32Value)
+}
+
void Int32Value::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -1242,10 +1355,20 @@ Int32Value::~Int32Value() {
}
void Int32Value::SharedDtor() {
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
if (this != default_instance_) {
}
}
+void Int32Value::ArenaDtor(void* object) {
+ Int32Value* _this = reinterpret_cast< Int32Value* >(object);
+ (void)_this;
+}
+void Int32Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void Int32Value::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -1264,11 +1387,7 @@ const Int32Value& Int32Value::default_instance() {
Int32Value* Int32Value::default_instance_ = NULL;
Int32Value* Int32Value::New(::google::protobuf::Arena* arena) const {
- Int32Value* n = new Int32Value;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<Int32Value>(arena);
}
void Int32Value::Clear() {
@@ -1397,6 +1516,18 @@ bool Int32Value::IsInitialized() const {
void Int32Value::Swap(Int32Value* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ Int32Value temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void Int32Value::UnsafeArenaSwap(Int32Value* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void Int32Value::InternalSwap(Int32Value* other) {
@@ -1434,9 +1565,9 @@ void Int32Value::clear_value() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int UInt32Value::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
UInt32Value::UInt32Value()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1444,6 +1575,14 @@ UInt32Value::UInt32Value()
// @@protoc_insertion_point(constructor:google.protobuf.UInt32Value)
}
+UInt32Value::UInt32Value(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt32Value)
+}
+
void UInt32Value::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -1468,10 +1607,20 @@ UInt32Value::~UInt32Value() {
}
void UInt32Value::SharedDtor() {
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
if (this != default_instance_) {
}
}
+void UInt32Value::ArenaDtor(void* object) {
+ UInt32Value* _this = reinterpret_cast< UInt32Value* >(object);
+ (void)_this;
+}
+void UInt32Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void UInt32Value::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -1490,11 +1639,7 @@ const UInt32Value& UInt32Value::default_instance() {
UInt32Value* UInt32Value::default_instance_ = NULL;
UInt32Value* UInt32Value::New(::google::protobuf::Arena* arena) const {
- UInt32Value* n = new UInt32Value;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<UInt32Value>(arena);
}
void UInt32Value::Clear() {
@@ -1623,6 +1768,18 @@ bool UInt32Value::IsInitialized() const {
void UInt32Value::Swap(UInt32Value* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ UInt32Value temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void UInt32Value::UnsafeArenaSwap(UInt32Value* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void UInt32Value::InternalSwap(UInt32Value* other) {
@@ -1660,9 +1817,9 @@ void UInt32Value::clear_value() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int BoolValue::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
BoolValue::BoolValue()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1670,6 +1827,14 @@ BoolValue::BoolValue()
// @@protoc_insertion_point(constructor:google.protobuf.BoolValue)
}
+BoolValue::BoolValue(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.BoolValue)
+}
+
void BoolValue::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -1694,10 +1859,20 @@ BoolValue::~BoolValue() {
}
void BoolValue::SharedDtor() {
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
if (this != default_instance_) {
}
}
+void BoolValue::ArenaDtor(void* object) {
+ BoolValue* _this = reinterpret_cast< BoolValue* >(object);
+ (void)_this;
+}
+void BoolValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void BoolValue::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -1716,11 +1891,7 @@ const BoolValue& BoolValue::default_instance() {
BoolValue* BoolValue::default_instance_ = NULL;
BoolValue* BoolValue::New(::google::protobuf::Arena* arena) const {
- BoolValue* n = new BoolValue;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<BoolValue>(arena);
}
void BoolValue::Clear() {
@@ -1847,6 +2018,18 @@ bool BoolValue::IsInitialized() const {
void BoolValue::Swap(BoolValue* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ BoolValue temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void BoolValue::UnsafeArenaSwap(BoolValue* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void BoolValue::InternalSwap(BoolValue* other) {
@@ -1884,9 +2067,9 @@ void BoolValue::clear_value() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int StringValue::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
StringValue::StringValue()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1894,6 +2077,14 @@ StringValue::StringValue()
// @@protoc_insertion_point(constructor:google.protobuf.StringValue)
}
+StringValue::StringValue(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.StringValue)
+}
+
void StringValue::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -1919,11 +2110,21 @@ StringValue::~StringValue() {
}
void StringValue::SharedDtor() {
- value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
+ value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
if (this != default_instance_) {
}
}
+void StringValue::ArenaDtor(void* object) {
+ StringValue* _this = reinterpret_cast< StringValue* >(object);
+ (void)_this;
+}
+void StringValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void StringValue::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -1942,15 +2143,11 @@ const StringValue& StringValue::default_instance() {
StringValue* StringValue::default_instance_ = NULL;
StringValue* StringValue::New(::google::protobuf::Arena* arena) const {
- StringValue* n = new StringValue;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<StringValue>(arena);
}
void StringValue::Clear() {
- value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
bool StringValue::MergePartialFromCodedStream(
@@ -2065,8 +2262,7 @@ void StringValue::MergeFrom(const ::google::protobuf::Message& from) {
void StringValue::MergeFrom(const StringValue& from) {
if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
if (from.value().size() > 0) {
-
- value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
+ set_value(from.value());
}
}
@@ -2089,6 +2285,18 @@ bool StringValue::IsInitialized() const {
void StringValue::Swap(StringValue* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ StringValue temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void StringValue::UnsafeArenaSwap(StringValue* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void StringValue::InternalSwap(StringValue* other) {
@@ -2110,36 +2318,44 @@ void StringValue::InternalSwap(StringValue* other) {
// optional string value = 1;
void StringValue::clear_value() {
- value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
const ::std::string& StringValue::value() const {
// @@protoc_insertion_point(field_get:google.protobuf.StringValue.value)
- return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void StringValue::set_value(const ::std::string& value) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
// @@protoc_insertion_point(field_set:google.protobuf.StringValue.value)
}
void StringValue::set_value(const char* value) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+ GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_char:google.protobuf.StringValue.value)
}
- void StringValue::set_value(const char* value, size_t size) {
+ void StringValue::set_value(const char* value,
+ size_t size) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
- ::std::string(reinterpret_cast<const char*>(value), size));
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+ reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.StringValue.value)
}
::std::string* StringValue::mutable_value() {
// @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value)
- return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
::std::string* StringValue::release_value() {
- return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* StringValue::unsafe_arena_release_value() {
+ GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+ return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ GetArenaNoVirtual());
}
void StringValue::set_allocated_value(::std::string* value) {
if (value != NULL) {
@@ -2147,7 +2363,20 @@ void StringValue::clear_value() {
} else {
}
- value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+ GetArenaNoVirtual());
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
+}
+ void StringValue::unsafe_arena_set_allocated_value(
+ ::std::string* value) {
+ GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+ if (value != NULL) {
+
+ } else {
+
+ }
+ value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ value, GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
}
@@ -2155,9 +2384,9 @@ void StringValue::clear_value() {
// ===================================================================
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int BytesValue::kValueFieldNumber;
-#endif // !_MSC_VER
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
BytesValue::BytesValue()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2165,6 +2394,14 @@ BytesValue::BytesValue()
// @@protoc_insertion_point(constructor:google.protobuf.BytesValue)
}
+BytesValue::BytesValue(::google::protobuf::Arena* arena)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(arena) {
+ SharedCtor();
+ RegisterArenaDtor(arena);
+ // @@protoc_insertion_point(arena_constructor:google.protobuf.BytesValue)
+}
+
void BytesValue::InitAsDefaultInstance() {
_is_default_instance_ = true;
}
@@ -2190,11 +2427,21 @@ BytesValue::~BytesValue() {
}
void BytesValue::SharedDtor() {
- value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (GetArenaNoVirtual() != NULL) {
+ return;
+ }
+
+ value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
if (this != default_instance_) {
}
}
+void BytesValue::ArenaDtor(void* object) {
+ BytesValue* _this = reinterpret_cast< BytesValue* >(object);
+ (void)_this;
+}
+void BytesValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
void BytesValue::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
@@ -2213,15 +2460,11 @@ const BytesValue& BytesValue::default_instance() {
BytesValue* BytesValue::default_instance_ = NULL;
BytesValue* BytesValue::New(::google::protobuf::Arena* arena) const {
- BytesValue* n = new BytesValue;
- if (arena != NULL) {
- arena->Own(n);
- }
- return n;
+ return ::google::protobuf::Arena::CreateMessage<BytesValue>(arena);
}
void BytesValue::Clear() {
- value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
bool BytesValue::MergePartialFromCodedStream(
@@ -2324,8 +2567,7 @@ void BytesValue::MergeFrom(const ::google::protobuf::Message& from) {
void BytesValue::MergeFrom(const BytesValue& from) {
if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
if (from.value().size() > 0) {
-
- value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
+ set_value(from.value());
}
}
@@ -2348,6 +2590,18 @@ bool BytesValue::IsInitialized() const {
void BytesValue::Swap(BytesValue* other) {
if (other == this) return;
+ if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+ InternalSwap(other);
+ } else {
+ BytesValue temp;
+ temp.MergeFrom(*this);
+ CopyFrom(*other);
+ other->CopyFrom(temp);
+ }
+}
+void BytesValue::UnsafeArenaSwap(BytesValue* other) {
+ if (other == this) return;
+ GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void BytesValue::InternalSwap(BytesValue* other) {
@@ -2369,36 +2623,44 @@ void BytesValue::InternalSwap(BytesValue* other) {
// optional bytes value = 1;
void BytesValue::clear_value() {
- value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
const ::std::string& BytesValue::value() const {
// @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value)
- return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void BytesValue::set_value(const ::std::string& value) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
// @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value)
}
void BytesValue::set_value(const char* value) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+ GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_char:google.protobuf.BytesValue.value)
}
- void BytesValue::set_value(const void* value, size_t size) {
+ void BytesValue::set_value(const void* value,
+ size_t size) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
- ::std::string(reinterpret_cast<const char*>(value), size));
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+ reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.BytesValue.value)
}
::std::string* BytesValue::mutable_value() {
// @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value)
- return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
::std::string* BytesValue::release_value() {
- return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* BytesValue::unsafe_arena_release_value() {
+ GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+ return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ GetArenaNoVirtual());
}
void BytesValue::set_allocated_value(::std::string* value) {
if (value != NULL) {
@@ -2406,7 +2668,20 @@ void BytesValue::clear_value() {
} else {
}
- value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+ GetArenaNoVirtual());
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
+}
+ void BytesValue::unsafe_arena_set_allocated_value(
+ ::std::string* value) {
+ GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+ if (value != NULL) {
+
+ } else {
+
+ }
+ value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ value, GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
}
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 15bcc7a2..7dca938c 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -61,9 +61,14 @@ class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const DoubleValue& default_instance();
+ void UnsafeArenaSwap(DoubleValue* other);
void Swap(DoubleValue* other);
// implements Message ----------------------------------------------
@@ -90,6 +95,11 @@ class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(DoubleValue* other);
+ protected:
+ explicit DoubleValue(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -115,6 +125,9 @@ class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message {
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
double value_;
mutable int _cached_size_;
@@ -139,9 +152,14 @@ class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const FloatValue& default_instance();
+ void UnsafeArenaSwap(FloatValue* other);
void Swap(FloatValue* other);
// implements Message ----------------------------------------------
@@ -168,6 +186,11 @@ class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(FloatValue* other);
+ protected:
+ explicit FloatValue(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -193,6 +216,9 @@ class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message {
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
float value_;
mutable int _cached_size_;
@@ -217,9 +243,14 @@ class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const Int64Value& default_instance();
+ void UnsafeArenaSwap(Int64Value* other);
void Swap(Int64Value* other);
// implements Message ----------------------------------------------
@@ -246,6 +277,11 @@ class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(Int64Value* other);
+ protected:
+ explicit Int64Value(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -271,6 +307,9 @@ class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message {
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
::google::protobuf::int64 value_;
mutable int _cached_size_;
@@ -295,9 +334,14 @@ class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const UInt64Value& default_instance();
+ void UnsafeArenaSwap(UInt64Value* other);
void Swap(UInt64Value* other);
// implements Message ----------------------------------------------
@@ -324,6 +368,11 @@ class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(UInt64Value* other);
+ protected:
+ explicit UInt64Value(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -349,6 +398,9 @@ class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message {
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
::google::protobuf::uint64 value_;
mutable int _cached_size_;
@@ -373,9 +425,14 @@ class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const Int32Value& default_instance();
+ void UnsafeArenaSwap(Int32Value* other);
void Swap(Int32Value* other);
// implements Message ----------------------------------------------
@@ -402,6 +459,11 @@ class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(Int32Value* other);
+ protected:
+ explicit Int32Value(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -427,6 +489,9 @@ class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message {
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
::google::protobuf::int32 value_;
mutable int _cached_size_;
@@ -451,9 +516,14 @@ class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const UInt32Value& default_instance();
+ void UnsafeArenaSwap(UInt32Value* other);
void Swap(UInt32Value* other);
// implements Message ----------------------------------------------
@@ -480,6 +550,11 @@ class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(UInt32Value* other);
+ protected:
+ explicit UInt32Value(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -505,6 +580,9 @@ class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message {
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
::google::protobuf::uint32 value_;
mutable int _cached_size_;
@@ -529,9 +607,14 @@ class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const BoolValue& default_instance();
+ void UnsafeArenaSwap(BoolValue* other);
void Swap(BoolValue* other);
// implements Message ----------------------------------------------
@@ -558,6 +641,11 @@ class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(BoolValue* other);
+ protected:
+ explicit BoolValue(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -583,6 +671,9 @@ class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message {
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
bool value_;
mutable int _cached_size_;
@@ -607,9 +698,14 @@ class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const StringValue& default_instance();
+ void UnsafeArenaSwap(StringValue* other);
void Swap(StringValue* other);
// implements Message ----------------------------------------------
@@ -636,6 +732,11 @@ class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(StringValue* other);
+ protected:
+ explicit StringValue(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -661,11 +762,17 @@ class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message {
::std::string* mutable_value();
::std::string* release_value();
void set_allocated_value(::std::string* value);
+ ::std::string* unsafe_arena_release_value();
+ void unsafe_arena_set_allocated_value(
+ ::std::string* value);
// @@protoc_insertion_point(class_scope:google.protobuf.StringValue)
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
::google::protobuf::internal::ArenaStringPtr value_;
mutable int _cached_size_;
@@ -690,9 +797,14 @@ class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message {
return *this;
}
+ inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+ inline void* GetMaybeArenaPointer() const {
+ return MaybeArenaPtr();
+ }
static const ::google::protobuf::Descriptor* descriptor();
static const BytesValue& default_instance();
+ void UnsafeArenaSwap(BytesValue* other);
void Swap(BytesValue* other);
// implements Message ----------------------------------------------
@@ -719,6 +831,11 @@ class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message {
void SharedDtor();
void SetCachedSize(int size) const;
void InternalSwap(BytesValue* other);
+ protected:
+ explicit BytesValue(::google::protobuf::Arena* arena);
+ private:
+ static void ArenaDtor(void* object);
+ inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
@@ -744,11 +861,17 @@ class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message {
::std::string* mutable_value();
::std::string* release_value();
void set_allocated_value(::std::string* value);
+ ::std::string* unsafe_arena_release_value();
+ void unsafe_arena_set_allocated_value(
+ ::std::string* value);
// @@protoc_insertion_point(class_scope:google.protobuf.BytesValue)
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ friend class ::google::protobuf::Arena;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
bool _is_default_instance_;
::google::protobuf::internal::ArenaStringPtr value_;
mutable int _cached_size_;
@@ -895,36 +1018,44 @@ inline void BoolValue::set_value(bool value) {
// optional string value = 1;
inline void StringValue::clear_value() {
- value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
inline const ::std::string& StringValue::value() const {
// @@protoc_insertion_point(field_get:google.protobuf.StringValue.value)
- return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void StringValue::set_value(const ::std::string& value) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
// @@protoc_insertion_point(field_set:google.protobuf.StringValue.value)
}
inline void StringValue::set_value(const char* value) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+ GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_char:google.protobuf.StringValue.value)
}
-inline void StringValue::set_value(const char* value, size_t size) {
+inline void StringValue::set_value(const char* value,
+ size_t size) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
- ::std::string(reinterpret_cast<const char*>(value), size));
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+ reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.StringValue.value)
}
inline ::std::string* StringValue::mutable_value() {
// @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value)
- return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
inline ::std::string* StringValue::release_value() {
- return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* StringValue::unsafe_arena_release_value() {
+ GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+ return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ GetArenaNoVirtual());
}
inline void StringValue::set_allocated_value(::std::string* value) {
if (value != NULL) {
@@ -932,7 +1063,20 @@ inline void StringValue::set_allocated_value(::std::string* value) {
} else {
}
- value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+ GetArenaNoVirtual());
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
+}
+inline void StringValue::unsafe_arena_set_allocated_value(
+ ::std::string* value) {
+ GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+ if (value != NULL) {
+
+ } else {
+
+ }
+ value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ value, GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
}
@@ -942,36 +1086,44 @@ inline void StringValue::set_allocated_value(::std::string* value) {
// optional bytes value = 1;
inline void BytesValue::clear_value() {
- value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
inline const ::std::string& BytesValue::value() const {
// @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value)
- return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void BytesValue::set_value(const ::std::string& value) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
// @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value)
}
inline void BytesValue::set_value(const char* value) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+ GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_char:google.protobuf.BytesValue.value)
}
-inline void BytesValue::set_value(const void* value, size_t size) {
+inline void BytesValue::set_value(const void* value,
+ size_t size) {
- value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
- ::std::string(reinterpret_cast<const char*>(value), size));
+ value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+ reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.BytesValue.value)
}
inline ::std::string* BytesValue::mutable_value() {
// @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value)
- return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
}
inline ::std::string* BytesValue::release_value() {
- return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* BytesValue::unsafe_arena_release_value() {
+ GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+ return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ GetArenaNoVirtual());
}
inline void BytesValue::set_allocated_value(::std::string* value) {
if (value != NULL) {
@@ -979,7 +1131,20 @@ inline void BytesValue::set_allocated_value(::std::string* value) {
} else {
}
- value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+ GetArenaNoVirtual());
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
+}
+inline void BytesValue::unsafe_arena_set_allocated_value(
+ ::std::string* value) {
+ GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+ if (value != NULL) {
+
+ } else {
+
+ }
+ value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ value, GetArenaNoVirtual());
// @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
}
diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto
index a1d6e446..040d8a24 100644
--- a/src/google/protobuf/wrappers.proto
+++ b/src/google/protobuf/wrappers.proto
@@ -37,11 +37,12 @@ syntax = "proto3";
package google.protobuf;
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "WrappersProto";
-option java_package = "com.google.protobuf";
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option java_package = "com.google.protobuf";
+option java_outer_classname = "WrappersProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
option objc_class_prefix = "GPB";
// Wrapper message for `double`.