aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/google/protobuf/api.pb.cc2
-rw-r--r--src/google/protobuf/compiler/command_line_interface_unittest.cc5
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc4
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc2
-rw-r--r--src/google/protobuf/compiler/main.cc10
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_extension.cc2
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_field.cc2
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_file.cc451
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_file.h15
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_generator.cc51
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_generator.h11
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers.cc363
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers.h61
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_map_field.cc2
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_message.cc16
-rw-r--r--src/google/protobuf/compiler/parser.cc2
-rw-r--r--src/google/protobuf/compiler/php/php_generator.cc781
-rw-r--r--src/google/protobuf/compiler/php/php_generator.h57
-rw-r--r--src/google/protobuf/compiler/subprocess.cc12
-rw-r--r--src/google/protobuf/descriptor.pb.cc18
-rw-r--r--src/google/protobuf/duration.pb.cc2
-rw-r--r--src/google/protobuf/stubs/atomicops_internals_generic_gcc.h18
-rw-r--r--src/google/protobuf/stubs/callback.h4
-rw-r--r--src/google/protobuf/stubs/common_unittest.cc2
-rw-r--r--src/google/protobuf/stubs/map_util.h7
-rw-r--r--src/google/protobuf/stubs/once_unittest.cc5
-rw-r--r--src/google/protobuf/stubs/substitute.cc4
-rw-r--r--src/google/protobuf/testing/file.cc17
-rw-r--r--src/google/protobuf/timestamp.pb.cc2
-rw-r--r--src/google/protobuf/type.pb.cc2
-rw-r--r--src/google/protobuf/util/internal/default_value_objectwriter.cc6
-rw-r--r--src/google/protobuf/util/internal/json_stream_parser.cc2
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.cc2
-rw-r--r--src/google/protobuf/util/json_util_test.cc28
-rw-r--r--src/google/protobuf/util/message_differencer.cc6
36 files changed, 1563 insertions, 413 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 1964a541..c8b85447 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -162,6 +162,7 @@ nobase_include_HEADERS = \
google/protobuf/compiler/js/js_generator.h \
google/protobuf/compiler/objectivec/objectivec_generator.h \
google/protobuf/compiler/objectivec/objectivec_helpers.h \
+ google/protobuf/compiler/php/php_generator.h \
google/protobuf/compiler/python/python_generator.h \
google/protobuf/compiler/ruby/ruby_generator.h \
google/protobuf/util/type_resolver.h \
@@ -443,6 +444,7 @@ libprotoc_la_SOURCES = \
google/protobuf/compiler/objectivec/objectivec_oneof.h \
google/protobuf/compiler/objectivec/objectivec_primitive_field.cc \
google/protobuf/compiler/objectivec/objectivec_primitive_field.h \
+ google/protobuf/compiler/php/php_generator.cc \
google/protobuf/compiler/python/python_generator.cc \
google/protobuf/compiler/ruby/ruby_generator.cc \
google/protobuf/compiler/csharp/csharp_doc_comment.cc \
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index 131ca206..d7fb644c 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -1006,7 +1006,7 @@ void Method::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 0ebf9b6a..dee438c6 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -719,6 +719,11 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) {
ExpectGenerated("test_generator", "", "foo.proto", "Foo");
}
+TEST_F(CommandLineInterfaceTest, Win32ErrorMessage) {
+ EXPECT_EQ("The system cannot find the file specified.\r\n",
+ Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
+}
+
#endif // defined(_WIN32) || defined(__CYGWIN__)
TEST_F(CommandLineInterfaceTest, PathLookup) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index aa00962e..0034b121 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -2419,7 +2419,7 @@ GenerateClear(io::Printer* printer) {
" &reinterpret_cast<$classname$*>(16)->f)\n"
"#endif\n\n"
"#define ZR_(first, last) do {\\\n"
- " ::memset(&first, 0,\\\n"
+ " ::memset(&(first), 0,\\\n"
" ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n"
"} while (0)\n\n";
for (int i = 0; i < runs_of_fields_.size(); i++) {
@@ -2956,7 +2956,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// on the CodedOutputStream.
printer->Print(
" ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
- " ::google::protobuf::internal::NewPermanentCallback(\n"
+ " ::google::protobuf::NewPermanentCallback(\n"
" &MutableUnknownFieldsFor$classname$, this));\n"
" ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
" &unknown_fields_string, false);\n",
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 5d82946d..b7b6039a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -1252,7 +1252,7 @@ class GeneratedServiceTest : public testing::Test {
foo_(descriptor_->FindMethodByName("Foo")),
bar_(descriptor_->FindMethodByName("Bar")),
stub_(&mock_channel_),
- done_(::google::protobuf::internal::NewPermanentCallback(&DoNothing)) {}
+ done_(NewPermanentCallback(&DoNothing)) {}
virtual void SetUp() {
ASSERT_TRUE(foo_ != NULL);
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 2f3c5b8f..b83b8f32 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -35,8 +35,7 @@
#include <google/protobuf/compiler/python/python_generator.h>
#include <google/protobuf/compiler/java/java_generator.h>
#include <google/protobuf/compiler/javanano/javanano_generator.h>
-// TODO(teboring): Add it back when php implementation is ready
-// #include <google/protobuf/compiler/php/php_generator.h>
+#include <google/protobuf/compiler/php/php_generator.h>
#include <google/protobuf/compiler/ruby/ruby_generator.h>
#include <google/protobuf/compiler/csharp/csharp_generator.h>
#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
@@ -68,11 +67,10 @@ int main(int argc, char* argv[]) {
cli.RegisterGenerator("--javanano_out", &javanano_generator,
"Generate Java Nano source file.");
- // TODO(teboring): Add it back when php implementation is ready
// PHP
- // google::protobuf::compiler::php::Generator php_generator;
- // cli.RegisterGenerator("--php_out", &php_generator,
- // "Generate PHP source file.");
+ google::protobuf::compiler::php::Generator php_generator;
+ cli.RegisterGenerator("--php_out", &php_generator,
+ "Generate PHP source file.");
// Ruby
google::protobuf::compiler::ruby::Generator rb_generator;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
index c0e7253a..d0de1eca 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
@@ -85,7 +85,7 @@ void ExtensionGenerator::GenerateStaticVariablesInitialization(
if (descriptor_->containing_type()->options().message_set_wire_format())
options.push_back("GPBExtensionSetWireFormat");
- vars["options"] = BuildFlagsString(options);
+ vars["options"] = BuildFlagsString(FLAGTYPE_EXTENSION, options);
ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
string singular_type;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
index d2a6e882..527b7c0c 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
@@ -93,7 +93,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
field_flags.push_back("GPBFieldHasEnumDescriptor");
}
- (*variables)["fieldflags"] = BuildFlagsString(field_flags);
+ (*variables)["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);
(*variables)["default"] = DefaultValue(descriptor);
(*variables)["default_name"] = GPBGenericValueFieldName(descriptor);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
index 438f4113..7ad127bb 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -37,6 +37,7 @@
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/strutil.h>
+#include <algorithm> // std::find()
#include <iostream>
#include <sstream>
@@ -45,218 +46,120 @@
namespace google {
namespace protobuf {
-
-// This is also found in GPBBootstrap.h, and needs to be kept in sync. It
-// is the version check done to ensure generated code works with the current
-// runtime being used.
-const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001;
-
namespace compiler {
namespace objectivec {
namespace {
-class ImportWriter {
- public:
- ImportWriter(const Options& options)
- : options_(options),
- need_to_parse_mapping_file_(true) {}
-
- void AddFile(const FileGenerator* file);
- void Print(io::Printer *printer) const;
-
- private:
- class ProtoFrameworkCollector : public LineConsumer {
- public:
- ProtoFrameworkCollector(map<string, string>* inout_proto_file_to_framework_name)
- : map_(inout_proto_file_to_framework_name) {}
-
- virtual bool ConsumeLine(const StringPiece& line, string* out_error);
-
- private:
- map<string, string>* map_;
- };
+// This is also found in GPBBootstrap.h, and needs to be kept in sync.
+const int32 GOOGLE_PROTOBUF_OBJC_VERSION = 30002;
- void ParseFrameworkMappings();
+const char* kHeaderExtension = ".pbobjc.h";
- const Options options_;
- map<string, string> proto_file_to_framework_name_;
- bool need_to_parse_mapping_file_;
-
- vector<string> protobuf_framework_imports_;
- vector<string> protobuf_non_framework_imports_;
- vector<string> other_framework_imports_;
- vector<string> other_imports_;
-};
-
-void ImportWriter::AddFile(const FileGenerator* file) {
- const FileDescriptor* file_descriptor = file->Descriptor();
- const string extension(".pbobjc.h");
-
- if (IsProtobufLibraryBundledProtoFile(file_descriptor)) {
- protobuf_framework_imports_.push_back(
- FilePathBasename(file_descriptor) + extension);
- protobuf_non_framework_imports_.push_back(file->Path() + extension);
- return;
+// Checks if a message contains any extension definitions (on the message or
+// a nested message under it).
+bool MessageContainsExtensions(const Descriptor* message) {
+ if (message->extension_count() > 0) {
+ return true;
}
-
- // Lazy parse any mappings.
- if (need_to_parse_mapping_file_) {
- ParseFrameworkMappings();
+ for (int i = 0; i < message->nested_type_count(); i++) {
+ if (MessageContainsExtensions(message->nested_type(i))) {
+ return true;
+ }
}
+ return false;
+}
- map<string, string>::iterator proto_lookup =
- proto_file_to_framework_name_.find(file_descriptor->name());
- if (proto_lookup != proto_file_to_framework_name_.end()) {
- other_framework_imports_.push_back(
- proto_lookup->second + "/" +
- FilePathBasename(file_descriptor) + extension);
- return;
+// Checks if the file contains any extensions definitions (at the root or
+// nested under a message).
+bool FileContainsExtensions(const FileDescriptor* file) {
+ if (file->extension_count() > 0) {
+ return true;
}
-
- if (!options_.generate_for_named_framework.empty()) {
- other_framework_imports_.push_back(
- options_.generate_for_named_framework + "/" +
- FilePathBasename(file_descriptor) + extension);
- return;
+ for (int i = 0; i < file->message_type_count(); i++) {
+ if (MessageContainsExtensions(file->message_type(i))) {
+ return true;
+ }
}
-
- other_imports_.push_back(file->Path() + extension);
+ return false;
}
-void ImportWriter::Print(io::Printer* printer) const {
- assert(protobuf_non_framework_imports_.size() ==
- protobuf_framework_imports_.size());
-
- bool add_blank_line = false;
-
- if (protobuf_framework_imports_.size() > 0) {
- const string framework_name(ProtobufLibraryFrameworkName);
- const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
-
- printer->Print(
- "#if $cpp_symbol$\n",
- "cpp_symbol", cpp_symbol);
- for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin();
- iter != protobuf_framework_imports_.end(); ++iter) {
- printer->Print(
- " #import <$framework_name$/$header$>\n",
- "framework_name", framework_name,
- "header", *iter);
- }
- printer->Print(
- "#else\n");
- for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin();
- iter != protobuf_non_framework_imports_.end(); ++iter) {
- printer->Print(
- " #import \"$header$\"\n",
- "header", *iter);
- }
- printer->Print(
- "#endif\n");
-
- add_blank_line = true;
+// Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all
+// deps as visited and prunes them from the needed files list.
+void PruneFileAndDepsMarkingAsVisited(
+ const FileDescriptor* file,
+ vector<const FileDescriptor*>* files,
+ set<const FileDescriptor*>* files_visited) {
+ vector<const FileDescriptor*>::iterator iter =
+ std::find(files->begin(), files->end(), file);
+ if (iter != files->end()) {
+ files->erase(iter);
}
+ files_visited->insert(file);
+ for (int i = 0; i < file->dependency_count(); i++) {
+ PruneFileAndDepsMarkingAsVisited(file->dependency(i), files, files_visited);
+ }
+}
- if (other_framework_imports_.size() > 0) {
- if (add_blank_line) {
- printer->Print("\n");
- }
-
- for (vector<string>::const_iterator iter = other_framework_imports_.begin();
- iter != other_framework_imports_.end(); ++iter) {
- printer->Print(
- " #import <$header$>\n",
- "header", *iter);
- }
-
- add_blank_line = true;
+// Helper for CollectMinimalFileDepsContainingExtensions.
+void CollectMinimalFileDepsContainingExtensionsWorker(
+ const FileDescriptor* file,
+ vector<const FileDescriptor*>* files,
+ set<const FileDescriptor*>* files_visited) {
+ if (files_visited->find(file) != files_visited->end()) {
+ return;
}
+ files_visited->insert(file);
- if (other_imports_.size() > 0) {
- if (add_blank_line) {
- printer->Print("\n");
+ if (FileContainsExtensions(file)) {
+ files->push_back(file);
+ for (int i = 0; i < file->dependency_count(); i++) {
+ const FileDescriptor* dep = file->dependency(i);
+ PruneFileAndDepsMarkingAsVisited(dep, files, files_visited);
}
-
- for (vector<string>::const_iterator iter = other_imports_.begin();
- iter != other_imports_.end(); ++iter) {
- printer->Print(
- " #import \"$header$\"\n",
- "header", *iter);
+ } else {
+ for (int i = 0; i < file->dependency_count(); i++) {
+ const FileDescriptor* dep = file->dependency(i);
+ CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
+ files_visited);
}
}
}
-void ImportWriter::ParseFrameworkMappings() {
- need_to_parse_mapping_file_ = false;
- if (options_.named_framework_to_proto_path_mappings_path.empty()) {
- return; // Nothing to do.
- }
-
- ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
- string parse_error;
- if (!ParseSimpleFile(options_.named_framework_to_proto_path_mappings_path,
- &collector, &parse_error)) {
- cerr << "error parsing " << options_.named_framework_to_proto_path_mappings_path
- << " : " << parse_error << endl;
- cerr.flush();
+// Collect the deps of the given file that contain extensions. This can be used to
+// create the chain of roots that need to be wired together.
+//
+// NOTE: If any changes are made to this and the supporting functions, you will
+// need to manually validate what the generated code is for the test files:
+// objectivec/Tests/unittest_extension_chain_*.proto
+// There are comments about what the expected code should be line and limited
+// testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports
+// specifically).
+void CollectMinimalFileDepsContainingExtensions(
+ const FileDescriptor* file,
+ vector<const FileDescriptor*>* files) {
+ set<const FileDescriptor*> files_visited;
+ for (int i = 0; i < file->dependency_count(); i++) {
+ const FileDescriptor* dep = file->dependency(i);
+ CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
+ &files_visited);
}
}
-bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
- const StringPiece& line, string* out_error) {
- int offset = line.find(':');
- if (offset == StringPiece::npos) {
- *out_error =
- string("Framework/proto file mapping line without colon sign: '") +
- line.ToString() + "'.";
- return false;
- }
- StringPiece framework_name(line, 0, offset);
- StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1);
- StringPieceTrimWhitespace(&framework_name);
-
- int start = 0;
- while (start < proto_file_list.length()) {
- offset = proto_file_list.find(',', start);
- if (offset == StringPiece::npos) {
- offset = proto_file_list.length();
- }
-
- StringPiece proto_file(proto_file_list, start, offset - start);
- StringPieceTrimWhitespace(&proto_file);
- if (proto_file.size() != 0) {
- map<string, string>::iterator existing_entry =
- map_->find(proto_file.ToString());
- if (existing_entry != map_->end()) {
- cerr << "warning: duplicate proto file reference, replacing framework entry for '"
- << proto_file.ToString() << "' with '" << framework_name.ToString()
- << "' (was '" << existing_entry->second << "')." << endl;
- cerr.flush();
- }
-
- if (proto_file.find(' ') != StringPiece::npos) {
- cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '"
- << proto_file.ToString() << "'" << endl;
- cerr.flush();
- }
-
- (*map_)[proto_file.ToString()] = framework_name.ToString();
+bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) {
+ for (int i = 0; i < file->dependency_count(); i++) {
+ if (dep == file->dependency(i)) {
+ return true;
}
-
- start = offset + 1;
}
-
- return true;
+ return false;
}
} // namespace
-
FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
: file_(file),
root_class_name_(FileClassName(file)),
- is_public_dep_(false),
options_(options) {
for (int i = 0; i < file_->enum_type_count(); i++) {
EnumGenerator *generator = new EnumGenerator(file_->enum_type(i));
@@ -275,8 +178,6 @@ FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
}
FileGenerator::~FileGenerator() {
- STLDeleteContainerPointers(dependency_generators_.begin(),
- dependency_generators_.end());
STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
STLDeleteContainerPointers(message_generators_.begin(),
message_generators_.end());
@@ -289,24 +190,28 @@ void FileGenerator::GenerateHeader(io::Printer *printer) {
// Add some verification that the generated code matches the source the
// code is being compiled with.
+ // NOTE: This captures the raw numeric values at the time the generator was
+ // compiled, since that will be the versions for the ObjC runtime at that
+ // time. The constants in the generated code will then get their values at
+ // at compile time (so checking against the headers being used to compile).
printer->Print(
- "#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n"
- "#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.\n"
+ "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n"
+ "#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n"
+ "#endif\n"
+ "#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n"
+ "#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n"
"#endif\n"
"\n",
- "protoc_gen_objc_version",
- SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION));
+ "google_protobuf_objc_version", SimpleItoa(GOOGLE_PROTOBUF_OBJC_VERSION));
// #import any headers for "public imports" in the proto file.
{
- ImportWriter import_writer(options_);
- const vector<FileGenerator *> &dependency_generators = DependencyGenerators();
- for (vector<FileGenerator *>::const_iterator iter =
- dependency_generators.begin();
- iter != dependency_generators.end(); ++iter) {
- if ((*iter)->IsPublicDependency()) {
- import_writer.AddFile(*iter);
- }
+ ImportWriter import_writer(
+ options_.generate_for_named_framework,
+ options_.named_framework_to_proto_path_mappings_path);
+ const string header_extension(kHeaderExtension);
+ for (int i = 0; i < file_->public_dependency_count(); i++) {
+ import_writer.AddFile(file_->public_dependency(i), header_extension);
}
import_writer.Print(printer);
}
@@ -406,21 +311,41 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
// #import the runtime support.
PrintFileRuntimePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h");
+ vector<const FileDescriptor*> deps_with_extensions;
+ CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions);
+
{
- ImportWriter import_writer(options_);
+ ImportWriter import_writer(
+ options_.generate_for_named_framework,
+ options_.named_framework_to_proto_path_mappings_path);
+ const string header_extension(kHeaderExtension);
// #import the header for this proto file.
- import_writer.AddFile(this);
+ import_writer.AddFile(file_, header_extension);
// #import the headers for anything that a plain dependency of this proto
// file (that means they were just an include, not a "public" include).
- const vector<FileGenerator *> &dependency_generators =
- DependencyGenerators();
- for (vector<FileGenerator *>::const_iterator iter =
- dependency_generators.begin();
- iter != dependency_generators.end(); ++iter) {
- if (!(*iter)->IsPublicDependency()) {
- import_writer.AddFile(*iter);
+ set<string> public_import_names;
+ for (int i = 0; i < file_->public_dependency_count(); i++) {
+ public_import_names.insert(file_->public_dependency(i)->name());
+ }
+ for (int i = 0; i < file_->dependency_count(); i++) {
+ const FileDescriptor *dep = file_->dependency(i);
+ bool public_import = (public_import_names.count(dep->name()) != 0);
+ if (!public_import) {
+ import_writer.AddFile(dep, header_extension);
+ }
+ }
+
+ // If any indirect dependency provided extensions, it needs to be directly
+ // imported so it can get merged into the root's extensions registry.
+ // See the Note by CollectMinimalFileDepsContainingExtensions before
+ // changing this.
+ for (vector<const FileDescriptor *>::iterator iter =
+ deps_with_extensions.begin();
+ iter != deps_with_extensions.end(); ++iter) {
+ if (!IsDirectDependency(*iter, file_)) {
+ import_writer.AddFile(*iter, header_extension);
}
}
@@ -460,46 +385,37 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
"@implementation $root_class_name$\n\n",
"root_class_name", root_class_name_);
- // Generate the extension initialization structures for the top level and
- // any nested messages.
- ostringstream extensions_stringstream;
- if (file_->extension_count() + file_->message_type_count() > 0) {
- io::OstreamOutputStream extensions_outputstream(&extensions_stringstream);
- io::Printer extensions_printer(&extensions_outputstream, '$');
- for (vector<ExtensionGenerator *>::iterator iter =
- extension_generators_.begin();
- iter != extension_generators_.end(); ++iter) {
- (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
- }
- for (vector<MessageGenerator *>::iterator iter =
- message_generators_.begin();
- iter != message_generators_.end(); ++iter) {
- (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
- }
- extensions_stringstream.flush();
- }
+ const bool file_contains_extensions = FileContainsExtensions(file_);
// If there were any extensions or this file has any dependencies, output
// a registry to override to create the file specific registry.
- const string& extensions_str = extensions_stringstream.str();
- if (extensions_str.length() > 0 || file_->dependency_count() > 0) {
+ if (file_contains_extensions || !deps_with_extensions.empty()) {
printer->Print(
"+ (GPBExtensionRegistry*)extensionRegistry {\n"
" // This is called by +initialize so there is no need to worry\n"
" // about thread safety and initialization of registry.\n"
" static GPBExtensionRegistry* registry = nil;\n"
" if (!registry) {\n"
- " GPBDebugCheckRuntimeVersion();\n"
+ " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"
" registry = [[GPBExtensionRegistry alloc] init];\n");
printer->Indent();
printer->Indent();
- if (extensions_str.length() > 0) {
+ if (file_contains_extensions) {
printer->Print(
"static GPBExtensionDescription descriptions[] = {\n");
printer->Indent();
- printer->Print(extensions_str.c_str());
+ for (vector<ExtensionGenerator *>::iterator iter =
+ extension_generators_.begin();
+ iter != extension_generators_.end(); ++iter) {
+ (*iter)->GenerateStaticVariablesInitialization(printer);
+ }
+ for (vector<MessageGenerator *>::iterator iter =
+ message_generators_.begin();
+ iter != message_generators_.end(); ++iter) {
+ (*iter)->GenerateStaticVariablesInitialization(printer);
+ }
printer->Outdent();
printer->Print(
"};\n"
@@ -512,14 +428,21 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
"}\n");
}
- const vector<FileGenerator *> &dependency_generators =
- DependencyGenerators();
- for (vector<FileGenerator *>::const_iterator iter =
- dependency_generators.begin();
- iter != dependency_generators.end(); ++iter) {
+ if (deps_with_extensions.empty()) {
+ printer->Print(
+ "// None of the imports (direct or indirect) defined extensions, so no need to add\n"
+ "// them to this registry.\n");
+ } else {
printer->Print(
- "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
- "dependency", (*iter)->RootClassName());
+ "// Merge in the imports (direct or indirect) that defined extensions.\n");
+ for (vector<const FileDescriptor *>::iterator iter =
+ deps_with_extensions.begin();
+ iter != deps_with_extensions.end(); ++iter) {
+ const string root_class_name(FileClassName((*iter)));
+ printer->Print(
+ "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
+ "dependency", root_class_name);
+ }
}
printer->Outdent();
@@ -528,27 +451,39 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
printer->Print(
" }\n"
" return registry;\n"
- "}\n"
- "\n");
+ "}\n");
+ } else {
+ if (file_->dependency_count() > 0) {
+ printer->Print(
+ "// No extensions in the file and none of the imports (direct or indirect)\n"
+ "// defined extensions, so no need to generate +extensionRegistry.\n");
+ } else {
+ printer->Print(
+ "// No extensions in the file and no imports, so no need to generate\n"
+ "// +extensionRegistry.\n");
+ }
}
- printer->Print("@end\n\n");
+ printer->Print("\n@end\n\n");
// File descriptor only needed if there are messages to use it.
if (message_generators_.size() > 0) {
- string syntax;
+ map<string, string> vars;
+ vars["root_class_name"] = root_class_name_;
+ vars["package"] = file_->package();
+ vars["objc_prefix"] = FileClassPrefix(file_);
switch (file_->syntax()) {
case FileDescriptor::SYNTAX_UNKNOWN:
- syntax = "GPBFileSyntaxUnknown";
+ vars["syntax"] = "GPBFileSyntaxUnknown";
break;
case FileDescriptor::SYNTAX_PROTO2:
- syntax = "GPBFileSyntaxProto2";
+ vars["syntax"] = "GPBFileSyntaxProto2";
break;
case FileDescriptor::SYNTAX_PROTO3:
- syntax = "GPBFileSyntaxProto3";
+ vars["syntax"] = "GPBFileSyntaxProto3";
break;
}
- printer->Print(
+ printer->Print(vars,
"#pragma mark - $root_class_name$_FileDescriptor\n"
"\n"
"static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
@@ -556,16 +491,24 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
" // about thread safety of the singleton.\n"
" static GPBFileDescriptor *descriptor = NULL;\n"
" if (!descriptor) {\n"
- " GPBDebugCheckRuntimeVersion();\n"
- " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
- " syntax:$syntax$];\n"
+ " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n");
+ if (vars["objc_prefix"].size() > 0) {
+ printer->Print(
+ vars,
+ " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+ " objcPrefix:@\"$objc_prefix$\"\n"
+ " syntax:$syntax$];\n");
+ } else {
+ printer->Print(
+ vars,
+ " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+ " syntax:$syntax$];\n");
+ }
+ printer->Print(
" }\n"
" return descriptor;\n"
"}\n"
- "\n",
- "root_class_name", root_class_name_,
- "package", file_->package(),
- "syntax", syntax);
+ "\n");
}
for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
@@ -584,24 +527,6 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
"// @@protoc_insertion_point(global_scope)\n");
}
-const vector<FileGenerator *> &FileGenerator::DependencyGenerators() {
- if (file_->dependency_count() != dependency_generators_.size()) {
- set<string> public_import_names;
- for (int i = 0; i < file_->public_dependency_count(); i++) {
- public_import_names.insert(file_->public_dependency(i)->name());
- }
- for (int i = 0; i < file_->dependency_count(); i++) {
- FileGenerator *generator =
- new FileGenerator(file_->dependency(i), options_);
- const string& name = file_->dependency(i)->name();
- bool public_import = (public_import_names.count(name) != 0);
- generator->SetIsPublicDependency(public_import);
- dependency_generators_.push_back(generator);
- }
- }
- return dependency_generators_;
-}
-
// Helper to print the import of the runtime support at the top of generated
// files. This currently only supports the runtime coming from a framework
// as defined by the official CocoaPod.
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h
index 8e4388d8..a60a6885 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h
@@ -62,32 +62,17 @@ class FileGenerator {
void GenerateHeader(io::Printer* printer);
const string& RootClassName() const { return root_class_name_; }
- const string Path() const { return FilePath(file_); }
- const FileDescriptor* Descriptor() const { return file_; }
-
- bool IsPublicDependency() const { return is_public_dep_; }
-
- protected:
- void SetIsPublicDependency(bool is_public_dep) {
- is_public_dep_ = is_public_dep;
- }
private:
const FileDescriptor* file_;
string root_class_name_;
- // Access this field through the DependencyGenerators accessor call below.
- // Do not reference it directly.
- vector<FileGenerator*> dependency_generators_;
-
vector<EnumGenerator*> enum_generators_;
vector<MessageGenerator*> message_generators_;
vector<ExtensionGenerator*> extension_generators_;
- bool is_public_dep_;
const Options options_;
- const vector<FileGenerator*>& DependencyGenerators();
void PrintFileRuntimePreamble(
io::Printer* printer, const string& header_to_import) const;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
index a0b6d6cb..36407467 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -45,10 +45,22 @@ ObjectiveCGenerator::ObjectiveCGenerator() {}
ObjectiveCGenerator::~ObjectiveCGenerator() {}
+bool ObjectiveCGenerator::HasGenerateAll() const {
+ return true;
+}
+
bool ObjectiveCGenerator::Generate(const FileDescriptor* file,
const string& parameter,
- OutputDirectory* output_directory,
+ GeneratorContext* context,
string* error) const {
+ *error = "Unimplemented Generate() method. Call GenerateAll() instead.";
+ return false;
+}
+
+bool ObjectiveCGenerator::GenerateAll(const vector<const FileDescriptor*>& files,
+ const string& parameter,
+ GeneratorContext* context,
+ string* error) const {
// -----------------------------------------------------------------
// Parse generator options. These options are passed to the compiler using the
// --objc_opt flag. The options are passed as a comma separated list of
@@ -117,29 +129,32 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file,
// -----------------------------------------------------------------
- // Validate the objc prefix/package pairing.
- if (!ValidateObjCClassPrefix(file, generation_options, error)) {
+ // Validate the objc prefix/package pairings.
+ if (!ValidateObjCClassPrefixes(files, generation_options, error)) {
// *error will have been filled in.
return false;
}
- FileGenerator file_generator(file, generation_options);
- string filepath = FilePath(file);
+ for (int i = 0; i < files.size(); i++) {
+ const FileDescriptor* file = files[i];
+ FileGenerator file_generator(file, generation_options);
+ string filepath = FilePath(file);
- // Generate header.
- {
- scoped_ptr<io::ZeroCopyOutputStream> output(
- output_directory->Open(filepath + ".pbobjc.h"));
- io::Printer printer(output.get(), '$');
- file_generator.GenerateHeader(&printer);
- }
+ // Generate header.
+ {
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->Open(filepath + ".pbobjc.h"));
+ io::Printer printer(output.get(), '$');
+ file_generator.GenerateHeader(&printer);
+ }
- // Generate m file.
- {
- scoped_ptr<io::ZeroCopyOutputStream> output(
- output_directory->Open(filepath + ".pbobjc.m"));
- io::Printer printer(output.get(), '$');
- file_generator.GenerateSource(&printer);
+ // Generate m file.
+ {
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->Open(filepath + ".pbobjc.m"));
+ io::Printer printer(output.get(), '$');
+ file_generator.GenerateSource(&printer);
+ }
}
return true;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.h b/src/google/protobuf/compiler/objectivec/objectivec_generator.h
index 9ddca574..b1723318 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_generator.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.h
@@ -51,8 +51,15 @@ class LIBPROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator {
~ObjectiveCGenerator();
// implements CodeGenerator ----------------------------------------
- bool Generate(const FileDescriptor* file, const string& parameter,
- OutputDirectory* output_directory, string* error) const;
+ bool HasGenerateAll() const;
+ bool Generate(const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* context,
+ string* error) const;
+ bool GenerateAll(const vector<const FileDescriptor*>& files,
+ const string& parameter,
+ GeneratorContext* context,
+ string* error) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectiveCGenerator);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index 4a94373a..c7fd96ac 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -44,9 +44,10 @@
#include <google/protobuf/stubs/hash.h>
#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/strutil.h>
@@ -209,10 +210,14 @@ const char* const kReservedWordList[] = {
hash_set<string> kReservedWords =
MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
-string SanitizeNameForObjC(const string& input, const string& extension) {
+string SanitizeNameForObjC(const string& input,
+ const string& extension,
+ string* out_suffix_added) {
if (kReservedWords.count(input) > 0) {
+ if (out_suffix_added) *out_suffix_added = extension;
return input + extension;
}
+ if (out_suffix_added) out_suffix_added->clear();
return input;
}
@@ -261,6 +266,34 @@ bool IsSpecialName(const string& name, const string* special_names,
return false;
}
+string GetZeroEnumNameForFlagType(const FlagType flag_type) {
+ switch(flag_type) {
+ case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
+ return "GPBDescriptorInitializationFlag_None";
+ case FLAGTYPE_EXTENSION:
+ return "GPBExtensionNone";
+ case FLAGTYPE_FIELD:
+ return "GPBFieldNone";
+ default:
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return "0";
+ }
+}
+
+string GetEnumNameForFlagType(const FlagType flag_type) {
+ switch(flag_type) {
+ case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
+ return "GPBDescriptorInitializationFlags";
+ case FLAGTYPE_EXTENSION:
+ return "GPBExtensionOptions";
+ case FLAGTYPE_FIELD:
+ return "GPBFieldFlags";
+ default:
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return string();
+ }
+}
+
} // namespace
// Escape C++ trigraphs by escaping question marks to \?
@@ -307,6 +340,12 @@ string BaseFileName(const FileDescriptor* file) {
return basename;
}
+string FileClassPrefix(const FileDescriptor* file) {
+ // Default is empty string, no need to check has_objc_class_prefix.
+ string result = file->options().objc_class_prefix();
+ return result;
+}
+
string FilePath(const FileDescriptor* file) {
string output;
string basename;
@@ -337,19 +376,13 @@ string FilePathBasename(const FileDescriptor* file) {
return output;
}
-string FileClassPrefix(const FileDescriptor* file) {
- // Default is empty string, no need to check has_objc_class_prefix.
- string result = file->options().objc_class_prefix();
- return result;
-}
-
string FileClassName(const FileDescriptor* file) {
string name = FileClassPrefix(file);
name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true);
name += "Root";
// There aren't really any reserved words that end in "Root", but playing
// it safe and checking.
- return SanitizeNameForObjC(name, "_RootClass");
+ return SanitizeNameForObjC(name, "_RootClass", NULL);
}
string ClassNameWorker(const Descriptor* descriptor) {
@@ -371,11 +404,15 @@ string ClassNameWorker(const EnumDescriptor* descriptor) {
}
string ClassName(const Descriptor* descriptor) {
+ return ClassName(descriptor, NULL);
+}
+
+string ClassName(const Descriptor* descriptor, string* out_suffix_added) {
// 1. Message names are used as is (style calls for CamelCase, trust it).
// 2. Check for reserved word at the very end and then suffix things.
string prefix = FileClassPrefix(descriptor->file());
string name = ClassNameWorker(descriptor);
- return SanitizeNameForObjC(prefix + name, "_Class");
+ return SanitizeNameForObjC(prefix + name, "_Class", out_suffix_added);
}
string EnumName(const EnumDescriptor* descriptor) {
@@ -389,7 +426,7 @@ string EnumName(const EnumDescriptor* descriptor) {
// yields Fixed_Class, Fixed_Size.
string name = FileClassPrefix(descriptor->file());
name += ClassNameWorker(descriptor);
- return SanitizeNameForObjC(name, "_Enum");
+ return SanitizeNameForObjC(name, "_Enum", NULL);
}
string EnumValueName(const EnumValueDescriptor* descriptor) {
@@ -404,7 +441,7 @@ string EnumValueName(const EnumValueDescriptor* descriptor) {
const string& name = class_name + "_" + value_str;
// There aren't really any reserved words with an underscore and a leading
// capital letter, but playing it safe and checking.
- return SanitizeNameForObjC(name, "_Value");
+ return SanitizeNameForObjC(name, "_Value", NULL);
}
string EnumValueShortName(const EnumValueDescriptor* descriptor) {
@@ -441,7 +478,7 @@ string UnCamelCaseEnumShortName(const string& name) {
string ExtensionMethodName(const FieldDescriptor* descriptor) {
const string& name = NameFromFieldDescriptor(descriptor);
const string& result = UnderscoresToCamelCase(name, false);
- return SanitizeNameForObjC(result, "_Extension");
+ return SanitizeNameForObjC(result, "_Extension", NULL);
}
string FieldName(const FieldDescriptor* field) {
@@ -456,7 +493,7 @@ string FieldName(const FieldDescriptor* field) {
result += "_p";
}
}
- return SanitizeNameForObjC(result, "_p");
+ return SanitizeNameForObjC(result, "_p", NULL);
}
string FieldNameCapitalized(const FieldDescriptor* field) {
@@ -816,17 +853,21 @@ bool HasNonZeroDefaultValue(const FieldDescriptor* field) {
return false;
}
-string BuildFlagsString(const vector<string>& strings) {
+string BuildFlagsString(const FlagType flag_type,
+ const vector<string>& strings) {
if (strings.size() == 0) {
- return "0";
+ return GetZeroEnumNameForFlagType(flag_type);
+ } else if (strings.size() == 1) {
+ return strings[0];
}
- string string;
+ string string("(" + GetEnumNameForFlagType(flag_type) + ")(");
for (size_t i = 0; i != strings.size(); ++i) {
if (i > 0) {
string.append(" | ");
}
string.append(strings[i]);
}
+ string.append(")");
return string;
}
@@ -979,28 +1020,20 @@ bool LoadExpectedPackagePrefixes(const Options &generation_options,
generation_options.expected_prefixes_path, &collector, out_error);
}
-} // namespace
-
-bool ValidateObjCClassPrefix(const FileDescriptor* file,
- const Options& generation_options,
- string* out_error) {
+bool ValidateObjCClassPrefix(
+ const FileDescriptor* file,
+ const string& expected_prefixes_path,
+ const map<string, string>& expected_package_prefixes,
+ string* out_error) {
const string prefix = file->options().objc_class_prefix();
const string package = file->package();
// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
// error cases, so it seems to be ok to use as a back door for warnings.
- // Load any expected package prefixes to validate against those.
- map<string, string> expected_package_prefixes;
- if (!LoadExpectedPackagePrefixes(generation_options,
- &expected_package_prefixes,
- out_error)) {
- return false;
- }
-
// Check: Error - See if there was an expected prefix for the package and
// report if it doesn't match (wrong or missing).
- map<string, string>::iterator package_match =
+ map<string, string>::const_iterator package_match =
expected_package_prefixes.find(package);
if (package_match != expected_package_prefixes.end()) {
// There was an entry, and...
@@ -1021,27 +1054,11 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file,
}
// If there was no prefix option, we're done at this point.
- if (prefix.length() == 0) {
+ if (prefix.empty()) {
// No prefix, nothing left to check.
return true;
}
- // Check: Error - Make sure the prefix wasn't expected for a different
- // package (overlap is allowed, but it has to be listed as an expected
- // overlap).
- for (map<string, string>::iterator i = expected_package_prefixes.begin();
- i != expected_package_prefixes.end(); ++i) {
- if (i->second == prefix) {
- *out_error =
- "error: Found 'option objc_class_prefix = \"" + prefix +
- "\";' in '" + file->name() +
- "'; that prefix is already used for 'package " + i->first +
- ";'. It can only be reused by listing it in the expected file (" +
- generation_options.expected_prefixes_path + ").";
- return false; // Only report first usage of the prefix.
- }
- }
-
// Check: Warning - Make sure the prefix is is a reasonable value according
// to Apple's rules (the checks above implicitly whitelist anything that
// doesn't meet these rules).
@@ -1063,6 +1080,56 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file,
cerr.flush();
}
+ // Look for any other package that uses the same prefix.
+ string other_package_for_prefix;
+ for (map<string, string>::const_iterator i = expected_package_prefixes.begin();
+ i != expected_package_prefixes.end(); ++i) {
+ if (i->second == prefix) {
+ other_package_for_prefix = i->first;
+ break;
+ }
+ }
+
+ // Check: Warning - If the file does not have a package, check whether
+ // the prefix declared is being used by another package or not.
+ if (package.empty()) {
+ // The file does not have a package and ...
+ if (other_package_for_prefix.empty()) {
+ // ... no other package has declared that prefix.
+ cerr << endl
+ << "protoc:0: warning: File '" << file->name() << "' has no "
+ << "package. Consider adding a new package to the proto and adding '"
+ << "new.package = " << prefix << "' to the expected prefixes file ("
+ << expected_prefixes_path << ")." << endl;
+ cerr.flush();
+ } else {
+ // ... another package has declared the same prefix.
+ cerr << endl
+ << "protoc:0: warning: File '" << file->name() << "' has no package "
+ << "and package '" << other_package_for_prefix << "' already uses '"
+ << prefix << "' as its prefix. Consider either adding a new package "
+ << "to the proto, or reusing one of the packages already using this "
+ << "prefix in the expected prefixes file ("
+ << expected_prefixes_path << ")." << endl;
+ cerr.flush();
+ }
+ return true;
+ }
+
+ // Check: Error - Make sure the prefix wasn't expected for a different
+ // package (overlap is allowed, but it has to be listed as an expected
+ // overlap).
+ if (!other_package_for_prefix.empty()) {
+ *out_error =
+ "error: Found 'option objc_class_prefix = \"" + prefix +
+ "\";' in '" + file->name() +
+ "'; that prefix is already used for 'package " +
+ other_package_for_prefix + ";'. It can only be reused by listing " +
+ "it in the expected file (" +
+ expected_prefixes_path + ").";
+ return false; // Only report first usage of the prefix.
+ }
+
// Check: Warning - If the given package/prefix pair wasn't expected, issue a
// warning issue a warning suggesting it gets added to the file.
if (!expected_package_prefixes.empty()) {
@@ -1070,13 +1137,39 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file,
<< "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
<< prefix << "\";' in '" << file->name() << "';"
<< " consider adding it to the expected prefixes file ("
- << generation_options.expected_prefixes_path << ")." << endl;
+ << expected_prefixes_path << ")." << endl;
cerr.flush();
}
return true;
}
+} // namespace
+
+bool ValidateObjCClassPrefixes(const vector<const FileDescriptor*>& files,
+ const Options& generation_options,
+ string* out_error) {
+ // Load the expected package prefixes, if available, to validate against.
+ map<string, string> expected_package_prefixes;
+ if (!LoadExpectedPackagePrefixes(generation_options,
+ &expected_package_prefixes,
+ out_error)) {
+ return false;
+ }
+
+ for (int i = 0; i < files.size(); i++) {
+ bool is_valid =
+ ValidateObjCClassPrefix(files[i],
+ generation_options.expected_prefixes_path,
+ expected_package_prefixes,
+ out_error);
+ if (!is_valid) {
+ return false;
+ }
+ }
+ return true;
+}
+
TextFormatDecodeData::TextFormatDecodeData() { }
TextFormatDecodeData::~TextFormatDecodeData() { }
@@ -1399,6 +1492,178 @@ bool ParseSimpleFile(
return parser.Finish();
}
+ImportWriter::ImportWriter(
+ const string& generate_for_named_framework,
+ const string& named_framework_to_proto_path_mappings_path)
+ : generate_for_named_framework_(generate_for_named_framework),
+ named_framework_to_proto_path_mappings_path_(
+ named_framework_to_proto_path_mappings_path),
+ need_to_parse_mapping_file_(true) {
+}
+
+ImportWriter::~ImportWriter() {}
+
+void ImportWriter::AddFile(const FileDescriptor* file,
+ const string& header_extension) {
+ const string file_path(FilePath(file));
+
+ if (IsProtobufLibraryBundledProtoFile(file)) {
+ protobuf_framework_imports_.push_back(
+ FilePathBasename(file) + header_extension);
+ protobuf_non_framework_imports_.push_back(file_path + header_extension);
+ return;
+ }
+
+ // Lazy parse any mappings.
+ if (need_to_parse_mapping_file_) {
+ ParseFrameworkMappings();
+ }
+
+ map<string, string>::iterator proto_lookup =
+ proto_file_to_framework_name_.find(file->name());
+ if (proto_lookup != proto_file_to_framework_name_.end()) {
+ other_framework_imports_.push_back(
+ proto_lookup->second + "/" +
+ FilePathBasename(file) + header_extension);
+ return;
+ }
+
+ if (!generate_for_named_framework_.empty()) {
+ other_framework_imports_.push_back(
+ generate_for_named_framework_ + "/" +
+ FilePathBasename(file) + header_extension);
+ return;
+ }
+
+ other_imports_.push_back(file_path + header_extension);
+}
+
+void ImportWriter::Print(io::Printer* printer) const {
+ assert(protobuf_non_framework_imports_.size() ==
+ protobuf_framework_imports_.size());
+
+ bool add_blank_line = false;
+
+ if (protobuf_framework_imports_.size() > 0) {
+ const string framework_name(ProtobufLibraryFrameworkName);
+ const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
+
+ printer->Print(
+ "#if $cpp_symbol$\n",
+ "cpp_symbol", cpp_symbol);
+ for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin();
+ iter != protobuf_framework_imports_.end(); ++iter) {
+ printer->Print(
+ " #import <$framework_name$/$header$>\n",
+ "framework_name", framework_name,
+ "header", *iter);
+ }
+ printer->Print(
+ "#else\n");
+ for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin();
+ iter != protobuf_non_framework_imports_.end(); ++iter) {
+ printer->Print(
+ " #import \"$header$\"\n",
+ "header", *iter);
+ }
+ printer->Print(
+ "#endif\n");
+
+ add_blank_line = true;
+ }
+
+ if (other_framework_imports_.size() > 0) {
+ if (add_blank_line) {
+ printer->Print("\n");
+ }
+
+ for (vector<string>::const_iterator iter = other_framework_imports_.begin();
+ iter != other_framework_imports_.end(); ++iter) {
+ printer->Print(
+ " #import <$header$>\n",
+ "header", *iter);
+ }
+
+ add_blank_line = true;
+ }
+
+ if (other_imports_.size() > 0) {
+ if (add_blank_line) {
+ printer->Print("\n");
+ }
+
+ for (vector<string>::const_iterator iter = other_imports_.begin();
+ iter != other_imports_.end(); ++iter) {
+ printer->Print(
+ " #import \"$header$\"\n",
+ "header", *iter);
+ }
+ }
+}
+
+void ImportWriter::ParseFrameworkMappings() {
+ need_to_parse_mapping_file_ = false;
+ if (named_framework_to_proto_path_mappings_path_.empty()) {
+ return; // Nothing to do.
+ }
+
+ ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
+ string parse_error;
+ if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_,
+ &collector, &parse_error)) {
+ cerr << "error parsing " << named_framework_to_proto_path_mappings_path_
+ << " : " << parse_error << endl;
+ cerr.flush();
+ }
+}
+
+bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
+ const StringPiece& line, string* out_error) {
+ int offset = line.find(':');
+ if (offset == StringPiece::npos) {
+ *out_error =
+ string("Framework/proto file mapping line without colon sign: '") +
+ line.ToString() + "'.";
+ return false;
+ }
+ StringPiece framework_name(line, 0, offset);
+ StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1);
+ StringPieceTrimWhitespace(&framework_name);
+
+ int start = 0;
+ while (start < proto_file_list.length()) {
+ offset = proto_file_list.find(',', start);
+ if (offset == StringPiece::npos) {
+ offset = proto_file_list.length();
+ }
+
+ StringPiece proto_file(proto_file_list, start, offset - start);
+ StringPieceTrimWhitespace(&proto_file);
+ if (proto_file.size() != 0) {
+ map<string, string>::iterator existing_entry =
+ map_->find(proto_file.ToString());
+ if (existing_entry != map_->end()) {
+ cerr << "warning: duplicate proto file reference, replacing framework entry for '"
+ << proto_file.ToString() << "' with '" << framework_name.ToString()
+ << "' (was '" << existing_entry->second << "')." << endl;
+ cerr.flush();
+ }
+
+ if (proto_file.find(' ') != StringPiece::npos) {
+ cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '"
+ << proto_file.ToString() << "'" << endl;
+ cerr.flush();
+ }
+
+ (*map_)[proto_file.ToString()] = framework_name.ToString();
+ }
+
+ start = offset + 1;
+ }
+
+ return true;
+}
+
} // namespace objectivec
} // namespace compiler
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
index c96d5ea5..316069e1 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -69,6 +69,9 @@ bool IsRetainedName(const string& name);
// handling under ARC.
bool IsInitName(const string& name);
+// Gets the objc_class_prefix.
+string FileClassPrefix(const FileDescriptor* file);
+
// Gets the path of the file we're going to generate (sans the .pb.h
// extension). The path will be dependent on the objectivec package
// declared in the proto package.
@@ -85,6 +88,7 @@ string FileClassName(const FileDescriptor* file);
// These return the fully-qualified class name corresponding to the given
// descriptor.
string ClassName(const Descriptor* descriptor);
+string ClassName(const Descriptor* descriptor, string* out_suffix_added);
string EnumName(const EnumDescriptor* descriptor);
// Returns the fully-qualified name of the enum value corresponding to the
@@ -139,6 +143,12 @@ enum ObjectiveCType {
OBJECTIVECTYPE_MESSAGE
};
+enum FlagType {
+ FLAGTYPE_DESCRIPTOR_INITIALIZATION,
+ FLAGTYPE_EXTENSION,
+ FLAGTYPE_FIELD
+};
+
template<class TDescriptor>
string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, bool preSpace = true, bool postNewline = false) {
if (descriptor->options().deprecated()) {
@@ -170,7 +180,7 @@ string GPBGenericValueFieldName(const FieldDescriptor* field);
string DefaultValue(const FieldDescriptor* field);
bool HasNonZeroDefaultValue(const FieldDescriptor* field);
-string BuildFlagsString(const vector<string>& strings);
+string BuildFlagsString(const FlagType type, const vector<string>& strings);
// Builds HeaderDoc/appledoc style comments out of the comments in the .proto
// file.
@@ -187,12 +197,12 @@ string ProtobufFrameworkImportSymbol(const string& framework_name);
// Checks if the file is one of the proto's bundled with the library.
bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file);
-// Checks the prefix for a given file and outputs any warnings needed, if
-// there are flat out errors, then out_error is filled in and the result is
-// false.
-bool ValidateObjCClassPrefix(const FileDescriptor* file,
- const Options& generation_options,
- string* out_error);
+// Checks the prefix for the given files and outputs any warnings as needed. If
+// there are flat out errors, then out_error is filled in with the first error
+// and the result is false.
+bool ValidateObjCClassPrefixes(const vector<const FileDescriptor*>& files,
+ const Options& generation_options,
+ string* out_error);
// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
// the input into the expected output.
@@ -227,6 +237,43 @@ class LIBPROTOC_EXPORT LineConsumer {
bool ParseSimpleFile(
const string& path, LineConsumer* line_consumer, string* out_error);
+
+// Helper class for parsing framework import mappings and generating
+// import statements.
+class LIBPROTOC_EXPORT ImportWriter {
+ public:
+ ImportWriter(const string& generate_for_named_framework,
+ const string& named_framework_to_proto_path_mappings_path);
+ ~ImportWriter();
+
+ void AddFile(const FileDescriptor* file, const string& header_extension);
+ void Print(io::Printer *printer) const;
+
+ private:
+ class ProtoFrameworkCollector : public LineConsumer {
+ public:
+ ProtoFrameworkCollector(map<string, string>* inout_proto_file_to_framework_name)
+ : map_(inout_proto_file_to_framework_name) {}
+
+ virtual bool ConsumeLine(const StringPiece& line, string* out_error);
+
+ private:
+ map<string, string>* map_;
+ };
+
+ void ParseFrameworkMappings();
+
+ const string generate_for_named_framework_;
+ const string named_framework_to_proto_path_mappings_path_;
+ map<string, string> proto_file_to_framework_name_;
+ bool need_to_parse_mapping_file_;
+
+ vector<string> protobuf_framework_imports_;
+ vector<string> protobuf_non_framework_imports_;
+ vector<string> other_framework_imports_;
+ vector<string> other_imports_;
+};
+
} // namespace objectivec
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
index ac5d8aea..0bc9dc10 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
@@ -115,7 +115,7 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
if (value_field_flags.find("GPBFieldHasEnumDescriptor") != string::npos) {
field_flags.push_back("GPBFieldHasEnumDescriptor");
}
- variables_["fieldflags"] = BuildFlagsString(field_flags);
+ variables_["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);
ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
const bool value_is_object_type =
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
index 822da893..4c6e1b55 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -521,7 +521,8 @@ void MessageGenerator::GenerateSource(io::Printer* printer) {
if (descriptor_->options().message_set_wire_format()) {
init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat");
}
- vars["init_flags"] = BuildFlagsString(init_flags);
+ vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION,
+ init_flags);
printer->Print(
vars,
@@ -579,6 +580,19 @@ void MessageGenerator::GenerateSource(io::Printer* printer) {
" [localDescriptor setupExtensionRanges:ranges\n"
" count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
}
+ if (descriptor_->containing_type() != NULL) {
+ string parent_class_name = ClassName(descriptor_->containing_type());
+ printer->Print(
+ " [localDescriptor setupContainingMessageClassName:GPBStringifySymbol($parent_name$)];\n",
+ "parent_name", parent_class_name);
+ }
+ string suffix_added;
+ ClassName(descriptor_, &suffix_added);
+ if (suffix_added.size() > 0) {
+ printer->Print(
+ " [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n",
+ "suffix", suffix_added);
+ }
printer->Print(
" NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
" descriptor = localDescriptor;\n"
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 214d7c9c..09c7a2b6 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -525,7 +525,6 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
SourceCodeInfo source_code_info;
source_code_info_ = &source_code_info;
- vector<string> top_doc_comments;
if (LookingAtType(io::Tokenizer::TYPE_START)) {
// Advance to first token.
input_->NextWithComments(NULL, &upcoming_detached_comments_,
@@ -571,6 +570,7 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
input_ = NULL;
source_code_info_ = NULL;
+ assert(file != NULL);
source_code_info.Swap(file->mutable_source_code_info());
return !had_errors_;
}
diff --git a/src/google/protobuf/compiler/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc
new file mode 100644
index 00000000..75ddb405
--- /dev/null
+++ b/src/google/protobuf/compiler/php/php_generator.cc
@@ -0,0 +1,781 @@
+// 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/php/php_generator.h>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <sstream>
+
+using google::protobuf::internal::scoped_ptr;
+
+const std::string kDescriptorFile = "google/protobuf/descriptor.proto";
+const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal";
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace php {
+
+// Forward decls.
+std::string PhpName(const std::string& full_name, bool is_descriptor);
+std::string DefaultForField(google::protobuf::FieldDescriptor* field);
+std::string IntToString(int32 value);
+std::string GeneratedFileName(const std::string& proto_file,
+ bool is_descriptor);
+std::string LabelForField(google::protobuf::FieldDescriptor* field);
+std::string TypeName(google::protobuf::FieldDescriptor* field);
+std::string UnderscoresToCamelCase(const string& name, bool cap_first_letter);
+std::string EscapeDollor(const string& to_escape);
+std::string BinaryToHex(const string& binary);
+void GenerateMessage(const string& name_prefix,
+ const google::protobuf::Descriptor* message,
+ bool is_descriptor,
+ google::protobuf::io::Printer* printer);
+void GenerateEnum(const google::protobuf::EnumDescriptor* en,
+ google::protobuf::io::Printer* printer);
+void Indent(google::protobuf::io::Printer* printer);
+void Outdent(google::protobuf::io::Printer* printer);
+
+std::string MessageName(const google::protobuf::Descriptor* message,
+ bool is_descriptor) {
+ string message_name = message->name();
+ const google::protobuf::Descriptor* descriptor = message->containing_type();
+ while (descriptor != NULL) {
+ message_name = descriptor->name() + '_' + message_name;
+ descriptor = descriptor->containing_type();
+ }
+ return PhpName(message->file()->package(), is_descriptor) + '\\' +
+ message_name;
+}
+
+std::string MessageFullName(const google::protobuf::Descriptor* message,
+ bool is_descriptor) {
+ if (is_descriptor) {
+ return StringReplace(message->full_name(),
+ "google.protobuf",
+ "google.protobuf.internal", false);
+ } else {
+ return message->full_name();
+ }
+}
+
+std::string EnumFullName(const google::protobuf::EnumDescriptor* envm,
+ bool is_descriptor) {
+ if (is_descriptor) {
+ return StringReplace(envm->full_name(),
+ "google.protobuf",
+ "google.protobuf.internal", false);
+ } else {
+ return envm->full_name();
+ }
+}
+
+std::string EnumClassName(const google::protobuf::EnumDescriptor* envm) {
+ string enum_class_name = envm->name();
+ const google::protobuf::Descriptor* descriptor = envm->containing_type();
+ while (descriptor != NULL) {
+ enum_class_name = descriptor->name() + '_' + enum_class_name;
+ descriptor = descriptor->containing_type();
+ }
+ return enum_class_name;
+}
+
+std::string EnumName(const google::protobuf::EnumDescriptor* envm,
+ bool is_descriptor) {
+ string enum_name = EnumClassName(envm);
+ return PhpName(envm->file()->package(), is_descriptor) + '\\' + enum_name;
+}
+
+std::string PhpName(const std::string& full_name, bool is_descriptor) {
+ if (is_descriptor) {
+ return kDescriptorPackageName;
+ }
+
+ std::string result;
+ bool cap_next_letter = true;
+ for (int i = 0; i < full_name.size(); i++) {
+ if ('a' <= full_name[i] && full_name[i] <= 'z' && cap_next_letter) {
+ result += full_name[i] + ('A' - 'a');
+ cap_next_letter = false;
+ } else if (full_name[i] == '.') {
+ result += '\\';
+ cap_next_letter = true;
+ } else {
+ result += full_name[i];
+ cap_next_letter = false;
+ }
+ }
+ return result;
+}
+
+std::string DefaultForField(const google::protobuf::FieldDescriptor* field) {
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_INT32:
+ case FieldDescriptor::TYPE_INT64:
+ case FieldDescriptor::TYPE_UINT32:
+ case FieldDescriptor::TYPE_UINT64:
+ case FieldDescriptor::TYPE_SINT32:
+ case FieldDescriptor::TYPE_SINT64:
+ case FieldDescriptor::TYPE_FIXED32:
+ case FieldDescriptor::TYPE_FIXED64:
+ case FieldDescriptor::TYPE_SFIXED32:
+ case FieldDescriptor::TYPE_SFIXED64:
+ case FieldDescriptor::TYPE_ENUM: return "0";
+ case FieldDescriptor::TYPE_DOUBLE:
+ case FieldDescriptor::TYPE_FLOAT: return "0.0";
+ case FieldDescriptor::TYPE_BOOL: return "false";
+ case FieldDescriptor::TYPE_STRING:
+ case FieldDescriptor::TYPE_BYTES: return "''";
+ case FieldDescriptor::TYPE_MESSAGE:
+ case FieldDescriptor::TYPE_GROUP: return "null";
+ default: assert(false); return "";
+ }
+}
+
+std::string GeneratedFileName(const std::string& proto_file,
+ bool is_descriptor) {
+ if (is_descriptor) {
+ return "descriptor_internal.pb.php";
+ } else {
+ int lastindex = proto_file.find_last_of(".");
+ return proto_file.substr(0, lastindex) + ".pb.php";
+ }
+}
+
+std::string IntToString(int32 value) {
+ std::ostringstream os;
+ os << value;
+ return os.str();
+}
+
+std::string LabelForField(const google::protobuf::FieldDescriptor* field) {
+ switch (field->label()) {
+ case FieldDescriptor::LABEL_OPTIONAL: return "optional";
+ case FieldDescriptor::LABEL_REQUIRED: return "required";
+ case FieldDescriptor::LABEL_REPEATED: return "repeated";
+ default: assert(false); return "";
+ }
+}
+
+std::string TypeName(const google::protobuf::FieldDescriptor* field) {
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_INT32: return "int32";
+ case FieldDescriptor::TYPE_INT64: return "int64";
+ case FieldDescriptor::TYPE_UINT32: return "uint32";
+ case FieldDescriptor::TYPE_UINT64: return "uint64";
+ case FieldDescriptor::TYPE_SINT32: return "sint32";
+ case FieldDescriptor::TYPE_SINT64: return "sint64";
+ case FieldDescriptor::TYPE_FIXED32: return "fixed32";
+ case FieldDescriptor::TYPE_FIXED64: return "fixed64";
+ case FieldDescriptor::TYPE_SFIXED32: return "sfixed32";
+ case FieldDescriptor::TYPE_SFIXED64: return "sfixed64";
+ case FieldDescriptor::TYPE_DOUBLE: return "double";
+ case FieldDescriptor::TYPE_FLOAT: return "float";
+ case FieldDescriptor::TYPE_BOOL: return "bool";
+ case FieldDescriptor::TYPE_ENUM: return "enum";
+ case FieldDescriptor::TYPE_STRING: return "string";
+ case FieldDescriptor::TYPE_BYTES: return "bytes";
+ case FieldDescriptor::TYPE_MESSAGE: return "message";
+ case FieldDescriptor::TYPE_GROUP: return "group";
+ default: assert(false); return "";
+ }
+}
+
+std::string EnumOrMessageSuffix(
+ const google::protobuf::FieldDescriptor* field, bool is_descriptor) {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ return ", '" + MessageFullName(field->message_type(), is_descriptor) + "'";
+ }
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+ return ", '" + EnumFullName(field->enum_type(), is_descriptor) + "'";
+ }
+ return "";
+}
+
+// Converts a name to camel-case. If cap_first_letter is true, capitalize the
+// first letter.
+std::string UnderscoresToCamelCase(const string& input, bool cap_first_letter) {
+ std::string result;
+ for (int i = 0; i < input.size(); i++) {
+ if ('a' <= input[i] && input[i] <= 'z') {
+ if (cap_first_letter) {
+ result += input[i] + ('A' - 'a');
+ } else {
+ result += input[i];
+ }
+ cap_first_letter = false;
+ } else if ('A' <= input[i] && input[i] <= 'Z') {
+ if (i == 0 && !cap_first_letter) {
+ // Force first letter to lower-case unless explicitly told to
+ // capitalize it.
+ result += input[i] + ('a' - 'A');
+ } else {
+ // Capital letters after the first are left as-is.
+ result += input[i];
+ }
+ cap_first_letter = false;
+ } else if ('0' <= input[i] && input[i] <= '9') {
+ result += input[i];
+ cap_first_letter = true;
+ } else {
+ cap_first_letter = true;
+ }
+ }
+ // Add a trailing "_" if the name should be altered.
+ if (input[input.size() - 1] == '#') {
+ result += '_';
+ }
+ return result;
+}
+
+std::string EscapeDollor(const string& to_escape) {
+ return StringReplace(to_escape, "$", "\\$", true);
+}
+
+std::string BinaryToHex(const string& src) {
+ string dest;
+ size_t i;
+ unsigned char symbol[16] = {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f',
+ };
+
+ dest.resize(src.size() * 2);
+ char* append_ptr = &dest[0];
+
+ for (i = 0; i < src.size(); i++) {
+ *append_ptr++ = symbol[(src[i] & 0xf0) >> 4];
+ *append_ptr++ = symbol[src[i] & 0x0f];
+ }
+
+ return dest;
+}
+
+void Indent(google::protobuf::io::Printer* printer) {
+ printer->Indent();
+ printer->Indent();
+}
+void Outdent(google::protobuf::io::Printer* printer) {
+ printer->Outdent();
+ printer->Outdent();
+}
+
+void GenerateField(const google::protobuf::FieldDescriptor* field,
+ google::protobuf::io::Printer* printer, bool is_descriptor) {
+ if (field->is_repeated()) {
+ printer->Print(
+ "private $@name@;\n",
+ "name", field->name());
+ } else if (field->containing_oneof()) {
+ // Oneof fields are handled by GenerateOneofField.
+ return;
+ } else {
+ printer->Print(
+ "private $@name@ = @default@;\n",
+ "name", field->name(),
+ "default", DefaultForField(field));
+ }
+
+ if (is_descriptor) {
+ printer->Print(
+ "private $has_@name@ = false;\n",
+ "name", field->name());
+ }
+}
+
+void GenerateOneofField(const google::protobuf::OneofDescriptor* oneof,
+ google::protobuf::io::Printer* printer) {
+ // Oneof property needs to be protected in order to be accessed by parent
+ // class in implementation.
+ printer->Print(
+ "protected $@name@;\n",
+ "name", oneof->name());
+}
+
+void GenerateFieldAccessor(const google::protobuf::FieldDescriptor* field,
+ bool is_descriptor,
+ google::protobuf::io::Printer* printer) {
+ const OneofDescriptor* oneof = field->containing_oneof();
+
+ // Generate getter.
+ if (oneof != NULL) {
+ printer->Print(
+ "public function get@camel_name@()\n"
+ "{\n"
+ " return $this->readOneof(@number@);\n"
+ "}\n\n",
+ "camel_name", UnderscoresToCamelCase(field->name(), true),
+ "number", IntToString(field->number()));
+ } else {
+ printer->Print(
+ "public function get@camel_name@()\n"
+ "{\n"
+ " return $this->@name@;\n"
+ "}\n\n",
+ "camel_name", UnderscoresToCamelCase(field->name(), true), "name",
+ field->name());
+ }
+
+ // Generate setter.
+ printer->Print(
+ "public function set@camel_name@(@var@)\n"
+ "{\n",
+ "camel_name", UnderscoresToCamelCase(field->name(), true),
+ "var", (field->is_repeated() ||
+ field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+ "&$var": "$var");
+
+ Indent(printer);
+
+ // Type check.
+ if (field->is_map()) {
+ } else if (field->is_repeated()) {
+ printer->Print(
+ "GPBUtil::checkRepeatedField($var, GPBType::@type@",
+ "type", ToUpper(field->type_name()));
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ ", \\@class_name@);\n",
+ "class_name",
+ MessageName(field->message_type(), is_descriptor) + "::class");
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+ printer->Print(
+ ", @class_name@);\n",
+ "class_name",
+ EnumName(field->enum_type(), is_descriptor) + "::class");
+ } else {
+ printer->Print(");\n");
+ }
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ "GPBUtil::checkMessage($var, \\@class_name@::class);\n",
+ "class_name", MessageName(field->message_type(), is_descriptor));
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+ printer->Print(
+ "GPBUtil::checkEnum($var, \\@class_name@::class);\n",
+ "class_name", EnumName(field->enum_type(), is_descriptor));
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+ printer->Print(
+ "GPBUtil::checkString($var, @utf8@);\n",
+ "utf8",
+ field->type() == FieldDescriptor::TYPE_STRING ? "True": "False");
+ } else {
+ printer->Print(
+ "GPBUtil::check@type@($var);\n",
+ "type", UnderscoresToCamelCase(field->cpp_type_name(), true));
+ }
+
+ if (oneof != NULL) {
+ printer->Print(
+ "$this->writeOneof(@number@, $var);\n",
+ "number", IntToString(field->number()));
+ } else {
+ printer->Print(
+ "$this->@name@ = $var;\n",
+ "name", field->name());
+ }
+
+ // Set has bit for proto2 only.
+ if (is_descriptor) {
+ printer->Print(
+ "$this->has_@field_name@ = true;\n",
+ "field_name", field->name());
+ }
+
+ Outdent(printer);
+
+ printer->Print(
+ "}\n\n");
+
+ // Generate has method for proto2 only.
+ if (is_descriptor) {
+ printer->Print(
+ "public function has@camel_name@()\n"
+ "{\n"
+ " return $this->has_@field_name@;\n"
+ "}\n\n",
+ "camel_name", UnderscoresToCamelCase(field->name(), true),
+ "field_name", field->name());
+ }
+}
+
+void GenerateRepeatedFieldDecode(
+ const google::protobuf::FieldDescriptor* field,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "if ($input->read@cap_wire_type@($var)) return False;\n"
+ "$this->get@cap_field_name@() []= $var;\n",
+ "cap_field_name", UnderscoresToCamelCase(field->name(), true),
+ "cap_wire_type", UnderscoresToCamelCase(field->type_name(), true));
+}
+
+void GeneratePrimitiveFieldDecode(
+ const google::protobuf::FieldDescriptor* field,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "if ($input->read@cap_wire_type@($var)) return False;\n"
+ "$this->set@cap_field_name@($var);\n",
+ "cap_field_name", UnderscoresToCamelCase(field->name(), true),
+ "cap_wire_type", UnderscoresToCamelCase(field->type_name(), true));
+}
+
+void GenerateFieldDecode(const google::protobuf::FieldDescriptor* field,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "case @number@:\n",
+ "number", IntToString(field->number()));
+ Indent(printer);
+
+ if (field->is_repeated()) {
+ GenerateRepeatedFieldDecode(field, printer);
+ } else {
+ GeneratePrimitiveFieldDecode(field, printer);
+ }
+
+ printer->Print(
+ "break;\n");
+ Outdent(printer);
+}
+
+void GenerateMessage(const string& name_prefix,
+ const google::protobuf::Descriptor* message,
+ bool is_descriptor,
+ google::protobuf::io::Printer* printer) {
+ // Don't generate MapEntry messages -- we use the PHP extension's native
+ // support for map fields instead.
+ if (message->options().map_entry()) {
+ return;
+ }
+
+ string message_name = name_prefix.empty()?
+ message->name() : name_prefix + "_" + message->name();
+
+ printer->Print(
+ "class @name@ extends \\Google\\Protobuf\\Internal\\Message\n"
+ "{\n",
+ "name", message_name);
+ Indent(printer);
+
+ // Field and oneof definitions.
+ for (int i = 0; i < message->field_count(); i++) {
+ const FieldDescriptor* field = message->field(i);
+ GenerateField(field, printer, is_descriptor);
+ }
+ for (int i = 0; i < message->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof = message->oneof_decl(i);
+ GenerateOneofField(oneof, printer);
+ }
+ printer->Print("\n");
+
+ // Field and oneof accessors.
+ for (int i = 0; i < message->field_count(); i++) {
+ const FieldDescriptor* field = message->field(i);
+ GenerateFieldAccessor(field, is_descriptor, printer);
+ }
+ for (int i = 0; i < message->oneof_decl_count(); i++) {
+ const google::protobuf::OneofDescriptor* oneof = message->oneof_decl(i);
+ printer->Print(
+ "public function get@camel_name@()\n"
+ "{\n"
+ " return $this->@name@;\n"
+ "}\n\n",
+ "camel_name", UnderscoresToCamelCase(oneof->name(), true), "name",
+ oneof->name());
+ }
+
+ Outdent(printer);
+ printer->Print("}\n\n");
+
+ // Nested messages and enums.
+ for (int i = 0; i < message->nested_type_count(); i++) {
+ GenerateMessage(message_name, message->nested_type(i), is_descriptor,
+ printer);
+ }
+ for (int i = 0; i < message->enum_type_count(); i++) {
+ GenerateEnum(message->enum_type(i), printer);
+ }
+}
+
+void GenerateEnumToPool(const google::protobuf::EnumDescriptor* en,
+ bool is_descriptor,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "$pool->addEnum('@name@', @class_name@::class)\n",
+ "name", EnumFullName(en, is_descriptor),
+ "class_name", en->name());
+ Indent(printer);
+
+ for (int i = 0; i < en->value_count(); i++) {
+ const EnumValueDescriptor* value = en->value(i);
+ printer->Print(
+ "->value(\"@name@\", @number@)\n",
+ "name", value->name(),
+ "number", IntToString(value->number()));
+ }
+ printer->Print("->finalizeToPool();\n\n");
+ Outdent(printer);
+}
+
+void GenerateMessageToPool(const string& name_prefix,
+ const google::protobuf::Descriptor* message,
+ bool is_descriptor,
+ google::protobuf::io::Printer* printer) {
+ // Don't generate MapEntry messages -- we use the PHP extension's native
+ // support for map fields instead.
+ if (message->options().map_entry()) {
+ return;
+ }
+ string class_name = name_prefix.empty()?
+ message->name() : name_prefix + "_" + message->name();
+
+ printer->Print(
+ "$pool->addMessage('@message@', @class_name@::class)\n",
+ "message", MessageFullName(message, is_descriptor),
+ "class_name", class_name);
+
+ Indent(printer);
+
+ for (int i = 0; i < message->field_count(); i++) {
+ const FieldDescriptor* field = message->field(i);
+ if (field->is_map()) {
+ const FieldDescriptor* key =
+ field->message_type()->FindFieldByName("key");
+ const FieldDescriptor* val =
+ field->message_type()->FindFieldByName("value");
+ printer->Print(
+ "->map('@field@', GPBType::@key@, "
+ "GPBType::@value@, @number@@other@)\n",
+ "field", field->name(),
+ "key", ToUpper(key->type_name()),
+ "value", ToUpper(val->type_name()),
+ "number", SimpleItoa(field->number()),
+ "other", EnumOrMessageSuffix(val, is_descriptor));
+ } else if (!field->containing_oneof()) {
+ printer->Print(
+ "->@label@('@field@', GPBType::@type@, @number@@other@)\n",
+ "field", field->name(),
+ "label", LabelForField(field),
+ "type", ToUpper(field->type_name()),
+ "number", SimpleItoa(field->number()),
+ "other", EnumOrMessageSuffix(field, is_descriptor));
+ }
+ }
+
+ // oneofs.
+ for (int i = 0; i < message->oneof_decl_count(); i++) {
+ const OneofDescriptor* oneof = message->oneof_decl(i);
+ printer->Print("->oneof(@name@)\n",
+ "name", oneof->name());
+ Indent(printer);
+ for (int index = 0; index < oneof->field_count(); index++) {
+ const FieldDescriptor* field = oneof->field(index);
+ printer->Print(
+ "->value('@field@', GPBType::@type@, @number@@other@)\n",
+ "field", field->name(),
+ "type", ToUpper(field->type_name()),
+ "number", SimpleItoa(field->number()),
+ "other", EnumOrMessageSuffix(field, is_descriptor));
+ }
+ printer->Print("->finish()\n");
+ Outdent(printer);
+ }
+
+ printer->Print(
+ "->finalizeToPool();\n");
+
+ Outdent(printer);
+
+ printer->Print(
+ "\n");
+
+ for (int i = 0; i < message->nested_type_count(); i++) {
+ GenerateMessageToPool(class_name, message->nested_type(i), is_descriptor,
+ printer);
+ }
+ for (int i = 0; i < message->enum_type_count(); i++) {
+ GenerateEnumToPool(message->enum_type(i), is_descriptor, printer);
+ }
+}
+
+void GenerateAddFileToPool(const google::protobuf::FileDescriptor* file,
+ bool is_descriptor,
+ google::protobuf::io::Printer* printer) {
+ if (is_descriptor) {
+ printer->Print("$pool = DescriptorPool::getGeneratedPool();\n\n");
+
+ for (int i = 0; i < file->message_type_count(); i++) {
+ GenerateMessageToPool("", file->message_type(i), is_descriptor, printer);
+ }
+ for (int i = 0; i < file->enum_type_count(); i++) {
+ GenerateEnumToPool(file->enum_type(i), is_descriptor, printer);
+ }
+
+ printer->Print(
+ "$pool->finish();\n");
+ } else {
+ // Add messages and enums to descriptor pool.
+ printer->Print("$pool = DescriptorPool::getGeneratedPool();\n\n");
+
+ FileDescriptorSet files;
+ FileDescriptorProto* file_proto = files.add_file();
+ file->CopyTo(file_proto);
+ string files_data;
+ files.SerializeToString(&files_data);
+
+ printer->Print("$pool->internalAddGeneratedFile(hex2bin(\n");
+ Indent(printer);
+
+ // Only write 30 bytes per line.
+ static const int kBytesPerLine = 30;
+ for (int i = 0; i < files_data.size(); i += kBytesPerLine) {
+ printer->Print(
+ "\"@data@\"@dot@\n",
+ "data", BinaryToHex(files_data.substr(i, kBytesPerLine)),
+ "dot", i + kBytesPerLine < files_data.size() ? " ." : "");
+ }
+
+ Outdent(printer);
+ printer->Print(
+ "));\n\n");
+ }
+
+}
+
+void GenerateEnum(const google::protobuf::EnumDescriptor* en,
+ google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "class @name@\n"
+ "{\n",
+ "name", EnumClassName(en));
+ Indent(printer);
+
+ for (int i = 0; i < en->value_count(); i++) {
+ const EnumValueDescriptor* value = en->value(i);
+ printer->Print("const @name@ = @number@;\n",
+ "name", value->name(),
+ "number", IntToString(value->number()));
+ }
+ Outdent(printer);
+ printer->Print("}\n\n");
+}
+
+void GenerateUseDeclaration(bool is_descriptor,
+ google::protobuf::io::Printer* printer) {
+ if (!is_descriptor) {
+ printer->Print(
+ "use Google\\Protobuf\\Internal\\DescriptorPool;\n"
+ "use Google\\Protobuf\\Internal\\GPBType;\n"
+ "use Google\\Protobuf\\Internal\\RepeatedField;\n"
+ "use Google\\Protobuf\\Internal\\GPBUtil;\n\n");
+ } else {
+ printer->Print(
+ "use Google\\Protobuf\\Internal\\DescriptorPool;\n"
+ "use Google\\Protobuf\\Internal\\GPBType;\n"
+ "use Google\\Protobuf\\Internal\\GPBWire;\n"
+ "use Google\\Protobuf\\Internal\\RepeatedField;\n"
+ "use Google\\Protobuf\\Internal\\InputStream;\n\n"
+ "use Google\\Protobuf\\Internal\\GPBUtil;\n\n");
+ }
+}
+
+void GenerateFile(const google::protobuf::FileDescriptor* file,
+ bool is_descriptor, google::protobuf::io::Printer* printer) {
+ printer->Print(
+ "<?php\n"
+ "# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "# source: @filename@\n"
+ "\n",
+ "filename", file->name());
+ if (!file->package().empty()) {
+ printer->Print("namespace @name@;\n\n",
+ "name", PhpName(file->package(), is_descriptor));
+ }
+
+ for (int i = 0; i < file->dependency_count(); i++) {
+ const std::string& name = file->dependency(i)->name();
+ printer->Print("require_once('@name@');\n", "name",
+ GeneratedFileName(name, is_descriptor));
+ }
+
+ GenerateUseDeclaration(is_descriptor, printer);
+
+ for (int i = 0; i < file->message_type_count(); i++) {
+ GenerateMessage("", file->message_type(i), is_descriptor, printer);
+ }
+ for (int i = 0; i < file->enum_type_count(); i++) {
+ GenerateEnum(file->enum_type(i), printer);
+ }
+
+ GenerateAddFileToPool(file, is_descriptor, printer);
+}
+
+bool Generator::Generate(
+ const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* generator_context,
+ string* error) const {
+ bool is_descriptor = parameter == "internal";
+
+ if (is_descriptor && file->name() != kDescriptorFile) {
+ *error =
+ "Can only generate PHP code for google/protobuf/descriptor.proto.\n";
+ return false;
+ }
+
+ if (!is_descriptor && file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
+ *error =
+ "Can only generate PHP code for proto3 .proto files.\n"
+ "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n";
+ return false;
+ }
+
+ std::string filename = GeneratedFileName(file->name(), is_descriptor);
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(filename));
+ io::Printer printer(output.get(), '@');
+
+ GenerateFile(file, is_descriptor, &printer);
+
+ return true;
+}
+
+} // namespace php
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/php/php_generator.h b/src/google/protobuf/compiler/php/php_generator.h
new file mode 100644
index 00000000..ce2b000a
--- /dev/null
+++ b/src/google/protobuf/compiler/php/php_generator.h
@@ -0,0 +1,57 @@
+// 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_PHP_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__
+
+#include <google/protobuf/compiler/code_generator.h>
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace php {
+
+class LIBPROTOC_EXPORT Generator
+ : public google::protobuf::compiler::CodeGenerator {
+ virtual bool Generate(
+ const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* generator_context,
+ string* error) const;
+};
+
+} // namespace php
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 6e258664..e929e4fb 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -261,12 +261,12 @@ string Subprocess::Win32ErrorMessage(DWORD error_code) {
char* message;
// WTF?
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, error_code, 0,
- (LPTSTR)&message, // NOT A BUG!
- 0, NULL);
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, error_code, 0,
+ (LPSTR)&message, // NOT A BUG!
+ 0, NULL);
string result = message;
LocalFree(message);
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 26494b6d..56c3b7fb 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -2535,7 +2535,7 @@ void DescriptorProto_ExtensionRange::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
@@ -2839,7 +2839,7 @@ void DescriptorProto_ReservedRange::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
@@ -7357,7 +7357,7 @@ void MethodDescriptorProto::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
@@ -8174,7 +8174,7 @@ void FileOptions::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
@@ -9582,7 +9582,7 @@ void MessageOptions::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
@@ -10196,7 +10196,7 @@ void FieldOptions::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
@@ -11192,7 +11192,7 @@ void EnumOptions::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
@@ -13053,7 +13053,7 @@ void UninterpretedOption::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
@@ -14941,7 +14941,7 @@ void GeneratedCodeInfo_Annotation::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index f916000e..884f6ccb 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -185,7 +185,7 @@ void Duration::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
diff --git a/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
index a0116a60..7314ee4f 100644
--- a/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
+++ b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
@@ -128,6 +128,24 @@ inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
return old_value;
}
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return __atomic_add_fetch(ptr, increment, __ATOMIC_RELAXED);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ __atomic_store_n(ptr, value, __ATOMIC_RELAXED);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return __atomic_load_n(ptr, __ATOMIC_RELAXED);
+}
+
#endif // defined(__LP64__)
} // namespace internal
diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h
index 87271c5e..bbd507a8 100644
--- a/src/google/protobuf/stubs/callback.h
+++ b/src/google/protobuf/stubs/callback.h
@@ -381,6 +381,8 @@ class MethodResultCallback_5_2 : public ResultCallback2<R, A1, A2> {
typename remove_reference<P5>::type p5_;
};
+} // namespace internal
+
// See Closure.
inline Closure* NewCallback(void (*function)()) {
return new internal::FunctionClosure0(function, true);
@@ -533,8 +535,6 @@ inline ResultCallback2<R, A1, A2>* NewPermanentCallback(
p2, p3, p4, p5);
}
-} // namespace internal
-
// A function which does nothing. Useful for creating no-op callbacks, e.g.:
// Closure* nothing = NewCallback(&DoNothing);
void LIBPROTOBUF_EXPORT DoNothing();
diff --git a/src/google/protobuf/stubs/common_unittest.cc b/src/google/protobuf/stubs/common_unittest.cc
index 25bae9b0..f9e2cfd4 100644
--- a/src/google/protobuf/stubs/common_unittest.cc
+++ b/src/google/protobuf/stubs/common_unittest.cc
@@ -41,8 +41,6 @@
namespace google {
namespace protobuf {
-using internal::NewCallback;
-using internal::NewPermanentCallback;
namespace {
// TODO(kenton): More tests.
diff --git a/src/google/protobuf/stubs/map_util.h b/src/google/protobuf/stubs/map_util.h
index 4cccbbed..887f12a6 100644
--- a/src/google/protobuf/stubs/map_util.h
+++ b/src/google/protobuf/stubs/map_util.h
@@ -208,7 +208,7 @@ typename Collection::value_type::second_type::element_type&
FindLinkedPtrOrDie(const Collection& collection,
const typename Collection::value_type::first_type& key) {
typename Collection::const_iterator it = collection.find(key);
- CHECK(it != collection.end()) << "key not found: " << key;
+ GOOGLE_CHECK(it != collection.end()) << "key not found: " << key;
// Since linked_ptr::operator*() is a const member returning a non const,
// we do not need a version of this function taking a non const collection.
return *it->second;
@@ -337,14 +337,15 @@ bool InsertIfNotPresent(
template <class Collection>
void InsertOrDie(Collection* const collection,
const typename Collection::value_type& value) {
- CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value;
+ GOOGLE_CHECK(InsertIfNotPresent(collection, value))
+ << "duplicate value: " << value;
}
// Same as above except doesn't log the value on error.
template <class Collection>
void InsertOrDieNoPrint(Collection* const collection,
const typename Collection::value_type& value) {
- CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
+ GOOGLE_CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
}
// Inserts the key-value pair into the collection. Dies if key was already
diff --git a/src/google/protobuf/stubs/once_unittest.cc b/src/google/protobuf/stubs/once_unittest.cc
index 37def58d..d5f7779e 100644
--- a/src/google/protobuf/stubs/once_unittest.cc
+++ b/src/google/protobuf/stubs/once_unittest.cc
@@ -43,7 +43,6 @@
namespace google {
namespace protobuf {
-using internal::NewCallback;
namespace {
class OnceInitTest : public testing::Test {
@@ -128,11 +127,11 @@ class OnceInitTest : public testing::Test {
};
TestThread* RunInitOnceInNewThread() {
- return new TestThread(internal::NewCallback(this, &OnceInitTest::InitOnce));
+ return new TestThread(NewCallback(this, &OnceInitTest::InitOnce));
}
TestThread* RunInitRecursiveOnceInNewThread() {
return new TestThread(
- internal::NewCallback(this, &OnceInitTest::InitRecursiveOnce));
+ NewCallback(this, &OnceInitTest::InitRecursiveOnce));
}
enum State {
diff --git a/src/google/protobuf/stubs/substitute.cc b/src/google/protobuf/stubs/substitute.cc
index c9d95899..7194a5b1 100644
--- a/src/google/protobuf/stubs/substitute.cc
+++ b/src/google/protobuf/stubs/substitute.cc
@@ -113,7 +113,9 @@ void SubstituteAndAppend(
for (int i = 0; format[i] != '\0'; i++) {
if (format[i] == '$') {
if (ascii_isdigit(format[i+1])) {
- const SubstituteArg* src = args_array[format[i+1] - '0'];
+ unsigned int index = format[i+1] - '0';
+ assert(index < 10);
+ const SubstituteArg* src = args_array[index];
memcpy(target, src->data(), src->size());
target += src->size();
++i; // Skip next char.
diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc
index 3d07b127..470512ed 100644
--- a/src/google/protobuf/testing/file.cc
+++ b/src/google/protobuf/testing/file.cc
@@ -91,6 +91,7 @@ bool File::WriteStringToFile(const string& contents, const string& name) {
if (fwrite(contents.data(), 1, contents.size(), file) != contents.size()) {
GOOGLE_LOG(ERROR) << "fwrite(" << name << "): " << strerror(errno);
+ fclose(file);
return false;
}
@@ -140,12 +141,12 @@ void File::DeleteRecursively(const string& name,
#ifdef _MSC_VER
// This interface is so weird.
- WIN32_FIND_DATA find_data;
- HANDLE find_handle = FindFirstFile((name + "/*").c_str(), &find_data);
+ WIN32_FIND_DATAA find_data;
+ HANDLE find_handle = FindFirstFileA((name + "/*").c_str(), &find_data);
if (find_handle == INVALID_HANDLE_VALUE) {
// Just delete it, whatever it is.
- DeleteFile(name.c_str());
- RemoveDirectory(name.c_str());
+ DeleteFileA(name.c_str());
+ RemoveDirectoryA(name.c_str());
return;
}
@@ -155,15 +156,15 @@ void File::DeleteRecursively(const string& name,
string path = name + "/" + entry_name;
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
DeleteRecursively(path, NULL, NULL);
- RemoveDirectory(path.c_str());
+ RemoveDirectoryA(path.c_str());
} else {
- DeleteFile(path.c_str());
+ DeleteFileA(path.c_str());
}
}
- } while(FindNextFile(find_handle, &find_data));
+ } while(FindNextFileA(find_handle, &find_data));
FindClose(find_handle);
- RemoveDirectory(name.c_str());
+ RemoveDirectoryA(name.c_str());
#else
// Use opendir()! Yay!
// lstat = Don't follow symbolic links.
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 0a18edbe..e6c9c58b 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -199,7 +199,7 @@ void Timestamp::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index 87a7864f..fc7d5332 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -1126,7 +1126,7 @@ void Field::Clear() {
#endif
#define ZR_(first, last) do {\
- ::memset(&first, 0,\
+ ::memset(&(first), 0,\
ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
} while (0)
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc
index 1e8dab70..3479949b 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter.cc
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc
@@ -165,7 +165,10 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
if (current_ == NULL) {
ow_->RenderBytes(name, value);
} else {
- RenderDataPiece(name, DataPiece(value, false, true));
+ // Since StringPiece is essentially a pointer, takes a copy of "value" to
+ // avoid ownership issues.
+ string_values_.push_back(new string(value.ToString()));
+ RenderDataPiece(name, DataPiece(*string_values_.back(), false, true));
}
return this;
}
@@ -583,7 +586,6 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
new Node(name.ToString(), NULL, PRIMITIVE, data, false,
child == NULL ? current_->path() : child->path(),
suppress_empty_list_, field_scrub_callback_.get()));
- child = node.get();
current_->AddChild(node.release());
} else {
child->set_data(data);
diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc
index 39be7b03..be51ce56 100644
--- a/src/google/protobuf/util/internal/json_stream_parser.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -315,7 +315,6 @@ util::Status JsonStreamParser::ParseStringHelper() {
// We're about to handle an escape, copy all bytes from last to data.
if (last < data) {
parsed_storage_.append(last, data - last);
- last = data;
}
// If we ran out of string after the \, cancel or report an error
// depending on if we expect more data later.
@@ -371,7 +370,6 @@ util::Status JsonStreamParser::ParseStringHelper() {
} else {
if (last < data) {
parsed_storage_.append(last, data - last);
- last = data;
}
parsed_ = StringPiece(parsed_storage_);
}
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index 1825f556..73e05cfe 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -907,7 +907,7 @@ Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
// conversions as much as possible. Because ToSnakeCase sometimes returns the
// wrong value.
google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback(
- ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow));
+ NewPermanentCallback(&RenderOneFieldPath, ow));
return DecodeCompactFieldMaskPaths(data.str(), callback.get());
}
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
index dacac5e0..24ff5fd6 100644
--- a/src/google/protobuf/util/json_util_test.cc
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -128,6 +128,34 @@ TEST_F(JsonUtilTest, TestDefaultValues) {
"\"repeatedMessageValue\":[]"
"}",
ToJson(m, options));
+
+ options.always_print_primitive_fields = true;
+ m.set_string_value("i am a test string value");
+ m.set_bytes_value("i am a test bytes value");
+ EXPECT_EQ(
+ "{\"boolValue\":false,"
+ "\"int32Value\":0,"
+ "\"int64Value\":\"0\","
+ "\"uint32Value\":0,"
+ "\"uint64Value\":\"0\","
+ "\"floatValue\":0,"
+ "\"doubleValue\":0,"
+ "\"stringValue\":\"i am a test string value\","
+ "\"bytesValue\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\","
+ "\"enumValue\":\"FOO\","
+ "\"repeatedBoolValue\":[],"
+ "\"repeatedInt32Value\":[],"
+ "\"repeatedInt64Value\":[],"
+ "\"repeatedUint32Value\":[],"
+ "\"repeatedUint64Value\":[],"
+ "\"repeatedFloatValue\":[],"
+ "\"repeatedDoubleValue\":[],"
+ "\"repeatedStringValue\":[],"
+ "\"repeatedBytesValue\":[],"
+ "\"repeatedEnumValue\":[],"
+ "\"repeatedMessageValue\":[]"
+ "}",
+ ToJson(m, options));
}
TEST_F(JsonUtilTest, ParseMessage) {
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index a6d0cb07..328b40d8 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -626,6 +626,7 @@ bool MessageDifferencer::CompareWithFieldsInternal(
}
if (reporter_ != NULL) {
+ assert(field1 != NULL);
int count = field1->is_repeated() ?
reflection1->FieldSize(message1, field1) : 1;
@@ -706,6 +707,7 @@ bool MessageDifferencer::CompareWithFieldsInternal(
}
bool fieldDifferent = false;
+ assert(field1 != NULL);
if (field1->is_repeated()) {
fieldDifferent = !CompareRepeatedField(message1, message2, field1,
parent_fields);
@@ -875,6 +877,7 @@ bool MessageDifferencer::CompareRepeatedField(
for (int i = 0; i < count1; ++i) {
if (match_list1[i] != -1) continue;
+ assert(reporter_ != NULL);
specific_field.index = i;
parent_fields->push_back(specific_field);
reporter_->ReportDeleted(message1, message2, *parent_fields);
@@ -1389,8 +1392,7 @@ bool MessageDifferencer::MatchRepeatedFieldIndices(
// doesn't necessarily imply Compare(b, c). Therefore a naive greedy
// algorithm will fail to find a maximum matching.
// Here we use the argumenting path algorithm.
- MaximumMatcher::NodeMatchCallback* callback =
- ::google::protobuf::internal::NewPermanentCallback(
+ MaximumMatcher::NodeMatchCallback* callback = NewPermanentCallback(
this, &MessageDifferencer::IsMatch,
repeated_field, key_comparator,
&message1, &message2, parent_fields);