aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf
diff options
context:
space:
mode:
authorFeng Xiao <xfxyjwf@gmail.com>2015-12-11 17:09:20 -0800
committerFeng Xiao <xfxyjwf@gmail.com>2015-12-11 17:10:28 -0800
commite841bac4fcf47f809e089a70d5f84ac37b3883df (patch)
treed25dc5fc814db182c04c5f276ff1a609c5965a5a /src/google/protobuf
parent99a6a95c751a28a3cc33dd2384959179f83f682c (diff)
downloadprotobuf-e841bac4fcf47f809e089a70d5f84ac37b3883df.tar.gz
protobuf-e841bac4fcf47f809e089a70d5f84ac37b3883df.tar.bz2
protobuf-e841bac4fcf47f809e089a70d5f84ac37b3883df.zip
Down-integrate from internal code base.
Diffstat (limited to 'src/google/protobuf')
-rw-r--r--src/google/protobuf/any.cc13
-rw-r--r--src/google/protobuf/any.h2
-rw-r--r--src/google/protobuf/any.pb.cc1
-rw-r--r--src/google/protobuf/any.proto17
-rw-r--r--src/google/protobuf/api.pb.cc1
-rw-r--r--src/google/protobuf/api.proto5
-rw-r--r--src/google/protobuf/arena.h14
-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.cc20
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc1
-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.cc40
-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_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.cc2620
-rwxr-xr-xsrc/google/protobuf/compiler/js/js_generator.h265
-rw-r--r--src/google/protobuf/compiler/main.cc6
-rw-r--r--src/google/protobuf/compiler/mock_code_generator.cc6
-rw-r--r--src/google/protobuf/compiler/parser.cc58
-rw-r--r--src/google/protobuf/compiler/parser.h2
-rw-r--r--src/google/protobuf/compiler/parser_unittest.cc56
-rw-r--r--src/google/protobuf/compiler/plugin.pb.cc1
-rw-r--r--src/google/protobuf/compiler/subprocess.cc1
-rw-r--r--src/google/protobuf/descriptor.cc35
-rw-r--r--src/google/protobuf/descriptor.pb.cc1
-rw-r--r--src/google/protobuf/descriptor_unittest.cc193
-rw-r--r--src/google/protobuf/duration.pb.cc1
-rw-r--r--src/google/protobuf/duration.proto9
-rw-r--r--src/google/protobuf/dynamic_message.cc2
-rw-r--r--src/google/protobuf/empty.pb.cc43
-rw-r--r--src/google/protobuf/empty.pb.h13
-rw-r--r--src/google/protobuf/empty.proto8
-rw-r--r--src/google/protobuf/field_mask.pb.cc1
-rw-r--r--src/google/protobuf/field_mask.proto11
-rw-r--r--src/google/protobuf/io/coded_stream.h1
-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/map.h26
-rw-r--r--src/google/protobuf/repeated_field.h24
-rw-r--r--src/google/protobuf/source_context.pb.cc1
-rw-r--r--src/google/protobuf/source_context.proto7
-rw-r--r--src/google/protobuf/struct.pb.cc1
-rw-r--r--src/google/protobuf/struct.proto9
-rw-r--r--src/google/protobuf/stubs/strutil.cc86
-rw-r--r--src/google/protobuf/stubs/strutil.h24
-rw-r--r--src/google/protobuf/text_format.cc39
-rw-r--r--src/google/protobuf/text_format.h14
-rw-r--r--src/google/protobuf/timestamp.pb.cc43
-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.cc153
-rw-r--r--src/google/protobuf/type.pb.h55
-rw-r--r--src/google/protobuf/type.proto60
-rw-r--r--src/google/protobuf/unittest_custom_options.proto27
-rw-r--r--src/google/protobuf/util/field_comparator.h2
-rw-r--r--src/google/protobuf/util/field_comparator_test.cc7
-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.h23
-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_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.cc187
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource.h15
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource_test.cc10
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.cc1560
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.h318
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter_test.cc126
-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.cc29
-rw-r--r--src/google/protobuf/util/internal/utility.h5
-rw-r--r--src/google/protobuf/util/json_format_proto3.proto9
-rw-r--r--src/google/protobuf/util/message_differencer.cc22
-rw-r--r--src/google/protobuf/util/message_differencer.h10
-rwxr-xr-xsrc/google/protobuf/util/message_differencer_unittest.cc24
-rw-r--r--src/google/protobuf/util/type_resolver_util.cc45
-rw-r--r--src/google/protobuf/util/type_resolver_util_test.cc14
-rw-r--r--src/google/protobuf/wrappers.pb.cc429
-rw-r--r--src/google/protobuf/wrappers.pb.h205
-rw-r--r--src/google/protobuf/wrappers.proto9
101 files changed, 6756 insertions, 2209 deletions
diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc
index 7351d377..f3ca06bf 100644
--- a/src/google/protobuf/any.cc
+++ b/src/google/protobuf/any.cc
@@ -65,9 +65,16 @@ 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) {
diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h
index f760ad5d..c8dbef13 100644
--- a/src/google/protobuf/any.h
+++ b/src/google/protobuf/any.h
@@ -75,7 +75,7 @@ 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 321fd315..0bf523b3 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -7,6 +7,7 @@
#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>
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 ed90702c..e589a89d 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -7,6 +7,7 @@
#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>
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.h b/src/google/protobuf/arena.h
index 40c1e7c2..6a35183e 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -591,14 +591,12 @@ class LIBPROTOBUF_EXPORT Arena {
// 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> {
- };
-
+ 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
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 26a4f0b0..deb3d0f1 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -271,15 +271,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
@@ -288,24 +308,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_;
};
@@ -1353,7 +1371,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 <<
@@ -1443,6 +1461,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());
}
@@ -1522,6 +1541,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());
}
@@ -1654,6 +1674,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());
}
@@ -1665,6 +1686,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);
}
@@ -1699,7 +1721,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) {
@@ -1709,13 +1733,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 fa792dae..4ce81a75 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -886,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) {
@@ -919,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) {
@@ -1413,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_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 9aa41534..37e4bae4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -252,6 +252,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
"#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",
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 e8bf15d0..e3e87c58 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -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"
@@ -855,9 +853,9 @@ GenerateParsingCode(io::Printer* printer) const {
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_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..1e308464
--- /dev/null
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -0,0 +1,2620 @@
+// 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_t DecodeUTF8Codepoint(uint8_t* 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_t codepoint = 0;
+ if (is_utf8) {
+ // Decode the next UTF-8 codepoint.
+ size_t have_bytes = in.size() - i;
+ uint8_t bytes[3] = {
+ static_cast<uint8_t>(in[i]),
+ static_cast<uint8_t>(((i + 1) < in.size()) ? in[i + 1] : 0),
+ static_cast<uint8_t>(((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_t>(static_cast<uint8_t>(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";
+ }
+}
+
+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 584e5a40..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[]) {
@@ -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/parser.cc b/src/google/protobuf/compiler/parser.cc
index a389a4fc..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;
@@ -1627,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 3ba1e170..2c561c23 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -498,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 0d729e0b..1d623dd9 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -1170,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"
@@ -1839,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"
@@ -1890,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.
@@ -1905,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.",
@@ -1919,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 636673ae..a2da8eee 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -7,6 +7,7 @@
#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>
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 9a1c6fe8..1aac360b 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -2050,6 +2050,7 @@ class SourceLocationCommentPrinter {
}
private:
+
bool have_source_loc_;
SourceLocation source_loc_;
DebugStringOptions options_;
@@ -2951,7 +2952,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.
//
@@ -3996,7 +3998,7 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
if (!unused_dependency_.empty()) {
- LogUnusedDependency(result);
+ LogUnusedDependency(proto, result);
}
if (had_errors_) {
@@ -4143,6 +4145,7 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
}
}
+
void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
const Descriptor* parent,
FieldDescriptor* result,
@@ -4248,8 +4251,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:
@@ -4421,6 +4424,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
AllocateOptions(proto.options(), result);
}
+
AddSymbol(result->full_name(), parent, result->name(),
proto, Symbol(result));
}
@@ -5533,11 +5537,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;
}
@@ -6191,7 +6203,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;
@@ -6217,9 +6230,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.pb.cc b/src/google/protobuf/descriptor.pb.cc
index bc846609..eda6280f 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -7,6 +7,7 @@
#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>
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index ccd0650d..be8e0b72 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -178,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.
@@ -3120,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:
@@ -5123,7 +5196,6 @@ TEST_F(ValidationErrorTest, AllowEnumAlias) {
}
TEST_F(ValidationErrorTest, UnusedImportWarning) {
-
pool_.AddUnusedImportTrackFile("bar.proto");
BuildFile(
"name: \"bar.proto\" "
@@ -5155,7 +5227,7 @@ TEST_F(ValidationErrorTest, UnusedImportWarning) {
// }
//
pool_.AddUnusedImportTrackFile("forward.proto");
- BuildFile(
+ BuildFileWithWarnings(
"name: \"forward.proto\""
"dependency: \"base.proto\""
"dependency: \"bar.proto\""
@@ -5165,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 {
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index c7eed0d5..b325944e 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -7,6 +7,7 @@
#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>
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 091fc975..bb400476 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -69,8 +69,8 @@
#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>
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 4a4f6eae..f2eec782 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -7,6 +7,7 @@
#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();
@@ -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/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index f834363b..01a6ce56 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -7,6 +7,7 @@
#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>
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/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index cb1869a7..2da096c5 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
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/map.h b/src/google/protobuf/map.h
index 4bd76f25..dfc62420 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -188,7 +188,6 @@ 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;
@@ -497,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_),
@@ -546,9 +545,7 @@ class Map {
}
#if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \
- !defined(GOOGLE_PROTOBUF_OS_NACL) && \
- !defined(GOOGLE_PROTOBUF_OS_ANDROID) && \
- !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN)
+ !defined(GOOGLE_PROTOBUF_OS_NACL) && !defined(GOOGLE_PROTOBUF_OS_ANDROID)
template<class NodeType, class... Args>
void construct(NodeType* p, Args&&... args) {
new (static_cast<void*>(p)) NodeType(std::forward<Args>(args)...);
@@ -586,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() {}
@@ -627,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() {}
@@ -744,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 {
@@ -815,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;
@@ -854,7 +850,6 @@ 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;
@@ -879,7 +874,6 @@ 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;
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index 5530fefe..432236ce 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.
@@ -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 1be3297e..f2eb7ae7 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -7,6 +7,7 @@
#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>
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 273645d9..e020597a 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -7,6 +7,7 @@
#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>
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/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/text_format.cc b/src/google/protobuf/text_format.cc
index 38b9069b..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>
@@ -380,6 +381,7 @@ class TextFormat::Parser::ParserImpl {
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(),
@@ -389,7 +391,6 @@ class TextFormat::Parser::ParserImpl {
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;
}
@@ -1357,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);
@@ -1423,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);
}
@@ -1775,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;
}
@@ -1926,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/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index f0b09195..c1c4402c 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -7,6 +7,7 @@
#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();
@@ -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 5792dff2..7b47b3bd 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -7,6 +7,7 @@
#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();
@@ -1026,6 +1028,7 @@ const int Field::kOneofIndexFieldNumber;
const int Field::kPackedFieldNumber;
const int Field::kOptionsFieldNumber;
const int Field::kJsonNameFieldNumber;
+const int Field::kDefaultValueFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Field::Field()
@@ -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,6 +1882,49 @@ 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
// ===================================================================
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index 2533eb4e..76fe8a65 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -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/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 d3d34602..23f7d51d 100644
--- a/src/google/protobuf/util/field_comparator_test.cc
+++ b/src/google/protobuf/util/field_comparator_test.cc
@@ -35,7 +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/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 bcb526e8..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,
@@ -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..b7a537ab 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() {}
+ ~BaseDefaultValueObjectWriterTest() override {}
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()) {}
+ ~DefaultValueObjectWriterTest() override {}
+};
+
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_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 2bbb1597..034d616f 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -140,10 +140,10 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
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) {
@@ -601,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.
@@ -676,8 +650,7 @@ void ProtoStreamObjectSource::InitRendererMap() {
&ProtoStreamObjectSource::RenderString;
(*renderers_)["google.protobuf.BytesValue"] =
&ProtoStreamObjectSource::RenderBytes;
- (*renderers_)["google.protobuf.Any"] =
- &ProtoStreamObjectSource::RenderAny;
+ (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny;
(*renderers_)["google.protobuf.Struct"] =
&ProtoStreamObjectSource::RenderStruct;
(*renderers_)["google.protobuf.Value"] =
@@ -704,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.
@@ -811,40 +815,15 @@ Status ProtoStreamObjectSource::RenderField(
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:
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index 3cd37aa1..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,
@@ -210,6 +202,12 @@ 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
@@ -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 0958997c..786bf0be 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -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)
@@ -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,604 +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);
-}
-
-bool ProtoStreamObjectWriter::ProtoElement::InsertMapKeyIfNotPresent(
+bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
StringPiece map_key) {
return InsertIfNotPresent(&map_keys_, map_key.ToString());
}
-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);
-}
-
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
- // object within that type is a struct type. So start a struct.
- const google::protobuf::Field* field = StartStructValueInStruct(NULL);
- StartStruct(field);
+ // 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;
}
- 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())) {
- if (!ValidMapKey(name)) {
- ++invalid_depth_;
+ 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.
+ //
+ // 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;
}
- 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()) {
+ // 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)) {
- ++invalid_depth_;
+ IncrementInvalidDepth();
return this;
}
- field = StartMapEntry(name);
- if (field == NULL) return this;
+ // 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;
+ }
- 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;
+ // Render
+ // "values": [
+ if (IsStructListValue(*element()->parent_field())) {
+ // case iii above. Bind directly to g.p.ListValue
+ Push("values", Item::MESSAGE, true, true);
+ 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.
+ // Report an error.
+ InvalidValue("Map", StrCat("Cannot have repeated items ('", name,
+ "') within a map."));
+ 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;
+ // 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;
+ }
- field = StartListValueInStruct(field);
- if (field == NULL) 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;
+ }
+ }
- 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_;
+ // 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;
}
- // 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_.reset(element_->pop());
+ // 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 && 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);
- }
- 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;
}
@@ -1083,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;
}
@@ -1105,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;
}
@@ -1162,224 +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()) {
- if (!ValidMapKey(name)) return this;
- 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>*
@@ -1446,45 +1054,12 @@ 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::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());
- }
- return true;
-}
-
bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
- if (element_ == NULL) return true;
+ if (current_ == NULL) return true;
- if (!element_->InsertMapKeyIfNotPresent(unnormalized_name)) {
- InvalidName(
- unnormalized_name,
+ if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) {
+ listener()->InvalidName(
+ location(), unnormalized_name,
StrCat("Repeated map key: '", unnormalized_name, "' is already set."));
return false;
}
@@ -1492,134 +1067,30 @@ bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
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;
-}
-
-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());
+ // 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));
}
-// 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) {
@@ -1630,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(),
@@ -1638,12 +1109,23 @@ 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
} // namespace util
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
index 6e133679..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,73 +152,37 @@ 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 a field of an element.
- ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
- const google::protobuf::Type& type, ElementType element_type);
+ // Constructor for the root item.
+ Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
+ bool is_placeholder, bool is_list);
- virtual ~ProtoElement() {}
+ // Constructor for a field of a message.
+ Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
- // 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);
-
- // Marks the oneof 'index' as taken. Future inputs to this oneof will
- // generate an error.
- void TakeOneofIndex(int32 index);
-
// Inserts map key into hash set if and only if the key did NOT already
// exist in hash set.
// The hash set (map_keys_) is ONLY used to keep track of map keys.
@@ -266,6 +190,9 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
// already present.
bool InsertMapKeyIfNotPresent(StringPiece map_key);
+ 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
// ProtoStreamObjectWriter.
@@ -274,126 +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_;
-
- // 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_;
+ ItemType item_type_;
// Set of map keys already seen for the type_. Used to validate incoming
// messages so no map key appears more than once.
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.
@@ -417,69 +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 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 map key for type_ is not duplicated key.
// If map key is duplicated key, this function returns false.
- // Note that caller should make sure that the current proto element (element_)
+ // 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();
+
+ 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 cb9f97f7..c7667c21 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -241,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);
@@ -796,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);
}
@@ -864,6 +875,18 @@ INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
::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;
@@ -922,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;
@@ -962,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);
@@ -981,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;
@@ -1066,12 +1159,12 @@ TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) {
TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) {
EXPECT_CALL(
listener_,
- InvalidName(_, StringPiece("k1"),
- StringPiece("Repeated map key: 'k1' is already set.")));
+ InvalidName(_, StringPiece("gBike"),
+ StringPiece("Repeated map key: 'gBike' is already set.")));
ow_->StartObject("")
->StartObject("object")
- ->RenderString("k1", "v1")
- ->RenderString("k1", "v2")
+ ->RenderString("gBike", "v1")
+ ->RenderString("gBike", "v2")
->EndObject()
->EndObject();
}
@@ -1121,10 +1214,11 @@ INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
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")
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 61899c24..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) {
@@ -316,16 +330,23 @@ string FloatAsString(float 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 (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 5ba97bd2..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(
diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto
index e8137677..a1e24c18 100644
--- a/src/google/protobuf/util/json_format_proto3.proto
+++ b/src/google/protobuf/util/json_format_proto3.proto
@@ -165,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/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index 47237e5a..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());
}
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index 34c173db..3ea74e67 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -397,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.
@@ -791,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..4e9ca348 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) {
diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc
index a0996954..96393903 100644
--- a/src/google/protobuf/util/type_resolver_util.cc
+++ b/src/google/protobuf/util/type_resolver_util.cc
@@ -159,7 +159,10 @@ class DescriptorPoolTypeResolver : public TypeResolver {
}
field->set_number(descriptor->number());
field->set_name(descriptor->name());
- field->set_json_name(converter::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) {
@@ -200,6 +203,46 @@ 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_;
};
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/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index e153687b..212dd219 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -7,6 +7,7 @@
#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();
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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)
}
@@ -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`.