| Index: third_party/protobuf/src/google/protobuf/compiler/php/php_generator.cc
|
| diff --git a/third_party/protobuf/src/google/protobuf/compiler/php/php_generator.cc b/third_party/protobuf/src/google/protobuf/compiler/php/php_generator.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..83e629b99744fec133323e008fd792dbcc5ee46b
|
| --- /dev/null
|
| +++ b/third_party/protobuf/src/google/protobuf/compiler/php/php_generator.cc
|
| @@ -0,0 +1,795 @@
|
| +// 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 MessagePrefix(const google::protobuf::Descriptor* message) {
|
| + // Empty cannot be php class name.
|
| + if (message->name() == "Empty" &&
|
| + message->file()->package() == "google.protobuf") {
|
| + return "GPB";
|
| + } else {
|
| + return "";
|
| + }
|
| +}
|
| +
|
| +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();
|
| + }
|
| + message_name = MessagePrefix(message) + message_name;
|
| +
|
| + 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 + "_" + MessagePrefix(message) + 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
|
|
|