• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_reader_plugin.h"
17 #include "string_help.h"
18 namespace SysTuning {
19 namespace ProtoReader {
20 const std::string SYS_NAMESPACE = "SysTuning";
21 const int32_t MIN_OPTIONS_SIZE = 2;
22 
Generate(const FileDescriptor * file,const std::string & options,GeneratorContext * context,std::string * error) const23 bool ProtoReaderPlugin::Generate(const FileDescriptor *file,
24                                  const std::string &options,
25                                  GeneratorContext *context,
26                                  std::string *error) const
27 {
28     std::string newFileName = file->name().substr(0, file->name().find("proto")) + "pbreader";
29     const std::unique_ptr<ZeroCopyOutputStream> generateFile(context->Open(newFileName + ".h"));
30     Printer generatePrinterHead(generateFile.get(), '$');
31     ProtoReaderGenerator protoReaderGenerator(file, &generatePrinterHead);
32     std::vector<std::string> option = base::SplitStringToVec(const_cast<std::string &>(options), "=");
33     if (option.size() < MIN_OPTIONS_SIZE) {
34         return false;
35     }
36     if (option[0] == "wrapper_namespace") {
37         protoReaderGenerator.wrapperNamespace_ = option[1];
38     }
39     if (!protoReaderGenerator.WriteProtoReader()) {
40         *error = protoReaderGenerator.GetError();
41         return false;
42     }
43     return true;
44 }
45 
WriteProtoReader()46 bool ProtoReaderGenerator::WriteProtoReader()
47 {
48     GetPBReaderInfo();
49     WriteBegin();
50     for (const EnumDescriptor *enumDescriptor : vEnumDescriptor_) {
51         WriteEnumDescriptor(enumDescriptor);
52     }
53 
54     for (const Descriptor *descriptor : vDescriptor_) {
55         WriteDecoder(descriptor);
56     }
57     WriteEnd();
58     return error_.empty();
59 }
ParserDescriptors()60 void ProtoReaderGenerator::ParserDescriptors()
61 {
62     std::vector<const Descriptor *> vDescriptor;
63     vDescriptor.reserve(static_cast<size_t>(fileDescriptor_->message_type_count()));
64     for (int32_t i = 0; i < fileDescriptor_->message_type_count(); ++i) {
65         vDescriptor.push_back(fileDescriptor_->message_type(i));
66     }
67 
68     while (!vDescriptor.empty()) {
69         const Descriptor *descriptor = vDescriptor.back();
70         vDescriptor.pop_back();
71         vDescriptor_.push_back(descriptor);
72         for (int32_t i = 0; i < descriptor->nested_type_count(); ++i) {
73             vDescriptor.push_back(descriptor->nested_type(i));
74         }
75     }
76 
77     for (int32_t i = 0; i < fileDescriptor_->enum_type_count(); ++i) {
78         vEnumDescriptor_.push_back(fileDescriptor_->enum_type(i));
79     }
80 
81     for (const Descriptor *descriptor : vDescriptor_) {
82         for (int32_t i = 0; i < descriptor->enum_type_count(); ++i) {
83             vEnumDescriptor_.push_back(descriptor->enum_type(i));
84         }
85     }
86 }
87 
ParserDependencies()88 void ProtoReaderGenerator::ParserDependencies()
89 {
90     for (int32_t i = 0; i < fileDescriptor_->public_dependency_count(); ++i) {
91         publicImports_.insert(fileDescriptor_->public_dependency(i));
92     }
93 
94     std::vector<const FileDescriptor *> vFileDescriptor;
95     for (int32_t i = 0; i < fileDescriptor_->dependency_count(); ++i) {
96         const FileDescriptor *fileDescriptor = fileDescriptor_->dependency(i);
97         vFileDescriptor.push_back(fileDescriptor);
98     }
99 
100     for (const FileDescriptor *fileDescriptor : vFileDescriptor) {
101         for (int32_t i = 0; i < fileDescriptor->public_dependency_count(); ++i) {
102             vFileDescriptor.push_back(fileDescriptor->public_dependency(i));
103         }
104     }
105 
106     for (const Descriptor *descriptor : vDescriptor_) {
107         for (int32_t i = 0; i < descriptor->field_count(); ++i) {
108             if (descriptor->field(i)->type() == FieldDescriptor::TYPE_MESSAGE) {
109                 if (!publicImports_.count(descriptor->field(i)->message_type()->file())) {
110                     referencedMessages_.insert(descriptor->field(i)->message_type());
111                 }
112             } else if (descriptor->field(i)->type() == FieldDescriptor::TYPE_ENUM) {
113                 if (!publicImports_.count(descriptor->field(i)->enum_type()->file())) {
114                     referencedEnums_.insert(descriptor->field(i)->enum_type());
115                 }
116             }
117         }
118     }
119 }
120 
ParserNamespace()121 void ProtoReaderGenerator::ParserNamespace()
122 {
123     vNamespaces_.push_back(SYS_NAMESPACE);
124     if (!wrapperNamespace_.empty()) {
125         vNamespaces_.push_back(wrapperNamespace_);
126     }
127 
128     fullNamespacePrefix_ = "::";
129     for (const std::string &namespaces : vNamespaces_)
130         fullNamespacePrefix_ += namespaces + "::";
131 }
132 
GetPBReaderInfo()133 void ProtoReaderGenerator::GetPBReaderInfo()
134 {
135     ParserNamespace();
136     ParserDescriptors();
137     ParserDependencies();
138 }
139 
WriteBegin()140 void ProtoReaderGenerator::WriteBegin()
141 {
142     std::string notify = "// Autogenerated by the ProtoReader plugin. DO NOT EDIT.\n";
143     std::string fileDefinded = fileDescriptor_->name() + "_H";
144     fileDefinded = ToUppercase(fileDefinded);
145     fileDefinded_ = fileDefinded.replace(fileDefinded.find("."), 1, "_");
146 
147     codePrinter_->Print(
148         "$notify$\n"
149         "#ifndef $fileDefinded$\n"
150         "#define $fileDefinded$\n\n"
151         "#include <stddef.h>\n"
152         "#include <stdint.h>\n\n"
153         "#include \"proto_reader/include/proto_reader.h\"\n"
154         "#include \"proto_reader/include/data_area.h\"\n",
155         "notify", notify, "fileDefinded", fileDefinded_);
156     codePrinter_->Print("\n");
157 
158     for (const std::string &tsNamespace : vNamespaces_) {
159         codePrinter_->Print("namespace $namespace$ {\n", "namespace", tsNamespace);
160     }
161     codePrinter_->Print("\n");
162 
163     for (const Descriptor *descriptor : referencedMessages_) {
164         codePrinter_->Print("class $class$;\n", "class", GetDescriptorClass(descriptor));
165     }
166     for (const EnumDescriptor *enumDescriptor : referencedEnums_) {
167         codePrinter_->Print("enum $class$ : int32_t;\n", "class", GetDescriptorClass(enumDescriptor));
168     }
169     codePrinter_->Print("\n");
170 }
171 
WriteEnumDescriptor(const EnumDescriptor * enumDescriptor)172 void ProtoReaderGenerator::WriteEnumDescriptor(const EnumDescriptor *enumDescriptor)
173 {
174     codePrinter_->Print("enum $class$ : int32_t {\n", "class", GetDescriptorClass(enumDescriptor));
175     codePrinter_->Indent();
176 
177     std::string minName = "";
178     std::string maxName = "";
179     int32_t minNum = std::numeric_limits<int32_t>::max();
180     int32_t maxNum = -1;
181 
182     std::string containingName;
183     if (enumDescriptor->containing_type() != nullptr) {
184         containingName = GetDescriptorClass(enumDescriptor) + "_";
185     }
186 
187     for (int32_t i = 0; i < enumDescriptor->value_count(); ++i) {
188         codePrinter_->Print("$name$ = $number$,\n", "name", containingName + enumDescriptor->value(i)->name(), "number",
189                             std::to_string(enumDescriptor->value(i)->number()));
190         if (enumDescriptor->value(i)->number() < minNum) {
191             minNum = enumDescriptor->value(i)->number();
192             minName = containingName + enumDescriptor->value(i)->name();
193         }
194         if (enumDescriptor->value(i)->number() > maxNum) {
195             maxNum = enumDescriptor->value(i)->number();
196             maxName = containingName + enumDescriptor->value(i)->name();
197         }
198     }
199     codePrinter_->Outdent();
200     codePrinter_->Print("};\n\n");
201     codePrinter_->Print("const $class$ $class$_MIN = $min$;\n", "class", GetDescriptorClass(enumDescriptor), "min",
202                         minName);
203     codePrinter_->Print("const $class$ $class$_MAX = $max$;\n", "class", GetDescriptorClass(enumDescriptor), "max",
204                         maxName);
205     codePrinter_->Print("\n");
206 }
207 
WriteDecoder(const Descriptor * descriptor)208 void ProtoReaderGenerator::WriteDecoder(const Descriptor *descriptor)
209 {
210     int32_t maxFieldID = 0;
211     for (int32_t i = 0; i < descriptor->field_count(); ++i) {
212         const FieldDescriptor *field = descriptor->field(i);
213         maxFieldID = std::max(maxFieldID, field->number());
214     }
215     std::string className = GetDescriptorClass(descriptor) + "_Reader";
216     codePrinter_->Print(
217         "class $name$ : public "
218         "TypedProtoReader<$maxDataAreaID$> {\n",
219         "name", className, "maxDataAreaID", std::to_string(maxFieldID));
220     codePrinter_->Print(" public:\n");
221     maxFieldID = 1 + maxFieldID;
222     WriteEnum(descriptor);
223     codePrinter_->Indent();
224     codePrinter_->Print(
225         "$name$(const uint8_t* data, size_t len) "
226         ": TypedProtoReader(data, len) {}\n",
227         "name", className);
228     codePrinter_->Print(
229         "explicit $name$(const std::string& raw) : "
230         "TypedProtoReader(reinterpret_cast<const uint8_t*>(raw.data()), "
231         "raw.size()) {}\n",
232         "name", className);
233     codePrinter_->Print(
234         "explicit $name$(const BytesView& raw) : "
235         "TypedProtoReader(raw.data_, raw.size_) {}\n",
236         "name", className);
237     WriteFunc(descriptor, maxFieldID);
238     codePrinter_->Outdent();
239     codePrinter_->Print("};\n\n");
240 }
241 
WriteEnum(const Descriptor * descriptor)242 void ProtoReaderGenerator::WriteEnum(const Descriptor *descriptor)
243 {
244     if (descriptor->field_count()) {
245         codePrinter_->Print("enum : int32_t {\n");
246         codePrinter_->Indent();
247 
248         for (int32_t i = 0; i < descriptor->field_count(); ++i) {
249             const FieldDescriptor *field = descriptor->field(i);
250             codePrinter_->Print("$name$ = $id$,\n", "name", GetFieldNumberConstant(field), "id",
251                                 std::to_string(field->number()));
252         }
253         codePrinter_->Outdent();
254         codePrinter_->Print("};\n");
255     }
256 }
257 
WriteFunc(const Descriptor * descriptor,const int32_t maxFieldID)258 void ProtoReaderGenerator::WriteFunc(const Descriptor *descriptor, const int32_t maxFieldID)
259 {
260     for (int32_t i = 0; i < descriptor->field_count(); ++i) {
261         const FieldDescriptor *field = descriptor->field(i);
262         if (field->number() > maxFieldID) {
263             codePrinter_->Print("// dataArea $name$ exceeded the maximum\n", "name", field->name());
264             continue;
265         }
266         TypeDesc typeDesc{};
267         auto t = fieldTypeDesc_.find(field->type());
268         if (t != fieldTypeDesc_.end()) {
269             typeDesc = t->second;
270         }
271         std::string toFunc = typeDesc.toFunc;
272         std::string type = typeDesc.type;
273         codePrinter_->Print("bool has_$name$() const { return at<$id$>().DataAreaValid(); }\n", "name",
274                             field->lowercase_name(), "id", std::to_string(field->number()));
275         if (field->is_packed()) {
276             TypeDesc fieldTypeDesc{};
277             auto fieldType = fieldTypeDesc_.find(field->type());
278             if (fieldType != fieldTypeDesc_.end()) {
279                 fieldTypeDesc = fieldType->second;
280             }
281             const char *protoReaderWireType = fieldTypeDesc.packedBufferType.c_str();
282             codePrinter_->Print(
283                 "PackedRepeatedDataAreaIterator<ProtoWireType::$protoReaderWireType$, $type$> "
284                 "$name$(bool* parseErrorInfo) const { return "
285                 "GetPackedRepeated<ProtoWireType::$protoReaderWireType$, $type$>($id$, "
286                 "parseErrorInfo); }\n",
287                 "protoReaderWireType", protoReaderWireType, "type", type, "name", field->lowercase_name(), "id",
288                 std::to_string(field->number()));
289         } else if (field->is_repeated()) {
290             codePrinter_->Print(
291                 "RepeatedDataAreaIterator<$type$> $name$() const { "
292                 "return "
293                 "ProtoReaderBase::GetRepeated<$type$>($id$); }\n",
294                 "name", field->lowercase_name(), "type", type, "id", std::to_string(field->number()));
295         } else {
296             codePrinter_->Print("$type$ $name$() const { return at<$id$>().$toFunc$(); }\n", "name",
297                                 field->lowercase_name(), "id", std::to_string(field->number()), "type", type, "toFunc",
298                                 toFunc);
299         }
300     }
301 }
302 
WriteEnd()303 void ProtoReaderGenerator::WriteEnd()
304 {
305     for (uint32_t i = vNamespaces_.size(); i > 0; --i) {
306         codePrinter_->Print("} // namespace $namespace$\n", "namespace", vNamespaces_.at(i - 1));
307     }
308     codePrinter_->Print("#endif // $fileDefinded$\n", "fileDefinded", fileDefinded_);
309 }
310 
GetFieldNumberConstant(const FieldDescriptor * field)311 std::string ProtoReaderGenerator::GetFieldNumberConstant(const FieldDescriptor *field)
312 {
313     std::string name = field->camelcase_name();
314     if (!name.empty()) {
315         name.at(0) = Uppercase(name.at(0));
316         name = "k" + name + "DataAreaNumber";
317         return name;
318     }
319     return "";
320 }
321 } // namespace ProtoReader
322 } // namespace SysTuning
323 
main(int argc,char * argv[])324 int main(int argc, char *argv[])
325 {
326     SysTuning::ProtoReader::ProtoReaderPlugin protoReaderGenerate;
327     return google::protobuf::compiler::PluginMain(argc, argv, &protoReaderGenerate);
328 }
329