1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "proto_encoder_plugin_generator.h"
17
18 using google::protobuf::FileDescriptor;
19 using google::protobuf::EnumDescriptor;
20 using google::protobuf::Descriptor;
21 using google::protobuf::io::Printer;
22 using google::protobuf::EnumValueDescriptor;
23 using google::protobuf::FieldDescriptor;
24
25 class OptGeneratorImpl {
26 public:
OptGeneratorImpl(const FileDescriptor * file)27 explicit OptGeneratorImpl(const FileDescriptor* file) : fileContent_(file), printer_(nullptr) {}
28
GetPrefix(const std::string & fileName)29 static std::string GetPrefix(const std::string& fileName)
30 {
31 std::string prefix = "";
32 for (size_t i = 0; i < fileName.length(); i++) {
33 if (fileName.c_str()[i] == '.') {
34 break;
35 }
36 prefix += fileName.c_str()[i];
37 }
38 return prefix;
39 }
40
SetNames(const std::string & fileName,const std::string & packageName)41 std::string SetNames(const std::string& fileName, const std::string& packageName)
42 {
43 fileName_ = fileName;
44 packageName_ = packageName + "::";
45 headFileName_ = "";
46
47 for (size_t i = 0; i < fileName.length(); i++) {
48 if (fileName.c_str()[i] == '.') {
49 break;
50 }
51 headFileName_ += fileName.c_str()[i];
52 }
53 baseName_ = SwapName(headFileName_);
54 return headFileName_;
55 }
56
57 // Swap variable style. e.g: cpu_plugin_config to cpuPluginConfig
SwapName(const std::string & s)58 static std::string SwapName(const std::string& s)
59 {
60 std::string ret = "";
61 bool b = true;
62 for (size_t i = 0; i < s.length(); i++) {
63 char c = s[i];
64 if (c == '_') {
65 b = true;
66 } else if (b && islower(c)) {
67 ret += (c + 'A' - 'a');
68 b = false;
69 } else {
70 ret += c;
71 }
72 }
73 return ret;
74 }
75
Tolowercase(const std::string & s)76 static std::string Tolowercase(const std::string& s)
77 {
78 std::string str = s;
79 std::transform(str.begin(), str.end(), str.begin(), [](const char& c) {
80 return std::tolower(c);
81 });
82 return str;
83 }
84
GenHeader()85 void GenHeader()
86 {
87 GenPrefix();
88 GenerateEnum();
89 GenerateClass();
90 GenSurfix();
91 }
92
GenPrefix()93 void GenPrefix()
94 {
95 printer_->Print("// Generated by protoencoder plugin.\n");
96 printer_->Print("#pragma once\n");
97 printer_->Print("#include \"base_message.h\"\n");
98
99 for (int i = 0; i < fileContent_->dependency_count(); ++i) {
100 printer_->Print("#include \"@name@.pbencoder.h\"\n", "name",
101 GetPrefix(fileContent_->dependency(i)->name()));
102 }
103
104 printer_->Print("namespace OHOS {\n");
105 printer_->Print("namespace Developtools {\n");
106 printer_->Print("namespace Profiler {\n");
107 printer_->Print("namespace ProtoEncoder {\n");
108 }
109
GenerateEnum()110 void GenerateEnum()
111 {
112 for (int i = 0; i < fileContent_->enum_type_count(); ++i) {
113 printer_->Print("enum @class@ : uint32_t {\n", "class", fileContent_->enum_type(i)->name());
114 printer_->Indent();
115
116 for (int j = 0; j < fileContent_->enum_type(i)->value_count(); ++j) {
117 const EnumValueDescriptor* value = fileContent_->enum_type(i)->value(j);
118 const std::string value_name = value->name();
119 printer_->Print("@name@ = @number@,\n", "name", value_name, "number",
120 std::to_string(value->number()));
121 }
122 printer_->Outdent();
123 printer_->Print("};\n");
124 }
125 }
126
GenerateNestClass(const Descriptor * message)127 void GenerateNestClass(const Descriptor* message)
128 {
129 for (int i = 0; i < message->nested_type_count(); ++i) {
130 const Descriptor* nestmessage = message->nested_type(i);
131 GenerateNestClass(nestmessage);
132 printer_->Print(
133 "class @name@ : public BaseMessage {\n"
134 " public:\n",
135 "name", nestmessage->name());
136 printer_->Indent();
137 printer_->Print("@name@() = default;\n", "name", nestmessage->name());
138 printer_->Print(
139 "explicit @name@(RandomWriteCtx* writeCtx, MessagePool* messagePool = nullptr) : BaseMessage(writeCtx, messagePool) {}\n",
140 "name", nestmessage->name());
141 GenerateFieldsID(nestmessage);
142 GenerateFunction(nestmessage);
143 printer_->Outdent();
144 printer_->Print("};\n\n");
145 }
146 }
147
GenerateClass()148 void GenerateClass()
149 {
150 // forward declaration
151 for (int i = 0; i < fileContent_->message_type_count(); ++i) {
152 const Descriptor* message = fileContent_->message_type(i);
153 printer_->Print("class @name@;\n", "name", message->name());
154 }
155
156 for (int i = 0; i < fileContent_->message_type_count(); ++i) {
157 const Descriptor* message = fileContent_->message_type(i);
158 GenerateNestClass(message);
159
160 printer_->Print(
161 "class @name@ : public BaseMessage {\n"
162 " public:\n",
163 "name", message->name());
164 printer_->Indent();
165 printer_->Print("@name@() = default;\n", "name", message->name());
166 printer_->Print(
167 "explicit @name@(RandomWriteCtx* writeCtx, MessagePool* messagePool = nullptr) : BaseMessage(writeCtx, messagePool) {}\n",
168 "name", message->name());
169 GenerateFieldsID(message);
170 GenerateFunction(message);
171 printer_->Outdent();
172 printer_->Print("};\n\n");
173 }
174 }
175
GenerateFieldsID(const Descriptor * message)176 void GenerateFieldsID(const Descriptor* message)
177 {
178 for (int i = 0; i < message->field_count(); ++i) {
179 const FieldDescriptor* field = message->field(i);
180 printer_->Print("static const uint32_t FIELDID_@name@ = @id@;\n",
181 "name", field->name(), "id", std::to_string(field->number()));
182 }
183 }
184
GenerateFunction(const Descriptor * message)185 void GenerateFunction(const Descriptor* message)
186 {
187 // field->is_repeated()
188 for (int i = 0; i < message->field_count(); ++i) {
189 const FieldDescriptor* field = message->field(i);
190 if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
191 printer_->Print("inline @typename@* @mora@_@name@()\n",
192 "mora", field->is_repeated()?"add":"mutable",
193 "typename", field->message_type()->name(),
194 "name", Tolowercase(field->name()));
195 printer_->Print("{\n");
196 printer_->Indent();
197 printer_->Print("return AddSubMessage<@typename@>(FIELDID_@name@);\n",
198 "typename", field->message_type()->name(),
199 "name", field->name());
200 printer_->Outdent();
201 printer_->Print("}\n");
202 } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
203 printer_->Print("inline void set_@name@(const void* bytes, uint32_t size)\n",
204 "name", Tolowercase(field->name()));
205 printer_->Print("{\n");
206 printer_->Indent();
207 printer_->Print("AddBytes(FIELDID_@name@, bytes, size);\n", "name", field->name());
208 printer_->Outdent();
209 printer_->Print("}\n");
210 printer_->Print("void set_@name@(GetDataCallback getData)\n", "name", Tolowercase(field->name()));
211 printer_->Print("{\n");
212 printer_->Indent();
213 printer_->Print("return AddBytesByCallBack(FIELDID_@name@, getData);\n", "name", field->name());
214 printer_->Outdent();
215 printer_->Print("}\n");
216 printer_->Print("inline RandomWriteCtx* startAdd_@name@()\n", "name", Tolowercase(field->name()));
217 printer_->Print("{\n");
218 printer_->Indent();
219 printer_->Print("return StartAddBytes(FIELDID_@name@);\n", "name", field->name());
220 printer_->Outdent();
221 printer_->Print("}\n");
222 printer_->Print("inline void finishAdd_@name@(int32_t size)\n", "name", Tolowercase(field->name()));
223 printer_->Print("{\n");
224 printer_->Indent();
225 printer_->Print("return FinishAddBytes(size);\n", "name", field->name());
226 printer_->Outdent();
227 printer_->Print("}\n");
228 } else if (field->type() == FieldDescriptor::TYPE_STRING) {
229 printer_->Print("inline void @sora@_@name@(const std::string& str)\n",
230 "sora", field->is_repeated()?"add":"set",
231 "name", Tolowercase(field->name()));
232 printer_->Print("{\n");
233 printer_->Indent();
234 printer_->Print("AddBytes(FIELDID_@name@, str.data(), str.size());\n", "name", field->name());
235 printer_->Outdent();
236 printer_->Print("}\n");
237 printer_->Print("inline void @sora@_@name@(std::string&& str)\n",
238 "sora", field->is_repeated()?"add":"set",
239 "name", Tolowercase(field->name()));
240 printer_->Print("{\n");
241 printer_->Indent();
242 printer_->Print("AddBytes(FIELDID_@name@, str.data(), str.size());\n", "name", field->name());
243 printer_->Outdent();
244 printer_->Print("}\n");
245 printer_->Print("inline void @sora@_@name@(const char* str)\n",
246 "sora", field->is_repeated()?"add":"set",
247 "name", Tolowercase(field->name()));
248 printer_->Print("{\n");
249 printer_->Indent();
250 printer_->Print("AddBytes(FIELDID_@name@, str, strlen(str));\n", "name", field->name());
251 printer_->Outdent();
252 printer_->Print("}\n");
253 printer_->Print("inline void @sora@_@name@(const char* str, uint32_t len)\n",
254 "sora", field->is_repeated()?"add":"set",
255 "name", Tolowercase(field->name()));
256 printer_->Print("{\n");
257 printer_->Indent();
258 printer_->Print("AddBytes(FIELDID_@name@, str, len);\n", "name", field->name());
259 printer_->Outdent();
260 printer_->Print("}\n");
261 } else {
262 // varint, fix32, fix64
263 printer_->Print("inline void @sora@_@name@(@paramtype@ v)\n",
264 "sora", field->is_repeated()?"add":"set", "name", Tolowercase(field->name()),
265 "paramtype", GetParamType(field));
266 printer_->Print("{\n");
267 printer_->Indent();
268 printer_->Print("@type@(FIELDID_@name@, v);\n", "type",
269 GetInnerType(field), "name", field->name());
270 printer_->Outdent();
271 printer_->Print("}\n");
272 // packed
273 if (!field->is_repeated()) {
274 continue;
275 }
276 if (field->type() == FieldDescriptor::TYPE_SINT32 ||
277 field->type() == FieldDescriptor::TYPE_SINT64) {
278 perror("repeated signed(zigzag) fields are not supported in libprotobuf\n");
279 continue;
280 }
281 if (!field->is_packed()) {
282 continue;
283 }
284 printer_->Print("inline void add_@name@(const @paramtype@* array, uint32_t size)\n",
285 "name", Tolowercase(field->name()),
286 "paramtype", GetParamType(field));
287 printer_->Print("{\n");
288 printer_->Indent();
289 printer_->Print("@type@(FIELDID_@name@, array, size);\n",
290 "type", GetInnerType(field, true), "name", field->name());
291 printer_->Outdent();
292 printer_->Print("}\n");
293
294 printer_->Print("inline void add_@name@(const std::vector<@paramtype@>& array)\n",
295 "name", Tolowercase(field->name()),
296 "paramtype", GetParamType(field));
297 printer_->Print("{\n");
298 printer_->Indent();
299 printer_->Print("@type@(FIELDID_@name@, array.data(), array.size());\n",
300 "type", GetInnerType(field, true), "name", field->name());
301 printer_->Outdent();
302 printer_->Print("}\n");
303 }
304 }
305 }
306
GetParamType(const FieldDescriptor * field)307 static std::string GetParamType(const FieldDescriptor* field)
308 {
309 switch (field->type()) {
310 case FieldDescriptor::TYPE_BOOL:
311 return "bool";
312 case FieldDescriptor::TYPE_ENUM:
313 case FieldDescriptor::TYPE_UINT32:
314 case FieldDescriptor::TYPE_FIXED32:
315 return "uint32_t";
316 case FieldDescriptor::TYPE_INT32:
317 case FieldDescriptor::TYPE_SINT32:
318 case FieldDescriptor::TYPE_SFIXED32:
319 return "int32_t";
320 case FieldDescriptor::TYPE_INT64:
321 case FieldDescriptor::TYPE_SINT64:
322 case FieldDescriptor::TYPE_SFIXED64:
323 return "int64_t";
324 case FieldDescriptor::TYPE_UINT64:
325 case FieldDescriptor::TYPE_FIXED64:
326 return "uint64_t";
327 case FieldDescriptor::TYPE_DOUBLE:
328 return "double";
329 case FieldDescriptor::TYPE_FLOAT:
330 return "float";
331 case FieldDescriptor::TYPE_STRING:
332 case FieldDescriptor::TYPE_GROUP:
333 case FieldDescriptor::TYPE_MESSAGE:
334 case FieldDescriptor::TYPE_BYTES:
335 return "";
336 default:
337 return "";
338 }
339 return "";
340 }
341
GetInnerType(const FieldDescriptor * field,bool packed=false)342 static std::string GetInnerType(const FieldDescriptor* field, bool packed = false)
343 {
344 switch (field->type()) {
345 case FieldDescriptor::TYPE_BOOL:
346 case FieldDescriptor::TYPE_ENUM:
347 case FieldDescriptor::TYPE_INT32:
348 case FieldDescriptor::TYPE_INT64:
349 case FieldDescriptor::TYPE_UINT32:
350 case FieldDescriptor::TYPE_UINT64:
351 return packed ? "AddPackedVarint" : "AddVarint";
352 case FieldDescriptor::TYPE_SINT32:
353 case FieldDescriptor::TYPE_SINT64:
354 return "AddZigZagVarint";
355 case FieldDescriptor::TYPE_FIXED64:
356 case FieldDescriptor::TYPE_SFIXED64:
357 case FieldDescriptor::TYPE_DOUBLE:
358 return packed ? "AddPackedFixed" : "AddFixed64";
359 case FieldDescriptor::TYPE_FIXED32:
360 case FieldDescriptor::TYPE_SFIXED32:
361 case FieldDescriptor::TYPE_FLOAT:
362 return packed ? "AddPackedFixed" : "AddFixed32";
363 case FieldDescriptor::TYPE_STRING:
364 case FieldDescriptor::TYPE_GROUP:
365 case FieldDescriptor::TYPE_MESSAGE:
366 case FieldDescriptor::TYPE_BYTES:
367 return "";
368 default:
369 return "";
370 }
371 return "";
372 }
373
GenSurfix()374 void GenSurfix()
375 {
376 printer_->Print("} // namespace ProtoEncoder\n");
377 printer_->Print("} // namespace Profiler\n");
378 printer_->Print("} // namespace Developtools\n");
379 printer_->Print("} // namespace OHOS\n");
380 }
381
SetPrinter(Printer * stub_h_printer)382 void SetPrinter(Printer* stub_h_printer)
383 {
384 printer_ = stub_h_printer;
385 }
386 private:
387 std::string fileName_ = "";
388 std::string baseName_ = "";
389 std::string packageName_ = "";
390 std::string headFileName_ = "";
391 std::vector<std::string> namespaces_;
392 const FileDescriptor* const fileContent_;
393 std::vector<const Descriptor*> stack_;
394 std::vector<const EnumDescriptor*> enums_;
395 Printer* printer_;
396 };
397
ProtoEncoderGenerator()398 ProtoEncoderGenerator::ProtoEncoderGenerator() {}
399
~ProtoEncoderGenerator()400 ProtoEncoderGenerator::~ProtoEncoderGenerator() {}
401
Generate(const google::protobuf::FileDescriptor * file,const std::string & parameter,google::protobuf::compiler::GeneratorContext * context,std::string * error) const402 bool ProtoEncoderGenerator::Generate(const google::protobuf::FileDescriptor* file,
403 const std::string& parameter,
404 google::protobuf::compiler::GeneratorContext* context,
405 std::string* error) const
406 {
407 auto pcsp = std::make_shared<OptGeneratorImpl>(file);
408 std::string baseName = pcsp->SetNames(file->name(), file->package());
409 std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> headerOutput(context->Open(baseName +
410 ".pbencoder.h"));
411 std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> sourceOutput(context->Open(baseName +
412 ".pbencoder.cc"));
413 Printer hPrinter(headerOutput.get(), '@');
414 pcsp->SetPrinter(&hPrinter);
415 pcsp->GenHeader();
416
417 Printer ccPrinter(sourceOutput.get(), '@');
418 ccPrinter.Print("// empty\n");
419 return true;
420 }
421