Home | History | Annotate | Download | only in cpp
      1 #include "Errors.h"
      2 #include "stream_proto_utils.h"
      3 #include "string_utils.h"
      4 
      5 #include <iomanip>
      6 #include <iostream>
      7 #include <sstream>
      8 
      9 using namespace android::stream_proto;
     10 using namespace google::protobuf::io;
     11 using namespace std;
     12 
     13 const bool GENERATE_MAPPING = true;
     14 
     15 static string
     16 make_filename(const FileDescriptorProto& file_descriptor)
     17 {
     18     return file_descriptor.name() + ".h";
     19 }
     20 
     21 static void
     22 write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& indent)
     23 {
     24     const int N = enu.value_size();
     25     text << indent << "// enum " << enu.name() << endl;
     26     for (int i=0; i<N; i++) {
     27         const EnumValueDescriptorProto& value = enu.value(i);
     28         text << indent << "const int "
     29                 << make_constant_name(value.name())
     30                 << " = " << value.number() << ";" << endl;
     31     }
     32 
     33     if (GENERATE_MAPPING) {
     34         string name = make_constant_name(enu.name());
     35         string prefix = name + "_";
     36         text << indent << "const int _ENUM_" << name << "_COUNT = " << N << ";" << endl;
     37         text << indent << "const char* _ENUM_" << name << "_NAMES[" << N << "] = {" << endl;
     38         for (int i=0; i<N; i++) {
     39             text << indent << INDENT << "\"" << stripPrefix(enu.value(i).name(), prefix) << "\"," << endl;
     40         }
     41         text << indent << "};" << endl;
     42         text << indent << "const int _ENUM_" << name << "_VALUES[" << N << "] = {" << endl;
     43         for (int i=0; i<N; i++) {
     44             text << indent << INDENT << make_constant_name(enu.value(i).name()) << "," << endl;
     45         }
     46         text << indent << "};" << endl;
     47     }
     48 
     49     text << endl;
     50 }
     51 
     52 static void
     53 write_field(stringstream& text, const FieldDescriptorProto& field, const string& indent)
     54 {
     55     string optional_comment = field.label() == FieldDescriptorProto::LABEL_OPTIONAL
     56             ? "optional " : "";
     57     string repeated_comment = field.label() == FieldDescriptorProto::LABEL_REPEATED
     58             ? "repeated " : "";
     59     string proto_type = get_proto_type(field);
     60     string packed_comment = field.options().packed()
     61             ? " [packed=true]" : "";
     62     text << indent << "// " << optional_comment << repeated_comment << proto_type << ' '
     63             << field.name() << " = " << field.number() << packed_comment << ';' << endl;
     64 
     65     text << indent << "const uint64_t " << make_constant_name(field.name()) << " = 0x";
     66 
     67     ios::fmtflags fmt(text.flags());
     68     text << setfill('0') << setw(16) << hex << get_field_id(field);
     69     text.flags(fmt);
     70 
     71     text << "LL;" << endl;
     72 
     73     text << endl;
     74 }
     75 
     76 static void
     77 write_message(stringstream& text, const DescriptorProto& message, const string& indent)
     78 {
     79     int N;
     80     const string indented = indent + INDENT;
     81 
     82     text << indent << "// message " << message.name() << endl;
     83     text << indent << "namespace " << message.name() << " {" << endl;
     84 
     85     // Enums
     86     N = message.enum_type_size();
     87     for (int i=0; i<N; i++) {
     88         write_enum(text, message.enum_type(i), indented);
     89     }
     90 
     91     // Nested classes
     92     N = message.nested_type_size();
     93     for (int i=0; i<N; i++) {
     94         write_message(text, message.nested_type(i), indented);
     95     }
     96 
     97     // Fields
     98     N = message.field_size();
     99     for (int i=0; i<N; i++) {
    100         write_field(text, message.field(i), indented);
    101     }
    102 
    103     if (GENERATE_MAPPING) {
    104         N = message.field_size();
    105         text << indented << "const int _FIELD_COUNT = " << N << ";" << endl;
    106         text << indented << "const char* _FIELD_NAMES[" << N << "] = {" << endl;
    107         for (int i=0; i<N; i++) {
    108             text << indented << INDENT << "\"" << message.field(i).name() << "\"," << endl;
    109         }
    110         text << indented << "};" << endl;
    111         text << indented << "const uint64_t _FIELD_IDS[" << N << "] = {" << endl;
    112         for (int i=0; i<N; i++) {
    113             text << indented << INDENT << make_constant_name(message.field(i).name()) << "," << endl;
    114         }
    115         text << indented << "};" << endl << endl;
    116     }
    117 
    118     text << indent << "} //" << message.name() << endl;
    119     text << endl;
    120 }
    121 
    122 static void
    123 write_header_file(CodeGeneratorResponse* response, const FileDescriptorProto& file_descriptor)
    124 {
    125     stringstream text;
    126 
    127     text << "// Generated by protoc-gen-cppstream. DO NOT MODIFY." << endl;
    128     text << "// source: " << file_descriptor.name() << endl << endl;
    129 
    130     string header = "ANDROID_" + replace_string(file_descriptor.name(), '/', '_');
    131     header = replace_string(header, '.', '_') + "_stream_h";
    132     header = make_constant_name(header);
    133 
    134     text << "#ifndef " << header << endl;
    135     text << "#define " << header << endl;
    136     text << endl;
    137 
    138     vector<string> namespaces = split(file_descriptor.package(), '.');
    139     for (vector<string>::iterator it = namespaces.begin(); it != namespaces.end(); it++) {
    140         text << "namespace " << *it << " {" << endl;
    141     }
    142     text << endl;
    143 
    144     size_t N;
    145     N = file_descriptor.enum_type_size();
    146     for (size_t i=0; i<N; i++) {
    147         write_enum(text, file_descriptor.enum_type(i), "");
    148     }
    149 
    150     N = file_descriptor.message_type_size();
    151     for (size_t i=0; i<N; i++) {
    152         write_message(text, file_descriptor.message_type(i), "");
    153     }
    154 
    155     for (vector<string>::iterator it = namespaces.begin(); it != namespaces.end(); it++) {
    156         text << "} // " << *it << endl;
    157     }
    158 
    159     text << endl;
    160     text << "#endif // " << header << endl;
    161 
    162     CodeGeneratorResponse::File* file_response = response->add_file();
    163     file_response->set_name(make_filename(file_descriptor));
    164     file_response->set_content(text.str());
    165 }
    166 
    167 int main(int argc, char const *argv[])
    168 {
    169     (void)argc;
    170     (void)argv;
    171 
    172     GOOGLE_PROTOBUF_VERIFY_VERSION;
    173 
    174     CodeGeneratorRequest request;
    175     CodeGeneratorResponse response;
    176 
    177     // Read the request
    178     request.ParseFromIstream(&cin);
    179 
    180     // Build the files we need.
    181     const int N = request.proto_file_size();
    182     for (int i=0; i<N; i++) {
    183         const FileDescriptorProto& file_descriptor = request.proto_file(i);
    184         if (should_generate_for_file(request, file_descriptor.name())) {
    185             write_header_file(&response, file_descriptor);
    186         }
    187     }
    188 
    189     // If we had errors, don't write the response. Print the errors and exit.
    190     if (ERRORS.HasErrors()) {
    191         ERRORS.Print();
    192         return 1;
    193     }
    194 
    195     // If we didn't have errors, write the response and exit happily.
    196     response.SerializeToOstream(&cout);
    197 
    198     /* code */
    199     return 0;
    200 }
    201