From ec2886fa0b0a05f303354bf6199cb212f581cf42 Mon Sep 17 00:00:00 2001 From: fangyunzhong Date: Thu, 24 Nov 2022 10:54:11 +0800 Subject: [PATCH] =?UTF-8?q?feature=E6=A8=A1=E5=9D=97=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E6=89=93=E5=8C=85=EF=BC=8C=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E6=98=BE=E7=A4=BA=E7=9A=84=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E5=92=8Clabel=E4=B8=8D=E6=AD=A3=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: fangyunzhong --- include/cmd_parser.h | 3 + include/config_parser.h | 21 ++++ include/file_manager.h | 2 +- include/resource_data.h | 29 ++++++ include/resource_item.h | 1 + include/resource_pack.h | 9 ++ include/resource_table.h | 11 +++ include/resource_util.h | 19 ++++ src/cmd_list.cpp | 3 +- src/cmd_parser.cpp | 15 ++- src/config_parser.cpp | 139 +++++++++++++++++++++++++- src/file_manager.cpp | 10 +- src/resource_item.cpp | 5 + src/resource_pack.cpp | 190 +++++++++++++++++++++++++++++++++++- src/resource_table.cpp | 205 ++++++++++++++++++++++++++++++++++++++- src/resource_util.cpp | 97 ++++++++++++++++++ 16 files changed, 744 insertions(+), 15 deletions(-) diff --git a/include/cmd_parser.h b/include/cmd_parser.h index 6800a9e..0702e66 100644 --- a/include/cmd_parser.h +++ b/include/cmd_parser.h @@ -52,6 +52,7 @@ public: int32_t GetPriority() const; const std::vector &GetAppend() const; bool GetCombine() const; + const std::string &GetDependEntry() const; private: void InitCommand(); @@ -73,6 +74,7 @@ private: uint32_t SetPriority(const std::string& argValue); uint32_t AddAppend(const std::string& argValue); uint32_t SetCombine(); + uint32_t AddDependEntry(const std::string& argValue); bool IsAscii(const std::string& argValue) const; static const struct option CMD_OPTS[]; @@ -94,6 +96,7 @@ private: int32_t priority_ = -1; std::vector append_; bool combine_ = false; + std::string dependEntry_; }; template diff --git a/include/config_parser.h b/include/config_parser.h index aab30b2..0f85dd0 100644 --- a/include/config_parser.h +++ b/include/config_parser.h @@ -37,9 +37,21 @@ public: uint32_t Init(); const std::string &GetPackageName() const; const std::string &GetModuleName() const; + int32_t GetAbilityIconId() const; + int32_t GetAbilityLabelId() const; + bool SetAppIcon(std::string &icon, int32_t id); + bool SetAppLabel(std::string &label, int32_t id); ModuleType GetModuleType() const; uint32_t ParseRefence(); uint32_t Save(const std::string &filePath) const; + void SetDependEntry(const bool isDenpend) + { + dependEntry = isDenpend; + } + bool IsDependEntry() + { + return dependEntry; + } static void SetUseModule() { useModule_ = true; @@ -51,16 +63,25 @@ public: private: bool ParseModule(Json::Value &moduleNode); bool ParseDistro(Json::Value &distroNode); + bool ParseAbilities(const Json::Value &abilites); + bool ParseAbilitiy(const Json::Value &ability, bool &isMainAbility); + bool IsMainAbility(const Json::Value &skills); + bool IsHomeAction(const Json::Value &actions); + bool dependEntry = false; bool ParseRefImpl(Json::Value &parent, const std::string &key, Json::Value &node); bool ParseJsonArrayRef(Json::Value &parent, const std::string &key, Json::Value &node); bool ParseJsonStringRef(Json::Value &parent, const std::string &key, Json::Value &node); bool GetRefIdFromString(std::string &value, bool &update, const std::string &match) const; bool ParseModuleType(const std::string &type); + bool ParseAbilitiesForDepend(Json::Value &moduleNode); std::string filePath_; std::string packageName_; std::string moduleName_; ModuleType moduleType_; Json::Value rootNode_; + std::string mainAbility_; + int32_t abilityIconId_; + int32_t abilityLabelId_; static const std::map MODULE_TYPES; static const std::map JSON_STRING_IDS; static const std::map JSON_ARRAY_IDS; diff --git a/include/file_manager.h b/include/file_manager.h index 7706208..58f330e 100644 --- a/include/file_manager.h +++ b/include/file_manager.h @@ -37,11 +37,11 @@ public: moduleName_ = moduleName; }; uint32_t ScanIncrement(const std::string &output); + uint32_t MergeResourceItem(const std::map> &resourceInfos); private: uint32_t ScanModule(const std::string &input, const std::string &output, std::map> &resTypeOfDirs); - uint32_t MergeResourceItem(const std::map> &resourceInfos); uint32_t ParseReference(const std::string &output, const std::vector &sxmlFolders); bool NeedParseReferenceInSolidXml(ResType resType) const; void FilterRefSolidXml(const std::string &output, std::vector &outputPaths, diff --git a/include/resource_data.h b/include/resource_data.h index 5fe7062..6226c43 100644 --- a/include/resource_data.h +++ b/include/resource_data.h @@ -31,8 +31,10 @@ const static std::string RAW_FILE_DIR = "rawfile"; const static std::string ID_DEFINED_FILE = "id_defined.json"; const static std::string RESOURCE_INDEX_FILE = "resources.index"; const static std::string SEPARATOR = "/"; +const static std::string WIN_SEPARATOR = "\\"; const static std::string NEW_LINE_PATH = "\r\nat "; 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 2.010" }; const static int32_t TAG_LEN = 4; @@ -142,6 +144,11 @@ struct KeyParam { uint32_t value; }; +struct IdData { + uint32_t id; + uint32_t dataOffset; +}; + const std::map g_fileClusterMap = { { "element", ResType::ELEMENT }, { "media", ResType::MEDIA }, @@ -162,6 +169,28 @@ const std::map g_contentClusterMap = { { "float", ResType::FLOAT } }; +const std::map g_resTypeMap = { + { static_cast(ResType::ELEMENT), ResType::ELEMENT}, + { static_cast(ResType::ANIMATION), ResType::ANIMATION}, + { static_cast(ResType::LAYOUT), ResType::LAYOUT}, + { static_cast(ResType::RAW), ResType::RAW}, + { static_cast(ResType::INTEGER), ResType::INTEGER}, + { static_cast(ResType::STRING), ResType::STRING}, + { static_cast(ResType::STRARRAY), ResType::STRARRAY}, + { static_cast(ResType::INTARRAY), ResType::INTARRAY}, + { static_cast(ResType::BOOLEAN), ResType::BOOLEAN}, + { static_cast(ResType::COLOR), ResType::COLOR}, + { static_cast(ResType::ID), ResType::ID}, + { static_cast(ResType::THEME), ResType::THEME}, + { static_cast(ResType::PLURAL), ResType::PLURAL}, + { static_cast(ResType::FLOAT), ResType::FLOAT}, + { static_cast(ResType::MEDIA), ResType::MEDIA}, + { static_cast(ResType::PROF), ResType::PROF}, + { static_cast(ResType::GRAPHIC), ResType::GRAPHIC}, + { static_cast(ResType::PATTERN), ResType::PATTERN}, + { static_cast(ResType::INVALID_RES_TYPE), ResType::INVALID_RES_TYPE}, +}; + struct DirectoryInfo { std::string limitKey; std::string fileCluster; diff --git a/include/resource_item.h b/include/resource_item.h index 835199f..9f1c81e 100644 --- a/include/resource_item.h +++ b/include/resource_item.h @@ -33,6 +33,7 @@ public: bool SetData(const int8_t *data, uint32_t length); void SetFilePath(const std::string &filePath); void SetLimitKey(const std::string &limitKey); + void SetName(const std::string &name); const int8_t *GetData() const; uint32_t GetDataLength() const; diff --git a/include/resource_pack.h b/include/resource_pack.h index b92be4a..99a21bc 100644 --- a/include/resource_pack.h +++ b/include/resource_pack.h @@ -19,6 +19,8 @@ #include "cmd_parser.h" #include "config_parser.h" #include "resource_util.h" +#include "resource_item.h" +#include "resource_data.h" namespace OHOS { namespace Global { @@ -47,6 +49,13 @@ private: uint32_t PackPreview(); uint32_t PackAppend(); uint32_t PackCombine(); + uint32_t HandleFeature(); + uint32_t FindResourceItems(const std::map> &resInfoLocal, + std::vector &items, int32_t id) const; + uint32_t HandleLabel(std::vector &items, ConfigParser &config) const; + uint32_t HandleIcon(std::vector &items, ConfigParser &config) const; + void SaveResourceItem(const ResourceItem &resourceItem, int32_t nextId) const; + bool CopyIcon(std::string &dataPath, const std::string &idName, std::string &fileName) const; PackageParser packageParser_; std::string moduleName_; using HeaderCreater = std::function; diff --git a/include/resource_table.h b/include/resource_table.h index 5191ea7..0ae979c 100644 --- a/include/resource_table.h +++ b/include/resource_table.h @@ -30,6 +30,7 @@ public: virtual ~ResourceTable(); uint32_t CreateResourceTable(); uint32_t CreateResourceTable(const std::map>> &items); + uint32_t LoadResTable(const std::string path, std::map> &resInfos); private: struct TableData { int32_t id; @@ -71,6 +72,16 @@ private: void SaveLimitKeyConfigs(const std::map &limitKeyConfigs, std::ostringstream &out) const; void SaveIdSets(const std::map &idSets, std::ostringstream &out) const; + bool ReadFileHeader(std::ifstream &in, IndexHeader &indexHeader, int32_t &pos, int32_t length) const; + bool ReadLimitKeys(std::ifstream &in, std::map> &limitKeys, + uint32_t count, int32_t &pos, int32_t length) const; + bool ReadIdTables(std::ifstream &in, std::map> &datas, + uint32_t count, int32_t &pos, int32_t length) const; + bool ReadDataRecordPrepare(std::ifstream &in, RecordItem &record, int32_t &pos, int32_t length) const; + bool ReadDataRecordStart(std::ifstream &in, RecordItem &record, + const std::map> &limitKeys, + const std::map> &datas, + std::map> &resInfos) const; std::string indexFilePath_; }; } diff --git a/include/resource_util.h b/include/resource_util.h index be2483c..649e1d3 100644 --- a/include/resource_util.h +++ b/include/resource_util.h @@ -33,6 +33,14 @@ public: */ static void Split(const std::string &str, std::vector &out, const std::string &splitter); + /** + * @brief Replace sub-string in string + * @param sourceStr: The original string to operate on + * @param oldStr: The string to be replaced + * @param newStr: The new string used + */ + static void StringReplace(std::string &sourceStr, const std::string &oldStr, const std::string &newStr); + /** * @brief check file exist. * @param path: file path. @@ -157,6 +165,13 @@ public: * @return true is legal, other false; */ static bool IslegalPath(const std::string &path); + + /** + * @brief get an keyParams for limitkey + * @param keyParams + * @return limitkey + */ + static std::string PaserKeyParam(const std::vector &keyParams); private: enum class IgnoreType { IGNORE_FILE, @@ -164,6 +179,10 @@ private: IGNORE_ALL }; static const std::map IGNORE_FILE_REGEX; + static std::string GetLocaleLimitkey(const KeyParam &KeyParam); + static std::string GetDeviceTypeLimitkey(const KeyParam &KeyParam); + static std::string GetResolutionLimitkey(const KeyParam &KeyParam); + static std::string GetKeyParamValue(const KeyParam &KeyParam); }; } } diff --git a/src/cmd_list.cpp b/src/cmd_list.cpp index 7c8e45b..d7279a5 100644 --- a/src/cmd_list.cpp +++ b/src/cmd_list.cpp @@ -34,7 +34,8 @@ uint32_t CmdList::Init(const string &filePath, function uint32_t { return SetCombine(); }); + handles_.emplace('d', bind(&PackageParser::AddDependEntry, this, _1)); } uint32_t PackageParser::HandleProcess(int c, const string& argValue) diff --git a/src/config_parser.cpp b/src/config_parser.cpp index c405823..5d9e780 100644 --- a/src/config_parser.cpp +++ b/src/config_parser.cpp @@ -89,6 +89,16 @@ const string &ConfigParser::GetModuleName() const return moduleName_; } +int32_t ConfigParser::GetAbilityIconId() const +{ + return abilityIconId_; +} + +int32_t ConfigParser::GetAbilityLabelId() const +{ + return abilityLabelId_; +} + ConfigParser::ModuleType ConfigParser::GetModuleType() const { return moduleType_; @@ -110,6 +120,28 @@ uint32_t ConfigParser::Save(const string &filePath) const return RESTOOL_ERROR; } +bool ConfigParser::SetAppIcon(string &icon, int32_t id) +{ + if (!rootNode_["app"].isObject()) { + cerr << "Error: 'app' not object" << endl; + return false; + } + rootNode_["app"]["icon"] = icon; + rootNode_["app"]["iconId"] = id; + return true; +} + +bool ConfigParser::SetAppLabel(string &label, int32_t id) +{ + if (!rootNode_["app"].isObject()) { + cerr << "Error: 'app' not object" << endl; + return false; + } + rootNode_["app"]["label"] = label; + rootNode_["app"]["labelId"] = id; + return true; +} + // below private bool ConfigParser::ParseModule(Json::Value &moduleNode) { @@ -126,7 +158,10 @@ bool ConfigParser::ParseModule(Json::Value &moduleNode) if (moduleNode.isMember("package") && moduleNode["package"].isString()) { packageName_ = moduleNode["package"].asString(); } - return ParseDistro(moduleNode["distro"]); + if (!ParseDistro(moduleNode["distro"])) { + return false; + } + return ParseAbilitiesForDepend(moduleNode); } if (moduleNode["name"].isString()) { @@ -144,6 +179,21 @@ bool ConfigParser::ParseModule(Json::Value &moduleNode) return true; } +bool ConfigParser::ParseAbilitiesForDepend(Json::Value &moduleNode) +{ + if (!IsDependEntry()) { + return true; + } + if (moduleNode["mainAbility"].isString()) { + mainAbility_ = moduleNode["mainAbility"].asString(); + if (mainAbility_[0] == '.') { + mainAbility_ = packageName_ + mainAbility_; + } + return ParseAbilities(moduleNode["abilities"]); + } + return true; +} + bool ConfigParser::ParseDistro(Json::Value &distroNode) { if (!distroNode.isObject()) { @@ -170,6 +220,93 @@ bool ConfigParser::ParseDistro(Json::Value &distroNode) return true; } +bool ConfigParser::ParseAbilities(const Json::Value &abilites) +{ + if (abilites.empty()) { + return true; + } + if (!abilites.isArray()) { + cerr << "Error: abilites not array." << NEW_LINE_PATH << filePath_ << endl; + return false; + } + bool isMainAbility = false; + for (Json::ArrayIndex i = 0; i < abilites.size(); i++) { + if (!ParseAbilitiy(abilites[i], isMainAbility)) { + cerr << "Error: ParseAbilitiy fail." << endl; + return false; + } + if (isMainAbility) { + break; + } + } + return true; +} + +bool ConfigParser::ParseAbilitiy(const Json::Value &ability, bool &isMainAbility) +{ + if (ability.empty()) { + return true; + } + if (!ability["name"].isString()) { + return false; + } + string name = ability["name"].asString(); + if (name[0] == '.') { + name = packageName_ + name; + } + if (mainAbility_ != name && !IsMainAbility(ability["skills"])) { + return true; + } + if (ability["iconId"].isInt()) { + abilityIconId_ = ability["iconId"].asInt(); + } + if (abilityIconId_ <= 0) { + cerr << "Error: iconId don't found in 'ability'." << NEW_LINE_PATH << filePath_ << endl; + return false; + } + if (ability["labelId"].isInt()) { + abilityLabelId_ = ability["labelId"].asInt(); + } + if (abilityLabelId_ <= 0) { + cerr << "Error: labelId don't found in 'ability'." << NEW_LINE_PATH << filePath_ << endl; + return false; + } + isMainAbility = true; + return true; +} + +bool ConfigParser::IsMainAbility(const Json::Value &skills) +{ + if (!skills.isArray()) { + return false; + } + for (Json::ArrayIndex i = 0; i < skills.size(); i++) { + if (!skills[i].isObject()) { + return false; + } + if (IsHomeAction(skills[i]["actions"])) { + return true; + } + } + return false; +} + +bool ConfigParser::IsHomeAction(const Json::Value &actions) +{ + if (!actions.isArray()) { + return false; + } + for (Json::ArrayIndex i = 0; i < actions.size(); i++) { + if (!actions[i].isObject()) { + return false; + } + if (actions[i].asString() == "action.system.home") { + return true; + } + } + return false; +} + bool ConfigParser::ParseRefImpl(Json::Value &parent, const std::string &key, Json::Value &node) { if (node.isArray()) { diff --git a/src/file_manager.cpp b/src/file_manager.cpp index 5f1795d..2aba0a4 100644 --- a/src/file_manager.cpp +++ b/src/file_manager.cpp @@ -52,6 +52,11 @@ uint32_t FileManager::ScanIncrement(const string &output) return ParseReference(output, sxmlFolders); } +uint32_t FileManager::MergeResourceItem(const map> &resourceInfos) +{ + return ResourceModule::MergeResourceItem(items_, resourceInfos); +} + // below private founction uint32_t FileManager::ScanModule(const string &input, const string &output, map> &resTypeOfDirs) @@ -65,11 +70,6 @@ uint32_t FileManager::ScanModule(const string &input, const string &output, return RESTOOL_SUCCESS; } -uint32_t FileManager::MergeResourceItem(const map> &resourceInfos) -{ - return ResourceModule::MergeResourceItem(items_, resourceInfos); -} - uint32_t FileManager::ParseReference(const string &output, const vector &sxmlFolders) { ReferenceParser referenceParser; diff --git a/src/resource_item.cpp b/src/resource_item.cpp index 6db4b36..25ecc1c 100644 --- a/src/resource_item.cpp +++ b/src/resource_item.cpp @@ -74,6 +74,11 @@ void ResourceItem::SetLimitKey(const string &limitKey) limitKey_ = limitKey; } +void ResourceItem::SetName(const string &name) +{ + name_ = name; +} + const int8_t *ResourceItem::GetData() const { return data_; diff --git a/src/resource_pack.cpp b/src/resource_pack.cpp index 0275203..9e86d97 100644 --- a/src/resource_pack.cpp +++ b/src/resource_pack.cpp @@ -14,8 +14,8 @@ */ #include "resource_pack.h" -#include -#include +#include +#include #include "file_entry.h" #include "file_manager.h" #include "header.h" @@ -365,12 +365,198 @@ uint32_t ResourcePack::PackNormal() } ResourceTable resourceTable; + if (!packageParser_.GetDependEntry().empty()) { + if (HandleFeature() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + if (GenerateHeader() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } + if (resourceTable.CreateResourceTable() != RESTOOL_SUCCESS) { return RESTOOL_ERROR; } return RESTOOL_SUCCESS; } +uint32_t ResourcePack::HandleFeature() +{ + string output = packageParser_.GetOutput(); + string featureDependEntry = packageParser_.GetDependEntry(); + if (featureDependEntry.empty()) { + return RESTOOL_SUCCESS; + } + string jsonFile = FileEntry::FilePath(featureDependEntry).Append(CONFIG_JSON).GetPath(); + ConfigParser entryJson(jsonFile); + entryJson.SetDependEntry(true); + if (entryJson.Init() != RESTOOL_SUCCESS) { + cerr << "Error: config json invalid." << NEW_LINE_PATH << jsonFile << endl; + return RESTOOL_ERROR; + } + + int32_t labelId = entryJson.GetAbilityLabelId(); + int32_t iconId = entryJson.GetAbilityIconId(); + if (labelId <= 0 || iconId <= 0) { + cerr << "Error: Entry MainAbility must have 'icon' and 'label'." << endl; + return RESTOOL_ERROR; + } + string path = FileEntry::FilePath(featureDependEntry).Append(RESOURCE_INDEX_FILE).GetPath(); + map> resInfoLocal; + ResourceTable resourceTable; + if (resourceTable.LoadResTable(path, resInfoLocal) != RESTOOL_SUCCESS) { + cerr << "Error: LoadResTable fail." << endl; + return RESTOOL_ERROR; + } + jsonFile = FileEntry::FilePath(output).Append(CONFIG_JSON).GetPath(); + ConfigParser config(jsonFile); + if (config.Init() != RESTOOL_SUCCESS) { + cerr << "Error: config json invalid." << NEW_LINE_PATH << jsonFile << endl; + return RESTOOL_ERROR; + } + vector items; + if (FindResourceItems(resInfoLocal, items, labelId) != RESTOOL_SUCCESS || + HandleLabel(items, config) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + items.clear(); + if (FindResourceItems(resInfoLocal, items, iconId) != RESTOOL_SUCCESS || + HandleIcon(items, config) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + string outputPath = FileEntry::FilePath(output).Append(ConfigParser::GetConfigName()).GetPath(); + if (config.Save(outputPath) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + entryJson.SetDependEntry(false); + return RESTOOL_SUCCESS; +} + +uint32_t ResourcePack::FindResourceItems(const map> &resInfoLocal, + vector &items, int32_t id) const +{ + auto ret = resInfoLocal.find(id); + if (ret == resInfoLocal.end()) { + cerr << "Error: FindResourceItems don't found '" << id << "'." << endl; + return RESTOOL_ERROR; + } + ResType type = ResType::INVALID_RES_TYPE; + items = ret->second; + if (items.empty()) { + cerr << "Error: FindResourceItems resource item empty '" << id << "'." << endl; + return RESTOOL_ERROR; + } + for (auto &it : items) { + if (type == ResType::INVALID_RES_TYPE) { + type = it.GetResType(); + } + if (type != it.GetResType()) { + cerr << "Error: FindResourceItems invalid restype '" << ResourceUtil::ResTypeToString(type); + cerr << "' vs '" << ResourceUtil::ResTypeToString(it.GetResType()) << "'." << endl; + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t ResourcePack::HandleLabel(vector &items, ConfigParser &config) const +{ + int32_t nextId = 0; + string idName; + for (auto it : items) { + if (it.GetResType() != ResType::STRING) { + cerr << "Error: HandleLabel invalid restype '"; + cerr << ResourceUtil::ResTypeToString(it.GetResType()) << "'." << endl; + return RESTOOL_ERROR; + } + idName = it.GetName() + "_entry"; + it.SetName(idName); + string data(reinterpret_cast(it.GetData())); + if (!it.SetData(reinterpret_cast(data.c_str()), it.GetDataLength()-1)) { + return RESTOOL_ERROR; + } + if (nextId <= 0) { + nextId = IdWorker::GetInstance().GenerateId(ResType::STRING, idName); + } + SaveResourceItem(it, nextId); + } + string label = "$string:" +idName; + config.SetAppLabel(label, nextId); + return RESTOOL_SUCCESS; +} + +bool ResourcePack::CopyIcon(string &dataPath, const string &idName, string &fileName) const +{ + string featureDependEntry = packageParser_.GetDependEntry(); + string source = FileEntry::FilePath(featureDependEntry).Append(dataPath).GetPath(); + string suffix = FileEntry::FilePath(source).GetExtension(); + fileName = idName + suffix; + string output = packageParser_.GetOutput(); +#ifdef _WIN32 + ResourceUtil::StringReplace(dataPath, SEPARATOR, WIN_SEPARATOR); +#endif + string dstDir = FileEntry::FilePath(output).Append(dataPath).GetParent().GetPath(); + string dst = FileEntry::FilePath(dstDir).Append(fileName).GetPath(); + if (!ResourceUtil::CreateDirs(dstDir)) { + cerr << "Error: Create Dirs fail '" << dstDir << "'."<< endl; + return false; + } + if (!ResourceUtil::CopyFleInner(source, dst)) { + cerr << "Error: copy file fail from '" << source << "' to '" << dst << "'." << endl; + return false; + } + return true; +} + +uint32_t ResourcePack::HandleIcon(vector &items, ConfigParser &config) const +{ + int32_t nextId = 0; + string idName; + for (auto it : items) { + if (it.GetResType() != ResType::MEDIA) { + cerr << "Error: HandleLabel invalid restype '"; + cerr << ResourceUtil::ResTypeToString(it.GetResType()) << "'." << endl; + return RESTOOL_ERROR; + } + string dataPath(reinterpret_cast(it.GetData())); + string::size_type pos = dataPath.find_first_of(SEPARATOR); + if (pos == string::npos) { + cerr << "Error: HandleIcon invalid '" << dataPath << "'."<< endl; + return RESTOOL_ERROR; + } + dataPath = dataPath.substr(pos + 1); + idName = it.GetName() + "_entry"; + string fileName; + if (!CopyIcon(dataPath, idName, fileName)) { + return RESTOOL_ERROR; + } + string data = FileEntry::FilePath(moduleName_).Append(dataPath).GetParent().Append(fileName).GetPath(); + ResourceUtil::StringReplace(data, WIN_SEPARATOR, SEPARATOR); + ResourceItem resourceItem(fileName, it.GetKeyParam(), ResType::MEDIA); + resourceItem.SetLimitKey(it.GetLimitKey()); + if (!resourceItem.SetData(reinterpret_cast(data.c_str()), data.length())) { + return RESTOOL_ERROR; + } + if (nextId <= 0) { + nextId = IdWorker::GetInstance().GenerateId(ResType::MEDIA, idName); + } + SaveResourceItem(resourceItem, nextId); + } + string icon = "$media:" + idName; + config.SetAppIcon(icon, nextId); + return RESTOOL_SUCCESS; +} + +void ResourcePack::SaveResourceItem(const ResourceItem &resourceItem, int32_t nextId) const +{ + map> resInfo; + vector vet; + vet.push_back(resourceItem); + resInfo.insert(make_pair(nextId, vet)); + FileManager &fileManager = FileManager::GetInstance(); + fileManager.MergeResourceItem(resInfo); +} + uint32_t ResourcePack::PackPreview() { PreviewManager preview; diff --git a/src/resource_table.cpp b/src/resource_table.cpp index 525aa99..cf88890 100644 --- a/src/resource_table.cpp +++ b/src/resource_table.cpp @@ -79,6 +79,52 @@ uint32_t ResourceTable::CreateResourceTable(const map> &resInfos) +{ + ifstream in(path, ios::binary); + if (!in.is_open()) { + cerr << "Error: open failed." << NEW_LINE_PATH << path <> limitKeys; + if (!ReadLimitKeys(in, limitKeys, indexHeader.limitKeyConfigSize, pos, length)) { + in.close(); + return RESTOOL_ERROR; + } + + map> datas; + if (!ReadIdTables(in, datas, indexHeader.limitKeyConfigSize, pos, length)) { + in.close(); + return RESTOOL_ERROR; + } + + while (in.tellg() < length) { + RecordItem record; + if (!ReadDataRecordPrepare(in, record, pos, length) || + !ReadDataRecordStart(in, record, limitKeys, datas, resInfos)) { + in.close(); + return RESTOOL_ERROR; + } + } + in.close(); + return RESTOOL_SUCCESS; +} // below private uint32_t ResourceTable::SaveToResouorceIndex(const map> &configs) const { @@ -97,7 +143,7 @@ uint32_t ResourceTable::SaveToResouorceIndex(const map ofstream out(indexFilePath_, ofstream::out | ofstream::binary); if (!out.is_open()) { - cerr << "Error: open failed '" << indexFilePath_ << ", reason: " << strerror(errno) << endl; + cerr << "Error: open failed '" << indexFilePath_ << "', reason: " << strerror(errno) << endl; return RESTOOL_ERROR; } @@ -146,7 +192,7 @@ bool ResourceTable::Prepare(const map> &configs, for (const auto &config : configs) { auto limitKeyConfig = limitKeyConfigs.find(config.first); if (limitKeyConfig == limitKeyConfigs.end()) { - cerr << "Error: limit key config don't find '" << config.first << "'" << endl; + cerr << "Error: limit key config don't find '" << config.first << "'." << endl; return false; } limitKeyConfig->second.offset = pos; @@ -169,13 +215,13 @@ bool ResourceTable::SaveRecordItem(const map> &configs for (const auto &config : configs) { auto idSet = idSets.find(config.first); if (idSet == idSets.end()) { - cerr << "Error: id set don't find '" << config.first << "'" << endl; + cerr << "Error: id set don't find '" << config.first << "'." << endl; return false; } for (const auto &tableData : config.second) { if (idSet->second.data.find(tableData.id) == idSet->second.data.end()) { - cerr << "Error: resource table don't find id '" << tableData.id << "'" << endl; + cerr << "Error: resource table don't find id '" << tableData.id << "'." << endl; return false; } idSet->second.data[tableData.id] = pos; @@ -232,6 +278,157 @@ void ResourceTable::SaveIdSets(const map &idSets, ostringstream & } } } + +bool ResourceTable::ReadFileHeader(ifstream &in, IndexHeader &indexHeader, int32_t &pos, int32_t length) const +{ + pos += sizeof(indexHeader); + if (pos > length) { + cerr << "Error: invalid resources.index File Header." << endl; + return false; + } + in.read(reinterpret_cast(indexHeader.version), VERSION_MAX_LEN); + in.read(reinterpret_cast(&indexHeader.fileSize), INT_TO_BYTES); + in.read(reinterpret_cast(&indexHeader.limitKeyConfigSize), INT_TO_BYTES); + return true; +} + +bool ResourceTable::ReadLimitKeys(ifstream &in, map> &limitKeys, + uint32_t count, int32_t &pos, int32_t length) const +{ + for (uint32_t i = 0; i< count; i++) { + pos = pos + TAG_LEN + INT_TO_BYTES + INT_TO_BYTES; + if (pos > length) { + cerr << "Error: invalid resources.index KEYS." << endl; + return false; + } + LimitKeyConfig limitKey; + in.read(reinterpret_cast(limitKey.keyTag), TAG_LEN); + string keyTag(reinterpret_cast(limitKey.keyTag), TAG_LEN); + if (keyTag != "KEYS") { + cerr << "Error: invalid resources.index key tag = " << keyTag << endl; + return false; + } + in.read(reinterpret_cast(&limitKey.offset), INT_TO_BYTES); + in.read(reinterpret_cast(&limitKey.keyCount), INT_TO_BYTES); + + vector keyParams; + for (uint32_t j = 0; j < limitKey.keyCount; j++) { + pos = pos + INT_TO_BYTES + INT_TO_BYTES; + if (pos > length) { + cerr << "Error: invalid resources.index keyParams." << endl; + return false; + } + KeyParam keyParam; + in.read(reinterpret_cast(&keyParam.keyType), INT_TO_BYTES); + in.read(reinterpret_cast(&keyParam.value), INT_TO_BYTES); + keyParams.push_back(keyParam); + } + limitKeys[limitKey.offset] = keyParams; + } + return true; +} + +bool ResourceTable::ReadIdTables(std::ifstream &in, std::map> &datas, + uint32_t count, int32_t &pos, int32_t length) const +{ + for (uint32_t i = 0; i< count; i++) { + pos = pos + TAG_LEN + INT_TO_BYTES; + if (pos > length) { + cerr << "Error: invalid resources.index IDSS." << endl; + return false; + } + IdSet idss; + int32_t offset = in.tellg(); + in.read(reinterpret_cast(idss.idTag), TAG_LEN); + string idTag(reinterpret_cast(idss.idTag), TAG_LEN); + if (idTag != "IDSS") { + cerr << "Error: invalid resources.index id tag = " << idTag << endl; + return false; + } + in.read(reinterpret_cast(&idss.idCount), INT_TO_BYTES); + + for (uint32_t j = 0; j < idss.idCount; j++) { + pos = pos + INT_TO_BYTES + INT_TO_BYTES; + if (pos > length) { + cerr << "Error: invalid resources.index id data." << endl; + return false; + } + IdData data; + in.read(reinterpret_cast(&data.id), INT_TO_BYTES); + in.read(reinterpret_cast(&data.dataOffset), INT_TO_BYTES); + datas[data.dataOffset] = make_pair(data.id, offset); + } + } + return true; +} + +bool ResourceTable::ReadDataRecordPrepare(ifstream &in, RecordItem &record, int32_t &pos, int32_t length) const +{ + pos = pos + INT_TO_BYTES; + if (pos > length) { + cerr << "Error: invalid resources.index data record." << endl; + return false; + } + in.read(reinterpret_cast(&record.size), INT_TO_BYTES); + pos = pos + record.size; + if (pos > length) { + cerr << "Error: invalid resources.index record.size." << endl; + return false; + } + in.read(reinterpret_cast(&record.resType), INT_TO_BYTES); + in.read(reinterpret_cast(&record.id), INT_TO_BYTES); + return true; +} + +bool ResourceTable::ReadDataRecordStart(std::ifstream &in, RecordItem &record, + const std::map> &limitKeys, + const std::map> &datas, + std::map> &resInfos) const +{ + int32_t offset = in.tellg(); + offset = offset - INT_TO_BYTES - INT_TO_BYTES - INT_TO_BYTES; + uint16_t value_size = 0; + in.read(reinterpret_cast(&value_size), sizeof(uint16_t)); + if (value_size + sizeof(uint16_t) > record.size) { + cerr << "Error: invalid resources.index value size." << endl; + return false; + } + int8_t values[value_size]; + in.read(reinterpret_cast(&values), value_size); + + uint16_t name_size = 0; + in.read(reinterpret_cast(&name_size), sizeof(uint16_t)); + if (value_size + sizeof(uint16_t) + name_size + sizeof(uint16_t) > record.size) { + cerr << "Error: invalid resources.index name size." << endl; + return false; + } + int8_t name[name_size]; + in.read(reinterpret_cast(name), name_size); + string filename(reinterpret_cast(name)); + + auto idTableOffset = datas.find(offset); + if (idTableOffset == datas.end()) { + cerr << "Error: invalid resources.index id offset." << endl; + return false; + } + + if (idTableOffset->second.first != record.id) { + cerr << "Error: invalid resources.index id." << endl; + return false; + } + + if (limitKeys.find(idTableOffset->second.second) == limitKeys.end()) { + cerr << "Error: invalid resources.index limit key offset." << endl; + return false; + } + const vector &keyparams = limitKeys.find(datas.find(offset)->second.second)->second; + ResourceItem resourceitem(filename, keyparams, g_resTypeMap.find(record.resType)->second); + resourceitem.SetLimitKey(ResourceUtil::PaserKeyParam(keyparams)); + resourceitem.SetData(values, value_size); + resInfos[record.id].push_back(resourceitem); + return true; +} + } } } diff --git a/src/resource_util.cpp b/src/resource_util.cpp index 3c3fd8a..23be92b 100644 --- a/src/resource_util.cpp +++ b/src/resource_util.cpp @@ -272,6 +272,103 @@ bool ResourceUtil::IslegalPath(const string &path) { return path == "element" || path == "media" || path == "profile"; } + +void ResourceUtil::StringReplace(string &sourceStr, const string &oldStr, const string &newStr) +{ + string::size_type pos = 0; + string::size_type oldSize = oldStr.size(); + string::size_type newSize = newStr.size(); + while ((pos = sourceStr.find(oldStr, pos)) != string::npos) { + sourceStr.replace(pos, oldSize, newStr.c_str()); + pos += newSize; + } +} + +string ResourceUtil::GetLocaleLimitkey(const KeyParam &KeyParam) +{ + string str(reinterpret_cast(&KeyParam.value)); + reverse(str.begin(), str.end()); + return str; +} + +string ResourceUtil::GetDeviceTypeLimitkey(const KeyParam &KeyParam) +{ + auto ret = find_if(g_deviceMap.begin(), g_deviceMap.end(), [KeyParam](const auto &iter) { + return KeyParam.value == static_cast(iter.second); + }); + if (ret == g_deviceMap.end()) { + return string(); + } + return ret->first; +} + +string ResourceUtil::GetResolutionLimitkey(const KeyParam &KeyParam) +{ + auto ret = find_if(g_resolutionMap.begin(), g_resolutionMap.end(), [KeyParam](const auto &iter) { + return KeyParam.value == static_cast(iter.second); + }); + if (ret == g_resolutionMap.end()) { + return string(); + } + return ret->first; +} + +string ResourceUtil::GetKeyParamValue(const KeyParam &KeyParam) +{ + string val; + switch (KeyParam.keyType) { + case KeyType::ORIENTATION: + val = KeyParam.value == static_cast(OrientationType::VERTICAL) ? "vertical" : "horizontal"; + break; + case KeyType::NIGHTMODE: + val = KeyParam.value == static_cast(NightMode::DARK) ? "dark" : "light"; + break; + case KeyType::DEVICETYPE: + val = GetDeviceTypeLimitkey(KeyParam); + break; + case KeyType::RESOLUTION: + val = GetResolutionLimitkey(KeyParam); + break; + case KeyType::LANGUAGE: + case KeyType::REGION: + val = GetLocaleLimitkey(KeyParam); + break; + default: + val = to_string(KeyParam.value); + break; + } + return val; +} + +string ResourceUtil::PaserKeyParam(const vector &keyParams) +{ + if (keyParams.size() == 0) { + return "base"; + } + string result; + for (const auto &keyparam : keyParams) { + string limitKey = GetKeyParamValue(keyparam); + if (limitKey.empty()) { + continue; + } + if (keyparam.keyType == KeyType::MCC) { + limitKey = "mcc" + limitKey; + } + if (keyparam.keyType == KeyType::MNC) { + limitKey = "mnc" + limitKey; + } + if (keyparam.keyType == KeyType::REGION || keyparam.keyType == KeyType::MNC) { + result = result + "_" + limitKey; + } else { + result = result + "-" + limitKey; + } + } + if (!result.empty()) { + result = result.substr(1); + } + return result; +} + } } }