diff --git a/BUILD.gn b/BUILD.gn index ce5fafb7ea6c1a87dc396dd88cb55e914ce265f8..bba7d1bb65a25437262eecc16587649f8dd746c6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -82,6 +82,12 @@ ohos_executable("restool") { "-lshlwapi", ] } + if (is_linux) { + defines = [ "__LINUX__" ] + } + if (is_mac) { + defines = [ "__MAC__" ] + } subsystem_name = "developtools" part_name = "global_resource_tool" } @@ -104,3 +110,10 @@ ohos_prebuilt_etc("restool_systemres") { subsystem_name = "developtools" part_name = "global_resource_tool" } + +ohos_prebuilt_etc("restool_faq") { + source = "${restool_faq_path}" + subsystem_name = "developtools" + part_name = "global_resource_tool" + install_enable = false +} \ No newline at end of file diff --git a/include/resource_util.h b/include/resource_util.h index f01fc978554bed5c2cd8f1e3cb06c5d436777dbb..c04ae2b88faf8cae0e378124d24fa0c1f3975089 100644 --- a/include/resource_util.h +++ b/include/resource_util.h @@ -67,9 +67,10 @@ public: * @brief open json file. * @param path: json file path. * @param root: json root node + * @param printError: if true, print error message. * @return true if open success, other false. */ - static bool OpenJsonFile(const std::string &path, cJSON **root); + static bool OpenJsonFile(const std::string &path, cJSON **root, const bool &printError = true); /** * @brief save json file. diff --git a/include/restool_errors.h b/include/restool_errors.h index d89f64787ec99b6a3c07a4647279709537d27418..3bcb79d1f2dcea974ec076f0f2fa7315ebd8f804 100644 --- a/include/restool_errors.h +++ b/include/restool_errors.h @@ -29,6 +29,7 @@ namespace Restool { constexpr uint32_t RESTOOL_SUCCESS = 0; constexpr uint32_t RESTOOL_ERROR = -1; constexpr uint16_t BUFFER_SIZE = 4096; +const std::string ERROR_MORE_INFO_FILE = "restool_faq.json"; // 11200xxx unknown error constexpr uint32_t ERR_CODE_UNDEFINED_ERROR = 11200000; @@ -122,6 +123,11 @@ constexpr uint32_t ERR_CODE_INVALID_RESOURCE_INDEX = 11211124; const std::string ERR_TYPE_RESOURCE_DUMP = "Resource Dump Error"; constexpr uint32_t ERR_CODE_PARSE_HAP_ERROR = 11212001; +enum class Language { + CN, + EN +}; + struct MoreInfo { std::string cn; std::string en; @@ -176,6 +182,7 @@ private: } }; +void InitFaq(const std::string &restoolPath); ErrorInfo GetError(const uint32_t &errCode); void PrintError(const uint32_t &errCode); void PrintError(const ErrorInfo &error); diff --git a/restool.gni b/restool.gni index f9d487dae6318a45c15c096e289f35c0866005c5..13476e1d99c8e3f9007814d87df033fd5062b8b6 100755 --- a/restool.gni +++ b/restool.gni @@ -12,3 +12,4 @@ # limitations under the License. id_defined_path = "//base/global/system_resources/systemres/main/resources/base/element/id_defined.json" +restool_faq_path = "//developtools/global_resource_tool/restool_faq.json" diff --git a/restool_faq.json b/restool_faq.json new file mode 100644 index 0000000000000000000000000000000000000000..2cbfe1f65081c4f4e5038c11383faae09d82a139 --- /dev/null +++ b/restool_faq.json @@ -0,0 +1,13 @@ +{ + "default": { + "cn": "https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/restool", + "en": "https://developer.huawei.com/consumer/en/doc/harmonyos-guides/restool" + }, + "faqs": [ + { + "code": 11201001, + "cn": "https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-compiling-and-building-181", + "en": "https://developer.huawei.com/consumer/en/doc/harmonyos-faqs/faqs-compiling-and-building-181" + } + ] +} \ No newline at end of file diff --git a/src/resource_util.cpp b/src/resource_util.cpp index 3e238d03af523e0279f6bce9dfe80fbf0f663986..992245952e3a99e578dac8b45043d75da6327bc7 100644 --- a/src/resource_util.cpp +++ b/src/resource_util.cpp @@ -81,18 +81,22 @@ bool ResourceUtil::RmoveFile(const string &path) return FileEntry::RemoveFile(path); } -bool ResourceUtil::OpenJsonFile(const string &path, cJSON **root) +bool ResourceUtil::OpenJsonFile(const string &path, cJSON **root, const bool &printError) { ifstream ifs(FileEntry::AdaptLongPath(path), ios::binary); if (!ifs.is_open()) { - PrintError(GetError(ERR_CODE_OPEN_JSON_FAIL).FormatCause(path.c_str(), strerror(errno))); + if (printError) { + PrintError(GetError(ERR_CODE_OPEN_JSON_FAIL).FormatCause(path.c_str(), strerror(errno))); + } return false; } string jsonString((istreambuf_iterator(ifs)), istreambuf_iterator()); *root = cJSON_Parse(jsonString.c_str()); if (!*root) { - PrintError(GetError(ERR_CODE_JSON_FORMAT_ERROR).SetPosition(path)); + if (printError) { + PrintError(GetError(ERR_CODE_JSON_FORMAT_ERROR).SetPosition(path)); + } ifs.close(); return false; } diff --git a/src/restool.cpp b/src/restool.cpp index a70de84de5f3f99785210b44b0cd002a83642603..dfe9ae00e02b844166c154f26935702e8e7d5e8c 100644 --- a/src/restool.cpp +++ b/src/restool.cpp @@ -30,6 +30,7 @@ int main(int argc, char *argv[]) PrintError(GetError(ERR_CODE_UNKNOWN_COMMAND_ERROR).FormatCause("argv null")); return RESTOOL_ERROR; } + InitFaq(std::string(argv[0])); auto &parser = CmdParser::GetInstance(); return parser.Parse(argc, argv, 1); } diff --git a/src/restool_errors.cpp b/src/restool_errors.cpp index d9b63671aece9e735e821ffb55b0e04a0ab8cf40..e3e63d8ae3f5cf9cb199f0ba5bff2b95f575b076 100644 --- a/src/restool_errors.cpp +++ b/src/restool_errors.cpp @@ -14,7 +14,9 @@ */ #include +#include +#include "resource_util.h" #include "restool_errors.h" namespace OHOS { @@ -520,15 +522,176 @@ const std::map ERRORS_MAP = { { ERR_CODE_PARSE_HAP_ERROR, ERR_TYPE_RESOURCE_DUMP, "Failed to parse the HAP, %s.", "", {}, {} } }, }; +#ifdef __WIN32 +constexpr int WIN_LOCALE_CN = 2052; +#endif +const std::string LOCALE_CN = "zh_CN"; + +std::map faqInfos; +MoreInfo defaultMoreInfo = {}; +Language osLanguage = Language::EN; + +std::string ExecuteCommand(const std::string &cmd) +{ + std::string result; + FILE *pipe = popen(cmd.c_str(), "r"); + if (!pipe) { + return result; + } + char buffer[BUFFER_SIZE]; + while (!feof(pipe)) { + if (fgets(buffer, BUFFER_SIZE, pipe) != NULL) { + result += buffer; + } + } + pclose(pipe); + return result; +} + +#ifdef __WIN32 +Language GetWinLanguage() +{ + std::string result = ExecuteCommand("wmic os get locale"); + size_t pos = 0; + std::string locale = "Locale"; + if ((pos = result.find(locale)) != std::string::npos) { + result.replace(pos, locale.length(), ""); + } + if (result.empty()) { + return Language::CN; + } + char *end; + errno = 0; + int localeCode = static_cast(strtol(result.c_str(), &end, 16)); + if (end == result.c_str() || errno == ERANGE || localeCode == INT_MIN || localeCode == INT_MAX) { + return Language::CN; + } + if (localeCode == WIN_LOCALE_CN) { + return Language::CN; + } + return Language::EN; +} +#endif + +#ifdef __LINUX__ +std::vector split(const std::string &s, const char &delimiter) +{ + std::vector tokens; + std::string token; + std::stringstream tokenStream(s); + while (std::getline(tokenStream, token, delimiter)) { tokens.push_back(token); } + return tokens; +} + +Language GetLinuxLanguage() +{ + std::string result = ExecuteCommand("locale"); + if (result.empty()) { + return Language::CN; + } + std::vector localeLines = split(result, '\n'); + for (const std::string &line : localeLines) { + std::vector keyValue = split(line, '='); + if (keyValue.size() <= 1) { + continue; + } + std::string key = keyValue[0]; + std::string value = keyValue[1]; + if ((key == "LC_ALL" || key == "LC_MESSAGES" || key == "LANG" || key == "LANGUAGE") + && value.find(LOCALE_CN) != std::string::npos) { + return Language::CN; + } + } + return Language::EN; +} +#endif + +#ifdef __MAC__ +Language GetMacLanguage() +{ + std::string result = ExecuteCommand("defaults read -globalDomain AppleLocale"); + if (result.empty()) { + return Language::CN; + } + if (result.find(LOCALE_CN) != std::string::npos) { + return Language::CN; + } + return Language::EN; +} +#endif + +Language GetOsLanguage() +{ +#ifdef __WIN32 + return GetWinLanguage(); +#endif + +#ifdef __LINUX__ + return GetLinuxLanguage(); +#endif + +#ifdef __MAC__ + return GetMacLanguage(); +#endif + return Language::CN; +} + +void GetMoreInfo(cJSON *node, MoreInfo &info) +{ + if (node && cJSON_IsObject(node)) { + cJSON *cn = cJSON_GetObjectItem(node, "cn"); + if (cn && cJSON_IsString(cn)) { + info.cn = cn->valuestring; + } + cJSON *en = cJSON_GetObjectItem(node, "en"); + if (en && cJSON_IsString(en)) { + info.en = en->valuestring; + } + } +} + +void InitFaq(const std::string &restoolPath) +{ + osLanguage = GetOsLanguage(); + cJSON *root; + std::string moreInfoPath = FileEntry::FilePath(restoolPath).GetParent().Append(ERROR_MORE_INFO_FILE).GetPath(); + if (!ResourceUtil::OpenJsonFile(moreInfoPath, &root, false)) { + return; + } + if (!root || !cJSON_IsObject(root)) { + cJSON_Delete(root); + return; + } + cJSON *defaultNode = cJSON_GetObjectItem(root, "default"); + GetMoreInfo(defaultNode, defaultMoreInfo); + cJSON *faqsNode = cJSON_GetObjectItem(root, "faqs"); + if (!faqsNode || !cJSON_IsArray(faqsNode) || cJSON_GetArraySize(faqsNode) == 0) { + cJSON_Delete(root); + return; + } + for (cJSON *infoNode = faqsNode->child; infoNode; infoNode = faqsNode->next) { + cJSON *codeNode = cJSON_GetObjectItem(infoNode, "code"); + if (!codeNode || !cJSON_IsNumber(codeNode)) { + continue; + } + uint32_t code = static_cast(codeNode->valueint); + MoreInfo info = {}; + GetMoreInfo(infoNode, info); + faqInfos[code] = info; + } + cJSON_Delete(root); +} + ErrorInfo GetError(const uint32_t &errCode) { ErrorInfo error; - if (ERRORS_MAP.count(errCode) == 0) { - return error; - } auto it = ERRORS_MAP.find(errCode); if (it != ERRORS_MAP.end()) { - return it->second; + error = it->second; + } + auto faq = faqInfos.find(errCode); + if (faq != faqInfos.end()) { + error.moreInfo_ = faq->second; } return error; } @@ -551,8 +714,22 @@ void PrintError(const ErrorInfo &error) if (!error.solutions_.empty()) { errMsg.append("* Try the following:").append("\n"); for (const auto &solution : error.solutions_) { errMsg.append(" > ").append(solution).append("\n"); } - if (!error.moreInfo_.cn.empty()) { - errMsg.append("> More info: ").append(error.moreInfo_.cn).append("\n"); + std::string moreInfo; + if (osLanguage == Language::CN) { + if (!error.moreInfo_.cn.empty()) { + moreInfo = error.moreInfo_.cn; + } else { + moreInfo = defaultMoreInfo.cn; + } + } else { + if (!error.moreInfo_.en.empty()) { + moreInfo = error.moreInfo_.en; + } else { + moreInfo = defaultMoreInfo.en; + } + } + if (!moreInfo.empty()) { + errMsg.append("> More info: ").append(moreInfo).append("\n"); } } std::cerr << errMsg;