@ -37,6 +37,16 @@
# include <google/protobuf/io/printer.h>
# include <google/protobuf/io/zero_copy_stream.h>
# include <google/protobuf/stubs/strutil.h>
# include <google/protobuf/any.pb.h>
# include <google/protobuf/api.pb.h>
# include <google/protobuf/duration.pb.h>
# include <google/protobuf/empty.pb.h>
# include <google/protobuf/field_mask.pb.h>
# include <google/protobuf/source_context.pb.h>
# include <google/protobuf/struct.pb.h>
# include <google/protobuf/timestamp.pb.h>
# include <google/protobuf/type.pb.h>
# include <google/protobuf/wrappers.pb.h>
# include <sstream>
@ -91,6 +101,9 @@ std::string UnderscoresToCamelCase(const string& name, bool cap_first_letter);
std : : string BinaryToHex ( const string & binary ) ;
void Indent ( io : : Printer * printer ) ;
void Outdent ( io : : Printer * printer ) ;
void GenerateAddFilesToPool ( const FileDescriptor * file ,
const std : : set < string > & aggregate_metadata_prefixes ,
io : : Printer * printer ) ;
void GenerateMessageDocComment ( io : : Printer * printer , const Descriptor * message ,
int is_descriptor ) ;
void GenerateMessageConstructorDocComment ( io : : Printer * printer ,
@ -111,7 +124,6 @@ void GenerateServiceDocComment(io::Printer* printer,
void GenerateServiceMethodDocComment ( io : : Printer * printer ,
const MethodDescriptor * method ) ;
std : : string ReservedNamePrefix ( const string & classname ,
const FileDescriptor * file ) {
bool is_reserved = false ;
@ -924,13 +936,20 @@ void GenerateMessageToPool(const string& name_prefix, const Descriptor* message,
}
}
void GenerateAddFileToPool ( const FileDescriptor * file , bool is_descriptor ,
void GenerateAddFileToPool (
const FileDescriptor * file ,
bool is_descriptor ,
bool aggregate_metadata ,
const std : : set < string > & aggregate_metadata_prefixes ,
io : : Printer * printer ) {
printer - > Print (
" public static $is_initialized = false; \n \n "
" public static function initOnce() { \n " ) ;
Indent ( printer ) ;
if ( aggregate_metadata ) {
GenerateAddFilesToPool ( file , aggregate_metadata_prefixes , printer ) ;
} else {
printer - > Print (
" $pool = \\ Google \\ Protobuf \\ Internal \\ "
" DescriptorPool::getGeneratedPool(); \n \n "
@ -994,14 +1013,9 @@ void GenerateAddFileToPool(const FileDescriptor* file, bool is_descriptor,
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 ( ) ? " . " : " " ) ;
}
" \" ^data^ \" \n " ,
" data " , BinaryToHex ( files_data ) ) ;
Outdent ( printer ) ;
printer - > Print (
@ -1009,10 +1023,146 @@ void GenerateAddFileToPool(const FileDescriptor* file, bool is_descriptor,
}
printer - > Print (
" static::$is_initialized = true; \n " ) ;
}
Outdent ( printer ) ;
printer - > Print ( " } \n " ) ;
}
static void AnalyzeDependencyForFile (
const FileDescriptor * file ,
std : : set < const FileDescriptor * > * nodes_without_dependency ,
std : : map < const FileDescriptor * , std : : set < const FileDescriptor * > > * deps ,
std : : map < const FileDescriptor * , int > * dependency_count ) {
int count = file - > dependency_count ( ) ;
for ( int i = 0 ; i < file - > dependency_count ( ) ; i + + ) {
const FileDescriptor * dependency = file - > dependency ( i ) ;
if ( dependency - > name ( ) = = kDescriptorFile ) {
count - - ;
break ;
}
}
if ( count = = 0 ) {
nodes_without_dependency - > insert ( file ) ;
} else {
( * dependency_count ) [ file ] = count ;
for ( int i = 0 ; i < file - > dependency_count ( ) ; i + + ) {
const FileDescriptor * dependency = file - > dependency ( i ) ;
if ( dependency - > name ( ) = = kDescriptorFile ) {
continue ;
}
if ( deps - > find ( dependency ) = = deps - > end ( ) ) {
( * deps ) [ dependency ] = std : : set < const FileDescriptor * > ( ) ;
}
( * deps ) [ dependency ] . insert ( file ) ;
AnalyzeDependencyForFile (
dependency , nodes_without_dependency , deps , dependency_count ) ;
}
}
}
static bool NeedsUnwrapping (
const FileDescriptor * file ,
const std : : set < string > & aggregate_metadata_prefixes ) {
bool has_aggregate_metadata_prefix = false ;
if ( aggregate_metadata_prefixes . empty ( ) ) {
has_aggregate_metadata_prefix = true ;
} else {
for ( const auto & prefix : aggregate_metadata_prefixes ) {
if ( HasPrefixString ( file - > package ( ) , prefix ) ) {
has_aggregate_metadata_prefix = true ;
break ;
}
}
}
return has_aggregate_metadata_prefix ;
}
void GenerateAddFilesToPool (
const FileDescriptor * file ,
const std : : set < string > & aggregate_metadata_prefixes ,
io : : Printer * printer ) {
printer - > Print (
" $pool = \\ Google \\ Protobuf \\ Internal \\ "
" DescriptorPool::getGeneratedPool(); \n "
" if (static::$is_initialized == true) { \n "
" return; \n "
" } \n " ) ;
// Sort files according to dependency
std : : map < const FileDescriptor * , std : : set < const FileDescriptor * > > deps ;
std : : map < const FileDescriptor * , int > dependency_count ;
std : : set < const FileDescriptor * > nodes_without_dependency ;
FileDescriptorSet sorted_file_set ;
AnalyzeDependencyForFile (
file , & nodes_without_dependency , & deps , & dependency_count ) ;
while ( ! nodes_without_dependency . empty ( ) ) {
auto file = * nodes_without_dependency . begin ( ) ;
nodes_without_dependency . erase ( file ) ;
for ( auto dependent : deps [ file ] ) {
if ( dependency_count [ dependent ] = = 1 ) {
dependency_count . erase ( dependent ) ;
nodes_without_dependency . insert ( dependent ) ;
} else {
dependency_count [ dependent ] - = 1 ;
}
}
bool needs_aggregate = NeedsUnwrapping ( file , aggregate_metadata_prefixes ) ;
if ( needs_aggregate ) {
auto file_proto = sorted_file_set . add_file ( ) ;
file - > CopyTo ( file_proto ) ;
// Filter out descriptor.proto as it cannot be depended on for now.
RepeatedPtrField < string > * dependency = file_proto - > mutable_dependency ( ) ;
for ( RepeatedPtrField < string > : : iterator it = dependency - > begin ( ) ;
it ! = dependency - > end ( ) ; + + it ) {
if ( * it ! = kDescriptorFile ) {
dependency - > erase ( it ) ;
break ;
}
}
// Filter out all extensions, since we do not support extension yet.
file_proto - > clear_extension ( ) ;
RepeatedPtrField < DescriptorProto > * message_type =
file_proto - > mutable_message_type ( ) ;
for ( RepeatedPtrField < DescriptorProto > : : iterator it = message_type - > begin ( ) ;
it ! = message_type - > end ( ) ; + + it ) {
it - > clear_extension ( ) ;
}
} else {
std : : string dependency_filename =
GeneratedMetadataFileName ( file , false ) ;
printer - > Print (
" \\ ^name^::initOnce(); \n " ,
" name " , FilenameToClassname ( dependency_filename ) ) ;
}
}
string files_data ;
sorted_file_set . SerializeToString ( & files_data ) ;
printer - > Print ( " $pool->internalAddGeneratedFile(hex2bin( \n " ) ;
Indent ( printer ) ;
printer - > Print (
" \" ^data^ \" \n " ,
" data " , BinaryToHex ( files_data ) ) ;
Outdent ( printer ) ;
printer - > Print (
" ), true); \n " ) ;
printer - > Print (
" static::$is_initialized = true; \n " ) ;
}
void GenerateUseDeclaration ( bool is_descriptor , io : : Printer * printer ) {
if ( ! is_descriptor ) {
printer - > Print (
@ -1051,6 +1201,8 @@ std::string FilenameToClassname(const string& filename) {
void GenerateMetadataFile ( const FileDescriptor * file ,
bool is_descriptor ,
bool aggregate_metadata ,
const std : : set < string > & aggregate_metadata_prefixes ,
GeneratorContext * generator_context ) {
std : : string filename = GeneratedMetadataFileName ( file , is_descriptor ) ;
std : : unique_ptr < io : : ZeroCopyOutputStream > output (
@ -1079,7 +1231,8 @@ void GenerateMetadataFile(const FileDescriptor* file,
}
Indent ( & printer ) ;
GenerateAddFileToPool ( file , is_descriptor , & printer ) ;
GenerateAddFileToPool ( file , is_descriptor , aggregate_metadata ,
aggregate_metadata_prefixes , & printer ) ;
Outdent ( & printer ) ;
printer . Print ( " } \n \n " ) ;
@ -1229,6 +1382,7 @@ void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
void GenerateMessageFile ( const FileDescriptor * file , const Descriptor * message ,
bool is_descriptor ,
bool aggregate_metadata ,
GeneratorContext * generator_context ) {
// Don't generate MapEntry messages -- we use the PHP extension's native
// support for map fields instead.
@ -1285,10 +1439,12 @@ void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message,
GeneratedMetadataFileName ( file , is_descriptor ) ;
std : : string metadata_fullname = FilenameToClassname ( metadata_filename ) ;
printer . Print (
" \\ ^fullname^::initOnce(); \n "
" parent::__construct($data); \n " ,
" \\ ^fullname^::initOnce(); \n " ,
" fullname " , metadata_fullname ) ;
printer . Print (
" parent::__construct($data); \n " ) ;
Outdent ( & printer ) ;
printer . Print ( " } \n \n " ) ;
@ -1328,6 +1484,7 @@ void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message,
// Nested messages and enums.
for ( int i = 0 ; i < message - > nested_type_count ( ) ; i + + ) {
GenerateMessageFile ( file , message - > nested_type ( i ) , is_descriptor ,
aggregate_metadata ,
generator_context ) ;
}
for ( int i = 0 ; i < message - > enum_type_count ( ) ; i + + ) {
@ -1384,10 +1541,15 @@ void GenerateServiceFile(const FileDescriptor* file,
}
void GenerateFile ( const FileDescriptor * file , bool is_descriptor ,
bool aggregate_metadata ,
const std : : set < string > & aggregate_metadata_prefixes ,
GeneratorContext * generator_context ) {
GenerateMetadataFile ( file , is_descriptor , generator_context ) ;
GenerateMetadataFile ( file , is_descriptor , aggregate_metadata ,
aggregate_metadata_prefixes , generator_context ) ;
for ( int i = 0 ; i < file - > message_type_count ( ) ; i + + ) {
GenerateMessageFile ( file , file - > message_type ( i ) , is_descriptor ,
aggregate_metadata ,
generator_context ) ;
}
for ( int i = 0 ; i < file - > enum_type_count ( ) ; i + + ) {
@ -1653,8 +1815,17 @@ void GenerateServiceMethodDocComment(io::Printer* printer,
bool Generator : : Generate ( const FileDescriptor * file , const string & parameter ,
GeneratorContext * generator_context ,
string * error ) const {
bool is_descriptor = parameter = = " internal " ;
return Generate ( file , false , false , std : : set < string > ( ) ,
generator_context , error ) ;
}
bool Generator : : Generate (
const FileDescriptor * file ,
bool is_descriptor ,
bool aggregate_metadata ,
const std : : set < string > & aggregate_metadata_prefixes ,
GeneratorContext * generator_context ,
string * error ) const {
if ( is_descriptor & & file - > name ( ) ! = kDescriptorFile ) {
* error =
" Can only generate PHP code for google/protobuf/descriptor.proto. \n " ;
@ -1668,11 +1839,47 @@ bool Generator::Generate(const FileDescriptor* file, const string& parameter,
return false ;
}
GenerateFile ( file , is_descriptor , generator_context ) ;
GenerateFile ( file , is_descriptor , aggregate_metadata ,
aggregate_metadata_prefixes , generator_context ) ;
return true ;
}
bool Generator : : GenerateAll ( const std : : vector < const FileDescriptor * > & files ,
const std : : string & parameter ,
GeneratorContext * generator_context ,
std : : string * error ) const {
bool is_descriptor = false ;
bool aggregate_metadata = false ;
std : : set < string > aggregate_metadata_prefixes ;
for ( const auto & option : Split ( parameter , " , " ) ) {
const auto option_pair = Split ( option , " = " ) ;
if ( HasPrefixString ( option_pair [ 0 ] , " aggregate_metadata " ) ) {
string options_string = option_pair [ 1 ] ;
const auto options = Split ( options_string , " # " , false ) ;
aggregate_metadata = true ;
for ( int i = 0 ; i < options . size ( ) ; i + + ) {
aggregate_metadata_prefixes . insert ( options [ i ] ) ;
GOOGLE_LOG ( INFO ) < < options [ i ] ;
}
}
if ( option_pair [ 0 ] = = " internal " ) {
is_descriptor = true ;
}
}
for ( auto file : files ) {
if ( ! Generate (
file , is_descriptor , aggregate_metadata ,
aggregate_metadata_prefixes ,
generator_context , error ) ) {
return false ;
}
}
return true ;
}
} // namespace php
} // namespace compiler
} // namespace protobuf