• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "cmd_parser.h"
17 #include <algorithm>
18 #include "resconfig_parser.h"
19 #include "resource_util.h"
20 #include "select_compile_parse.h"
21 
22 namespace OHOS {
23 namespace Global {
24 namespace Restool {
25 using namespace std;
26 const struct option PackageParser::CMD_OPTS[] = {
27     { "inputPath", required_argument, nullptr, Option::INPUTPATH },
28     { "packageName", required_argument, nullptr, Option::PACKAGENAME },
29     { "outputPath", required_argument, nullptr, Option::OUTPUTPATH },
30     { "resHeader", required_argument, nullptr, Option::RESHEADER },
31     { "forceWrite", no_argument, nullptr, Option::FORCEWRITE },
32     { "version", no_argument, nullptr, Option::VERSION},
33     { "modules", required_argument, nullptr, Option::MODULES },
34     { "json", required_argument, nullptr, Option::JSON },
35     { "startId", required_argument, nullptr, Option::STARTID },
36     { "fileList", required_argument, nullptr, Option::FILELIST },
37     { "append", required_argument, nullptr, Option::APPEND },
38     { "combine", required_argument, nullptr, Option::COMBINE },
39     { "dependEntry", required_argument, nullptr, Option::DEPENDENTRY },
40     { "help", no_argument, nullptr, Option::HELP},
41     { "ids", required_argument, nullptr, Option::IDS},
42     { "defined-ids", required_argument, nullptr, Option::DEFINED_IDS},
43     { "icon-check", no_argument, nullptr, Option::ICON_CHECK},
44     { "target-config", required_argument, nullptr, Option::TARGET_CONFIG},
45     { "defined-sysids", required_argument, nullptr, Option::DEFINED_SYSIDS},
46     { 0, 0, 0, 0},
47 };
48 
49 const string PackageParser::CMD_PARAMS = ":i:p:o:r:m:j:e:l:x:fhvz";
50 
Parse(int argc,char * argv[])51 uint32_t PackageParser::Parse(int argc, char *argv[])
52 {
53     InitCommand();
54     if (ParseCommand(argc, argv) != RESTOOL_SUCCESS) {
55         return RESTOOL_ERROR;
56     }
57     if (CheckParam() != RESTOOL_SUCCESS) {
58         return RESTOOL_ERROR;
59     }
60     AdaptResourcesDirForInput();
61     return RESTOOL_SUCCESS;
62 }
63 
GetInputs() const64 const vector<string> &PackageParser::GetInputs() const
65 {
66     return inputs_;
67 }
68 
GetPackageName() const69 const string &PackageParser::GetPackageName() const
70 {
71     return packageName_;
72 }
73 
GetOutput() const74 const string &PackageParser::GetOutput() const
75 {
76     return output_;
77 }
78 
GetResourceHeaders() const79 const vector<string> &PackageParser::GetResourceHeaders() const
80 {
81     return resourceHeaderPaths_;
82 }
83 
GetForceWrite() const84 bool PackageParser::GetForceWrite() const
85 {
86     return forceWrite_;
87 }
88 
GetModuleNames() const89 const vector<string> &PackageParser::GetModuleNames() const
90 {
91     return moduleNames_;
92 }
93 
GetConfig() const94 const string &PackageParser::GetConfig() const
95 {
96     return configPath_;
97 }
98 
GetRestoolPath() const99 const string &PackageParser::GetRestoolPath() const
100 {
101     return restoolPath_;
102 }
103 
GetStartId() const104 uint32_t PackageParser::GetStartId() const
105 {
106     return startId_;
107 }
108 
GetDependEntry() const109 const string &PackageParser::GetDependEntry() const
110 {
111     return dependEntry_;
112 }
113 
GetSysIdDefinedPaths() const114 const vector<std::string> &PackageParser::GetSysIdDefinedPaths() const
115 {
116     return sysIdDefinedPaths_;
117 }
118 
AddInput(const string & argValue)119 uint32_t PackageParser::AddInput(const string& argValue)
120 {
121     string inputPath = ResourceUtil::RealPath(argValue);
122     if (inputPath.empty()) {
123         cerr << "Error: invalid input '" << argValue << "'" << endl;
124         return RESTOOL_ERROR;
125     }
126 
127     auto ret = find_if(inputs_.begin(), inputs_.end(), [inputPath](auto iter) {return inputPath == iter;});
128     if (ret != inputs_.end()) {
129         cerr << "Error: repeat input '" << argValue << "'" << endl;
130         return RESTOOL_ERROR;
131     }
132 
133     if (!IsAscii(inputPath)) {
134         return RESTOOL_ERROR;
135     }
136     inputs_.push_back(inputPath);
137     return RESTOOL_SUCCESS;
138 }
139 
AddSysIdDefined(const std::string & argValue)140 uint32_t PackageParser::AddSysIdDefined(const std::string& argValue)
141 {
142     string sysIdDefinedPath = ResourceUtil::RealPath(argValue);
143     if (sysIdDefinedPath.empty()) {
144         cerr << "Error: invalid system id_defined.json path: '" << argValue << "'" << endl;
145         return RESTOOL_ERROR;
146     }
147 
148     auto ret = find_if(sysIdDefinedPaths_.begin(), sysIdDefinedPaths_.end(),
149         [sysIdDefinedPath](auto iter) {return sysIdDefinedPath == iter;});
150     if (ret != sysIdDefinedPaths_.end()) {
151         cerr << "Error: repeat system id_defined.json path: '" << argValue << "'" << endl;
152         return RESTOOL_ERROR;
153     }
154 
155     if (!IsAscii(sysIdDefinedPath)) {
156         return RESTOOL_ERROR;
157     }
158     sysIdDefinedPaths_.push_back(sysIdDefinedPath);
159     return RESTOOL_SUCCESS;
160 }
161 
AddPackageName(const string & argValue)162 uint32_t PackageParser::AddPackageName(const string& argValue)
163 {
164     if (!packageName_.empty()) {
165         cerr << "Error: double package name " << packageName_ << " vs " << argValue << endl;
166         return RESTOOL_ERROR;
167     }
168 
169     packageName_ = argValue;
170     return RESTOOL_SUCCESS;
171 }
172 
AddOutput(const string & argValue)173 uint32_t PackageParser::AddOutput(const string& argValue)
174 {
175     if (!output_.empty()) {
176         cerr << "Error: double output " << output_ << " vs " << argValue << endl;
177         return RESTOOL_ERROR;
178     }
179 
180     output_ = ResourceUtil::RealPath(argValue);
181     if (output_.empty()) {
182         cerr << "Error: invalid output '" << argValue << "'" << endl;
183         return RESTOOL_ERROR;
184     }
185     if (!IsAscii(output_)) {
186         return RESTOOL_ERROR;
187     }
188     return RESTOOL_SUCCESS;
189 }
190 
AddResourceHeader(const string & argValue)191 uint32_t PackageParser::AddResourceHeader(const string& argValue)
192 {
193     if (find(resourceHeaderPaths_.begin(), resourceHeaderPaths_.end(), argValue) != resourceHeaderPaths_.end()) {
194         cerr << "Error: '" << argValue << "' input duplicated." << endl;
195         return RESTOOL_ERROR;
196     }
197     resourceHeaderPaths_.push_back(argValue);
198     return RESTOOL_SUCCESS;
199 }
200 
ForceWrite()201 uint32_t PackageParser::ForceWrite()
202 {
203     forceWrite_ = true;
204     return RESTOOL_SUCCESS;
205 }
206 
PrintVersion()207 uint32_t PackageParser::PrintVersion()
208 {
209     cout << "Info: Restool version= " << RESTOOL_VERSION << endl;
210     exit(RESTOOL_SUCCESS);
211     return RESTOOL_SUCCESS;
212 }
213 
AddMoudleNames(const string & argValue)214 uint32_t PackageParser::AddMoudleNames(const string& argValue)
215 {
216     if (!moduleNames_.empty()) {
217         cerr << "Error: -m double module name '" << argValue << "'" << endl;
218         return RESTOOL_ERROR;
219     }
220 
221     ResourceUtil::Split(argValue, moduleNames_, ",");
222     for (auto it = moduleNames_.begin(); it != moduleNames_.end(); it++) {
223         auto ret = find_if(moduleNames_.begin(), moduleNames_.end(), [it](auto iter) {return *it == iter;});
224         if (ret != it) {
225             cerr << "Error: double module name '" << *it << "'" << endl;
226             return RESTOOL_ERROR;
227         }
228     }
229     return RESTOOL_SUCCESS;
230 }
231 
AddConfig(const string & argValue)232 uint32_t PackageParser::AddConfig(const string& argValue)
233 {
234     if (!configPath_.empty()) {
235         cerr << "Error: double config.json " << configPath_ << " vs " << argValue << endl;
236         return RESTOOL_ERROR;
237     }
238 
239     configPath_ = argValue;
240     return RESTOOL_SUCCESS;
241 }
242 
AddStartId(const string & argValue)243 uint32_t PackageParser::AddStartId(const string& argValue)
244 {
245     startId_ = strtoll(argValue.c_str(), nullptr, 16); // 16 is hexadecimal number
246     if ((startId_ >= 0x01000000 && startId_ < 0x06ffffff) || (startId_ >= 0x08000000 && startId_ < 0xffffffff)) {
247         return RESTOOL_SUCCESS;
248     }
249     cerr << "Error: invalid start id " << argValue << endl;
250     return RESTOOL_ERROR;
251 }
252 
253 // -i input directory, add the resource directory
AdaptResourcesDirForInput()254 void PackageParser::AdaptResourcesDirForInput()
255 {
256     if (!isFileList_ && !combine_) { // -l and increment compile -i, no need to add resource directory
257         for (auto &path : inputs_) {
258             path = FileEntry::FilePath(path).Append(RESOURCES_DIR).GetPath();
259         }
260     }
261 }
262 
CheckParam() const263 uint32_t PackageParser::CheckParam() const
264 {
265     if (inputs_.empty() && append_.empty()) {
266         cerr << "Error: input path empty." << endl;
267         return RESTOOL_ERROR;
268     }
269 
270     if (output_.empty()) {
271         cerr << "Error: output path empty." << endl;
272         return RESTOOL_ERROR;
273     }
274 
275     if (isTtargetConfig_ && !append_.empty()) {
276         cerr << "Error: -x and --target-config cannot be used together." << endl;
277         return RESTOOL_ERROR;
278     }
279 
280     if (!append_.empty()) {
281         return RESTOOL_SUCCESS;
282     }
283 
284     if (packageName_.empty()) {
285         cerr << "Error: package name empty." << endl;
286         return RESTOOL_ERROR;
287     }
288 
289     if (resourceHeaderPaths_.empty()) {
290         cerr << "Error: resource header path empty." << endl;
291         return RESTOOL_ERROR;
292     }
293 
294     if (startId_ != 0 && !idDefinedInputPath_.empty()) {
295         cerr << "Error: set -e and --defined-ids cannot be used together." << endl;
296         return RESTOOL_ERROR;
297     }
298 
299     return RESTOOL_SUCCESS;
300 }
301 
IsFileList() const302 bool PackageParser::IsFileList() const
303 {
304     return isFileList_;
305 }
306 
AddAppend(const string & argValue)307 uint32_t PackageParser::AddAppend(const string& argValue)
308 {
309     string appendPath = ResourceUtil::RealPath(argValue);
310     if (appendPath.empty()) {
311         cout << "Warning: invalid compress '" << argValue << "'" << endl;
312         appendPath = argValue;
313     }
314     auto ret = find_if(append_.begin(), append_.end(), [appendPath](auto iter) {return appendPath == iter;});
315     if (ret != append_.end()) {
316         cerr << "Error: repeat input '" << argValue << "'" << endl;
317         return RESTOOL_ERROR;
318     }
319     if (!IsAscii(appendPath)) {
320         return RESTOOL_ERROR;
321     }
322     append_.push_back(appendPath);
323     return RESTOOL_SUCCESS;
324 }
325 
GetAppend() const326 const vector<string> &PackageParser::GetAppend() const
327 {
328     return append_;
329 }
330 
SetCombine()331 uint32_t PackageParser::SetCombine()
332 {
333     combine_ = true;
334     return RESTOOL_SUCCESS;
335 }
336 
GetCombine() const337 bool PackageParser::GetCombine() const
338 {
339     return combine_;
340 }
341 
AddDependEntry(const string & argValue)342 uint32_t PackageParser::AddDependEntry(const string& argValue)
343 {
344     dependEntry_ = argValue;
345     return RESTOOL_SUCCESS;
346 }
347 
ShowHelp() const348 uint32_t PackageParser::ShowHelp() const
349 {
350     auto &parser = CmdParser<PackageParser>::GetInstance();
351     parser.ShowUseage();
352     exit(RESTOOL_SUCCESS);
353     return RESTOOL_SUCCESS;
354 }
355 
SetIdDefinedOutput(const string & argValue)356 uint32_t PackageParser::SetIdDefinedOutput(const string& argValue)
357 {
358     idDefinedOutput_ = argValue;
359     return RESTOOL_SUCCESS;
360 }
361 
GetIdDefinedOutput() const362 const string &PackageParser::GetIdDefinedOutput() const
363 {
364     return idDefinedOutput_;
365 }
366 
SetIdDefinedInputPath(const string & argValue)367 uint32_t PackageParser::SetIdDefinedInputPath(const string& argValue)
368 {
369     idDefinedInputPath_ = argValue;
370     return RESTOOL_SUCCESS;
371 }
372 
GetIdDefinedInputPath() const373 const string &PackageParser::GetIdDefinedInputPath() const
374 {
375     return idDefinedInputPath_;
376 }
377 
IconCheck()378 uint32_t PackageParser::IconCheck()
379 {
380     isIconCheck_ = true;
381     return RESTOOL_SUCCESS;
382 }
383 
GetIconCheck() const384 bool PackageParser::GetIconCheck() const
385 {
386     return isIconCheck_;
387 }
388 
ParseTargetConfig(const string & argValue)389 uint32_t PackageParser::ParseTargetConfig(const string& argValue)
390 {
391     if (isTtargetConfig_) {
392         cerr << "Error: repeat input '--target-config'" << endl;
393         return RESTOOL_ERROR;
394     }
395     if (!SelectCompileParse::ParseTargetConfig(argValue, targetConfig_)) {
396         cerr << "Error: '" << argValue << "' is not valid parameter." << endl;
397         return RESTOOL_ERROR;
398     }
399     isTtargetConfig_ = true;
400     return RESTOOL_SUCCESS;
401 }
402 
GetTargetConfigValues() const403 const TargetConfig &PackageParser::GetTargetConfigValues() const
404 {
405     return targetConfig_;
406 }
407 
IsTargetConfig() const408 bool PackageParser::IsTargetConfig() const
409 {
410     return isTtargetConfig_;
411 }
412 
IsAscii(const string & argValue) const413 bool PackageParser::IsAscii(const string& argValue) const
414 {
415 #ifdef __WIN32
416     auto result = find_if(argValue.begin(), argValue.end(), [](auto iter) {
417         if ((iter & 0x80) != 0) {
418             return true;
419         }
420         return false;
421     });
422     if (result != argValue.end()) {
423         cerr << "Error: '" << argValue << "' must be ASCII" << endl;
424         return false;
425     }
426 #endif
427     return true;
428 }
429 
InitCommand()430 void PackageParser::InitCommand()
431 {
432     using namespace placeholders;
433     handles_.emplace(Option::INPUTPATH, bind(&PackageParser::AddInput, this, _1));
434     handles_.emplace(Option::PACKAGENAME, bind(&PackageParser::AddPackageName, this, _1));
435     handles_.emplace(Option::OUTPUTPATH, bind(&PackageParser::AddOutput, this, _1));
436     handles_.emplace(Option::RESHEADER, bind(&PackageParser::AddResourceHeader, this, _1));
437     handles_.emplace(Option::FORCEWRITE, [this](const string &) -> uint32_t { return ForceWrite(); });
438     handles_.emplace(Option::VERSION, [this](const string &) -> uint32_t { return PrintVersion(); });
439     handles_.emplace(Option::MODULES, bind(&PackageParser::AddMoudleNames, this, _1));
440     handles_.emplace(Option::JSON, bind(&PackageParser::AddConfig, this,  _1));
441     handles_.emplace(Option::STARTID, bind(&PackageParser::AddStartId, this, _1));
442     handles_.emplace(Option::APPEND, bind(&PackageParser::AddAppend, this, _1));
443     handles_.emplace(Option::COMBINE, [this](const string &) -> uint32_t { return SetCombine(); });
444     handles_.emplace(Option::DEPENDENTRY, bind(&PackageParser::AddDependEntry, this, _1));
445     handles_.emplace(Option::HELP, [this](const string &) -> uint32_t { return ShowHelp(); });
446     handles_.emplace(Option::IDS, bind(&PackageParser::SetIdDefinedOutput, this, _1));
447     handles_.emplace(Option::DEFINED_IDS, bind(&PackageParser::SetIdDefinedInputPath, this, _1));
448     handles_.emplace(Option::ICON_CHECK, [this](const string &) -> uint32_t { return IconCheck(); });
449     handles_.emplace(Option::TARGET_CONFIG, bind(&PackageParser::ParseTargetConfig, this, _1));
450     handles_.emplace(Option::DEFINED_SYSIDS, bind(&PackageParser::AddSysIdDefined, this, _1));
451 }
452 
HandleProcess(int c,const string & argValue)453 uint32_t PackageParser::HandleProcess(int c, const string& argValue)
454 {
455     auto handler = handles_.find(c);
456     if (handler == handles_.end()) {
457         cerr << "Error: unsupport " << c << endl;
458         return RESTOOL_ERROR;
459     }
460     return handler->second(argValue);
461 }
462 
ParseFileList(const string & fileListPath)463 uint32_t PackageParser::ParseFileList(const string& fileListPath)
464 {
465     isFileList_ = true;
466     ResConfigParser resConfigParser;
467     if (resConfigParser.Init(fileListPath, [this](int c, const string &argValue) -> uint32_t {
468         return HandleProcess(c, argValue);
469     }) != RESTOOL_SUCCESS) {
470         return RESTOOL_ERROR;
471     }
472     return RESTOOL_SUCCESS;
473 }
474 
CheckError(int argc,char * argv[],int c,int optIndex)475 uint32_t PackageParser::CheckError(int argc, char *argv[], int c, int optIndex)
476 {
477     if (optIndex != -1) {
478         if ((optarg == nullptr && (optind - 1 < 0 || optind - 1 >= argc)) ||
479             (optarg != nullptr && (optind - 2 < 0 || optind - 2 >= argc))) { // 1 or 2 menas optind offset value
480             return RESTOOL_ERROR;
481         }
482         string curOpt = (optarg == nullptr) ? argv[optind - 1] : argv[optind - 2];
483         if (curOpt != ("--" + string(CMD_OPTS[optIndex].name))) {
484             cerr << "Error: unknown option " << curOpt << endl;
485             return RESTOOL_ERROR;
486         }
487     }
488     if (c == Option::UNKNOWN) {
489         if (optopt == 0 && (optind - 1 < 0 || optind - 1 >= argc)) {
490             return RESTOOL_ERROR;
491         }
492         string optUnknown = (optopt == 0) ? argv[optind - 1] : ("-" + string(1, optopt));
493         cerr << "Error: unknown option " << optUnknown << endl;
494         return RESTOOL_ERROR;
495     }
496     if (c == Option::NO_ARGUMENT) {
497         if (optind - 1 < 0 || optind - 1 >= argc) {
498             return RESTOOL_ERROR;
499         }
500         if (IsLongOpt(argc, argv)) {
501             cerr << "Error: option " << argv[optind - 1] << " must have argument" << endl;
502         } else {
503             cerr << "Error: unknown option " << argv[optind - 1] << endl;
504         }
505         return RESTOOL_ERROR;
506     }
507     return RESTOOL_SUCCESS;
508 }
509 
ParseCommand(int argc,char * argv[])510 uint32_t PackageParser::ParseCommand(int argc, char *argv[])
511 {
512     restoolPath_ = string(argv[0]);
513     while (true) {
514         int optIndex = -1;
515         int c = getopt_long(argc, argv, CMD_PARAMS.c_str(), CMD_OPTS, &optIndex);
516         if (CheckError(argc, argv, c, optIndex) != RESTOOL_SUCCESS) {
517             return RESTOOL_ERROR;
518         }
519         if (c == Option::END) {
520             if (argc == optind) {
521                 break;
522             }
523             string errmsg = "Error: invalid arguments : ";
524             for (int i = optind; i < argc; i++) {
525                 errmsg.append(argv[i]).append(" ");
526             }
527             cerr << errmsg << endl;
528             return RESTOOL_ERROR;
529         }
530 
531         string argValue = (optarg != nullptr) ? optarg : "";
532         if (c == Option::FILELIST) {
533             return ParseFileList(argValue);
534         }
535         if (HandleProcess(c, argValue) != RESTOOL_SUCCESS) {
536             return RESTOOL_ERROR;
537         }
538     }
539     return RESTOOL_SUCCESS;
540 }
541 
IsLongOpt(int argc,char * argv[]) const542 bool PackageParser::IsLongOpt(int argc, char *argv[]) const
543 {
544     if (optind - 1 < 0 || optind - 1 >= argc) {
545         return false;
546     }
547     for (auto iter : CMD_OPTS) {
548         if (optopt == iter.val && argv[optind - 1] == ("--" + string(iter.name))) {
549             return true;
550         }
551     }
552     return false;
553 }
554 }
555 }
556 }
557