• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 <iostream>
17 #include <sstream>
18 #ifdef __WIN32
19 #include <windows.h>
20 #else
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24 #endif
25 
26 #include "resource_util.h"
27 #include "restool_errors.h"
28 
29 namespace OHOS {
30 namespace Global {
31 namespace Restool {
32 const std::map<uint32_t, ErrorInfo> ERRORS_MAP = {
33     // 11200000
34     { ERR_CODE_UNDEFINED_ERROR,
35       { ERR_CODE_UNDEFINED_ERROR, "Undefined Error", "Unknown error: %s", "", { "Please try again." }, {} } },
36 
37     // 11201xxx
38     { ERR_CODE_LOAD_LIBRARY_FAIL,
39       { ERR_CODE_LOAD_LIBRARY_FAIL,
40         ERR_TYPE_DEPENDENCY,
41         "Failed to load the library '%s', %s",
42         "",
43         { "Make sure the library path is correct and has access permissions.",
44           "Install the missing third-party dependency libraries displayed in the error information.",
45           "Adding the path 'openharmony\\previewer\\common\\bin' in your SDK path to environment variables." },
46         {} } },
47 
48     // 11203xxx
49     { ERR_CODE_OPEN_JSON_FAIL,
50       { ERR_CODE_OPEN_JSON_FAIL,
51         ERR_TYPE_CONFIG,
52         "Failed to open the JSON file '%s', %s.",
53         "",
54         { "Make sure the JSON file path is correct and has access permissions." },
55         {} } },
56     { ERR_CODE_JSON_FORMAT_ERROR,
57       { ERR_CODE_JSON_FORMAT_ERROR,
58         ERR_TYPE_CONFIG,
59         "Failed to parse the JSON file: incorrect format.",
60         "",
61         { "Check the JSON file and delete unnecessary commas (,).",
62           "Check the JSON file to make sure the root bracket is {}." },
63         {} } },
64     { ERR_CODE_JSON_NODE_MISMATCH,
65       { ERR_CODE_JSON_NODE_MISMATCH,
66         ERR_TYPE_CONFIG,
67         "The value type of node '%s' does not match. Expected type: %s.",
68         "",
69         {},
70         {} } },
71     { ERR_CODE_JSON_NODE_MISSING,
72       { ERR_CODE_JSON_NODE_MISSING, ERR_TYPE_CONFIG, "The required node '%s' is missing.", "", {}, {} } },
73     { ERR_CODE_JSON_NODE_EMPTY,
74       { ERR_CODE_JSON_NODE_EMPTY, ERR_TYPE_CONFIG, "The array or object node '%s' cannot be empty.", "", {}, {} } },
75     { ERR_CODE_JSON_NOT_ONE_MEMBER,
76       { ERR_CODE_JSON_NOT_ONE_MEMBER,
77         ERR_TYPE_CONFIG,
78         "The node '%s' in the JSON file can only have one member.",
79         "",
80         {},
81         {} } },
82     { ERR_CODE_JSON_INVALID_NODE_NAME,
83       { ERR_CODE_JSON_INVALID_NODE_NAME, ERR_TYPE_CONFIG, "Invalid node name '%s'. Valid values: %s.", "", {}, {} } },
84 
85     // 11204xxx
86     { ERR_CODE_CREATE_FILE_ERROR,
87       { ERR_CODE_CREATE_FILE_ERROR,
88         ERR_TYPE_FILE_RESOURCE,
89         "Failed to create the directory or file '%s', %s.",
90         "",
91         { "Make sure the file path is correct and has access permissions." },
92         {} } },
93     { ERR_CODE_REMOVE_FILE_ERROR,
94       { ERR_CODE_REMOVE_FILE_ERROR,
95         ERR_TYPE_FILE_RESOURCE,
96         "Failed to delete the directory or file '%s', %s.",
97         "",
98         { "Make sure the file path is correct and has access permissions." },
99         {} } },
100     { ERR_CODE_COPY_FILE_ERROR,
101       { ERR_CODE_COPY_FILE_ERROR,
102         ERR_TYPE_FILE_RESOURCE,
103         "Failed to copy the file from '%s' to '%s', %s.",
104         "",
105         { "Make sure the src and dest file path is correct and has access permissions." },
106         {} } },
107     { ERR_CODE_OPEN_FILE_ERROR,
108       { ERR_CODE_OPEN_FILE_ERROR,
109         ERR_TYPE_FILE_RESOURCE,
110         "Failed to open the file '%s', %s.",
111         "",
112         { "Make sure the file path is correct and has access permissions." },
113         {} } },
114     { ERR_CODE_READ_FILE_ERROR,
115       { ERR_CODE_READ_FILE_ERROR,
116         ERR_TYPE_FILE_RESOURCE,
117         "Failed to read the file '%s', %s.",
118         "",
119         { "Make sure the file content is correct." },
120         {} } },
121 
122     // 11210xxx
123     { ERR_CODE_UNKNOWN_COMMAND_ERROR,
124       { ERR_CODE_UNKNOWN_COMMAND_ERROR,
125         ERR_TYPE_COMMAND_PARSE,
126         "Unknown command error: %s",
127         "",
128         { "For details, see the help with option -h/--help." },
129         {} } },
130     { ERR_CODE_UNKNOWN_OPTION,
131       { ERR_CODE_UNKNOWN_OPTION,
132         ERR_TYPE_COMMAND_PARSE,
133         "Unknown option '%s'.",
134         "",
135         { "For details, see the help with option -h/--help." },
136         {} } },
137     { ERR_CODE_MISSING_ARGUMENT,
138       { ERR_CODE_MISSING_ARGUMENT,
139         ERR_TYPE_COMMAND_PARSE,
140         "Option '%s' requires an argument.",
141         "",
142         { "For details, see the help with option -h/--help." },
143         {} } },
144     { ERR_CODE_INVALID_ARGUMENT,
145       { ERR_CODE_INVALID_ARGUMENT,
146         ERR_TYPE_COMMAND_PARSE,
147         "Invalid argument value '%s'.",
148         "",
149         { "For details, see the help with option -h/--help." },
150         {} } },
151     { ERR_CODE_INVALID_INPUT,
152       { ERR_CODE_INVALID_INPUT,
153         ERR_TYPE_COMMAND_PARSE,
154         "Invalid input path '%s'.",
155         "",
156         { "Make sure the input path of option -i/--inputPath is correct." },
157         {} } },
158     { ERR_CODE_DUPLICATE_INPUT,
159       { ERR_CODE_DUPLICATE_INPUT,
160         ERR_TYPE_COMMAND_PARSE,
161         "Duplicated input path '%s'.",
162         "",
163         { "Make sure the input path of option -i/--inputPath is unique." },
164         {} } },
165     { ERR_CODE_DOUBLE_PACKAGE_NAME,
166       { ERR_CODE_DOUBLE_PACKAGE_NAME,
167         ERR_TYPE_COMMAND_PARSE,
168         "The package name '%s' and '%s' conflict.",
169         "",
170         { "Make sure the option -p/--packageName only specified once." },
171         {} } },
172     { ERR_CODE_INVALID_OUTPUT,
173       { ERR_CODE_INVALID_OUTPUT,
174         ERR_TYPE_COMMAND_PARSE,
175         "Invalid output path '%s'.",
176         "",
177         { "Make sure the output path of option -o/--outputPath is correct." },
178         {} } },
179     { ERR_CODE_DOUBLE_OUTPUT,
180       { ERR_CODE_DOUBLE_OUTPUT,
181         ERR_TYPE_COMMAND_PARSE,
182         "The output paths '%s' and '%s' conflict.",
183         "",
184         { "Make sure the option -o/--outputPath only specified once." },
185         {} } },
186     { ERR_CODE_DUPLICATE_RES_HEADER,
187       { ERR_CODE_DUPLICATE_RES_HEADER,
188         ERR_TYPE_COMMAND_PARSE,
189         "Duplicated resource header path '%s'.",
190         "",
191         { "Make sure the path of option -r/--resHeader is unique." },
192         {} } },
193     { ERR_CODE_DOUBLE_MODULES,
194       { ERR_CODE_DOUBLE_MODULES,
195         ERR_TYPE_COMMAND_PARSE,
196         "The module names '%s' and '%s' conflict.",
197         "",
198         { "Make sure the option -m/--modules only specified once." },
199         {} } },
200     { ERR_CODE_DUPLICATE_MODULE_NAME,
201       { ERR_CODE_DUPLICATE_MODULE_NAME,
202         ERR_TYPE_COMMAND_PARSE,
203         "Duplicated module name '%s'.",
204         "",
205         { "Make sure the module names specified with option -m/--modules is unique." },
206         {} } },
207     { ERR_CODE_DOUBLE_CONFIG_JSON,
208       { ERR_CODE_DOUBLE_CONFIG_JSON,
209         ERR_TYPE_COMMAND_PARSE,
210         "The paths '%s' and '%s' of the module.json(in Stage Model) or config.json(in FA Model) file conflict.",
211         "",
212         { "Make sure the option -j/--json only specified once." },
213         {} } },
214     { ERR_CODE_INVALID_START_ID,
215       { ERR_CODE_INVALID_START_ID,
216         ERR_TYPE_COMMAND_PARSE,
217         "Invalid start ID '%s'. It is out of range.",
218         "",
219         { "Make sure the start id in the scope [0x01000000, 0x06FFFFFF) or [0x08000000, 0xFFFFFFFF)." },
220         {} } },
221     { ERR_CODE_DUPLICATE_APPEND_PATH,
222       { ERR_CODE_DUPLICATE_APPEND_PATH,
223         ERR_TYPE_COMMAND_PARSE,
224         "Duplicated append path '%s'.",
225         "",
226         { "Make sure the path of option -x/--append is unique." },
227         {} } },
228     { ERR_CODE_DOUBLE_TARGET_CONFIG,
229       { ERR_CODE_DOUBLE_TARGET_CONFIG,
230         ERR_TYPE_COMMAND_PARSE,
231         "The target configurations '%s' and '%s' conflict.",
232         "",
233         { "Make sure the option --target-config only specified once." },
234         {} } },
235     { ERR_CODE_INVALID_TARGET_CONFIG,
236       { ERR_CODE_INVALID_TARGET_CONFIG,
237         ERR_TYPE_COMMAND_PARSE,
238         "Invalid target configuration argument '%s'. The argument format for option --target-config should be like "
239         "'Locale[zh_CN,en_US];Device[phone]'.",
240         "",
241         { "For more information, see the developer documentation." },
242         {} } },
243     { ERR_CODE_INVALID_SYSTEM_ID_DEFINED,
244       { ERR_CODE_INVALID_SYSTEM_ID_DEFINED,
245         ERR_TYPE_COMMAND_PARSE,
246         "Invalid system id_defined.json path '%s'.",
247         "",
248         { "Make sure the system id_defined.json path is correct." },
249         {} } },
250     { ERR_CODE_DUPLICATE_SYSTEM_ID_DEFINED,
251       { ERR_CODE_DUPLICATE_SYSTEM_ID_DEFINED,
252         ERR_TYPE_COMMAND_PARSE,
253         "Duplicated system id_defined.json path '%s'.",
254         "",
255         { "Make sure the system id_defined.json path is unique." },
256         {} } },
257     { ERR_CODE_DOUBLE_COMPRESSION_PATH,
258       { ERR_CODE_DOUBLE_COMPRESSION_PATH,
259         ERR_TYPE_COMMAND_PARSE,
260         "The compression JSON paths '%s' and '%s' conflict.",
261         "",
262         { "Make sure the option --compressed-config only specified once." },
263         {} } },
264     { ERR_CODE_NON_ASCII,
265       { ERR_CODE_NON_ASCII,
266         ERR_TYPE_COMMAND_PARSE,
267         "The argument value '%s' is not an ASCII value.",
268         "",
269         { "Make sure all the arguments value characters is ASCII." },
270         {} } },
271     { ERR_CODE_EXCLUSIVE_OPTION,
272       { ERR_CODE_EXCLUSIVE_OPTION,
273         ERR_TYPE_COMMAND_PARSE,
274         "Options '%s' and '%s' cannot be used together.",
275         "",
276         {},
277         {} } },
278     { ERR_CODE_PACKAGE_NAME_EMPTY,
279       { ERR_CODE_PACKAGE_NAME_EMPTY,
280         ERR_TYPE_COMMAND_PARSE,
281         "The package name is empty. It should be specified with option -p/--packageName.",
282         "",
283         { "Specifies the package name with option -p/--packageName." },
284         {} } },
285     { ERR_CODE_RES_HEADER_PATH_EMPTY,
286       { ERR_CODE_RES_HEADER_PATH_EMPTY,
287         ERR_TYPE_COMMAND_PARSE,
288         "The resource header path (for example, ./ResourceTable.js, ./ResourceTable.h) is empty. It should be specified"
289         " with option -r/--resHeader.",
290         "",
291         { "Specifies header path with option -r/--resHeader." },
292         {} } },
293     { ERR_CODE_DUMP_MISSING_INPUT,
294       { ERR_CODE_DUMP_MISSING_INPUT,
295         ERR_TYPE_COMMAND_PARSE,
296         "The HAP path of the resource dump command is missing.",
297         "",
298         { "Specifies a HAP path with dump command." },
299         {} } },
300     { ERR_CODE_DUMP_INVALID_INPUT,
301       { ERR_CODE_DUMP_INVALID_INPUT,
302         ERR_TYPE_COMMAND_PARSE,
303         "Invalid HAP path '%s' in the resource dump command.",
304         "",
305         { "Make sure the HAP path of dump command is correct." },
306         {} } },
307     { ERR_CODE_INVALID_THREAD_COUNT,
308       { ERR_CODE_INVALID_THREAD_COUNT,
309         ERR_TYPE_COMMAND_PARSE,
310         "Invalid thread count '%s'. It should be an integer greater than 0.",
311         "",
312         {},
313         {} } },
314     { ERR_CODE_INVALID_IGNORE_FILE,
315       { ERR_CODE_INVALID_IGNORE_FILE,
316         ERR_TYPE_COMMAND_PARSE,
317         "Invalid ignore file pattern '%s', %s",
318         "",
319         { "Make sure the argument of the option --ignored-file is not empty and contains valid regular expressions." },
320         {} } },
321 
322     // 11211xxx
323     { ERR_CODE_OUTPUT_EXIST,
324       { ERR_CODE_OUTPUT_EXIST,
325         ERR_TYPE_RESOURCE_PACK,
326         "The output path exists. Specify option -f/--forceWrite to overwrite.",
327         "",
328         { "Remove the exist output dir or use option -f to force write." },
329         {} } },
330     { ERR_CODE_CONFIG_JSON_MISSING,
331       { ERR_CODE_CONFIG_JSON_MISSING,
332         ERR_TYPE_RESOURCE_PACK,
333         "There are multiple input paths, but the path of the module.json (in the stage model) or config.json "
334         "(in the FA model) file is not specified with option -j/--json.",
335         "",
336         { "Specifies option -j/--json." },
337         {} } },
338     { ERR_CODE_INVALID_MODULE_TYPE,
339       { ERR_CODE_INVALID_MODULE_TYPE,
340         ERR_TYPE_RESOURCE_PACK,
341         "Invalid module type '%s'. Valid values: [\"entry\", \"har\", \"shared\", \"feature\"].",
342         "",
343         {},
344         {} } },
345     { ERR_CODE_EXCLUSIVE_START_ID,
346       { ERR_CODE_EXCLUSIVE_START_ID,
347         ERR_TYPE_RESOURCE_PACK,
348         "The start ID '%lu' specified by option -e/--startId conflict with the IDs in the id_defined.json file.",
349         "",
350         { "Retain only one of the id_defined.json and the start id." },
351         {} } },
352     { ERR_CODE_ID_DEFINED_INVALID_TYPE,
353       { ERR_CODE_ID_DEFINED_INVALID_TYPE,
354         ERR_TYPE_RESOURCE_PACK,
355         "Invalid resource type '%s' in the id_defined.json file. Valid values: %s.",
356         "",
357         {},
358         {} } },
359     { ERR_CODE_ID_DEFINED_INVALID_ID,
360       { ERR_CODE_ID_DEFINED_INVALID_ID,
361         ERR_TYPE_RESOURCE_PACK,
362         "Invalid id value '%s' in the id_defined.json file. It should be a hexadecimal string, match the pattern "
363         "^0[xX][0-9a-fA-F]{8}, and be in the scope [0x01000000,0x06FFFFFF] or [0x08000000,0xFFFFFFFF].",
364         "",
365         {},
366         {} } },
367     { ERR_CODE_ID_DEFINED_ORDER_MISMATCH,
368       { ERR_CODE_ID_DEFINED_ORDER_MISMATCH,
369         ERR_TYPE_RESOURCE_PACK,
370         "The order value '%lu' in the id_defined.json file does not match the record element sequence '%lu'. "
371         "Expected value: %lu.",
372         "",
373         { "Make sure the order value is same as the sequence." },
374         {} } },
375     { ERR_CODE_ID_DEFINED_SAME_ID,
376       { ERR_CODE_ID_DEFINED_SAME_ID,
377         ERR_TYPE_RESOURCE_PACK,
378         "The names '%s' and '%s' in the id_defined.json file define the same ID.",
379         "",
380         {},
381         {} } },
382     { ERR_CODE_MODULE_NAME_NOT_FOUND,
383       { ERR_CODE_MODULE_NAME_NOT_FOUND,
384         ERR_TYPE_RESOURCE_PACK,
385         "The module name '%s' is not found in %s, which is specified by -m/--modules.",
386         "",
387         { "Make sure the module name in module.json(in Stage Model) or config.json(in FA Model) is correct." },
388         {} } },
389     { ERR_CODE_INVALID_RESOURCE_PATH,
390       { ERR_CODE_INVALID_RESOURCE_PATH,
391         ERR_TYPE_RESOURCE_PACK,
392         "Failed to scan resources: invalid path '%s', %s.",
393         "",
394         {},
395         {} } },
396     { ERR_CODE_INVALID_LIMIT_KEY,
397       { ERR_CODE_INVALID_LIMIT_KEY,
398         ERR_TYPE_RESOURCE_PACK,
399         "Invalid qualifier key '%s'. It should match the pattern of the qualifiers directory, for example zh_CN or "
400         "en_US.",
401         "",
402         { "For more information, see the developer documentation." },
403         {} } },
404     { ERR_CODE_INVALID_RESOURCE_DIR,
405       { ERR_CODE_INVALID_RESOURCE_DIR,
406         ERR_TYPE_RESOURCE_PACK,
407         "Invalid resource directory name '%s'. Valid values: %s.",
408         "",
409         {},
410         {} } },
411     { ERR_CODE_INVALID_TRANSLATE_PRIORITY,
412       { ERR_CODE_INVALID_TRANSLATE_PRIORITY,
413         ERR_TYPE_RESOURCE_PACK,
414         "Invalid translate priority value '%s'. Valid values: %s.",
415         "",
416         {},
417         {} } },
418     { ERR_CODE_INVALID_ELEMENT_TYPE,
419       { ERR_CODE_INVALID_ELEMENT_TYPE,
420         ERR_TYPE_RESOURCE_PACK,
421         "Unsupported element resource type '%s'. Valid values: %s.",
422         "",
423         {},
424         {} } },
425     { ERR_CODE_INVALID_COLOR_VALUE,
426       { ERR_CODE_INVALID_COLOR_VALUE,
427         ERR_TYPE_RESOURCE_PACK,
428         "Invalid color value '%s' of the resource '%s'. It can only reference '$color:xxx' or be '#rgb','#argb',"
429         "'#rrggbb', or '#aarrggbb'.",
430         "",
431         {},
432         {} } },
433     { ERR_CODE_INVALID_RESOURCE_REF,
434       { ERR_CODE_INVALID_RESOURCE_REF,
435         ERR_TYPE_RESOURCE_PACK,
436         "Invalid resource reference '%s'. Supported reference: '%sxxx'.",
437         "",
438         {},
439         {} } },
440     { ERR_CODE_PARENT_EMPTY,
441       { ERR_CODE_PARENT_EMPTY,
442         ERR_TYPE_RESOURCE_PACK,
443         "The parent value of resource '%s' is empty. It should be a valid resource name.",
444         "",
445         {},
446         {} } },
447     { ERR_CODE_ARRAY_TOO_LARGE,
448       { ERR_CODE_ARRAY_TOO_LARGE,
449         ERR_TYPE_RESOURCE_PACK,
450         "The array resource '%s' is too large. The total length of the value of the array elements cannot exceed "
451         "65535.",
452         "",
453         { "Separate the large array into multiple arrays." },
454         {} } },
455     { ERR_CODE_INVALID_QUANTITY,
456       { ERR_CODE_INVALID_QUANTITY,
457         ERR_TYPE_RESOURCE_PACK,
458         "Invalid quantity '%s' of the plural resource '%s'. Valid values: %s.",
459         "",
460         {},
461         {} } },
462     { ERR_CODE_DUPLICATE_QUANTITY,
463       { ERR_CODE_DUPLICATE_QUANTITY,
464         ERR_TYPE_RESOURCE_PACK,
465         "Duplicated quantity '%s' of the plural resource '%s'.",
466         "",
467         { "Make sure the quantity of the plural resource is unique." },
468         {} } },
469     { ERR_CODE_QUANTITY_NO_OTHER,
470       { ERR_CODE_QUANTITY_NO_OTHER,
471         ERR_TYPE_RESOURCE_PACK,
472         "The plural resource '%s' should contain the 'other' quantity.",
473         "",
474         {},
475         {} } },
476     { ERR_CODE_INVALID_SYMBOL,
477       { ERR_CODE_INVALID_SYMBOL,
478         ERR_TYPE_RESOURCE_PACK,
479         "Invalid value '%d' of the symbol resource '%s'. It should be in the scope [0xF0000,0xFFFFF] or "
480         "[0x100000,0x10FFFF]."
481         "",
482         {},
483         {} } },
484     { ERR_CODE_INVALID_RESOURCE_NAME,
485       { ERR_CODE_INVALID_RESOURCE_NAME,
486         ERR_TYPE_RESOURCE_PACK,
487         "Invalid resource name '%s'. It should match the pattern [a-zA-Z0-9_].",
488         "",
489         { "Modify the name to match the pattern [a-zA-Z0-9_]." },
490         {} } },
491     { ERR_CODE_RESOURCE_DUPLICATE,
492       { ERR_CODE_RESOURCE_DUPLICATE,
493         ERR_TYPE_RESOURCE_PACK,
494         "Resource '%s' conflict. It is first declared at '%s' and declared again at '%s'.",
495         "",
496         { "Make sure the resource name of the same type is unique." },
497         {} } },
498     { ERR_CODE_RESOURCE_ID_EXCEED,
499       { ERR_CODE_RESOURCE_ID_EXCEED,
500         ERR_TYPE_RESOURCE_PACK,
501         "The resource ID '%lu' exceeds the maximum ID '%lu'.",
502         "",
503         { "Delete useless resources and recompile.", "Specify a smaller start id." },
504         {} } },
505     { ERR_CODE_RESOURCE_ID_NOT_DEFINED,
506       { ERR_CODE_RESOURCE_ID_NOT_DEFINED,
507         ERR_TYPE_RESOURCE_PACK,
508         "The id of resource '%s' of the '%s' type is not defined.",
509         "",
510         { "Delete useless resources and recompile." },
511         {} } },
512     { ERR_CODE_REF_NOT_DEFINED,
513       { ERR_CODE_REF_NOT_DEFINED,
514         ERR_TYPE_RESOURCE_PACK,
515         "The resource reference '%s' is not defined.",
516         "",
517         { "Check whether this resource is defined anywhere." },
518         {} } },
519     { ERR_CODE_INVALID_RESOURCE_INDEX,
520       { ERR_CODE_INVALID_RESOURCE_INDEX,
521         ERR_TYPE_RESOURCE_PACK,
522         "Failed to parse the resources.index file, %s.",
523         "",
524         { "Verify that the format of the resource.index file is correct." },
525         {} } },
526 
527     // 11212xxx
528     { ERR_CODE_PARSE_HAP_ERROR,
529       { ERR_CODE_PARSE_HAP_ERROR, ERR_TYPE_RESOURCE_DUMP, "Failed to parse the HAP, %s.", "", {}, {} } },
530 };
531 
532 #ifdef __WIN32
533 constexpr int WIN_LOCALE_CN = 2052;
534 #endif
535 const std::string LOCALE_CMD_WIN = "wmic os get locale";
536 const std::string LOCALE_CMD_LINUX = "locale";
537 const std::string LOCALE_CMD_MAC = "defaults read -globalDomain AppleLocale";
538 const std::string LOCALE_CN = "zh_CN";
539 
540 std::map<uint32_t, MoreInfo> faqInfos;
541 MoreInfo defaultMoreInfo = {};
542 Language osLanguage = Language::EN;
543 
IsValidCmd(const std::string & cmd)544 bool IsValidCmd(const std::string &cmd)
545 {
546     if (cmd == LOCALE_CMD_WIN || cmd == LOCALE_CMD_LINUX || cmd == LOCALE_CMD_MAC) {
547         return true;
548     }
549     return false;
550 }
551 
552 #ifdef __WIN32
ExecuteCommand(const std::string & cmd)553 std::string ExecuteCommand(const std::string &cmd)
554 {
555     if (!IsValidCmd(cmd)) {
556         return "";
557     }
558     SECURITY_ATTRIBUTES saAttr;
559     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
560     saAttr.bInheritHandle = TRUE;
561     saAttr.lpSecurityDescriptor = NULL;
562     HANDLE hReadPipe;
563     HANDLE hWritePipe;
564     if (!CreatePipe(&hReadPipe, &hWritePipe, &saAttr, 0)) {
565         return "CreatePipe failed";
566     }
567     STARTUPINFO si;
568     PROCESS_INFORMATION pi;
569     ZeroMemory(&si, sizeof(si));
570     si.cb = sizeof(si);
571     si.hStdError = hWritePipe;
572     si.hStdOutput = hWritePipe;
573     si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
574     si.dwFlags |= STARTF_USESTDHANDLES;
575     ZeroMemory(&pi, sizeof(pi));
576 
577     if (!CreateProcess(NULL, const_cast<LPSTR>(cmd.c_str()), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
578         CloseHandle(hReadPipe);
579         CloseHandle(hWritePipe);
580         return "CreateProcess failed";
581     }
582     // close the write end of the pipe in the parent process
583     CloseHandle(hWritePipe);
584     std::string result;
585     DWORD bytesRead;
586     CHAR buffer[BUFFER_SIZE_SMALL];
587     while (ReadFile(hReadPipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL) && bytesRead != 0) {
588         buffer[bytesRead] = '\0';
589         result += buffer;
590     }
591     WaitForSingleObject(pi.hProcess, INFINITE);
592     CloseHandle(hReadPipe);
593     CloseHandle(pi.hProcess);
594     CloseHandle(pi.hThread);
595     return result;
596 }
597 #else
split(const std::string & s,const char & delimiter)598 std::vector<std::string> split(const std::string &s, const char &delimiter)
599 {
600     std::vector<std::string> tokens;
601     std::string token;
602     std::stringstream tokenStream(s);
603     while (std::getline(tokenStream, token, delimiter)) { tokens.push_back(token); }
604     return tokens;
605 }
606 
ExecuteCommand(const std::string & cmd)607 std::string ExecuteCommand(const std::string &cmd)
608 {
609     std::string result;
610     if (!IsValidCmd(cmd)) {
611         return result;
612     }
613     int pipefd[2];
614     pid_t pid;
615     if (pipe(pipefd) == -1) {
616         perror("open pipe failed");
617         return result;
618     }
619     pid = fork();
620     if (pid == -1) {
621         perror("fork failed");
622         return result;
623     }
624     if (pid == 0) {
625         // child process
626         close(pipefd[0]);
627         dup2(pipefd[1], STDOUT_FILENO);
628         close(pipefd[1]);
629         std::vector<std::string> cmds = split(cmd, ' ');
630         char *argv[cmds.size() + 1];
631         size_t i = 0;
632         for (i = 0; i < cmds.size(); ++i) {
633             argv[i] = cmds[i].data();
634         }
635         argv[i] = nullptr;
636         execvp(argv[0], argv);
637         // if execvp returns, there was an error.
638         perror("execvp failed");
639         throw std::runtime_error("execvp failed");
640     } else {
641         // parent process
642         // close unused write end
643         close(pipefd[1]);
644         char buffer[BUFFER_SIZE_SMALL];
645         ssize_t readBytes;
646         while ((readBytes = read(pipefd[0], buffer, sizeof(buffer) - 1)) > 0) {
647             buffer[readBytes] = '\0';
648             result += buffer;
649         }
650         close(pipefd[0]);
651         wait(nullptr);
652     }
653     return result;
654 }
655 #endif
656 
657 #ifdef __WIN32
GetWinLanguage()658 Language GetWinLanguage()
659 {
660     std::string result = ExecuteCommand(LOCALE_CMD_WIN);
661     size_t pos = 0;
662     std::string locale = "Locale";
663     if ((pos = result.find(locale)) != std::string::npos) {
664         result.replace(pos, locale.length(), "");
665     }
666     if (result.empty()) {
667         return Language::CN;
668     }
669     char *end;
670     errno = 0;
671     int localeCode = static_cast<int>(strtol(result.c_str(), &end, 16));
672     if (end == result.c_str() || errno == ERANGE || localeCode == INT_MIN || localeCode == INT_MAX) {
673         return Language::CN;
674     }
675     if (localeCode == WIN_LOCALE_CN) {
676         return Language::CN;
677     }
678     return Language::EN;
679 }
680 #endif
681 
682 #ifdef __LINUX__
GetLinuxLanguage()683 Language GetLinuxLanguage()
684 {
685     std::string result = ExecuteCommand(LOCALE_CMD_LINUX);
686     if (result.empty()) {
687         return Language::CN;
688     }
689     std::vector<std::string> localeLines = split(result, '\n');
690     for (const std::string &line : localeLines) {
691         std::vector<std::string> keyValue = split(line, '=');
692         if (keyValue.size() <= 1) {
693             continue;
694         }
695         std::string key = keyValue[0];
696         std::string value = keyValue[1];
697         if ((key == "LC_ALL" || key == "LC_MESSAGES" || key == "LANG" || key == "LANGUAGE")
698             && value.find(LOCALE_CN) != std::string::npos) {
699             return Language::CN;
700         }
701     }
702     return Language::EN;
703 }
704 #endif
705 
706 #ifdef __MAC__
GetMacLanguage()707 Language GetMacLanguage()
708 {
709     std::string result = ExecuteCommand(LOCALE_CMD_MAC);
710     if (result.empty()) {
711         return Language::CN;
712     }
713     if (result.find(LOCALE_CN) != std::string::npos) {
714         return Language::CN;
715     }
716     return Language::EN;
717 }
718 #endif
719 
GetOsLanguage()720 Language GetOsLanguage()
721 {
722 #ifdef __WIN32
723     return GetWinLanguage();
724 #endif
725 
726 #ifdef __LINUX__
727     return GetLinuxLanguage();
728 #endif
729 
730 #ifdef __MAC__
731     return GetMacLanguage();
732 #endif
733     return Language::CN;
734 }
735 
GetMoreInfo(cJSON * node,MoreInfo & info)736 void GetMoreInfo(cJSON *node, MoreInfo &info)
737 {
738     if (node && cJSON_IsObject(node)) {
739         cJSON *cn = cJSON_GetObjectItem(node, "cn");
740         if (cn && cJSON_IsString(cn)) {
741             info.cn = cn->valuestring;
742         }
743         cJSON *en = cJSON_GetObjectItem(node, "en");
744         if (en && cJSON_IsString(en)) {
745             info.en = en->valuestring;
746         }
747     }
748 }
749 
InitFaq(const std::string & restoolPath)750 void InitFaq(const std::string &restoolPath)
751 {
752     osLanguage = GetOsLanguage();
753     cJSON *root;
754     std::string moreInfoPath = FileEntry::FilePath(restoolPath).GetParent().Append(ERROR_MORE_INFO_FILE).GetPath();
755     if (!ResourceUtil::OpenJsonFile(moreInfoPath, &root, false)) {
756         return;
757     }
758     if (!root || !cJSON_IsObject(root)) {
759         cJSON_Delete(root);
760         return;
761     }
762     cJSON *defaultNode = cJSON_GetObjectItem(root, "default");
763     GetMoreInfo(defaultNode, defaultMoreInfo);
764     cJSON *faqsNode = cJSON_GetObjectItem(root, "faqs");
765     if (!faqsNode || !cJSON_IsArray(faqsNode) || cJSON_GetArraySize(faqsNode) == 0) {
766         cJSON_Delete(root);
767         return;
768     }
769     for (cJSON *infoNode = faqsNode->child; infoNode; infoNode = faqsNode->next) {
770         cJSON *codeNode = cJSON_GetObjectItem(infoNode, "code");
771         if (!codeNode || !cJSON_IsNumber(codeNode)) {
772             continue;
773         }
774         uint32_t code = static_cast<uint32_t>(codeNode->valueint);
775         MoreInfo info = {};
776         GetMoreInfo(infoNode, info);
777         faqInfos[code] = info;
778     }
779     cJSON_Delete(root);
780 }
781 
GetError(const uint32_t & errCode)782 ErrorInfo GetError(const uint32_t &errCode)
783 {
784     ErrorInfo error;
785     auto it = ERRORS_MAP.find(errCode);
786     if (it != ERRORS_MAP.end()) {
787         error = it->second;
788     }
789     auto faq = faqInfos.find(errCode);
790     if (faq != faqInfos.end()) {
791         error.moreInfo_ = faq->second;
792     }
793     return error;
794 }
795 
PrintError(const uint32_t & errCode)796 void PrintError(const uint32_t &errCode)
797 {
798     PrintError(GetError(errCode));
799 }
800 
PrintError(const ErrorInfo & error)801 void PrintError(const ErrorInfo &error)
802 {
803     std::string errMsg;
804     errMsg.append("Error Code: ").append(std::to_string(error.code_)).append("\n");
805     errMsg.append("Error: ").append(error.description_).append("\n");
806     errMsg.append("Error Message: ").append(error.cause_);
807     if (!error.position_.empty()) {
808         errMsg.append(" At file: ").append(error.position_);
809     }
810     errMsg.append("\n");
811     if (!error.solutions_.empty()) {
812         errMsg.append("* Try the following:").append("\n");
813         for (const auto &solution : error.solutions_) { errMsg.append("  > ").append(solution).append("\n"); }
814         std::string moreInfo;
815         if (osLanguage == Language::CN) {
816             if (!error.moreInfo_.cn.empty()) {
817                 moreInfo = error.moreInfo_.cn;
818             } else {
819                 moreInfo = defaultMoreInfo.cn;
820             }
821         } else {
822             if (!error.moreInfo_.en.empty()) {
823                 moreInfo = error.moreInfo_.en;
824             } else {
825                 moreInfo = defaultMoreInfo.en;
826             }
827         }
828         if (!moreInfo.empty()) {
829             errMsg.append("> More info: ").append(moreInfo).append("\n");
830         }
831     }
832     std::cerr << errMsg;
833 }
834 } // namespace Restool
835 } // namespace Global
836 } // namespace OHOS
837