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 
33 namespace OHOS {
34 namespace Idl {
35 const char *Options::optSupportArgs = "hvcs:m:p:d:r:o:D:t:";
36 static 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 
GetInstance()56 Options &Options::GetInstance()
57 {
58     static Options option;
59     return option;
60 }
61 
Parse(int argc,char * argv[])62 bool 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 
ParseSingle(int option,std::string optVal)88 bool 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 
ParseOptionWithValue(int option,std::string optVal)132 bool 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 
SetSystemLevel(const std::string & system)182 bool 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 
SetGenerateMode(const std::string & mode)199 bool 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 
SetLanguage(const std::string & language)217 bool 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 
SetMetadataFile(const std::string & file)238 bool Options::SetMetadataFile(const std::string &file)
239 {
240     doSaveMetadata = true;
241     metadataFile = file;
242     return true;
243 }
244 
SetPackage(const std::string & infPackage)245 void Options::SetPackage(const std::string &infPackage)
246 {
247     idlPackage = infPackage;
248 }
249 
AddSources(const std::string & sourceFile)250 void 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 
AddSourcesByDir(const std::string & dir)264 void 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 
AddPackagePath(const std::string & packagePath)274 bool 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 
SetOutDir(const std::string & dir)299 void Options::SetOutDir(const std::string &dir)
300 {
301     doOutDir = true;
302     genDir = dir;
303 }
304 
CheckOptions()305 bool 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 
CheckSaOptions()330 bool 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 
DoSupportSaType()355 bool 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 
CheckHdiOptions()404 bool 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 
SetHdiDefaultOption()436 void 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 
DoSupportHdiType()447 bool 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 
DoSupportSmType()477 bool 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 
SetSmDefaultOption()507 void Options::SetSmDefaultOption()
508 {
509     systemLevel = SystemLevel::INIT;
510     genMode = GenMode::INIT;
511     return;
512 }
513 
CheckSmOptions()514 bool 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 
SetHiTrace(const std::string & tag)546 bool Options::SetHiTrace(const std::string &tag)
547 {
548     doKeywords = true;
549     hitraceTag = tag;
550     doHitrace = true;
551     return true;
552 }
553 
SetLogDomainId(const std::string & id)554 bool Options::SetLogDomainId(const std::string &id)
555 {
556     doKeywords = true;
557     domainId = id;
558     return true;
559 }
560 
SetLogTag(const std::string & tag)561 bool Options::SetLogTag(const std::string &tag)
562 {
563     doKeywords = true;
564     logTag = tag;
565     return true;
566 }
567 
SetInterfaceType(const std::string & type)568 bool 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 
DoLogOn() const589 bool Options::DoLogOn() const
590 {
591     if (!domainId.empty() && !logTag.empty()) {
592         return true;
593     }
594     return false;
595 }
596 
DoLegalLog() const597 bool 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 
HasErrors() const611 bool Options::HasErrors() const
612 {
613     return !illegalOptions.empty();
614 }
615 
ShowErrors() const616 void 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 
HasWarning() const626 bool 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 
ShowWarning() const638 void Options::ShowWarning() const
639 {
640     printf("Warning : Executed successfully, but contains invalid commands !\n");
641 }
642 
ShowVersion() const643 void 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 
ShowUsage() const650 void 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  */
GetRootPackage(const std::string & package) const691 std::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  */
GetRootPath(const std::string & package) const708 std::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  */
GetSubPackage(const std::string & package) const725 std::string Options::GetSubPackage(const std::string &package) const
726 {
727     std::string rootPackage = GetRootPackage(package);
728     if (rootPackage.empty()) {
729         return package;
730     }
731 
732     return package.substr(rootPackage.size() + 1);
733 }
734 
735 /*
736  * -r option: -r ohos.hdi:./drivers/interface
737  * package:ohos.hdi.foo.v1_0
738  * packagePath:./drivers/interface/foo/v1_0
739  */
GetPackagePath(const std::string & package) const740 std::string Options::GetPackagePath(const std::string &package) const
741 {
742     std::string rootPackage = "";
743     std::string rootPath = "";
744     const auto &packagePaths = GetPackagePathMap();
745     for (const auto &packageRoot : packagePaths) {
746         if (StringHelper::StartWith(package, packageRoot.first)) {
747             rootPackage = packageRoot.first;
748             rootPath = packageRoot.second;
749         }
750     }
751 
752     if (rootPackage.empty()) {
753         // The current path is the root path
754         std::string curPath = File::AdapterPath(StringHelper::Replace(package, '.', SEPARATOR));
755         return File::AdapterRealPath(curPath);
756     }
757 
758     if (StringHelper::EndWith(rootPath, SEPARATOR)) {
759         rootPath.pop_back();
760     }
761 
762     std::string subPath = StringHelper::Replace(package.substr(rootPackage.size() + 1), '.', SEPARATOR);
763     return File::AdapterPath(rootPath + "/" + subPath);
764 }
765 
766 /*
767  * -r option: -r ohos.hdi:./drivers/interface
768  * import: ohos.hdi.foo.v1_0.MyTypes
769  * packagePath:./drivers/interface/foo/v1_0/MyTypes.idl
770  */
GetImportFilePath(const std::string & import) const771 std::string Options::GetImportFilePath(const std::string &import) const
772 {
773     size_t index = import.rfind('.');
774     if (index == std::string::npos) {
775         return import;
776     }
777 
778     std::string dir = GetPackagePath(StringHelper::SubStr(import, 0, index));
779     std::string className = import.substr(index + 1);
780     return StringHelper::Format("%s%c%s.idl", dir.c_str(), SEPARATOR, className.c_str());
781 }
782 } // namespace Idl
783 } // namespace OHOS