• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "cmd_list.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     { 0, 0, 0, 0},
46 };
47 
48 const string PackageParser::CMD_PARAMS = ":i:p:o:r:m:j:e:l:x:fhvz";
49 
Parse(int argc,char * argv[])50 uint32_t PackageParser::Parse(int argc, char *argv[])
51 {
52     InitCommand();
53     if (ParseCommand(argc, argv) != RESTOOL_SUCCESS) {
54         return RESTOOL_ERROR;
55     }
56     if (CheckParam() != RESTOOL_SUCCESS) {
57         return RESTOOL_ERROR;
58     }
59     AdaptResourcesDirForInput();
60     return RESTOOL_SUCCESS;
61 }
62 
GetInputs() const63 const vector<string> &PackageParser::GetInputs() const
64 {
65     return inputs_;
66 }
67 
GetPackageName() const68 const string &PackageParser::GetPackageName() const
69 {
70     return packageName_;
71 }
72 
GetOutput() const73 const string &PackageParser::GetOutput() const
74 {
75     return output_;
76 }
77 
GetResourceHeaders() const78 const vector<string> &PackageParser::GetResourceHeaders() const
79 {
80     return resourceHeaderPaths_;
81 }
82 
GetForceWrite() const83 bool PackageParser::GetForceWrite() const
84 {
85     return forceWrite_;
86 }
87 
GetModuleNames() const88 const vector<string> &PackageParser::GetModuleNames() const
89 {
90     return moduleNames_;
91 }
92 
GetConfig() const93 const string &PackageParser::GetConfig() const
94 {
95     return configPath_;
96 }
97 
GetRestoolPath() const98 const string &PackageParser::GetRestoolPath() const
99 {
100     return restoolPath_;
101 }
102 
GetStartId() const103 int32_t PackageParser::GetStartId() const
104 {
105     return startId_;
106 }
107 
GetDependEntry() const108 const string &PackageParser::GetDependEntry() const
109 {
110     return dependEntry_;
111 }
112 
AddInput(const string & argValue)113 uint32_t PackageParser::AddInput(const string& argValue)
114 {
115     string inputPath = ResourceUtil::RealPath(argValue);
116     if (inputPath.empty()) {
117         cerr << "Error: invalid input '" << argValue << "'" << endl;
118         return RESTOOL_ERROR;
119     }
120 
121     auto ret = find_if(inputs_.begin(), inputs_.end(), [inputPath](auto iter) {return inputPath == iter;});
122     if (ret != inputs_.end()) {
123         cerr << "Error: repeat input '" << argValue << "'" << endl;
124         return RESTOOL_ERROR;
125     }
126 
127     if (!IsAscii(inputPath)) {
128         return RESTOOL_ERROR;
129     }
130     inputs_.push_back(inputPath);
131     return RESTOOL_SUCCESS;
132 }
133 
AddPackageName(const string & argValue)134 uint32_t PackageParser::AddPackageName(const string& argValue)
135 {
136     if (!packageName_.empty()) {
137         cerr << "Error: double package name " << packageName_ << " vs " << argValue << endl;
138         return RESTOOL_ERROR;
139     }
140 
141     packageName_ = argValue;
142     return RESTOOL_SUCCESS;
143 }
144 
AddOutput(const string & argValue)145 uint32_t PackageParser::AddOutput(const string& argValue)
146 {
147     if (!output_.empty()) {
148         cerr << "Error: double output " << output_ << " vs " << argValue << endl;
149         return RESTOOL_ERROR;
150     }
151 
152     output_ = ResourceUtil::RealPath(argValue);
153     if (output_.empty()) {
154         cerr << "Error: invalid output '" << argValue << "'" << endl;
155         return RESTOOL_ERROR;
156     }
157     if (!IsAscii(output_)) {
158         return RESTOOL_ERROR;
159     }
160     return RESTOOL_SUCCESS;
161 }
162 
AddResourceHeader(const string & argValue)163 uint32_t PackageParser::AddResourceHeader(const string& argValue)
164 {
165     if (find(resourceHeaderPaths_.begin(), resourceHeaderPaths_.end(), argValue) != resourceHeaderPaths_.end()) {
166         cerr << "Error: '" << argValue << "' input duplicated." << endl;
167         return RESTOOL_ERROR;
168     }
169     resourceHeaderPaths_.push_back(argValue);
170     return RESTOOL_SUCCESS;
171 }
172 
ForceWrite()173 uint32_t PackageParser::ForceWrite()
174 {
175     forceWrite_ = true;
176     return RESTOOL_SUCCESS;
177 }
178 
PrintVersion()179 uint32_t PackageParser::PrintVersion()
180 {
181     cout << "Info: Restool version= " << RESTOOL_VERSION << endl;
182     exit(RESTOOL_SUCCESS);
183     return RESTOOL_SUCCESS;
184 }
185 
AddMoudleNames(const string & argValue)186 uint32_t PackageParser::AddMoudleNames(const string& argValue)
187 {
188     if (!moduleNames_.empty()) {
189         cerr << "Error: -m double module name '" << argValue << "'" << endl;
190         return RESTOOL_ERROR;
191     }
192 
193     ResourceUtil::Split(argValue, moduleNames_, ",");
194     for (auto it = moduleNames_.begin(); it != moduleNames_.end(); it++) {
195         auto ret = find_if(moduleNames_.begin(), moduleNames_.end(), [it](auto iter) {return *it == iter;});
196         if (ret != it) {
197             cerr << "Error: double module name '" << *it << "'" << endl;
198             return RESTOOL_ERROR;
199         }
200     }
201     return RESTOOL_SUCCESS;
202 }
203 
AddConfig(const string & argValue)204 uint32_t PackageParser::AddConfig(const string& argValue)
205 {
206     if (!configPath_.empty()) {
207         cerr << "Error: double config.json " << configPath_ << " vs " << argValue << endl;
208         return RESTOOL_ERROR;
209     }
210 
211     configPath_ = argValue;
212     return RESTOOL_SUCCESS;
213 }
214 
AddStartId(const string & argValue)215 uint32_t PackageParser::AddStartId(const string& argValue)
216 {
217     startId_ = strtol(argValue.c_str(), nullptr, 16); // 16 is hexadecimal number
218     if ((startId_ >= 0x01000000 && startId_ < 0x06ffffff) || (startId_ >= 0x08000000 && startId_ < 0x41ffffff)) {
219         return RESTOOL_SUCCESS;
220     }
221     cerr << "Error: invalid start id " << argValue << endl;
222     return RESTOOL_ERROR;
223 }
224 
225 // -i input directory, add the resource directory
AdaptResourcesDirForInput()226 void PackageParser::AdaptResourcesDirForInput()
227 {
228     if (!isFileList_ && !combine_) { // -l and increment compile -i, no need to add resource directory
229         for (auto &path : inputs_) {
230             path = FileEntry::FilePath(path).Append(RESOURCES_DIR).GetPath();
231         }
232     }
233 }
234 
CheckParam() const235 uint32_t PackageParser::CheckParam() const
236 {
237     if (inputs_.empty() && append_.empty()) {
238         cerr << "Error: input path empty." << endl;
239         return RESTOOL_ERROR;
240     }
241 
242     if (output_.empty()) {
243         cerr << "Error: output path empty." << endl;
244         return RESTOOL_ERROR;
245     }
246 
247     if (isTtargetConfig_ && !append_.empty()) {
248         cerr << "Error: -x and --target-config cannot be used together." << endl;
249         return RESTOOL_ERROR;
250     }
251 
252     if (!append_.empty()) {
253         return RESTOOL_SUCCESS;
254     }
255 
256     if (packageName_.empty()) {
257         cerr << "Error: package name empty." << endl;
258         return RESTOOL_ERROR;
259     }
260 
261     if (resourceHeaderPaths_.empty()) {
262         cerr << "Error: resource header path empty." << endl;
263         return RESTOOL_ERROR;
264     }
265 
266     if (startId_ != 0 && !idDefinedInputPath_.empty()) {
267         cerr << "Error: set -e and --defined-ids cannot be used together." << endl;
268         return RESTOOL_ERROR;
269     }
270 
271     return RESTOOL_SUCCESS;
272 }
273 
IsFileList() const274 bool PackageParser::IsFileList() const
275 {
276     return isFileList_;
277 }
278 
AddAppend(const string & argValue)279 uint32_t PackageParser::AddAppend(const string& argValue)
280 {
281     string appendPath = ResourceUtil::RealPath(argValue);
282     if (appendPath.empty()) {
283         cout << "Warning: invalid compress '" << argValue << "'" << endl;
284         appendPath = argValue;
285     }
286     auto ret = find_if(append_.begin(), append_.end(), [appendPath](auto iter) {return appendPath == iter;});
287     if (ret != append_.end()) {
288         cerr << "Error: repeat input '" << argValue << "'" << endl;
289         return RESTOOL_ERROR;
290     }
291     if (!IsAscii(appendPath)) {
292         return RESTOOL_ERROR;
293     }
294     append_.push_back(appendPath);
295     return RESTOOL_SUCCESS;
296 }
297 
GetAppend() const298 const vector<string> &PackageParser::GetAppend() const
299 {
300     return append_;
301 }
302 
SetCombine()303 uint32_t PackageParser::SetCombine()
304 {
305     combine_ = true;
306     return RESTOOL_SUCCESS;
307 }
308 
GetCombine() const309 bool PackageParser::GetCombine() const
310 {
311     return combine_;
312 }
313 
AddDependEntry(const string & argValue)314 uint32_t PackageParser::AddDependEntry(const string& argValue)
315 {
316     dependEntry_ = argValue;
317     return RESTOOL_SUCCESS;
318 }
319 
ShowHelp() const320 uint32_t PackageParser::ShowHelp() const
321 {
322     auto &parser = CmdParser<PackageParser>::GetInstance();
323     parser.ShowUseage();
324     exit(RESTOOL_SUCCESS);
325     return RESTOOL_SUCCESS;
326 }
327 
SetIdDefinedOutput(const string & argValue)328 uint32_t PackageParser::SetIdDefinedOutput(const string& argValue)
329 {
330     idDefinedOutput_ = argValue;
331     return RESTOOL_SUCCESS;
332 }
333 
GetIdDefinedOutput() const334 const string &PackageParser::GetIdDefinedOutput() const
335 {
336     return idDefinedOutput_;
337 }
338 
SetIdDefinedInputPath(const string & argValue)339 uint32_t PackageParser::SetIdDefinedInputPath(const string& argValue)
340 {
341     idDefinedInputPath_ = argValue;
342     return RESTOOL_SUCCESS;
343 }
344 
GetIdDefinedInputPath() const345 const string &PackageParser::GetIdDefinedInputPath() const
346 {
347     return idDefinedInputPath_;
348 }
349 
IconCheck()350 uint32_t PackageParser::IconCheck()
351 {
352     isIconCheck_ = true;
353     return RESTOOL_SUCCESS;
354 }
355 
GetIconCheck() const356 bool PackageParser::GetIconCheck() const
357 {
358     return isIconCheck_;
359 }
360 
ParseTargetConfig(const string & argValue)361 uint32_t PackageParser::ParseTargetConfig(const string& argValue)
362 {
363     if (isTtargetConfig_) {
364         cerr << "Error: repeat input '--target-config'" << endl;
365         return RESTOOL_ERROR;
366     }
367     if (!SelectCompileParse::ParseTargetConfig(argValue, targetConfig_)) {
368         cerr << "Error: '" << argValue << "' is not valid parameter." << endl;
369         return RESTOOL_ERROR;
370     }
371     isTtargetConfig_ = true;
372     return RESTOOL_SUCCESS;
373 }
374 
GetTargetConfigValues() const375 const TargetConfig &PackageParser::GetTargetConfigValues() const
376 {
377     return targetConfig_;
378 }
379 
IsTargetConfig() const380 bool PackageParser::IsTargetConfig() const
381 {
382     return isTtargetConfig_;
383 }
384 
IsAscii(const string & argValue) const385 bool PackageParser::IsAscii(const string& argValue) const
386 {
387 #ifdef __WIN32
388     auto result = find_if(argValue.begin(), argValue.end(), [](auto iter) {
389         if ((iter & 0x80) != 0) {
390             return true;
391         }
392         return false;
393     });
394     if (result != argValue.end()) {
395         cerr << "Error: '" << argValue << "' must be ASCII" << endl;
396         return false;
397     }
398 #endif
399     return true;
400 }
401 
InitCommand()402 void PackageParser::InitCommand()
403 {
404     using namespace placeholders;
405     handles_.emplace(Option::INPUTPATH, bind(&PackageParser::AddInput, this, _1));
406     handles_.emplace(Option::PACKAGENAME, bind(&PackageParser::AddPackageName, this, _1));
407     handles_.emplace(Option::OUTPUTPATH, bind(&PackageParser::AddOutput, this, _1));
408     handles_.emplace(Option::RESHEADER, bind(&PackageParser::AddResourceHeader, this, _1));
409     handles_.emplace(Option::FORCEWRITE, [this](const string &) -> uint32_t { return ForceWrite(); });
410     handles_.emplace(Option::VERSION, [this](const string &) -> uint32_t { return PrintVersion(); });
411     handles_.emplace(Option::MODULES, bind(&PackageParser::AddMoudleNames, this, _1));
412     handles_.emplace(Option::JSON, bind(&PackageParser::AddConfig, this,  _1));
413     handles_.emplace(Option::STARTID, bind(&PackageParser::AddStartId, this, _1));
414     handles_.emplace(Option::APPEND, bind(&PackageParser::AddAppend, this, _1));
415     handles_.emplace(Option::COMBINE, [this](const string &) -> uint32_t { return SetCombine(); });
416     handles_.emplace(Option::DEPENDENTRY, bind(&PackageParser::AddDependEntry, this, _1));
417     handles_.emplace(Option::HELP, [this](const string &) -> uint32_t { return ShowHelp(); });
418     handles_.emplace(Option::IDS, bind(&PackageParser::SetIdDefinedOutput, this, _1));
419     handles_.emplace(Option::DEFINED_IDS, bind(&PackageParser::SetIdDefinedInputPath, this, _1));
420     handles_.emplace(Option::ICON_CHECK, [this](const string &) -> uint32_t { return IconCheck(); });
421     handles_.emplace(Option::TARGET_CONFIG, bind(&PackageParser::ParseTargetConfig, this, _1));
422 }
423 
HandleProcess(int c,const string & argValue)424 uint32_t PackageParser::HandleProcess(int c, const string& argValue)
425 {
426     auto handler = handles_.find(c);
427     if (handler == handles_.end()) {
428         cerr << "Error: unsupport " << c << endl;
429         return RESTOOL_ERROR;
430     }
431     return handler->second(argValue);
432 }
433 
ParseFileList(const string & fileListPath)434 uint32_t PackageParser::ParseFileList(const string& fileListPath)
435 {
436     isFileList_ = true;
437     CmdList cmdList;
438     if (cmdList.Init(fileListPath, [this](int c, const string &argValue) -> int32_t {
439         return HandleProcess(c, argValue);
440     }) != RESTOOL_SUCCESS) {
441         return RESTOOL_ERROR;
442     }
443     return RESTOOL_SUCCESS;
444 }
445 
ParseCommand(int argc,char * argv[])446 uint32_t PackageParser::ParseCommand(int argc, char *argv[])
447 {
448     restoolPath_ = string(argv[0]);
449     while (true) {
450         int optIndex = -1;
451         opterr = 0;
452         int c = getopt_long(argc, argv, CMD_PARAMS.c_str(), CMD_OPTS, &optIndex);
453         if (optIndex != -1) {
454             string curOpt = (optarg == nullptr) ? argv[optind - 1] : argv[optind - 2];
455             if (curOpt != ("--" + string(CMD_OPTS[optIndex].name))) {
456                 cerr << "Error: unknown option " << curOpt << endl;
457                 return RESTOOL_ERROR;
458             }
459         }
460         if (c == Option::END) {
461             if (argc == optind) {
462                 break;
463             }
464             string errmsg = "Error: invalid arguments : ";
465             for (int i = optind; i < argc; i++) {
466                 errmsg.append(argv[i]).append(" ");
467             }
468             cerr << errmsg << endl;
469             return RESTOOL_ERROR;
470         }
471         if (c == Option::UNKNOWN) {
472             string optUnknown = (optopt == 0) ? argv[optind - 1] : ("-" + string(1, optopt));
473             cerr << "Error: unknown option " << optUnknown << endl;
474             return RESTOOL_ERROR;
475         }
476         if (c == Option::NO_ARGUMENT) {
477             if (IsLongOpt(argv)) {
478                 cerr << "Error: option " << argv[optind - 1] << " must have argument" << endl;
479             } else {
480                 cerr << "Error: unknown option " << argv[optind - 1] << endl;
481             }
482             return RESTOOL_ERROR;
483         }
484         string argValue = (optarg != nullptr) ? optarg : "";
485         if (c == Option::FILELIST) {
486             return ParseFileList(argValue);
487         }
488         if (HandleProcess(c, argValue) != RESTOOL_SUCCESS) {
489             return RESTOOL_ERROR;
490         }
491     }
492     return RESTOOL_SUCCESS;
493 }
494 
IsLongOpt(char * argv[]) const495 bool PackageParser::IsLongOpt(char *argv[]) const
496 {
497     for (auto iter : CMD_OPTS) {
498         if (optopt == iter.val && argv[optind - 1] == ("--" + string(iter.name))) {
499             return true;
500         }
501     }
502     return false;
503 }
504 }
505 }
506 }
507