blob: dc96d5c54c166863b1cf3981b26117ead6a3aef4 [file] [log] [blame]
Yi Jin0473f88b2017-10-09 11:21:40 -07001#include "Errors.h"
2#include "string_utils.h"
3
Yi Jin04625ad2017-10-17 18:29:33 -07004#include <frameworks/base/tools/streaming_proto/stream.pb.h>
5
Yi Jin0473f88b2017-10-09 11:21:40 -07006#include "google/protobuf/compiler/plugin.pb.h"
7#include "google/protobuf/io/zero_copy_stream_impl.h"
8#include "google/protobuf/text_format.h"
9
10#include <iomanip>
11#include <iostream>
12#include <sstream>
13
14using namespace android::stream_proto;
15using namespace google::protobuf;
16using namespace google::protobuf::compiler;
17using namespace google::protobuf::io;
18using namespace std;
19
20/**
21 * Position of the field type in a (long long) fieldId.
22 */
23const uint64_t FIELD_TYPE_SHIFT = 32;
24
25//
26// FieldId flags for whether the field is single, repeated or packed.
27// TODO: packed is not supported yet.
28//
29const uint64_t FIELD_COUNT_SHIFT = 40;
30const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
31const uint64_t FIELD_COUNT_UNKNOWN = 0;
32const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
33const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
34const uint64_t FIELD_COUNT_PACKED = 4ULL << FIELD_COUNT_SHIFT;
35
36// Indent
37const string INDENT = " ";
38
39/**
40 * See if this is the file for this request, and not one of the imported ones.
41 */
42static bool
43should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
44{
45 const int N = request.file_to_generate_size();
46 for (int i=0; i<N; i++) {
47 if (request.file_to_generate(i) == file) {
48 return true;
49 }
50 }
51 return false;
52}
53
54static string
55make_filename(const FileDescriptorProto& file_descriptor)
56{
57 return file_descriptor.name() + ".h";
58}
59
60static string
61get_proto_type(const FieldDescriptorProto& field)
62{
63 switch (field.type()) {
64 case FieldDescriptorProto::TYPE_DOUBLE:
65 return "double";
66 case FieldDescriptorProto::TYPE_FLOAT:
67 return "float";
68 case FieldDescriptorProto::TYPE_INT64:
69 return "int64";
70 case FieldDescriptorProto::TYPE_UINT64:
71 return "uint64";
72 case FieldDescriptorProto::TYPE_INT32:
73 return "int32";
74 case FieldDescriptorProto::TYPE_FIXED64:
75 return "fixed64";
76 case FieldDescriptorProto::TYPE_FIXED32:
77 return "fixed32";
78 case FieldDescriptorProto::TYPE_BOOL:
79 return "bool";
80 case FieldDescriptorProto::TYPE_STRING:
81 return "string";
82 case FieldDescriptorProto::TYPE_GROUP:
83 return "group<unsupported!>";
84 case FieldDescriptorProto::TYPE_MESSAGE:
85 return field.type_name();
86 case FieldDescriptorProto::TYPE_BYTES:
87 return "bytes";
88 case FieldDescriptorProto::TYPE_UINT32:
89 return "uint32";
90 case FieldDescriptorProto::TYPE_ENUM:
91 return field.type_name();
92 case FieldDescriptorProto::TYPE_SFIXED32:
93 return "sfixed32";
94 case FieldDescriptorProto::TYPE_SFIXED64:
95 return "sfixed64";
96 case FieldDescriptorProto::TYPE_SINT32:
97 return "sint32";
98 case FieldDescriptorProto::TYPE_SINT64:
99 return "sint64";
100 default:
101 // won't happen
102 return "void";
103 }
104}
105
106static void
107write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& indent)
108{
109 const int N = enu.value_size();
110 text << indent << "// enum " << enu.name() << endl;
111 for (int i=0; i<N; i++) {
112 const EnumValueDescriptorProto& value = enu.value(i);
113 text << indent << "const uint32_t "
114 << make_constant_name(value.name())
115 << " = " << value.number() << ";" << endl;
116 }
117 text << endl;
118}
119
120static uint64_t
121get_field_id(const FieldDescriptorProto& field)
122{
123 // Number
124 uint64_t result = (uint64_t)field.number();
125
126 // Type
127 result |= (uint64_t)field.type() << FIELD_TYPE_SHIFT;
128
129 // Count
130 if (field.options().packed()) {
131 result |= FIELD_COUNT_PACKED;
132 } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
133 result |= FIELD_COUNT_REPEATED;
134 } else {
135 result |= FIELD_COUNT_SINGLE;
136 }
137
138 return result;
139}
140
141static void
142write_field(stringstream& text, const FieldDescriptorProto& field, const string& indent)
143{
144 string optional_comment = field.label() == FieldDescriptorProto::LABEL_OPTIONAL
145 ? "optional " : "";
146 string repeated_comment = field.label() == FieldDescriptorProto::LABEL_REPEATED
147 ? "repeated " : "";
148 string proto_type = get_proto_type(field);
149 string packed_comment = field.options().packed()
150 ? " [packed=true]" : "";
151 text << indent << "// " << optional_comment << repeated_comment << proto_type << ' '
152 << field.name() << " = " << field.number() << packed_comment << ';' << endl;
153
154 text << indent << "const uint64_t " << make_constant_name(field.name()) << " = 0x";
155
156 ios::fmtflags fmt(text.flags());
157 text << setfill('0') << setw(16) << hex << get_field_id(field);
158 text.flags(fmt);
159
160 text << "LL;" << endl;
161
162 text << endl;
163}
164
Yi Jin04625ad2017-10-17 18:29:33 -0700165static inline bool
166should_generate_fields_mapping(const DescriptorProto& message)
167{
168 return message.options().GetExtension(stream).enable_fields_mapping();
169}
170
Yi Jin0473f88b2017-10-09 11:21:40 -0700171static void
172write_message(stringstream& text, const DescriptorProto& message, const string& indent)
173{
174 int N;
175 const string indented = indent + INDENT;
176
177 text << indent << "// message " << message.name() << endl;
Yi Jin04625ad2017-10-17 18:29:33 -0700178 text << indent << "namespace " << message.name() << " {" << endl;
Yi Jin0473f88b2017-10-09 11:21:40 -0700179
180 // Enums
181 N = message.enum_type_size();
182 for (int i=0; i<N; i++) {
183 write_enum(text, message.enum_type(i), indented);
184 }
185
186 // Nested classes
187 N = message.nested_type_size();
188 for (int i=0; i<N; i++) {
189 write_message(text, message.nested_type(i), indented);
190 }
191
192 // Fields
193 N = message.field_size();
194 for (int i=0; i<N; i++) {
195 write_field(text, message.field(i), indented);
196 }
197
Yi Jin04625ad2017-10-17 18:29:33 -0700198 if (should_generate_fields_mapping(message)) {
199 N = message.field_size();
200 text << indented << "const int _FIELD_COUNT = " << N << ";" << endl;
201 text << indented << "const char* _FIELD_NAMES[" << N << "] = {" << endl;
202 for (int i=0; i<N; i++) {
203 text << indented << INDENT << "\"" << message.field(i).name() << "\"," << endl;
204 }
205 text << indented << "};" << endl;
206 text << indented << "const uint64_t _FIELD_IDS[" << N << "] = {" << endl;
207 for (int i=0; i<N; i++) {
208 text << indented << INDENT << make_constant_name(message.field(i).name()) << "," << endl;
209 }
210 text << indented << "};" << endl << endl;
211 }
212
213 text << indent << "} //" << message.name() << endl;
Yi Jin0473f88b2017-10-09 11:21:40 -0700214 text << endl;
215}
216
217static void
Yi Jin04625ad2017-10-17 18:29:33 -0700218write_header_file(CodeGeneratorResponse* response, const FileDescriptorProto& file_descriptor)
Yi Jin0473f88b2017-10-09 11:21:40 -0700219{
220 stringstream text;
221
222 text << "// Generated by protoc-gen-cppstream. DO NOT MODIFY." << endl;
223 text << "// source: " << file_descriptor.name() << endl << endl;
224
225 string header = "ANDROID_" + replace_string(file_descriptor.name(), '/', '_');
226 header = replace_string(header, '.', '_') + "_stream_h";
227 header = make_constant_name(header);
228
229 text << "#ifndef " << header << endl;
230 text << "#define " << header << endl;
231 text << endl;
232
233 vector<string> namespaces = split(file_descriptor.package(), '.');
234 for (vector<string>::iterator it = namespaces.begin(); it != namespaces.end(); it++) {
235 text << "namespace " << *it << " {" << endl;
236 }
237 text << endl;
238
239 size_t N;
240 N = file_descriptor.enum_type_size();
241 for (size_t i=0; i<N; i++) {
242 write_enum(text, file_descriptor.enum_type(i), "");
243 }
244
245 N = file_descriptor.message_type_size();
246 for (size_t i=0; i<N; i++) {
247 write_message(text, file_descriptor.message_type(i), "");
248 }
249
250 for (vector<string>::iterator it = namespaces.begin(); it != namespaces.end(); it++) {
251 text << "} // " << *it << endl;
252 }
253
254 text << endl;
255 text << "#endif // " << header << endl;
256
257 CodeGeneratorResponse::File* file_response = response->add_file();
258 file_response->set_name(make_filename(file_descriptor));
259 file_response->set_content(text.str());
260}
261
262int main(int argc, char const *argv[])
263{
264 (void)argc;
265 (void)argv;
266
267 GOOGLE_PROTOBUF_VERIFY_VERSION;
268
269 CodeGeneratorRequest request;
270 CodeGeneratorResponse response;
271
272 // Read the request
273 request.ParseFromIstream(&cin);
274
275 // Build the files we need.
276 const int N = request.proto_file_size();
277 for (int i=0; i<N; i++) {
278 const FileDescriptorProto& file_descriptor = request.proto_file(i);
279 if (should_generate_for_file(request, file_descriptor.name())) {
Yi Jin04625ad2017-10-17 18:29:33 -0700280 write_header_file(&response, file_descriptor);
Yi Jin0473f88b2017-10-09 11:21:40 -0700281 }
282 }
283
284 // If we had errors, don't write the response. Print the errors and exit.
285 if (ERRORS.HasErrors()) {
286 ERRORS.Print();
287 return 1;
288 }
289
290 // If we didn't have errors, write the response and exit happily.
291 response.SerializeToOstream(&cout);
292
293 /* code */
294 return 0;
Yi Jin04625ad2017-10-17 18:29:33 -0700295}