• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
make_filename(const FileDescriptorProto & file_descriptor)16 make_filename(const FileDescriptorProto& file_descriptor)
17 {
18     return file_descriptor.name() + ".h";
19 }
20 
21 static void
write_enum(stringstream & text,const EnumDescriptorProto & enu,const string & indent)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 << "static const int _ENUM_" << name << "_COUNT = " << N << ";" << endl;
37         text << indent << "static 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 << "static 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
write_field(stringstream & text,const FieldDescriptorProto & field,const string & indent)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
write_message(stringstream & text,const DescriptorProto & message,const string & indent)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 << "static const int _FIELD_COUNT = " << N << ";" << endl;
106         text << indented << "static 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 << "static 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
write_header_file(CodeGeneratorResponse * response,const FileDescriptorProto & file_descriptor)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>::reverse_iterator it = namespaces.rbegin(); it != namespaces.rend(); 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 
main(int argc,char const * argv[])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