From b399dc9e64a63effef39df56a6fadd838d03f769 Mon Sep 17 00:00:00 2001 From: zt147369 Date: Tue, 12 Dec 2023 17:11:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=80=89=E6=8B=A9=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zt147369 --- BUILD.gn | 1 + include/cmd_parser.h | 6 ++ include/key_parser.h | 2 + include/resource_data.h | 55 ++++++++++- include/resource_util.h | 6 ++ include/select_compile_parse.h | 41 ++++++++ src/cmd_parser.cpp | 33 +++++++ src/key_parser.cpp | 31 ++++++ src/resource_append.cpp | 4 + src/resource_directory.cpp | 5 +- src/resource_util.cpp | 6 ++ src/select_compile_parse.cpp | 176 +++++++++++++++++++++++++++++++++ 12 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 include/select_compile_parse.h create mode 100644 src/select_compile_parse.cpp diff --git a/BUILD.gn b/BUILD.gn index 44c75a8..5196a61 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -41,6 +41,7 @@ ohos_executable("restool") { "src/resource_table.cpp", "src/resource_util.cpp", "src/restool.cpp", + "src/select_compile_parse.cpp", "src/task_handle.cpp", ] diff --git a/include/cmd_parser.h b/include/cmd_parser.h index ddab4ab..9dafad5 100644 --- a/include/cmd_parser.h +++ b/include/cmd_parser.h @@ -53,6 +53,8 @@ public: const std::string &GetIdDefinedOutput() const; const std::string &GetIdDefinedInputPath() const; bool GetIconCheck() const; + const TargetConfig &GetTargetConfigValues() const; + bool IsTargetConfig() const; private: void InitCommand(); @@ -79,6 +81,7 @@ private: bool IsAscii(const std::string& argValue) const; bool IsLongOpt(char *argv[]) const; uint32_t IconCheck(); + uint32_t ParseTargetConfig(const std::string& argValue); static const struct option CMD_OPTS[]; static const std::string CMD_PARAMS; @@ -100,6 +103,8 @@ private: std::string idDefinedOutput_; std::string idDefinedInputPath_; bool isIconCheck_ = false; + TargetConfig targetConfig_; + bool isTtargetConfig_; }; template @@ -140,6 +145,7 @@ void CmdParser::ShowUseage() std::cout << " --dependEntry Build result directory of the specified entry module when the feature"; std::cout << " module resources are independently built in the FA model.\n"; std::cout << " --icon-check Enable the PNG image verification function for icons and startwindows.\n"; + std::cout << " --target-config When used with '-i', selective compilation is supported.\n"; } template diff --git a/include/key_parser.h b/include/key_parser.h index eb20d14..90f7fa0 100644 --- a/include/key_parser.h +++ b/include/key_parser.h @@ -25,6 +25,8 @@ namespace Restool { class KeyParser { public: static bool Parse(const std::string &folderName, std::vector &keyparams); + static bool ParseLimit(const std::string &func, std::vector &limitValues, + TargetConfig &targetConfig); private: typedef bool (*parse_key_founction)(const std::string &folderName, std::vector &keyparams); diff --git a/include/resource_data.h b/include/resource_data.h index 7926605..63f9df6 100644 --- a/include/resource_data.h +++ b/include/resource_data.h @@ -39,7 +39,7 @@ const static std::string LONG_PATH_HEAD = "\\\\?\\"; const static std::string ID_DEFINED_INDENTATION = " "; const static int32_t VERSION_MAX_LEN = 128; const static int32_t INT_TO_BYTES = sizeof(uint32_t); -static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 4.103" }; +static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 4.104" }; const static int32_t TAG_LEN = 4; enum class KeyType { @@ -55,6 +55,7 @@ enum class KeyType { // RESERVER 9 INPUTDEVICE = 10, KEY_TYPE_MAX, + OTHER, }; enum class ResType { @@ -117,6 +118,7 @@ enum Option { DEFINED_IDS = 2, DEPENDENTRY = 3, ICON_CHECK = 4, + TARGET_CONFIG = 5, STARTID = 'e', FORCEWRITE = 'f', HELP = 'h', @@ -169,6 +171,10 @@ const std::map g_inputDeviceMap = { struct KeyParam { KeyType keyType; uint32_t value; + bool operator == (const KeyParam &other) + { + return keyType == other.keyType && value == other.value; + } }; struct IdData { @@ -250,6 +256,53 @@ struct FileInfo : DirectoryInfo { std::string filename; ResType fileType; }; + +struct TargetConfig { + std::vector mccmnc; + std::vector locale; + std::vector orientation; + std::vector device; + std::vector colormode; + std::vector density; +}; + +struct Mccmnc { + KeyParam mcc; + KeyParam mnc; + bool operator == (const Mccmnc &other) + { + if (mcc.value != other.mcc.value) { + return false; + } + if (mnc.keyType != KeyType::OTHER && other.mnc.keyType != KeyType::OTHER && + mnc.value != other.mnc.value) { + return false; + } + return true; + } +}; + +struct Locale { + KeyParam language; + KeyParam script; + KeyParam region; + bool operator == (const Locale &other) + { + if (language.value != other.language.value) { + return false; + } + if (script.keyType != KeyType::OTHER && other.script.keyType != KeyType::OTHER && + script.value != other.script.value) { + return false; + } + if (region.keyType != KeyType::OTHER && other.region.keyType != KeyType::OTHER && + region.value != other.region.value) { + return false; + } + return true; + } +}; + } } } diff --git a/include/resource_util.h b/include/resource_util.h index 31d9cef..1de7602 100644 --- a/include/resource_util.h +++ b/include/resource_util.h @@ -216,6 +216,12 @@ public: */ static bool isUnicodeInPlane15or16(int unicode); + /** + * @brief Remove spaces before and after strings + * @param str input string + */ + static void RemoveSpaces(std::string &str); + private: enum class IgnoreType { IGNORE_FILE, diff --git a/include/select_compile_parse.h b/include/select_compile_parse.h new file mode 100644 index 0000000..2c381a1 --- /dev/null +++ b/include/select_compile_parse.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_SELECT_COMPILE_PARSE_H +#define OHOS_RESTOOL_SELECT_COMPILE_PARSE_H + +#include "resource_data.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class SelectCompileParse { +public: + static bool ParseTargetConfig(const std::string &limitParams, TargetConfig &targetConfig); + static bool IsSelectCompile(std::vector &keyParams); + +private: + static bool IsSelectableMccmnc(std::vector &keyParams, size_t &index, std::vector &limit); + static bool IsSelectableLocale(std::vector &keyParams, size_t &index, std::vector &limit); + static bool IsSelectableOther(std::vector &keyParams, size_t &index, std::vector &limit); + static void InitMccmnc(std::vector &limit); + static void InitLocale(std::vector &limit); + static std::vector mccmncArray_; + static std::vector localeArray_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/src/cmd_parser.cpp b/src/cmd_parser.cpp index 6d2e4f7..9fe4d6a 100644 --- a/src/cmd_parser.cpp +++ b/src/cmd_parser.cpp @@ -17,6 +17,7 @@ #include #include "cmd_list.h" #include "resource_util.h" +#include "select_compile_parse.h" namespace OHOS { namespace Global { @@ -40,6 +41,7 @@ const struct option PackageParser::CMD_OPTS[] = { { "ids", required_argument, nullptr, Option::IDS}, { "defined-ids", required_argument, nullptr, Option::DEFINED_IDS}, { "icon-check", no_argument, nullptr, Option::ICON_CHECK}, + { "target-config", required_argument, nullptr, Option::TARGET_CONFIG}, { 0, 0, 0, 0}, }; @@ -242,9 +244,15 @@ uint32_t PackageParser::CheckParam() const return RESTOOL_ERROR; } + if (isTtargetConfig_ && !append_.empty()) { + cerr << "Error: -x and --target-config cannot be used together." << endl; + return RESTOOL_ERROR; + } + if (!append_.empty()) { return RESTOOL_SUCCESS; } + if (packageName_.empty()) { cerr << "Error: package name empty." << endl; return RESTOOL_ERROR; @@ -350,6 +358,30 @@ bool PackageParser::GetIconCheck() const return isIconCheck_; } +uint32_t PackageParser::ParseTargetConfig(const string& argValue) +{ + if (isTtargetConfig_) { + cerr << "Error: repeat input '--target-config'" << endl; + return RESTOOL_ERROR; + } + if (!SelectCompileParse::ParseTargetConfig(argValue, targetConfig_)) { + cerr << "Error: '" << argValue << "' is not valid parameter." << endl; + return RESTOOL_ERROR; + } + isTtargetConfig_ = true; + return RESTOOL_SUCCESS; +} + +const TargetConfig &PackageParser::GetTargetConfigValues() const +{ + return targetConfig_; +} + +bool PackageParser::IsTargetConfig() const +{ + return isTtargetConfig_; +} + bool PackageParser::IsAscii(const string& argValue) const { #ifdef __WIN32 @@ -386,6 +418,7 @@ void PackageParser::InitCommand() handles_.emplace(Option::IDS, bind(&PackageParser::SetIdDefinedOutput, this, _1)); handles_.emplace(Option::DEFINED_IDS, bind(&PackageParser::SetIdDefinedInputPath, this, _1)); handles_.emplace(Option::ICON_CHECK, [this](const string &) -> uint32_t { return IconCheck(); }); + handles_.emplace(Option::TARGET_CONFIG, bind(&PackageParser::ParseTargetConfig, this, _1)); } uint32_t PackageParser::HandleProcess(int c, const string& argValue) diff --git a/src/key_parser.cpp b/src/key_parser.cpp index db9a8f8..1fdd73e 100644 --- a/src/key_parser.cpp +++ b/src/key_parser.cpp @@ -73,6 +73,37 @@ bool KeyParser::ParseMatch(const vector &keys, return true; } +bool KeyParser::ParseLimit(const string &func, std::vector &limitValues, + TargetConfig &targetConfig) +{ + map> parseLimitFunc { + {"mccmnc", [&targetConfig](const string &limitValue) { return ParseMccMnc(limitValue, + targetConfig.mccmnc); }}, + {"locale", [&targetConfig](const string &limitValue) { return ParseLSR(limitValue, + targetConfig.locale); }}, + {"orientation", [&targetConfig](const string &limitValue) { return ParseOrientation(limitValue, + targetConfig.orientation); }}, + {"device", [&targetConfig](const string &limitValue) { return ParseDeviceType(limitValue, + targetConfig.device); }}, + {"colormode", [&targetConfig](const string &limitValue) { return ParseNightMode(limitValue, + targetConfig.colormode); }}, + {"density", [&targetConfig](const string &limitValue) { return ParseResolution(limitValue, + targetConfig.density); }} + }; + + auto iter = parseLimitFunc.find(func); + if (iter == parseLimitFunc.end()) { + return false; + } + for (auto &limitValue : limitValues) { + ResourceUtil::RemoveSpaces(limitValue); + if (!iter->second(limitValue)) { + return false; + } + } + return true; +} + bool KeyParser::ParseMatchBySeq(const vector &keys, vector &keyparams, const vector &founctions) { diff --git a/src/resource_append.cpp b/src/resource_append.cpp index 8aa32a5..f3765d2 100644 --- a/src/resource_append.cpp +++ b/src/resource_append.cpp @@ -25,6 +25,7 @@ #include "reference_parser.h" #include "resource_table.h" #include "resource_util.h" +#include "select_compile_parse.h" #ifdef __WIN32 #include "windows.h" #endif @@ -532,6 +533,9 @@ bool ResourceAppend::LoadResourceItemFromMem(const char buffer[], int32_t length keyParam.value = ParseInt32(buffer, length, offset); keyParams.push_back(keyParam); } + if (limitKeyStr != "base" && !limitKeyStr.empty() && !SelectCompileParse::IsSelectCompile(keyParams)) { + return true; + } // data string data = ParseString(buffer, length, offset); if (resType == ResType::RAW) { diff --git a/src/resource_directory.cpp b/src/resource_directory.cpp index 3c2f2a3..ff99414 100644 --- a/src/resource_directory.cpp +++ b/src/resource_directory.cpp @@ -17,6 +17,7 @@ #include #include "file_entry.h" #include "resource_util.h" +#include "select_compile_parse.h" namespace OHOS { namespace Global { @@ -60,7 +61,9 @@ bool ResourceDirectory::ScanResourceLimitKeyDir(const string &resourceTypeDir, c cerr << "Error: invalid limit key '" << limitKey << "'." << NEW_LINE_PATH << resourceTypeDir << endl; return false; } - + if (!SelectCompileParse::IsSelectCompile(keyParams)) { + return true; + } FileEntry f(resourceTypeDir); if (!f.Init()) { return false; diff --git a/src/resource_util.cpp b/src/resource_util.cpp index 802a9f9..a8e9754 100644 --- a/src/resource_util.cpp +++ b/src/resource_util.cpp @@ -428,6 +428,12 @@ bool ResourceUtil::isUnicodeInPlane15or16(int unicode) return (unicode >= 0xF0000 && unicode <= 0xFFFFF) || (unicode >= 0x100000 && unicode <= 0x10FFFF); } +void ResourceUtil::RemoveSpaces(string &str) +{ + str.erase(0, str.find_first_not_of(" ")); + str.erase(str.find_last_not_of(" ") + 1); // move back one place +} + } } } diff --git a/src/select_compile_parse.cpp b/src/select_compile_parse.cpp new file mode 100644 index 0000000..dc837be --- /dev/null +++ b/src/select_compile_parse.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "select_compile_parse.h" +#include +#include "key_parser.h" +#include "cmd_parser.h" +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +vector SelectCompileParse::mccmncArray_ = {}; +vector SelectCompileParse::localeArray_ = {}; + +// eg: Device[ phone, car ];ColorMode[ dark ] +bool SelectCompileParse::ParseTargetConfig(const string &limitParams, TargetConfig &targetConfig) +{ + vector limitArray; + ResourceUtil::Split(limitParams, limitArray, ";"); + if (limitArray.empty()) { + return false; + } + for (auto &it : limitArray) { + vector limit; + ResourceUtil::Split(it, limit, "["); + if (limit.size() != 2) { // 2 means the size of the valid parameter after split by '[' + return false; + } + ResourceUtil::RemoveSpaces(limit.back()); + if (limit.size() < 2 || limit.back().back() != ']') { // 2 means characters other than ']' + return false; + } + limit.back().pop_back(); + vector limitValues; + ResourceUtil::Split(limit.back(), limitValues, ","); + if (limitValues.empty()) { + return false; + } + auto &limitType = limit.front(); + ResourceUtil::RemoveSpaces(limitType); + transform(limitType.begin(), limitType.end(), limitType.begin(), ::tolower); + if (!KeyParser::ParseLimit(limitType, limitValues, targetConfig)) { + return false; + } + } + return true; +} + +bool SelectCompileParse::IsSelectCompile(vector &keyParams) +{ + if (keyParams.empty()) { + return true; + } + auto &cmdParser = CmdParser::GetInstance().GetCmdParser(); + bool isTtargetConfig = cmdParser.IsTargetConfig(); + if (!isTtargetConfig) { + return true; + } + TargetConfig targetConfig = cmdParser.GetTargetConfigValues(); + map> selectableFuncMatch { + {KeyType::MCC, bind(&IsSelectableMccmnc, keyParams, placeholders::_1, targetConfig.mccmnc)}, + {KeyType::LANGUAGE, bind(&IsSelectableLocale, keyParams, placeholders::_1, targetConfig.locale)}, + {KeyType::ORIENTATION, bind(&IsSelectableOther, keyParams, placeholders::_1, targetConfig.orientation)}, + {KeyType::DEVICETYPE, bind(&IsSelectableOther, keyParams, placeholders::_1, targetConfig.device)}, + {KeyType::NIGHTMODE, bind(&IsSelectableOther, keyParams, placeholders::_1, targetConfig.colormode)}, + {KeyType::RESOLUTION, bind(&IsSelectableOther, keyParams, placeholders::_1, targetConfig.density)}, + }; + for (size_t index = 0; index < keyParams.size(); index++) { + auto iter = selectableFuncMatch.find(keyParams[index].keyType); + if (iter == selectableFuncMatch.end()) { + continue; + } + if (!iter->second(index)) { + return false; + } + } + return true; +} + +// {KeyType::OTHER, 0} indicates that the default value is equal to null +void SelectCompileParse::InitMccmnc(vector &limit) +{ + if (!mccmncArray_.empty()) { + return; + } + for (size_t i = 0; i < limit.size(); i++) { + if (limit[i].keyType == KeyType::MCC) { + mccmncArray_.push_back({limit[i], {KeyType::OTHER, 0}}); + } + if (limit[i].keyType == KeyType::MNC) { + mccmncArray_.back().mnc = limit[i]; + } + } +} + +bool SelectCompileParse::IsSelectableMccmnc(vector &keyParams, size_t &index, vector &limit) +{ + if (limit.empty()) { + return true; + } + Mccmnc mccmncLimit({keyParams[index++], {KeyType::OTHER, 0}}); + if (index < keyParams.size() && keyParams[index].keyType == KeyType::MNC) { + mccmncLimit.mnc = keyParams[index]; + } else { + index--; + } + InitMccmnc(limit); + return find(mccmncArray_.begin(), mccmncArray_.end(), mccmncLimit) != mccmncArray_.end(); +} + +void SelectCompileParse::InitLocale(vector &limit) +{ + if (!localeArray_.empty()) { + return; + } + for (size_t i = 0; i < limit.size(); i++) { + if (limit[i].keyType == KeyType::LANGUAGE) { + localeArray_.push_back({limit[i], {KeyType::OTHER, 0}, + {KeyType::OTHER, 0}}); + } + if (limit[i].keyType == KeyType::SCRIPT) { + localeArray_.back().script = limit[i]; + } + if (limit[i].keyType == KeyType::REGION) { + localeArray_.back().region = limit[i]; + } + } +} + +bool SelectCompileParse::IsSelectableLocale(vector &keyParams, size_t &index, vector &limit) +{ + if (limit.empty()) { + return true; + } + Locale localeLimit({keyParams[index++], {KeyType::OTHER, 0}, {KeyType::OTHER, 0}}); + for (; index < keyParams.size(); index++) { + if (keyParams[index].keyType == KeyType::SCRIPT) { + localeLimit.script = keyParams[index]; + continue; + } + if (keyParams[index].keyType == KeyType::REGION) { + localeLimit.region = keyParams[index]; + break; + } + index--; + break; + } + InitLocale(limit); + return find(localeArray_.begin(), localeArray_.end(), localeLimit) != localeArray_.end();; +} + +bool SelectCompileParse::IsSelectableOther(vector &keyParams, size_t &index, vector &limit) +{ + if (limit.empty()) { + return true; + } + return find(limit.begin(), limit.end(), keyParams[index]) != limit.end(); +} + +} +} +}