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