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
write_header_file(const string & request_parameter,CodeGeneratorResponse * response,const FileDescriptorProto & file_descriptor)122 static void write_header_file(const string& request_parameter, CodeGeneratorResponse* response,
123 const FileDescriptorProto& file_descriptor) {
124 stringstream text;
125
126 text << "// Generated by protoc-gen-cppstream. DO NOT MODIFY." << endl;
127 text << "// source: " << file_descriptor.name() << endl << endl;
128
129 string header = "ANDROID_" + replace_string(file_descriptor.name(), '/', '_');
130 header = replace_string(header, '.', '_') + "_stream_h";
131 header = make_constant_name(header);
132
133 text << "#ifndef " << header << endl;
134 text << "#define " << header << endl;
135 text << endl;
136
137 vector<string> namespaces = split(file_descriptor.package(), '.');
138 for (vector<string>::iterator it = namespaces.begin(); it != namespaces.end(); it++) {
139 text << "namespace " << *it << " {" << endl;
140 }
141 text << endl;
142
143 size_t N;
144 N = file_descriptor.enum_type_size();
145 for (size_t i=0; i<N; i++) {
146 write_enum(text, file_descriptor.enum_type(i), "");
147 }
148
149 N = file_descriptor.message_type_size();
150 for (size_t i=0; i<N; i++) {
151 write_message(text, file_descriptor.message_type(i), "");
152 }
153
154 for (vector<string>::reverse_iterator it = namespaces.rbegin(); it != namespaces.rend(); it++) {
155 text << "} // " << *it << endl;
156 }
157
158 text << endl;
159 text << "#endif // " << header << endl;
160
161 if (request_parameter.find("experimental_allow_proto3_optional") != string::npos) {
162 response->set_supported_features(CodeGeneratorResponse::FEATURE_PROTO3_OPTIONAL);
163 }
164 CodeGeneratorResponse::File* file_response = response->add_file();
165 file_response->set_name(make_filename(file_descriptor));
166 file_response->set_content(text.str());
167 }
168
main(int argc,char const * argv[])169 int main(int argc, char const *argv[])
170 {
171 (void)argc;
172 (void)argv;
173
174 GOOGLE_PROTOBUF_VERIFY_VERSION;
175
176 CodeGeneratorRequest request;
177 CodeGeneratorResponse response;
178
179 // Read the request
180 request.ParseFromIstream(&cin);
181
182 // Build the files we need.
183 const int N = request.proto_file_size();
184 for (int i=0; i<N; i++) {
185 const FileDescriptorProto& file_descriptor = request.proto_file(i);
186 if (should_generate_for_file(request, file_descriptor.name())) {
187 write_header_file(request.parameter(), &response, file_descriptor);
188 }
189 }
190
191 // If we had errors, don't write the response. Print the errors and exit.
192 if (ERRORS.HasErrors()) {
193 ERRORS.Print();
194 return 1;
195 }
196
197 // If we didn't have errors, write the response and exit happily.
198 response.SerializeToOstream(&cout);
199
200 /* code */
201 return 0;
202 }
203