• 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/package_parser.h"
17 #include <algorithm>
18 #include <climits>
19 #include "resconfig_parser.h"
20 #include "resource_util.h"
21 #include "select_compile_parse.h"
22 #include "file_entry.h"
23 #include "resource_pack.h"
24 
25 namespace OHOS {
26 namespace Global {
27 namespace Restool {
28 using namespace std;
29 const struct option PackageParser::CMD_OPTS[] = {
30     { "inputPath", required_argument, nullptr, Option::INPUTPATH },
31     { "packageName", required_argument, nullptr, Option::PACKAGENAME },
32     { "outputPath", required_argument, nullptr, Option::OUTPUTPATH },
33     { "resHeader", required_argument, nullptr, Option::RESHEADER },
34     { "forceWrite", no_argument, nullptr, Option::FORCEWRITE },
35     { "version", no_argument, nullptr, Option::VERSION},
36     { "modules", required_argument, nullptr, Option::MODULES },
37     { "json", required_argument, nullptr, Option::JSON },
38     { "startId", required_argument, nullptr, Option::STARTID },
39     { "fileList", required_argument, nullptr, Option::FILELIST },
40     { "append", required_argument, nullptr, Option::APPEND },
41     { "combine", required_argument, nullptr, Option::COMBINE },
42     { "dependEntry", required_argument, nullptr, Option::DEPENDENTRY },
43     { "help", no_argument, nullptr, Option::HELP},
44     { "ids", required_argument, nullptr, Option::IDS},
45     { "defined-ids", required_argument, nullptr, Option::DEFINED_IDS},
46     { "icon-check", no_argument, nullptr, Option::ICON_CHECK},
47     { "target-config", required_argument, nullptr, Option::TARGET_CONFIG},
48     { "defined-sysids", required_argument, nullptr, Option::DEFINED_SYSIDS},
49     { "compressed-config", required_argument, nullptr, Option::COMPRESSED_CONFIG},
50     { "thread", required_argument, nullptr, Option::THREAD},
51     { 0, 0, 0, 0},
52 };
53 
54 const string PackageParser::CMD_PARAMS = ":i:p:o:r:m:j:e:l:x:fhvz";
55 
Parse(int argc,char * argv[])56 uint32_t PackageParser::Parse(int argc, char *argv[])
57 {
58     InitCommand();
59     if (ParseCommand(argc, argv) != RESTOOL_SUCCESS) {
60         return RESTOOL_ERROR;
61     }
62     if (CheckParam() != RESTOOL_SUCCESS) {
63         return RESTOOL_ERROR;
64     }
65     AdaptResourcesDirForInput();
66     return RESTOOL_SUCCESS;
67 }
68 
GetInputs() const69 const vector<string> &PackageParser::GetInputs() const
70 {
71     return inputs_;
72 }
73 
GetPackageName() const74 const string &PackageParser::GetPackageName() const
75 {
76     return packageName_;
77 }
78 
GetOutput() const79 const string &PackageParser::GetOutput() const
80 {
81     return output_;
82 }
83 
GetResourceHeaders() const84 const vector<string> &PackageParser::GetResourceHeaders() const
85 {
86     return resourceHeaderPaths_;
87 }
88 
GetForceWrite() const89 bool PackageParser::GetForceWrite() const
90 {
91     return forceWrite_;
92 }
93 
GetModuleNames() const94 const vector<string> &PackageParser::GetModuleNames() const
95 {
96     return moduleNames_;
97 }
98 
GetConfig() const99 const string &PackageParser::GetConfig() const
100 {
101     return configPath_;
102 }
103 
GetRestoolPath() const104 const string &PackageParser::GetRestoolPath() const
105 {
106     return restoolPath_;
107 }
108 
GetStartId() const109 uint32_t PackageParser::GetStartId() const
110 {
111     return startId_;
112 }
113 
GetDependEntry() const114 const string &PackageParser::GetDependEntry() const
115 {
116     return dependEntry_;
117 }
118 
GetSysIdDefinedPaths() const119 const vector<std::string> &PackageParser::GetSysIdDefinedPaths() const
120 {
121     return sysIdDefinedPaths_;
122 }
123 
AddInput(const string & argValue)124 uint32_t PackageParser::AddInput(const string& argValue)
125 {
126     string inputPath = ResourceUtil::RealPath(argValue);
127     if (inputPath.empty()) {
128         PrintError(GetError(ERR_CODE_INVALID_INPUT).FormatCause(argValue.c_str()));
129         return RESTOOL_ERROR;
130     }
131 
132     auto ret = find_if(inputs_.begin(), inputs_.end(), [inputPath](auto iter) {return inputPath == iter;});
133     if (ret != inputs_.end()) {
134         PrintError(GetError(ERR_CODE_DUPLICATE_INPUT).FormatCause(argValue.c_str()));
135         return RESTOOL_ERROR;
136     }
137 
138     if (!IsAscii(inputPath)) {
139         return RESTOOL_ERROR;
140     }
141 
142     if (IsOverlapInput(inputPath)) {
143         inputs_.emplace(inputs_.begin(), inputPath);
144     } else {
145         inputs_.push_back(inputPath);
146     }
147     return RESTOOL_SUCCESS;
148 }
149 
IsOverlapInput(const string & inputPath)150 bool PackageParser::IsOverlapInput(const string& inputPath)
151 {
152     if (isOverlap_) {
153         return false;
154     }
155 
156     string indexPath = FileEntry::FilePath(inputPath).Append(RESOURCE_INDEX_FILE).GetPath();
157     if (ResourceUtil::FileExist(indexPath)) {
158         isOverlap_ = true;
159         return true;
160     }
161 
162     string jsonIndexPath = ResourceUtil::GetMainPath(inputPath).Append(RESOURCE_INDEX_FILE).GetPath();
163     string txtResHeaderPath = ResourceUtil::GetMainPath(inputPath).Append("ResourceTable.txt").GetPath();
164     string jsResHeaderPath = ResourceUtil::GetMainPath(inputPath).Append("ResourceTable.js").GetPath();
165     string hResJsHeaderPath = ResourceUtil::GetMainPath(inputPath).Append("ResourceTable.h").GetPath();
166     if (ResourceUtil::FileExist(jsonIndexPath) &&
167         !ResourceUtil::FileExist(txtResHeaderPath) &&
168         !ResourceUtil::FileExist(jsResHeaderPath) &&
169         !ResourceUtil::FileExist(hResJsHeaderPath)) {
170         isOverlap_ = true;
171         return true;
172     }
173 
174     return false;
175 }
176 
AddSysIdDefined(const std::string & argValue)177 uint32_t PackageParser::AddSysIdDefined(const std::string& argValue)
178 {
179     string sysIdDefinedPath = ResourceUtil::RealPath(argValue);
180     if (sysIdDefinedPath.empty()) {
181         PrintError(GetError(ERR_CODE_INVALID_SYSTEM_ID_DEFINED).FormatCause(argValue.c_str()));
182         return RESTOOL_ERROR;
183     }
184 
185     auto ret = find_if(sysIdDefinedPaths_.begin(), sysIdDefinedPaths_.end(),
186         [sysIdDefinedPath](auto iter) {return sysIdDefinedPath == iter;});
187     if (ret != sysIdDefinedPaths_.end()) {
188         PrintError(GetError(ERR_CODE_DUPLICATE_SYSTEM_ID_DEFINED).FormatCause(argValue.c_str()));
189         return RESTOOL_ERROR;
190     }
191 
192     if (!IsAscii(sysIdDefinedPath)) {
193         return RESTOOL_ERROR;
194     }
195     sysIdDefinedPaths_.push_back(sysIdDefinedPath);
196     return RESTOOL_SUCCESS;
197 }
198 
AddPackageName(const string & argValue)199 uint32_t PackageParser::AddPackageName(const string& argValue)
200 {
201     if (!packageName_.empty()) {
202         PrintError(GetError(ERR_CODE_DOUBLE_PACKAGE_NAME).FormatCause(packageName_.c_str(), argValue.c_str()));
203         return RESTOOL_ERROR;
204     }
205 
206     packageName_ = argValue;
207     return RESTOOL_SUCCESS;
208 }
209 
AddOutput(const string & argValue)210 uint32_t PackageParser::AddOutput(const string& argValue)
211 {
212     if (!output_.empty()) {
213         PrintError(GetError(ERR_CODE_DOUBLE_OUTPUT).FormatCause(output_.c_str(), argValue.c_str()));
214         return RESTOOL_ERROR;
215     }
216 
217     output_ = ResourceUtil::RealPath(argValue);
218     if (output_.empty()) {
219         PrintError(GetError(ERR_CODE_INVALID_OUTPUT).FormatCause(argValue.c_str()));
220         return RESTOOL_ERROR;
221     }
222     if (!IsAscii(output_)) {
223         return RESTOOL_ERROR;
224     }
225     return RESTOOL_SUCCESS;
226 }
227 
AddResourceHeader(const string & argValue)228 uint32_t PackageParser::AddResourceHeader(const string &argValue)
229 {
230     if (find(resourceHeaderPaths_.begin(), resourceHeaderPaths_.end(), argValue) != resourceHeaderPaths_.end()) {
231         PrintError(GetError(ERR_CODE_DUPLICATE_RES_HEADER).FormatCause(argValue.c_str()));
232         return RESTOOL_ERROR;
233     }
234     resourceHeaderPaths_.push_back(argValue);
235     return RESTOOL_SUCCESS;
236 }
237 
ForceWrite()238 uint32_t PackageParser::ForceWrite()
239 {
240     forceWrite_ = true;
241     return RESTOOL_SUCCESS;
242 }
243 
PrintVersion()244 uint32_t PackageParser::PrintVersion()
245 {
246     cout << "Info: Restool version= " << RESTOOL_VERSION << endl;
247     exit(RESTOOL_SUCCESS);
248     return RESTOOL_SUCCESS;
249 }
250 
AddMoudleNames(const string & argValue)251 uint32_t PackageParser::AddMoudleNames(const string& argValue)
252 {
253     if (!moduleNames_.empty()) {
254         std::string existModuleNames;
255         for (const auto &module : moduleNames_) { existModuleNames.append(module).append(","); }
256         existModuleNames.pop_back();
257         PrintError(GetError(ERR_CODE_DOUBLE_MODULES).FormatCause(existModuleNames.c_str(), argValue.c_str()));
258         return RESTOOL_ERROR;
259     }
260 
261     ResourceUtil::Split(argValue, moduleNames_, ",");
262     for (auto it = moduleNames_.begin(); it != moduleNames_.end(); it++) {
263         auto ret = find_if(moduleNames_.begin(), moduleNames_.end(), [it](auto iter) {return *it == iter;});
264         if (ret != it) {
265             PrintError(GetError(ERR_CODE_DUPLICATE_MODULE_NAME).FormatCause(it->c_str()));
266             return RESTOOL_ERROR;
267         }
268     }
269     return RESTOOL_SUCCESS;
270 }
271 
AddConfig(const string & argValue)272 uint32_t PackageParser::AddConfig(const string& argValue)
273 {
274     if (!configPath_.empty()) {
275         PrintError(GetError(ERR_CODE_DOUBLE_CONFIG_JSON).FormatCause(configPath_.c_str(), argValue.c_str()));
276         return RESTOOL_ERROR;
277     }
278 
279     configPath_ = argValue;
280     return RESTOOL_SUCCESS;
281 }
282 
AddStartId(const string & argValue)283 uint32_t PackageParser::AddStartId(const string& argValue)
284 {
285     char *end;
286     errno = 0;
287     long long id = static_cast<long long>(strtoll(argValue.c_str(), &end, 16)); // 16 is hexadecimal number
288     if (end == argValue.c_str() || errno == ERANGE || *end != '\0' || id == LLONG_MAX || id == LLONG_MIN) {
289         PrintError(GetError(ERR_CODE_INVALID_START_ID).FormatCause(argValue.c_str()));
290         return RESTOOL_ERROR;
291     }
292     if (id <= 0) {
293         PrintError(GetError(ERR_CODE_INVALID_START_ID).FormatCause(argValue.c_str()));
294         return RESTOOL_ERROR;
295     }
296     if ((id >= 0x01000000 && id < 0x06ffffff) || (id >= 0x08000000 && id < 0xffffffff)) {
297         startId_ = static_cast<uint32_t>(id);
298         return RESTOOL_SUCCESS;
299     }
300     PrintError(GetError(ERR_CODE_INVALID_START_ID).FormatCause(argValue.c_str()));
301     return RESTOOL_ERROR;
302 }
303 
304 // -i input directory, add the resource directory
AdaptResourcesDirForInput()305 void PackageParser::AdaptResourcesDirForInput()
306 {
307     if (!isFileList_ && !combine_) { // -l and increment compile -i, no need to add resource directory
308         for (auto &path : inputs_) {
309             path = FileEntry::FilePath(path).Append(RESOURCES_DIR).GetPath();
310         }
311     }
312 }
313 
CheckParam() const314 uint32_t PackageParser::CheckParam() const
315 {
316     if (inputs_.empty() && append_.empty()) {
317         PrintError(GetError(ERR_CODE_INVALID_INPUT).FormatCause(""));
318         return RESTOOL_ERROR;
319     }
320 
321     if (output_.empty()) {
322         PrintError(GetError(ERR_CODE_INVALID_OUTPUT).FormatCause(""));
323         return RESTOOL_ERROR;
324     }
325 
326     if (isTargetConfig_ && !append_.empty()) {
327         PrintError(GetError(ERR_CODE_EXCLUSIVE_OPTION).FormatCause("-x", "--target-config"));
328         return RESTOOL_ERROR;
329     }
330 
331     if (!append_.empty()) {
332         return RESTOOL_SUCCESS;
333     }
334 
335     if (packageName_.empty()) {
336         PrintError(ERR_CODE_PACKAGE_NAME_EMPTY);
337         return RESTOOL_ERROR;
338     }
339 
340     if (resourceHeaderPaths_.empty()) {
341         PrintError(ERR_CODE_RES_HEADER_PATH_EMPTY);
342         return RESTOOL_ERROR;
343     }
344 
345     if (startId_ != 0 && !idDefinedInputPath_.empty()) {
346         PrintError(GetError(ERR_CODE_EXCLUSIVE_OPTION).FormatCause("-e", "--defined-ids"));
347         return RESTOOL_ERROR;
348     }
349 
350     return RESTOOL_SUCCESS;
351 }
352 
IsFileList() const353 bool PackageParser::IsFileList() const
354 {
355     return isFileList_;
356 }
357 
AddAppend(const string & argValue)358 uint32_t PackageParser::AddAppend(const string& argValue)
359 {
360     string appendPath = ResourceUtil::RealPath(argValue);
361     if (appendPath.empty()) {
362         cout << "Warning: invalid compress '" << argValue << "'" << endl;
363         appendPath = argValue;
364     }
365     auto ret = find_if(append_.begin(), append_.end(), [appendPath](auto iter) {return appendPath == iter;});
366     if (ret != append_.end()) {
367         PrintError(GetError(ERR_CODE_DUPLICATE_APPEND_PATH).FormatCause(argValue.c_str()));
368         return RESTOOL_ERROR;
369     }
370     if (!IsAscii(appendPath)) {
371         return RESTOOL_ERROR;
372     }
373     append_.push_back(appendPath);
374     return RESTOOL_SUCCESS;
375 }
376 
GetAppend() const377 const vector<string> &PackageParser::GetAppend() const
378 {
379     return append_;
380 }
381 
SetCombine()382 uint32_t PackageParser::SetCombine()
383 {
384     combine_ = true;
385     return RESTOOL_SUCCESS;
386 }
387 
GetCombine() const388 bool PackageParser::GetCombine() const
389 {
390     return combine_;
391 }
392 
AddDependEntry(const string & argValue)393 uint32_t PackageParser::AddDependEntry(const string& argValue)
394 {
395     dependEntry_ = argValue;
396     return RESTOOL_SUCCESS;
397 }
398 
ShowHelp() const399 uint32_t PackageParser::ShowHelp() const
400 {
401     auto &parser = CmdParser::GetInstance();
402     parser.ShowUseage();
403     exit(RESTOOL_SUCCESS);
404     return RESTOOL_SUCCESS;
405 }
406 
SetIdDefinedOutput(const string & argValue)407 uint32_t PackageParser::SetIdDefinedOutput(const string& argValue)
408 {
409     idDefinedOutput_ = argValue;
410     return RESTOOL_SUCCESS;
411 }
412 
GetIdDefinedOutput() const413 const string &PackageParser::GetIdDefinedOutput() const
414 {
415     return idDefinedOutput_;
416 }
417 
SetIdDefinedInputPath(const string & argValue)418 uint32_t PackageParser::SetIdDefinedInputPath(const string& argValue)
419 {
420     idDefinedInputPath_ = argValue;
421     return RESTOOL_SUCCESS;
422 }
423 
GetIdDefinedInputPath() const424 const string &PackageParser::GetIdDefinedInputPath() const
425 {
426     return idDefinedInputPath_;
427 }
428 
IconCheck()429 uint32_t PackageParser::IconCheck()
430 {
431     isIconCheck_ = true;
432     return RESTOOL_SUCCESS;
433 }
434 
GetIconCheck() const435 bool PackageParser::GetIconCheck() const
436 {
437     return isIconCheck_;
438 }
439 
ParseTargetConfig(const string & argValue)440 uint32_t PackageParser::ParseTargetConfig(const string& argValue)
441 {
442     if (isTargetConfig_) {
443         PrintError(GetError(ERR_CODE_DOUBLE_TARGET_CONFIG).FormatCause(targetConfigValue_.c_str(), argValue.c_str()));
444         return RESTOOL_ERROR;
445     }
446     if (!SelectCompileParse::ParseTargetConfig(argValue, targetConfig_)) {
447         PrintError(GetError(ERR_CODE_INVALID_TARGET_CONFIG).FormatCause(argValue.c_str()));
448         return RESTOOL_ERROR;
449     }
450     isTargetConfig_ = true;
451     targetConfigValue_ = argValue;
452     return RESTOOL_SUCCESS;
453 }
454 
ParseThread(const std::string & argValue)455 uint32_t PackageParser::ParseThread(const std::string &argValue)
456 {
457     if (argValue.empty()) {
458         return RESTOOL_SUCCESS;
459     }
460     char *end;
461     errno = 0;
462     int count = static_cast<int>(strtol(argValue.c_str(), &end, 10));
463     if (end == argValue.c_str() || errno == ERANGE || *end != '\0' || count == INT_MIN || count == INT_MAX) {
464         PrintError(GetError(ERR_CODE_INVALID_THREAD_COUNT).FormatCause(argValue.c_str()));
465         return RESTOOL_ERROR;
466     }
467     if (count <= 0) {
468         PrintError(GetError(ERR_CODE_INVALID_THREAD_COUNT).FormatCause(argValue.c_str()));
469         return RESTOOL_ERROR;
470     }
471     threadCount_ = static_cast<size_t>(count);
472     return RESTOOL_SUCCESS;
473 }
474 
GetThreadCount() const475 size_t PackageParser::GetThreadCount() const
476 {
477     return threadCount_;
478 }
479 
GetTargetConfigValues() const480 const TargetConfig &PackageParser::GetTargetConfigValues() const
481 {
482     return targetConfig_;
483 }
484 
IsTargetConfig() const485 bool PackageParser::IsTargetConfig() const
486 {
487     return isTargetConfig_;
488 }
489 
IsAscii(const string & argValue) const490 bool PackageParser::IsAscii(const string& argValue) const
491 {
492 #ifdef __WIN32
493     auto result = find_if(argValue.begin(), argValue.end(), [](auto iter) {
494         if ((iter & 0x80) != 0) {
495             return true;
496         }
497         return false;
498     });
499     if (result != argValue.end()) {
500         PrintError(GetError(ERR_CODE_NON_ASCII).FormatCause(argValue.c_str()));
501         return false;
502     }
503 #endif
504     return true;
505 }
506 
AddCompressionPath(const std::string & argValue)507 uint32_t PackageParser::AddCompressionPath(const std::string& argValue)
508 {
509     if (!compressionPath_.empty()) {
510         PrintError(GetError(ERR_CODE_DOUBLE_COMPRESSION_PATH).FormatCause(compressionPath_.c_str(), argValue.c_str()));
511         return RESTOOL_ERROR;
512     }
513     compressionPath_ = argValue;
514     return RESTOOL_SUCCESS;
515 }
516 
GetCompressionPath() const517 const std::string &PackageParser::GetCompressionPath() const
518 {
519     return compressionPath_;
520 }
521 
IsOverlap() const522 bool PackageParser::IsOverlap() const
523 {
524     return isOverlap_;
525 }
526 
InitCommand()527 void PackageParser::InitCommand()
528 {
529     using namespace placeholders;
530     handles_.emplace(Option::INPUTPATH, bind(&PackageParser::AddInput, this, _1));
531     handles_.emplace(Option::PACKAGENAME, bind(&PackageParser::AddPackageName, this, _1));
532     handles_.emplace(Option::OUTPUTPATH, bind(&PackageParser::AddOutput, this, _1));
533     handles_.emplace(Option::RESHEADER, bind(&PackageParser::AddResourceHeader, this, _1));
534     handles_.emplace(Option::FORCEWRITE, [this](const string &) -> uint32_t { return ForceWrite(); });
535     handles_.emplace(Option::VERSION, [this](const string &) -> uint32_t { return PrintVersion(); });
536     handles_.emplace(Option::MODULES, bind(&PackageParser::AddMoudleNames, this, _1));
537     handles_.emplace(Option::JSON, bind(&PackageParser::AddConfig, this, _1));
538     handles_.emplace(Option::STARTID, bind(&PackageParser::AddStartId, this, _1));
539     handles_.emplace(Option::APPEND, bind(&PackageParser::AddAppend, this, _1));
540     handles_.emplace(Option::COMBINE, [this](const string &) -> uint32_t { return SetCombine(); });
541     handles_.emplace(Option::DEPENDENTRY, bind(&PackageParser::AddDependEntry, this, _1));
542     handles_.emplace(Option::HELP, [this](const string &) -> uint32_t { return ShowHelp(); });
543     handles_.emplace(Option::IDS, bind(&PackageParser::SetIdDefinedOutput, this, _1));
544     handles_.emplace(Option::DEFINED_IDS, bind(&PackageParser::SetIdDefinedInputPath, this, _1));
545     handles_.emplace(Option::ICON_CHECK, [this](const string &) -> uint32_t { return IconCheck(); });
546     handles_.emplace(Option::TARGET_CONFIG, bind(&PackageParser::ParseTargetConfig, this, _1));
547     handles_.emplace(Option::DEFINED_SYSIDS, bind(&PackageParser::AddSysIdDefined, this, _1));
548     handles_.emplace(Option::COMPRESSED_CONFIG, bind(&PackageParser::AddCompressionPath, this, _1));
549     handles_.emplace(Option::THREAD, bind(&PackageParser::ParseThread, this, _1));
550 }
551 
HandleProcess(int c,const string & argValue)552 uint32_t PackageParser::HandleProcess(int c, const string &argValue)
553 {
554     auto handler = handles_.find(c);
555     if (handler == handles_.end()) {
556         cout << "Warning: unsupport " << c << endl;
557         return RESTOOL_ERROR;
558     }
559     return handler->second(argValue);
560 }
561 
ParseFileList(const string & fileListPath)562 uint32_t PackageParser::ParseFileList(const string& fileListPath)
563 {
564     isFileList_ = true;
565     ResConfigParser resConfigParser;
566     if (resConfigParser.Init(fileListPath, [this](int c, const string &argValue) -> uint32_t {
567         return HandleProcess(c, argValue);
568     }) != RESTOOL_SUCCESS) {
569         return RESTOOL_ERROR;
570     }
571     return RESTOOL_SUCCESS;
572 }
573 
CheckError(int argc,char * argv[],int c,int optIndex)574 uint32_t PackageParser::CheckError(int argc, char *argv[], int c, int optIndex)
575 {
576     if (optIndex != -1) {
577         if ((optarg == nullptr && (optind - 1 < 0 || optind - 1 >= argc)) ||
578             (optarg != nullptr && (optind - 2 < 0 || optind - 2 >= argc))) { // 1 or 2 menas optind offset value
579             return RESTOOL_ERROR;
580         }
581         string curOpt = (optarg == nullptr) ? argv[optind - 1] : argv[optind - 2];
582         if (curOpt != ("--" + string(CMD_OPTS[optIndex].name))) {
583             PrintError(GetError(ERR_CODE_UNKNOWN_OPTION).FormatCause(curOpt.c_str()));
584             return RESTOOL_ERROR;
585         }
586     }
587     if (c == Option::UNKNOWN) {
588         if (optopt == 0 && (optind - 1 < 0 || optind - 1 >= argc)) {
589             return RESTOOL_ERROR;
590         }
591         string optUnknown = (optopt == 0) ? argv[optind - 1] : ("-" + string(1, optopt));
592         PrintError(GetError(ERR_CODE_UNKNOWN_OPTION).FormatCause(optUnknown.c_str()));
593         return RESTOOL_ERROR;
594     }
595     if (c == Option::NO_ARGUMENT) {
596         if (optind - 1 < 0 || optind - 1 >= argc) {
597             return RESTOOL_ERROR;
598         }
599         if (IsLongOpt(argc, argv)) {
600             PrintError(GetError(ERR_CODE_MISSING_ARGUMENT).FormatCause(argv[optind - 1]));
601         } else {
602             PrintError(GetError(ERR_CODE_UNKNOWN_OPTION).FormatCause(argv[optind - 1]));
603         }
604         return RESTOOL_ERROR;
605     }
606     return RESTOOL_SUCCESS;
607 }
608 
ParseCommand(int argc,char * argv[])609 uint32_t PackageParser::ParseCommand(int argc, char *argv[])
610 {
611     restoolPath_ = string(argv[0]);
612     while (optind <= argc) {
613         int optIndex = -1;
614         int c = getopt_long(argc, argv, CMD_PARAMS.c_str(), CMD_OPTS, &optIndex);
615         if (CheckError(argc, argv, c, optIndex) != RESTOOL_SUCCESS) {
616             return RESTOOL_ERROR;
617         }
618         if (c == Option::END) {
619             if (argc == optind) {
620                 break;
621             }
622             string errmsg;
623             for (int i = optind; i < argc; i++) {
624                 errmsg.append(argv[i]).append(",");
625             }
626             errmsg.pop_back();
627             PrintError(GetError(ERR_CODE_INVALID_ARGUMENT).FormatCause(errmsg.c_str()));
628             return RESTOOL_ERROR;
629         }
630 
631         string argValue = (optarg != nullptr) ? optarg : "";
632         if (c == Option::FILELIST) {
633             return ParseFileList(argValue);
634         }
635         if (HandleProcess(c, argValue) != RESTOOL_SUCCESS) {
636             return RESTOOL_ERROR;
637         }
638     }
639     return RESTOOL_SUCCESS;
640 }
641 
IsLongOpt(int argc,char * argv[]) const642 bool PackageParser::IsLongOpt(int argc, char *argv[]) const
643 {
644     if (optind - 1 < 0 || optind - 1 >= argc) {
645         return false;
646     }
647     for (auto iter : CMD_OPTS) {
648         if (optopt == iter.val && argv[optind - 1] == ("--" + string(iter.name))) {
649             return true;
650         }
651     }
652     return false;
653 }
654 
ExecCommand()655 uint32_t PackageParser::ExecCommand()
656 {
657     return ResourcePack(*this).Package();
658 }
659 }
660 }
661 }
662