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
21 namespace OHOS {
22 namespace Global {
23 namespace Restool {
24 using namespace std;
25 const struct option PackageParser::CMD_OPTS[] = {
26 { "inputPath", required_argument, nullptr, Option::INPUTPATH },
27 { "packageName", required_argument, nullptr, Option::PACKAGENAME },
28 { "outputPath", required_argument, nullptr, Option::OUTPUTPATH },
29 { "resHeader", required_argument, nullptr, Option::RESHEADER },
30 { "forceWrite", no_argument, nullptr, Option::FORCEWRITE },
31 { "version", no_argument, nullptr, Option::VERSION},
32 { "modules", required_argument, nullptr, Option::MODULES },
33 { "json", required_argument, nullptr, Option::JSON },
34 { "startId", required_argument, nullptr, Option::STARTID },
35 { "fileList", required_argument, nullptr, Option::FILELIST },
36 { "append", required_argument, nullptr, Option::APPEND },
37 { "combine", required_argument, nullptr, Option::COMBINE },
38 { "dependEntry", required_argument, nullptr, Option::DEPENDENTRY },
39 { "help", no_argument, nullptr, Option::HELP},
40 { "ids", required_argument, nullptr, Option::IDS},
41 { "defined-ids", required_argument, nullptr, Option::DEFINED_IDS},
42 { "icon-check", no_argument, nullptr, Option::ICON_CHECK},
43 { 0, 0, 0, 0},
44 };
45
46 const string PackageParser::CMD_PARAMS = ":i:p:o:r:m:j:e:l:x:fhvz";
47
Parse(int argc,char * argv[])48 uint32_t PackageParser::Parse(int argc, char *argv[])
49 {
50 InitCommand();
51 if (ParseCommand(argc, argv) != RESTOOL_SUCCESS) {
52 return RESTOOL_ERROR;
53 }
54 if (CheckParam() != RESTOOL_SUCCESS) {
55 return RESTOOL_ERROR;
56 }
57 AdaptResourcesDirForInput();
58 return RESTOOL_SUCCESS;
59 }
60
GetInputs() const61 const vector<string> &PackageParser::GetInputs() const
62 {
63 return inputs_;
64 }
65
GetPackageName() const66 const string &PackageParser::GetPackageName() const
67 {
68 return packageName_;
69 }
70
GetOutput() const71 const string &PackageParser::GetOutput() const
72 {
73 return output_;
74 }
75
GetResourceHeaders() const76 const vector<string> &PackageParser::GetResourceHeaders() const
77 {
78 return resourceHeaderPaths_;
79 }
80
GetForceWrite() const81 bool PackageParser::GetForceWrite() const
82 {
83 return forceWrite_;
84 }
85
GetModuleNames() const86 const vector<string> &PackageParser::GetModuleNames() const
87 {
88 return moduleNames_;
89 }
90
GetConfig() const91 const string &PackageParser::GetConfig() const
92 {
93 return configPath_;
94 }
95
GetRestoolPath() const96 const string &PackageParser::GetRestoolPath() const
97 {
98 return restoolPath_;
99 }
100
GetStartId() const101 int32_t PackageParser::GetStartId() const
102 {
103 return startId_;
104 }
105
GetDependEntry() const106 const string &PackageParser::GetDependEntry() const
107 {
108 return dependEntry_;
109 }
110
AddInput(const string & argValue)111 uint32_t PackageParser::AddInput(const string& argValue)
112 {
113 string inputPath = ResourceUtil::RealPath(argValue);
114 if (inputPath.empty()) {
115 cerr << "Error: invalid input '" << argValue << "'" << endl;
116 return RESTOOL_ERROR;
117 }
118
119 auto ret = find_if(inputs_.begin(), inputs_.end(), [inputPath](auto iter) {return inputPath == iter;});
120 if (ret != inputs_.end()) {
121 cerr << "Error: repeat input '" << argValue << "'" << endl;
122 return RESTOOL_ERROR;
123 }
124
125 if (!IsAscii(inputPath)) {
126 return RESTOOL_ERROR;
127 }
128 inputs_.push_back(inputPath);
129 return RESTOOL_SUCCESS;
130 }
131
AddPackageName(const string & argValue)132 uint32_t PackageParser::AddPackageName(const string& argValue)
133 {
134 if (!packageName_.empty()) {
135 cerr << "Error: double package name " << packageName_ << " vs " << argValue << endl;
136 return RESTOOL_ERROR;
137 }
138
139 packageName_ = argValue;
140 return RESTOOL_SUCCESS;
141 }
142
AddOutput(const string & argValue)143 uint32_t PackageParser::AddOutput(const string& argValue)
144 {
145 if (!output_.empty()) {
146 cerr << "Error: double output " << output_ << " vs " << argValue << endl;
147 return RESTOOL_ERROR;
148 }
149
150 output_ = ResourceUtil::RealPath(argValue);
151 if (output_.empty()) {
152 cerr << "Error: invalid output '" << argValue << "'" << endl;
153 return RESTOOL_ERROR;
154 }
155 if (!IsAscii(output_)) {
156 return RESTOOL_ERROR;
157 }
158 return RESTOOL_SUCCESS;
159 }
160
AddResourceHeader(const string & argValue)161 uint32_t PackageParser::AddResourceHeader(const string& argValue)
162 {
163 if (find(resourceHeaderPaths_.begin(), resourceHeaderPaths_.end(), argValue) != resourceHeaderPaths_.end()) {
164 cerr << "Error: '" << argValue << "' input duplicated." << endl;
165 return RESTOOL_ERROR;
166 }
167 resourceHeaderPaths_.push_back(argValue);
168 return RESTOOL_SUCCESS;
169 }
170
ForceWrite()171 uint32_t PackageParser::ForceWrite()
172 {
173 forceWrite_ = true;
174 return RESTOOL_SUCCESS;
175 }
176
PrintVersion()177 uint32_t PackageParser::PrintVersion()
178 {
179 cout << "Info: Restool version= " << RESTOOL_VERSION << endl;
180 exit(RESTOOL_SUCCESS);
181 return RESTOOL_SUCCESS;
182 }
183
AddMoudleNames(const string & argValue)184 uint32_t PackageParser::AddMoudleNames(const string& argValue)
185 {
186 if (!moduleNames_.empty()) {
187 cerr << "Error: -m double module name '" << argValue << "'" << endl;
188 return RESTOOL_ERROR;
189 }
190
191 ResourceUtil::Split(argValue, moduleNames_, ",");
192 for (auto it = moduleNames_.begin(); it != moduleNames_.end(); it++) {
193 auto ret = find_if(moduleNames_.begin(), moduleNames_.end(), [it](auto iter) {return *it == iter;});
194 if (ret != it) {
195 cerr << "Error: double module name '" << *it << "'" << endl;
196 return RESTOOL_ERROR;
197 }
198 }
199 return RESTOOL_SUCCESS;
200 }
201
AddConfig(const string & argValue)202 uint32_t PackageParser::AddConfig(const string& argValue)
203 {
204 if (!configPath_.empty()) {
205 cerr << "Error: double config.json " << configPath_ << " vs " << argValue << endl;
206 return RESTOOL_ERROR;
207 }
208
209 configPath_ = argValue;
210 return RESTOOL_SUCCESS;
211 }
212
AddStartId(const string & argValue)213 uint32_t PackageParser::AddStartId(const string& argValue)
214 {
215 startId_ = strtol(argValue.c_str(), nullptr, 16); // 16 is hexadecimal number
216 if ((startId_ >= 0x01000000 && startId_ < 0x06ffffff) || (startId_ >= 0x08000000 && startId_ < 0x41ffffff)) {
217 return RESTOOL_SUCCESS;
218 }
219 cerr << "Error: invalid start id " << argValue << endl;
220 return RESTOOL_ERROR;
221 }
222
223 // -i input directory, add the resource directory
AdaptResourcesDirForInput()224 void PackageParser::AdaptResourcesDirForInput()
225 {
226 if (!isFileList_ && !combine_) { // -l and increment compile -i, no need to add resource directory
227 for (auto &path : inputs_) {
228 path = FileEntry::FilePath(path).Append(RESOURCES_DIR).GetPath();
229 }
230 }
231 }
232
CheckParam() const233 uint32_t PackageParser::CheckParam() const
234 {
235 if (inputs_.empty() && append_.empty()) {
236 cerr << "Error: input path empty." << endl;
237 return RESTOOL_ERROR;
238 }
239
240 if (output_.empty()) {
241 cerr << "Error: output path empty." << endl;
242 return RESTOOL_ERROR;
243 }
244
245 if (!append_.empty()) {
246 return RESTOOL_SUCCESS;
247 }
248 if (packageName_.empty()) {
249 cerr << "Error: package name empty." << endl;
250 return RESTOOL_ERROR;
251 }
252
253 if (resourceHeaderPaths_.empty()) {
254 cerr << "Error: resource header path empty." << endl;
255 return RESTOOL_ERROR;
256 }
257
258 if (startId_ != 0 && !idDefinedInputPath_.empty()) {
259 cerr << "Error: set -e and --defined-ids cannot be used together." << endl;
260 return RESTOOL_ERROR;
261 }
262
263 return RESTOOL_SUCCESS;
264 }
265
IsFileList() const266 bool PackageParser::IsFileList() const
267 {
268 return isFileList_;
269 }
270
AddAppend(const string & argValue)271 uint32_t PackageParser::AddAppend(const string& argValue)
272 {
273 string appendPath = ResourceUtil::RealPath(argValue);
274 if (appendPath.empty()) {
275 cout << "Warning: invaild compress '" << argValue << "'" << endl;
276 appendPath = argValue;
277 }
278 auto ret = find_if(append_.begin(), append_.end(), [appendPath](auto iter) {return appendPath == iter;});
279 if (ret != append_.end()) {
280 cerr << "Error: repeat input '" << argValue << "'" << endl;
281 return RESTOOL_ERROR;
282 }
283 if (!IsAscii(appendPath)) {
284 return RESTOOL_ERROR;
285 }
286 append_.push_back(appendPath);
287 return RESTOOL_SUCCESS;
288 }
289
GetAppend() const290 const vector<string> &PackageParser::GetAppend() const
291 {
292 return append_;
293 }
294
SetCombine()295 uint32_t PackageParser::SetCombine()
296 {
297 combine_ = true;
298 return RESTOOL_SUCCESS;
299 }
300
GetCombine() const301 bool PackageParser::GetCombine() const
302 {
303 return combine_;
304 }
305
AddDependEntry(const string & argValue)306 uint32_t PackageParser::AddDependEntry(const string& argValue)
307 {
308 dependEntry_ = argValue;
309 return RESTOOL_SUCCESS;
310 }
311
ShowHelp() const312 uint32_t PackageParser::ShowHelp() const
313 {
314 auto &parser = CmdParser<PackageParser>::GetInstance();
315 parser.ShowUseage();
316 exit(RESTOOL_SUCCESS);
317 return RESTOOL_SUCCESS;
318 }
319
SetIdDefinedOutput(const string & argValue)320 uint32_t PackageParser::SetIdDefinedOutput(const string& argValue)
321 {
322 idDefinedOutput_ = argValue;
323 return RESTOOL_SUCCESS;
324 }
325
GetIdDefinedOutput() const326 const string &PackageParser::GetIdDefinedOutput() const
327 {
328 return idDefinedOutput_;
329 }
330
SetIdDefinedInputPath(const string & argValue)331 uint32_t PackageParser::SetIdDefinedInputPath(const string& argValue)
332 {
333 idDefinedInputPath_ = argValue;
334 return RESTOOL_SUCCESS;
335 }
336
GetIdDefinedInputPath() const337 const string &PackageParser::GetIdDefinedInputPath() const
338 {
339 return idDefinedInputPath_;
340 }
341
IconCheck()342 uint32_t PackageParser::IconCheck()
343 {
344 isIconCheck_ = true;
345 return RESTOOL_SUCCESS;
346 }
347
GetIconCheck() const348 bool PackageParser::GetIconCheck() const
349 {
350 return isIconCheck_;
351 }
352
IsAscii(const string & argValue) const353 bool PackageParser::IsAscii(const string& argValue) const
354 {
355 #ifdef __WIN32
356 auto result = find_if(argValue.begin(), argValue.end(), [](auto iter) {
357 if ((iter & 0x80) != 0) {
358 return true;
359 }
360 return false;
361 });
362 if (result != argValue.end()) {
363 cerr << "Error: '" << argValue << "' must be ASCII" << endl;
364 return false;
365 }
366 #endif
367 return true;
368 }
369
InitCommand()370 void PackageParser::InitCommand()
371 {
372 using namespace placeholders;
373 handles_.emplace(Option::INPUTPATH, bind(&PackageParser::AddInput, this, _1));
374 handles_.emplace(Option::PACKAGENAME, bind(&PackageParser::AddPackageName, this, _1));
375 handles_.emplace(Option::OUTPUTPATH, bind(&PackageParser::AddOutput, this, _1));
376 handles_.emplace(Option::RESHEADER, bind(&PackageParser::AddResourceHeader, this, _1));
377 handles_.emplace(Option::FORCEWRITE, [this](const string &) -> uint32_t { return ForceWrite(); });
378 handles_.emplace(Option::VERSION, [this](const string &) -> uint32_t { return PrintVersion(); });
379 handles_.emplace(Option::MODULES, bind(&PackageParser::AddMoudleNames, this, _1));
380 handles_.emplace(Option::JSON, bind(&PackageParser::AddConfig, this, _1));
381 handles_.emplace(Option::STARTID, bind(&PackageParser::AddStartId, this, _1));
382 handles_.emplace(Option::APPEND, bind(&PackageParser::AddAppend, this, _1));
383 handles_.emplace(Option::COMBINE, [this](const string &) -> uint32_t { return SetCombine(); });
384 handles_.emplace(Option::DEPENDENTRY, bind(&PackageParser::AddDependEntry, this, _1));
385 handles_.emplace(Option::HELP, [this](const string &) -> uint32_t { return ShowHelp(); });
386 handles_.emplace(Option::IDS, bind(&PackageParser::SetIdDefinedOutput, this, _1));
387 handles_.emplace(Option::DEFINED_IDS, bind(&PackageParser::SetIdDefinedInputPath, this, _1));
388 handles_.emplace(Option::ICON_CHECK, [this](const string &) -> uint32_t { return IconCheck(); });
389 }
390
HandleProcess(int c,const string & argValue)391 uint32_t PackageParser::HandleProcess(int c, const string& argValue)
392 {
393 auto handler = handles_.find(c);
394 if (handler == handles_.end()) {
395 cout << "Error: unsupport " << c << endl;
396 return RESTOOL_ERROR;
397 }
398 return handler->second(argValue);
399 }
400
ParseFileList(const string & fileListPath)401 uint32_t PackageParser::ParseFileList(const string& fileListPath)
402 {
403 isFileList_ = true;
404 CmdList cmdList;
405 if (cmdList.Init(fileListPath, [this](int c, const string &argValue) -> int32_t {
406 return HandleProcess(c, argValue);
407 }) != RESTOOL_SUCCESS) {
408 return RESTOOL_ERROR;
409 }
410 return RESTOOL_SUCCESS;
411 }
412
ParseCommand(int argc,char * argv[])413 uint32_t PackageParser::ParseCommand(int argc, char *argv[])
414 {
415 restoolPath_ = string(argv[0]);
416 while (true) {
417 int optIndex = -1;
418 opterr = 0;
419 int c = getopt_long(argc, argv, CMD_PARAMS.c_str(), CMD_OPTS, &optIndex);
420 if (optIndex != -1) {
421 string curOpt = (optarg == nullptr) ? argv[optind - 1] : argv[optind - 2];
422 if (curOpt != ("--" + string(CMD_OPTS[optIndex].name))) {
423 cout << "Error: unknown option " << curOpt << endl;
424 return RESTOOL_ERROR;
425 }
426 }
427 if (c == Option::END) {
428 if (argc == optind) {
429 break;
430 }
431 string errmsg = "Error: invalid arguments : ";
432 for (int i = optind; i < argc; i++) {
433 errmsg.append(argv[i]).append(" ");
434 }
435 cout << errmsg << endl;
436 return RESTOOL_ERROR;
437 }
438 if (c == Option::UNKNOWN) {
439 string optUnknown = (optopt == 0) ? argv[optind - 1] : ("-" + string(1, optopt));
440 cout << "Error: unknown option " << optUnknown << endl;
441 return RESTOOL_ERROR;
442 }
443 if (c == Option::NO_ARGUMENT) {
444 if (IsLongOpt(argv)) {
445 cout << "Error: option " << argv[optind - 1] << " must have argument" << endl;
446 } else {
447 cout << "Error: unknown option " << argv[optind - 1] << endl;
448 }
449 return RESTOOL_ERROR;
450 }
451 string argValue = (optarg != nullptr) ? optarg : "";
452 if (c == Option::FILELIST) {
453 return ParseFileList(argValue);
454 }
455 if (HandleProcess(c, argValue) != RESTOOL_SUCCESS) {
456 return RESTOOL_ERROR;
457 }
458 }
459 return RESTOOL_SUCCESS;
460 }
461
IsLongOpt(char * argv[]) const462 bool PackageParser::IsLongOpt(char *argv[]) const
463 {
464 for (auto iter : CMD_OPTS) {
465 if (optopt == iter.val && argv[optind - 1] == ("--" + string(iter.name))) {
466 return true;
467 }
468 }
469 return false;
470 }
471 }
472 }
473 }
474