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