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