1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
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 "util/options.h"
17
18#include <cstdio>
19#include <cstring>
20#include <dirent.h>
21#include <getopt.h>
22#include <sys/stat.h>
23#include <unistd.h>
24
25#include <map>
26
27#include "util/common.h"
28#include "util/file.h"
29#include "util/logger.h"
30#include "util/string_helper.h"
31#include "util/string_builder.h"
32
33namespace OHOS {
34namespace Idl {
35const char *Options::optSupportArgs = "hvcs:m:p:d:r:o:D:t:";
36static struct option g_longOpts[] = {
37    {"help",          no_argument,       nullptr, 'h'},
38    {"version",       no_argument,       nullptr, 'v'},
39    {"system",        required_argument, nullptr, 'S'},
40    {"mode",          required_argument, nullptr, 'm'},
41    {"gen-c",         no_argument,       nullptr, '1'},
42    {"gen-cpp",       no_argument,       nullptr, '2'},
43    {"gen-java",      no_argument,       nullptr, '3'},
44    {"gen-rust",      no_argument,       nullptr, '4'},
45    {"gen-ts",        no_argument,       nullptr, '5'},
46    {"package",       required_argument, nullptr, 'p'},
47    {"dump-ast",      no_argument,       nullptr, 'a'},
48    {"dump-metadata", no_argument,       nullptr, 'e'},
49    {"hash",          no_argument,       nullptr, 'H'},
50    {"log-domainid",  required_argument, nullptr, 'i'},
51    {"log-tag",       required_argument, nullptr, 'g'},
52    {"intf-type",     required_argument, nullptr, 'T'},
53    {nullptr,         0,                 nullptr,  0 }
54};
55
56Options &Options::GetInstance()
57{
58    static Options option;
59    return option;
60}
61
62bool Options::Parse(int argc, char *argv[])
63{
64    int ret = true;
65    program = argv[0];
66    opterr = 0;
67    int op = 0;
68    int optIndex = 0;
69
70    while ((op = getopt_long_only(argc, argv, optSupportArgs, g_longOpts, &optIndex)) != -1) {
71        if (optind > 0 && optind <= argc) {
72            ret = ParseSingle(op, std::string(argv[optind - 1]));
73        }
74    }
75
76    if (doCompile) {
77        int i = 0;
78        while (++i < argc) {
79            if (argv[i][0] != '-' && StringHelper::EndWith(argv[i], ".idl")) {
80                AddSources(argv[i]);
81            }
82        }
83    }
84
85    return ret ? CheckOptions() : ret;
86}
87
88bool Options::ParseSingle(int option, std::string optVal)
89{
90    bool ret = true;
91    switch (option) {
92        case 'h':
93            doShowUsage = true;
94            break;
95        case 'v':
96            doShowVersion = true;
97            break;
98        case 'a':
99            doDumpAST = true;
100            break;
101        case 'e':
102            doDumpMetadata = true;
103            break;
104        case 'H':
105            doHashKey = true;
106            break;
107        case 'c':
108            doCompile = true;
109            break;
110        case '1':
111            SetLanguage("c");
112            break;
113        case '2':
114            SetLanguage("cpp");
115            break;
116        case '3':
117            SetLanguage("java");
118            break;
119        case '4':
120            SetLanguage("rust");
121            break;
122        case '5':
123            SetLanguage("ts");
124            break;
125        default:
126            ret = ParseOptionWithValue(option, optVal);
127            break;
128    }
129    return ret;
130}
131
132bool Options::ParseOptionWithValue(int option, std::string optVal)
133{
134    bool ret = true;
135    StringBuilder errors;
136
137    switch (option) {
138        case 'o':
139            outPutFile = optarg;
140            break;
141        case 'S':
142            ret = SetSystemLevel(optarg);
143            break;
144        case 'm':
145            ret = SetGenerateMode(optarg);
146            break;
147        case 's':
148            SetMetadataFile(optarg);
149            break;
150        case 'p':
151            SetPackage(optarg);
152            break;
153        case 'D':
154            AddSourcesByDir(optarg);
155            break;
156        case 'd':
157            SetOutDir(optarg);
158            break;
159        case 'r':
160            ret = AddPackagePath(optarg);
161            break;
162        case 't':
163            ret = SetHiTrace(optarg);
164            break;
165        case 'i':
166            ret = SetLogDomainId(optarg);
167            break;
168        case 'g':
169            ret = SetLogTag(optarg);
170            break;
171        case 'T':
172            ret = SetInterfaceType(optarg);
173            break;
174        default:
175            errors.Append(optVal.c_str());
176            break;
177    }
178    illegalOptions = errors.ToString();
179    return ret;
180}
181
182bool Options::SetSystemLevel(const std::string &system)
183{
184    static std::map<std::string, SystemLevel> systemLevelMap = {
185        {"mini", SystemLevel::MINI},
186        {"lite", SystemLevel::LITE},
187        {"full", SystemLevel::FULL},
188    };
189
190    auto levelIter = systemLevelMap.find(system);
191    if (levelIter == systemLevelMap.end()) {
192        Logger::E(TAG, "invalid system level set: '%s', please input mini/lite/full", system.c_str());
193        return false;
194    }
195    systemLevel = levelIter->second;
196    return true;
197}
198
199bool Options::SetGenerateMode(const std::string &mode)
200{
201    static std::map<std::string, GenMode> codeGenMap = {
202        {"low", GenMode::LOW},
203        {"passthrough", GenMode::PASSTHROUGH},
204        {"ipc", GenMode::IPC},
205        {"kernel", GenMode::KERNEL},
206    };
207
208    auto codeGenIter = codeGenMap.find(mode);
209    if (codeGenIter == codeGenMap.end()) {
210        Logger::E(TAG, "invalid generate mode set: '%s', please input low/passthrough/ipc/kernel/sa.", mode.c_str());
211        return false;
212    }
213    genMode = codeGenIter->second;
214    return true;
215}
216
217bool Options::SetLanguage(const std::string &language)
218{
219    static const std::map<std::string, Language> languageMap = {
220        {"c", Language::C},
221        {"cpp", Language::CPP},
222        {"java", Language::JAVA},
223        {"rust", Language::RUST},
224        {"ts", Language::TS},
225    };
226
227    const auto kindIter = languageMap.find(language);
228    if (kindIter == languageMap.end()) {
229        Logger::E(TAG, "invalid language '%s', please input c, cpp, java, rust or ts", language.c_str());
230        return false;
231    }
232
233    doGenerateCode = true;
234    genLanguage = kindIter->second;
235    return true;
236}
237
238bool Options::SetMetadataFile(const std::string &file)
239{
240    doSaveMetadata = true;
241    metadataFile = file;
242    return true;
243}
244
245void Options::SetPackage(const std::string &infPackage)
246{
247    idlPackage = infPackage;
248}
249
250void Options::AddSources(const std::string &sourceFile)
251{
252    std::string realPath = File::AdapterRealPath(sourceFile);
253    if (realPath.empty()) {
254        Logger::E(TAG, "invalid idl file path:%s", sourceFile.c_str());
255        return;
256    }
257
258    if (sourceFiles.insert(realPath).second == false) {
259        Logger::E(TAG, "this idl file has been add:%s", sourceFile.c_str());
260        return;
261    }
262}
263
264void Options::AddSourcesByDir(const std::string &dir)
265{
266    sourceDir = dir;
267    std::set<std::string> files = File::FindFiles(sourceDir);
268    if (!files.empty()) {
269        doCompile = true;
270        sourceFiles.insert(files.begin(), files.end());
271    }
272}
273
274bool Options::AddPackagePath(const std::string &packagePath)
275{
276    size_t index = packagePath.find(":");
277    if (index == std::string::npos || index == packagePath.size() - 1) {
278        Logger::E(TAG, "invalid option parameters '%s'.", packagePath.c_str());
279        return false;
280    }
281
282    std::string package = packagePath.substr(0, index);
283    std::string path = File::AdapterRealPath(packagePath.substr(index + 1));
284    if (path.empty()) {
285        Logger::E(TAG, "invalid path '%s'.", packagePath.substr(index + 1).c_str());
286        return false;
287    }
288
289    auto it = packagePathMap.find(package);
290    if (it != packagePathMap.end()) {
291        Logger::E(TAG, "The '%s:%s' has been set.", package.c_str(), path.c_str());
292        return false;
293    }
294
295    packagePathMap[package] = path;
296    return true;
297}
298
299void Options::SetOutDir(const std::string &dir)
300{
301    doOutDir = true;
302    genDir = dir;
303}
304
305bool Options::CheckOptions()
306{
307    if (doShowUsage || doShowVersion) {
308        return true;
309    }
310    if (HasErrors()) {
311        ShowErrors();
312        return false;
313    }
314    if (interfaceType == InterfaceType::SA) {
315        return CheckSaOptions();
316    } else if (interfaceType == InterfaceType::HDI) {
317        return CheckHdiOptions();
318    } else if (interfaceType == InterfaceType::SM ||
319                interfaceType == InterfaceType::SAM ||
320                interfaceType == InterfaceType::SAM_SM ||
321                interfaceType == InterfaceType::SAM_UDS ||
322                interfaceType == InterfaceType::SM_UDS) {
323        return CheckSmOptions();
324    } else {
325        Logger::E(TAG, "Interface type 'intf-type' value '%d' invalid, please input 'hdi' or 'sa'.", interfaceType);
326        return false;
327    }
328}
329
330bool Options::CheckSaOptions()
331{
332    if (!DoSupportSaType()) {
333        return false;
334    }
335
336    if (sourceFiles.empty() && !DoSaveMetadata()) {
337        Logger::E(TAG, "Option 'intf-type sa' must set idl file.");
338        return false;
339    }
340
341    if (!DoLegalLog()) {
342        Logger::E(TAG, "Option 'log-domainid' and 'log-tag' must be used together.");
343        return false;
344    }
345
346    attribute.doHitrace = doHitrace;
347    attribute.hitraceTag = hitraceTag;
348    attribute.logTag = logTag;
349    attribute.domainId = domainId;
350    attribute.doLog = DoLogOn();
351
352    return true;
353}
354
355bool Options::DoSupportSaType()
356{
357    bool ret = true;
358    if (genLanguage != Language::CPP && genLanguage != Language::RUST && genLanguage != Language::TS) {
359        Logger::E(TAG, "Option 'intf-type sa' only support language option 'gen-cpp', 'gen-rust' or 'gen-ts'.");
360        ret = false;
361    }
362
363    if (systemLevel != SystemLevel::INIT) {
364        Logger::E(TAG, "Option 'intf-type sa' not support option 'system'.");
365        ret = false;
366    }
367
368    if (genMode != GenMode::INIT) {
369        Logger::E(TAG, "Option 'intf-type sa' not support option 'm' or 'mode'.");
370        ret = false;
371    }
372
373    if (!idlPackage.empty()) {
374        Logger::E(TAG, "Option 'intf-type sa' not support option 'p' or 'package'.");
375        ret = false;
376    }
377
378    if (doHashKey) {
379        Logger::E(TAG, "Option 'intf-type sa' not support option 'hash'.");
380        ret = false;
381    }
382
383    if (!packagePathMap.empty()) {
384        Logger::E(TAG, "Option 'intf-type sa' not support option 'r'.");
385        ret = false;
386    }
387
388    if (!sourceDir.empty()) {
389        Logger::E(TAG, "Option 'intf-type sa' not support option 'D'.");
390        ret = false;
391    }
392
393    if (!outPutFile.empty()) {
394        Logger::E(TAG, "Option 'intf-type sa' not support option 'o'.");
395        ret = false;
396    }
397
398    if (!ret) {
399        printf("Use \"-h, --help\" to show usage.\n");
400    }
401    return ret;
402}
403
404bool Options::CheckHdiOptions()
405{
406    SetHdiDefaultOption();
407    if (!DoSupportHdiType()) {
408        return false;
409    }
410
411    if (doCompile) {
412        if (!DoGetHashKey() && !doDumpAST && !doGenerateCode && !doOutDir) {
413            Logger::E(TAG, "nothing to do.");
414            return false;
415        }
416
417        if (!doGenerateCode && doOutDir) {
418            Logger::E(TAG, "no target language.");
419            return false;
420        }
421
422        if (doGenerateCode && !doOutDir) {
423            Logger::E(TAG, "no out directory.");
424            return false;
425        }
426    } else {
427        if (DoGetHashKey() || doDumpAST || doGenerateCode || doOutDir) {
428            Logger::E(TAG, "no idl files.");
429            return false;
430        }
431    }
432
433    return true;
434}
435
436void Options::SetHdiDefaultOption()
437{
438    if (systemLevel == SystemLevel::INIT) {
439        systemLevel = SystemLevel::FULL;
440    }
441    if (genMode == GenMode::INIT) {
442        genMode = GenMode::IPC;
443    }
444    return;
445}
446
447bool Options::DoSupportHdiType()
448{
449    bool ret = true;
450
451    if (genLanguage != Language::C && genLanguage != Language::CPP && genLanguage != Language::JAVA) {
452        Logger::E(TAG, "Option 'intf-type hdi' only support language option 'gen-c', 'gen-cpp' or 'gen-java'.");
453        ret = false;
454    }
455
456    if (doDumpMetadata) {
457        Logger::E(TAG, "Option 'intf-type hdi' not support option 'dump-metadata'.");
458        ret = false;
459    }
460
461    if (doKeywords) {
462        Logger::E(TAG, "Option 'intf-type hdi' not support option '-t', '-log-domainid' or '-log-tag'.");
463        ret = false;
464    }
465
466    if (doSaveMetadata) {
467        Logger::E(TAG, "Option 'intf-type hdi' not support option '-s'.");
468        ret = false;
469    }
470
471    if (!ret) {
472        printf("Use \"-h, --help\" to show usage.\n");
473    }
474    return ret;
475}
476
477bool Options::DoSupportSmType()
478{
479    bool ret = true;
480
481    if (genLanguage != Language::CPP && genLanguage != Language::JAVA) {
482        Logger::E(TAG, "Option 'intf-type sm' only support language option 'gen-cpp' or 'gen-java'.");
483        ret = false;
484    }
485
486    if (doDumpMetadata) {
487        Logger::E(TAG, "Option 'intf-type sm' not support option 'dump-metadata'.");
488        ret = false;
489    }
490
491    if (doKeywords) {
492        Logger::E(TAG, "Option 'intf-type sm' not support option '-t', '-log-domainid' or '-log-tag'.");
493        ret = false;
494    }
495
496    if (doSaveMetadata) {
497        Logger::E(TAG, "Option 'intf-type sm' not support option '-s'.");
498        ret = false;
499    }
500
501    if (!ret) {
502        printf("Use \"-h, --help\" to show usage.\n");
503    }
504    return ret;
505}
506
507void Options::SetSmDefaultOption()
508{
509    systemLevel = SystemLevel::INIT;
510    genMode = GenMode::INIT;
511    return;
512}
513
514bool Options::CheckSmOptions()
515{
516    SetSmDefaultOption();
517    if (!DoSupportSmType()) {
518        return false;
519    }
520
521    if (doCompile) {
522        if (!DoGetHashKey() && !doDumpAST && !doGenerateCode && !doOutDir) {
523            Logger::E(TAG, "nothing to do.");
524            return false;
525        }
526
527        if (!doGenerateCode && doOutDir) {
528            Logger::E(TAG, "no target language.");
529            return false;
530        }
531
532        if (doGenerateCode && !doOutDir) {
533            Logger::E(TAG, "no out directory.");
534            return false;
535        }
536    } else {
537        if (DoGetHashKey() || doDumpAST || doGenerateCode || doOutDir) {
538            Logger::E(TAG, "no idl files.");
539            return false;
540        }
541    }
542
543    return true;
544}
545
546bool Options::SetHiTrace(const std::string &tag)
547{
548    doKeywords = true;
549    hitraceTag = tag;
550    doHitrace = true;
551    return true;
552}
553
554bool Options::SetLogDomainId(const std::string &id)
555{
556    doKeywords = true;
557    domainId = id;
558    return true;
559}
560
561bool Options::SetLogTag(const std::string &tag)
562{
563    doKeywords = true;
564    logTag = tag;
565    return true;
566}
567
568bool Options::SetInterfaceType(const std::string &type)
569{
570    static std::map<std::string, InterfaceType> Type = {
571        {"hdi", InterfaceType::HDI},
572        {"sa", InterfaceType::SA},
573        {"sm", InterfaceType::SM},
574        {"sam", InterfaceType::SAM},
575        {"sam_sm", InterfaceType::SAM_SM},
576        {"sam_uds", InterfaceType::SAM_UDS},
577        {"sm_uds", InterfaceType::SM_UDS},
578    };
579
580    auto codeGenIter = Type.find(type);
581    if (codeGenIter == Type.end()) {
582        Logger::E(TAG, "invalid interface type set: '%s', please input hdi/sa.", type.c_str());
583        return false;
584    }
585    interfaceType = codeGenIter->second;
586    return true;
587}
588
589bool Options::DoLogOn() const
590{
591    if (!domainId.empty() && !logTag.empty()) {
592        return true;
593    }
594    return false;
595}
596
597bool Options::DoLegalLog() const
598{
599    if (genLanguage == Language::CPP) {
600        if (!domainId.empty() && !logTag.empty()) {
601            return true;
602        } else if (domainId.empty() && logTag.empty()) {
603            return true;
604        } else {
605            return false;
606        }
607    }
608    return true;
609}
610
611bool Options::HasErrors() const
612{
613    return !illegalOptions.empty();
614}
615
616void Options::ShowErrors() const
617{
618    std::vector<std::string> illegalOptionsVec = StringHelper::Split(illegalOptions, " ");
619    for (size_t i = 0; i < illegalOptionsVec.size(); i++) {
620        Logger::E(TAG, "The Option \"%s\" is illegal.", illegalOptionsVec[i].c_str());
621    }
622    printf("Use \"-h, --help\" to show usage.\n");
623    return;
624}
625
626bool Options::HasWarning() const
627{
628    if (interfaceType == InterfaceType::SA) {
629        if (genLanguage == Language::RUST || genLanguage == Language::TS) {
630            if (DoSearchKeywords()) {
631                return true;
632            }
633        }
634    }
635    return false;
636}
637
638void Options::ShowWarning() const
639{
640    printf("Warning : Executed successfully, but contains invalid commands !\n");
641}
642
643void Options::ShowVersion() const
644{
645    printf("idl %d.%d\n"
646          "Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.\n\n",
647           VERSION_MAJOR, VERSION_MINOR);
648}
649
650void Options::ShowUsage() const
651{
652    printf("Compile a .idl file and generate C/C++/Ts/Rust and Java codes.\n"
653           "Usage: idl [options] file\n"
654           "Options:\n"
655           "  -h, --help                      Display command line options\n"
656           "  -v, --version                   Display toolchain version information\n"
657           "      --system <value>            Set system level 'mini','lite' or 'full', the default value is 'full', "
658           "only support 'intf-type hdi'\n"
659           "  -m, --mode <value>              Set generate code mode 'low', 'passthrough', 'ipc' or 'kernel',"
660           " the default value is 'ipc', only support 'intf-type hdi'\n"
661           "  -p, --package <package name>    Set package of idl files, only support 'intf-type hdi'\n"
662           "      --dump-ast                  Display the AST of the compiled file\n"
663           "      --dump-metadata             Display the metadata generated from the compiled file, "
664           "only support 'intf-type sa'\n"
665           "      --hash                      Generate hash info of idl files, only support 'intf-type hdi'\n"
666           "  -r <rootPackage>:<rootPath>     Set root path of root package, only support 'intf-type hdi'\n"
667           "  -c                              Compile the .idl file\n"
668           "  -D <directory>                  Directory of the idl file, only support 'intf-type hdi'\n"
669           "  -d <directory>                  Place generated codes into <directory>\n"
670           "  -o <file>                       Place the output into <file>, only support 'intf-type hdi'\n"
671           "  -s <file>                       Place the metadata into <file>, only support 'intf-type sa'\n"
672           "      --gen-c                     Generate C codes, only support 'intf-type hdi'\n"
673           "      --gen-cpp                   Generate C++ codes\n"
674           "      --gen-java                  Generate Java codes, only support 'intf-type hdi'\n"
675           "      --gen-rust                  Generate Rust codes, only support 'intf-type sa'\n"
676           "      --gen-ts                    Generate Ts codes, only support 'intf-type sa'\n"
677           "      --log-domainid <domainid>   Place the service domain in <domainid>, Enable log(Pair with -log-tag), "
678           "only support 'intf-type sa'\n"
679           "      --log-tag <tag>             Place the subsystem name in <tag>, Enable log(Pair with -log-domainid), "
680           "only support 'intf-type sa'\n"
681           "  -t <hitrace tag>                Place the constant name from hitrace_meter.h file in <hitrace tag>, "
682           "only support 'intf-type sa'\n"
683           "      --intf-type <tag>           Set type of generated codes 'sa' or 'hdi', default type is 'sa'\n");
684}
685
686/*
687 * -r option: -r ohos.hdi:./drivers/interface
688 * package:ohos.hdi.foo.v1_0
689 * rootPackage:ohos.hdi
690 */
691std::string Options::GetRootPackage(const std::string &package) const
692{
693    const auto &packagePaths = GetPackagePathMap();
694    for (const auto &packageRoot : packagePaths) {
695        if (StringHelper::StartWith(package, packageRoot.first)) {
696            return packageRoot.first;
697        }
698    }
699
700    return "";
701}
702
703/*
704 * -r option: -r ohos.hdi:./drivers/interface
705 * package:ohos.hdi.foo.v1_0
706 * rootPath:./drivers/interface
707 */
708std::string Options::GetRootPath(const std::string &package) const
709{
710    const auto &packagePaths = GetPackagePathMap();
711    for (const auto &packageRoot : packagePaths) {
712        if (StringHelper::StartWith(package, packageRoot.first)) {
713            return packageRoot.second;
714        }
715    }
716
717    return "";
718}
719
720/*
721 * -r option: -r ohos.hdi:./drivers/interface
722 * package:ohos.hdi.foo.v1_0
723 * subPackage:foo.v1_0
724 */
725std::string Options::GetSubPackage(const std::string &package) const
726{
727    if (interfaceType == InterfaceType::SM ||
728        interfaceType == InterfaceType::SM_UDS) {
729        return package;
730    }
731    std::string rootPackage = GetRootPackage(package);
732    if (rootPackage.empty()) {
733        return package;
734    }
735
736    return package.substr(rootPackage.size() + 1);
737}
738
739/*
740 * -r option: -r ohos.hdi:./drivers/interface
741 * package:ohos.hdi.foo.v1_0
742 * packagePath:./drivers/interface/foo/v1_0
743 */
744std::string Options::GetPackagePath(const std::string &package) const
745{
746    std::string rootPackage = "";
747    std::string rootPath = "";
748    const auto &packagePaths = GetPackagePathMap();
749    for (const auto &packageRoot : packagePaths) {
750        if (StringHelper::StartWith(package, packageRoot.first)) {
751            rootPackage = packageRoot.first;
752            rootPath = packageRoot.second;
753        }
754    }
755
756    if (rootPackage.empty()) {
757        // The current path is the root path
758        std::string curPath = File::AdapterPath(StringHelper::Replace(package, '.', SEPARATOR));
759        return File::AdapterRealPath(curPath);
760    }
761
762    if (StringHelper::EndWith(rootPath, SEPARATOR)) {
763        rootPath.pop_back();
764    }
765
766    std::string subPath = StringHelper::Replace(package.substr(rootPackage.size() + 1), '.', SEPARATOR);
767    return File::AdapterPath(rootPath + "/" + subPath);
768}
769
770/*
771 * -r option: -r ohos.hdi:./drivers/interface
772 * import: ohos.hdi.foo.v1_0.MyTypes
773 * packagePath:./drivers/interface/foo/v1_0/MyTypes.idl
774 */
775std::string Options::GetImportFilePath(const std::string &import) const
776{
777    size_t index = import.rfind('.');
778    if (index == std::string::npos) {
779        return import;
780    }
781
782    std::string dir = GetPackagePath(StringHelper::SubStr(import, 0, index));
783    std::string className = import.substr(index + 1);
784    return StringHelper::Format("%s%c%s.idl", dir.c_str(), SEPARATOR, className.c_str());
785}
786} // namespace Idl
787} // namespace OHOS