From c5f6033bcfe9d27ac557603eb9dfdcd8f4da682c Mon Sep 17 00:00:00 2001 From: HanSY Date: Mon, 2 Jun 2025 11:47:51 +0800 Subject: [PATCH] newModule Signed-off-by: HanSY --- include/config_parser.h | 7 +- include/resource_data.h | 4 +- include/resource_table.h | 112 +++++++++- src/config_parser.cpp | 10 +- src/resource_pack.cpp | 4 +- src/resource_table.cpp | 452 ++++++++++++++++++++++++++++++++++++++- 6 files changed, 570 insertions(+), 19 deletions(-) diff --git a/include/config_parser.h b/include/config_parser.h index c37b419..49dcfa0 100644 --- a/include/config_parser.h +++ b/include/config_parser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -67,6 +67,10 @@ public: { return filePath_; } + inline bool isSupportNewModule() + { + return newModule_; + } static void SetUseModule() { useModule_ = true; @@ -103,6 +107,7 @@ private: static const std::map JSON_ARRAY_IDS; static bool useModule_; cJSON *root_; + bool newModule_ = false; }; } } diff --git a/include/resource_data.h b/include/resource_data.h index 5056ebb..b96e0d7 100644 --- a/include/resource_data.h +++ b/include/resource_data.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -55,6 +55,7 @@ constexpr static int DEFAULT_POOL_SIZE = 8; static std::set g_resourceSet; static std::set g_hapResourceSet; const static int8_t INVALID_ID = -1; +const static int MIN_SUPPORT_NEW_MODULE_API_VERSION = 60000020; enum class IgnoreType { IGNORE_FILE, @@ -205,6 +206,7 @@ const std::map g_inputDeviceMap = { }; struct KeyParam { + static const uint32_t KEY_PARAM_LEN = 8; KeyType keyType; uint32_t value; bool operator == (const KeyParam &other) diff --git a/include/resource_table.h b/include/resource_table.h index 2c1ad47..2fb3e0c 100644 --- a/include/resource_table.h +++ b/include/resource_table.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -19,6 +19,8 @@ #include #include #include +#include + #include "resource_item.h" #include "restool_errors.h" @@ -27,7 +29,7 @@ namespace Global { namespace Restool { class ResourceTable { public: - ResourceTable(); + ResourceTable(bool isNewModule = false); virtual ~ResourceTable(); uint32_t CreateResourceTable(); uint32_t CreateResourceTable(const std::map>> &items); @@ -63,7 +65,69 @@ private: int32_t resType; uint32_t id; }; + + struct KeyConfig { + static const uint32_t KEY_CONFIG_HEADER_LEN = 12; + int8_t keyTag[TAG_LEN] = {'K', 'E', 'Y', 'S'}; + uint32_t configId = 0; + uint32_t keyCount = 0; + std::vector configs; + }; + + struct IndexHeaderV2 { + static const uint32_t INDEX_HEADER_LEN = VERSION_MAX_LEN + 12; + int8_t version[VERSION_MAX_LEN]; + uint32_t length = 0; + uint32_t keyCount = 0; + uint32_t dataBlockOffset = 0; + std::unordered_map keyConfigs; // + std::unordered_map idKeyConfigs; // + }; + + struct ResIndex { + static const uint32_t RES_INDEX_LEN = 12; + uint32_t resId = 0; + uint32_t offset = 0; + uint32_t length = 0; + std::string name; + }; + + struct ResTypeHeader { + static const uint32_t RES_TYPE_HEADER_LEN = 12; + ResType resType; + uint32_t length = 0; + uint32_t count = 0; + std::unordered_map resIndexs; // + }; + + struct IdSetHeader { + static const uint32_t ID_SET_HEADER_LEN = 16; + int8_t idTag[TAG_LEN] = {'I', 'D', 'S', 'S'}; + uint32_t length = 0; + uint32_t typeCount = 0; + uint32_t idCount = 0; + std::unordered_map resTypes; // + }; + + struct ResInfo { + static const uint32_t RES_INFO_LEN = 12; + static const uint32_t DATA_OFFSET_LEN = 8; + uint32_t resId = 0; + uint32_t length = 0; + uint32_t valueCount = 0; + std::unordered_map dataOffset; // + }; + + struct DataHeader { + static const uint32_t DATA_HEADER_LEN = 12; + int8_t idTag[TAG_LEN] = {'D', 'A', 'T', 'A'}; + uint32_t length = 0; + uint32_t idCount = 0; + std::unordered_map resInfos; // + }; + uint32_t SaveToResouorceIndex(const std::map> &configs) const; + uint32_t SaveToNewResouorceIndex(const std::map> &configs) const; uint32_t CreateIdDefined(const std::map> &allResource) const; bool InitIndexHeader(IndexHeader &indexHeader, uint32_t count) const; bool Prepare(const std::map> &configs, @@ -77,16 +141,48 @@ private: void SaveIdSets(const std::map &idSets, std::ostringstream &out) const; static bool ReadFileHeader(std::basic_istream &in, IndexHeader &indexHeader, uint64_t &pos, uint64_t length); static bool ReadLimitKeys(std::basic_istream &in, std::map> &limitKeys, - uint32_t count, uint64_t &pos, uint64_t length); + uint32_t count, uint64_t &pos, uint64_t length); static bool ReadIdTables(std::basic_istream &in, std::map> &datas, - uint32_t count, uint64_t &pos, uint64_t length); - static bool ReadDataRecordPrepare(std::basic_istream &in, RecordItem &record, uint64_t &pos, uint64_t length); + uint32_t count, uint64_t &pos, uint64_t length); + static bool ReadDataRecordPrepare(std::basic_istream &in, RecordItem &record, + uint64_t &pos, uint64_t length); static bool ReadDataRecordStart(std::basic_istream &in, RecordItem &record, - const std::map> &limitKeys, - const std::map> &datas, - std::map> &resInfos); + const std::map> &limitKeys, + const std::map> &datas, + std::map> &resInfos); + static bool InitHeader(IndexHeaderV2 &indexHeader, IdSetHeader &idSetHeader, + DataHeader &dataHeader, uint32_t count); + static void PrepareKeyConfig(IndexHeaderV2 &indexHeader, const uint32_t configId, + const std::string &config, const std::vector &data); + static void PrepareResIndex(IdSetHeader &idSetHeader, const TableData &tableData); + static void PrepareResInfo(DataHeader &dataHeader, const uint32_t resId, + const uint32_t configId, const uint32_t dataPoolLen); + static void WriteDataPool(std::ostringstream &dataPool, const ResourceItem &resourceItem, uint32_t &dataPoolLen); + static void WriteResInfo(std::ostringstream &dataBlock, const DataHeader &idSetHeader, + const uint32_t dataBlockOffset, std::unordered_map &idOffsetMap); + static void WriteIdSet(std::ostringstream &idSetBlock, const IdSetHeader &idSetHeader, + const std::unordered_map &idOffsetMap); + static void WriteResHeader(std::ostringstream &resHeaderBlock, const IndexHeaderV2 &indexHeader); + static void WriteToIndex(const IndexHeaderV2 &indexHeader, const IdSetHeader &idSetHeader, + const DataHeader &dataHeader, const std::ostringstream &dataPool, std::ofstream &out); + static bool IsNewModule(const IndexHeader &indexHeader); + static uint32_t LoadNewResTable(std::basic_istream &in, + std::map> &resInfos); + static bool ReadNewFileHeader(std::basic_istream &in, IndexHeaderV2 &indexHeader, + uint64_t &pos, uint64_t length); + static bool ReadIdSetHeader(std::basic_istream &in, IdSetHeader &idSetHeader, + uint64_t &pos, uint64_t length); + static bool ReadResources(std::basic_istream &in, const ResIndex &resIndex, + const ResTypeHeader &resTypeHeader, IndexHeaderV2 &indexHeader, uint64_t length, + std::map> &resInfos); + static bool ReadResInfo(std::basic_istream &in, ResInfo &resInfo, uint32_t offset, uint64_t length); + static bool ReadResConfig(std::basic_istream &in, uint32_t &resConfigId, uint32_t &dataOffset, + uint64_t &pos, uint64_t length); + static bool ReadResourceItem(std::basic_istream &in, ResourceItem &resourceItem, uint32_t dataOffset, + uint64_t &pos, uint64_t length); std::string indexFilePath_; std::string idDefinedPath_; + bool newResIndex_ = false; }; } } diff --git a/src/config_parser.cpp b/src/config_parser.cpp index 2447cfa..5e0a8ce 100644 --- a/src/config_parser.cpp +++ b/src/config_parser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -83,6 +83,14 @@ uint32_t ConfigParser::Init() return RESTOOL_ERROR; } + cJSON *appNode = cJSON_GetObjectItem(root_, "app"); + if (appNode && cJSON_IsObject(appNode)) { + cJSON *minAPIVersionNode = cJSON_GetObjectItem(appNode, "minAPIVersion"); + if (minAPIVersionNode && minAPIVersionNode->valueint > MIN_SUPPORT_NEW_MODULE_API_VERSION) { + newModule_ = true; + } + } + cJSON *moduleNode = cJSON_GetObjectItem(root_, "module"); if (!ParseModule(moduleNode)) { return RESTOOL_ERROR; diff --git a/src/resource_pack.cpp b/src/resource_pack.cpp index 49830c3..01e6d5f 100644 --- a/src/resource_pack.cpp +++ b/src/resource_pack.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -352,7 +352,7 @@ uint32_t ResourcePack::PackResources(const ResourceMerge &resourceMerge) CheckConfigJson(); } - ResourceTable resourceTable; + ResourceTable resourceTable(configJson_.isSupportNewModule()); if (!packageParser_.GetDependEntry().empty()) { if (HandleFeature() != RESTOOL_SUCCESS) { return RESTOOL_ERROR; diff --git a/src/resource_table.cpp b/src/resource_table.cpp index 2e53c7f..55073f2 100644 --- a/src/resource_table.cpp +++ b/src/resource_table.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 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 @@ -14,6 +14,8 @@ */ #include "resource_table.h" + +#include #include #include #include "cmd/cmd_parser.h" @@ -26,7 +28,7 @@ namespace OHOS { namespace Global { namespace Restool { using namespace std; -ResourceTable::ResourceTable() +ResourceTable::ResourceTable(bool isNewModule) { auto &parser = CmdParser::GetInstance(); auto &packageParser = parser.GetPackageParser(); @@ -34,6 +36,7 @@ ResourceTable::ResourceTable() idDefinedPath_ = FileEntry::FilePath(packageParser.GetIdDefinedOutput()).Append(ID_DEFINED_FILE).GetPath(); } indexFilePath_ = FileEntry::FilePath(packageParser.GetOutput()).Append(RESOURCE_INDEX_FILE).GetPath(); + newResIndex_ = isNewModule; } ResourceTable::~ResourceTable() @@ -57,8 +60,14 @@ uint32_t ResourceTable::CreateResourceTable() } } - if (SaveToResouorceIndex(configs) != RESTOOL_SUCCESS) { - return RESTOOL_ERROR; + if (!newResIndex_) { + if (SaveToResouorceIndex(configs) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } else { + if (SaveToNewResouorceIndex(configs) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } } if (!idDefinedPath_.empty()) { @@ -88,8 +97,14 @@ uint32_t ResourceTable::CreateResourceTable(const map &in, map> limitKeys; if (!ReadLimitKeys(in, limitKeys, indexHeader.limitKeyConfigSize, pos, static_cast(length))) { return RESTOOL_ERROR; @@ -246,6 +265,227 @@ uint32_t ResourceTable::SaveToResouorceIndex(const map return RESTOOL_SUCCESS; } +bool ResourceTable::InitHeader(IndexHeaderV2 &indexHeader, IdSetHeader &idSetHeader, + DataHeader &dataHeader, uint32_t count) +{ + const int8_t newModuleTag[3] = "V2"; + const size_t tagLen = 2; + int8_t newResToolVersion[VERSION_MAX_LEN] = {0}; + size_t nameIndex = find(RESTOOL_VERSION, RESTOOL_VERSION + VERSION_MAX_LEN, ' ') - RESTOOL_VERSION; + // copy "Restool" + if (memcpy_s(newResToolVersion, VERSION_MAX_LEN, RESTOOL_VERSION, nameIndex) != EOK) { + PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("memcpy error when init index header")); + return false; + } + // copy "V2" + if (memcpy_s(newResToolVersion + nameIndex, VERSION_MAX_LEN - nameIndex, newModuleTag, tagLen) != EOK) { + PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("memcpy error when init index header")); + return false; + } + // copy version id + if (memcpy_s(newResToolVersion + nameIndex + tagLen, VERSION_MAX_LEN - nameIndex - tagLen, + RESTOOL_VERSION + nameIndex, VERSION_MAX_LEN - nameIndex - tagLen) != EOK) { + PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("memcpy error when init index header")); + return false; + } + + if (memcpy_s(indexHeader.version, VERSION_MAX_LEN, newResToolVersion, VERSION_MAX_LEN) != EOK) { + PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("memcpy error when init index header")); + return false; + } + + indexHeader.keyCount = count; + indexHeader.length = IndexHeaderV2::INDEX_HEADER_LEN; + indexHeader.keyConfigs.reserve(indexHeader.keyCount); + idSetHeader.length = IdSetHeader::ID_SET_HEADER_LEN; + dataHeader.length = DataHeader::DATA_HEADER_LEN; + return true; +} + +void ResourceTable::PrepareKeyConfig(IndexHeaderV2 &indexHeader, const uint32_t configId, + const string &config, const vector &data) +{ + const vector &keyParams = data[0].resourceItem.GetKeyParam(); + KeyConfig keyConfig; + keyConfig.configId = configId; + keyConfig.keyCount = keyParams.size(); + keyConfig.configs.reserve(keyConfig.keyCount); + indexHeader.length += KeyConfig::KEY_CONFIG_HEADER_LEN; + for (const auto ¶m : keyParams) { + keyConfig.configs.push_back(param); + indexHeader.length += KeyParam::KEY_PARAM_LEN; + } + indexHeader.keyConfigs[config] = keyConfig; +} + +void ResourceTable::PrepareResIndex(IdSetHeader &idSetHeader, const TableData &tableData) +{ + ResType resType = tableData.resourceItem.GetResType(); + if (idSetHeader.resTypes.find(resType) == idSetHeader.resTypes.end()) { + ResTypeHeader resTypeHeader; + resTypeHeader.resType = resType; + resTypeHeader.length = ResTypeHeader::RES_TYPE_HEADER_LEN; + idSetHeader.resTypes[resTypeHeader.resType] = resTypeHeader; + idSetHeader.typeCount++; + idSetHeader.length += ResTypeHeader::RES_TYPE_HEADER_LEN; + } + if (idSetHeader.resTypes[resType].resIndexs.find(tableData.id) != idSetHeader.resTypes[resType].resIndexs.end()) { + return; + } + + ResIndex resIndex; + resIndex.resId = tableData.id; + resIndex.name = tableData.resourceItem.GetName(); + resIndex.length = resIndex.name.length(); + idSetHeader.resTypes[resType].resIndexs[tableData.id] = resIndex; + idSetHeader.resTypes[resType].length += ResIndex::RES_INDEX_LEN + resIndex.length; + idSetHeader.resTypes[resType].count++; + idSetHeader.length += ResIndex::RES_INDEX_LEN + resIndex.length; +} + +void ResourceTable::PrepareResInfo(DataHeader &dataHeader, const uint32_t resId, + const uint32_t configId, const uint32_t dataPoolLen) +{ + if (dataHeader.resInfos.find(resId) == dataHeader.resInfos.end()) { + ResInfo resInfo; + resInfo.resId = resId; + resInfo.length = ResInfo::RES_INFO_LEN; + dataHeader.resInfos[resInfo.resId] = resInfo; + dataHeader.length += ResInfo::RES_INFO_LEN; + dataHeader.idCount++; + } + dataHeader.resInfos[resId].dataOffset[configId] = dataPoolLen; + dataHeader.resInfos[resId].length += ResInfo::DATA_OFFSET_LEN; + dataHeader.resInfos[resId].valueCount++; + dataHeader.length += ResInfo::DATA_OFFSET_LEN; +} + +void ResourceTable::WriteDataPool(ostringstream &dataPool, const ResourceItem &resourceItem, uint32_t &dataPoolLen) +{ + uint32_t length = resourceItem.GetDataLength(); + const int8_t *data = resourceItem.GetData(); + dataPool.write(reinterpret_cast(&length), sizeof(uint16_t)); + dataPool.write(reinterpret_cast(data), length); + dataPoolLen += sizeof(uint16_t) + length; +} + +void ResourceTable::WriteResInfo(ostringstream &dataBlock, const DataHeader &idSetHeader, + const uint32_t dataBlockOffset, unordered_map &idOffsetMap) +{ + uint32_t offset = dataBlockOffset; + dataBlock.write(reinterpret_cast(idSetHeader.idTag), TAG_LEN); + dataBlock.write(reinterpret_cast(&idSetHeader.length), sizeof(uint32_t)); + dataBlock.write(reinterpret_cast(&idSetHeader.idCount), sizeof(uint32_t)); + offset += DataHeader::DATA_HEADER_LEN; + for (const auto &resInfo : idSetHeader.resInfos) { + idOffsetMap[resInfo.second.resId] = offset; + dataBlock.write(reinterpret_cast(&resInfo.second.resId), sizeof(uint32_t)); + dataBlock.write(reinterpret_cast(&resInfo.second.length), sizeof(uint32_t)); + dataBlock.write(reinterpret_cast(&resInfo.second.valueCount), sizeof(uint32_t)); + offset += ResInfo::RES_INFO_LEN; + for (const auto &dataOffset : resInfo.second.dataOffset) { + uint32_t configId = dataOffset.first; + uint32_t realOffset = dataOffset.second + idSetHeader.length + dataBlockOffset; + dataBlock.write(reinterpret_cast(&configId), sizeof(uint32_t)); + dataBlock.write(reinterpret_cast(&realOffset), sizeof(uint32_t)); + offset += ResInfo::DATA_OFFSET_LEN; + } + } +} + +void ResourceTable::WriteIdSet(ostringstream &idSetBlock, const IdSetHeader &idSetHeader, + const unordered_map &idOffsetMap) +{ + idSetBlock.write(reinterpret_cast(idSetHeader.idTag), TAG_LEN); + idSetBlock.write(reinterpret_cast(&idSetHeader.length), sizeof(uint32_t)); + idSetBlock.write(reinterpret_cast(&idSetHeader.typeCount), sizeof(uint32_t)); + idSetBlock.write(reinterpret_cast(&idSetHeader.idCount), sizeof(uint32_t)); + for (const auto &resType : idSetHeader.resTypes) { + idSetBlock.write(reinterpret_cast(&resType.second.resType), sizeof(uint32_t)); + idSetBlock.write(reinterpret_cast(&resType.second.length), sizeof(uint32_t)); + idSetBlock.write(reinterpret_cast(&resType.second.count), sizeof(uint32_t)); + for (const auto &resIndex : resType.second.resIndexs) { + uint32_t realOffset = idOffsetMap.find(resIndex.second.resId)->second; + idSetBlock.write(reinterpret_cast(&resIndex.second.resId), sizeof(uint32_t)); + idSetBlock.write(reinterpret_cast(&realOffset), sizeof(uint32_t)); + idSetBlock.write(reinterpret_cast(&resIndex.second.length), sizeof(uint32_t)); + idSetBlock.write(reinterpret_cast( + resIndex.second.name.c_str()), resIndex.second.length); + } + } +} + +void ResourceTable::WriteResHeader(ostringstream &resHeaderBlock, const IndexHeaderV2 &indexHeader) +{ + resHeaderBlock.write(reinterpret_cast(indexHeader.version), VERSION_MAX_LEN); + resHeaderBlock.write(reinterpret_cast(&indexHeader.length), sizeof(uint32_t)); + resHeaderBlock.write(reinterpret_cast(&indexHeader.keyCount), sizeof(uint32_t)); + resHeaderBlock.write(reinterpret_cast(&indexHeader.dataBlockOffset), sizeof(uint32_t)); + for (const auto &keyConfig : indexHeader.keyConfigs) { + resHeaderBlock.write(reinterpret_cast(keyConfig.second.keyTag), TAG_LEN); + resHeaderBlock.write(reinterpret_cast(&keyConfig.second.configId), sizeof(uint32_t)); + resHeaderBlock.write(reinterpret_cast(&keyConfig.second.keyCount), sizeof(uint32_t)); + for (const auto &config : keyConfig.second.configs) { + resHeaderBlock.write(reinterpret_cast(&config.keyType), sizeof(int32_t)); + resHeaderBlock.write(reinterpret_cast(&config.value), sizeof(int32_t)); + } + } +} + +void ResourceTable::WriteToIndex(const IndexHeaderV2 &indexHeader, const IdSetHeader &idSetHeader, + const DataHeader &dataHeader, const ostringstream &dataPool, ofstream &out) +{ + ostringstream dataBlock; + unordered_map idOffsetMap; + WriteResInfo(dataBlock, dataHeader, indexHeader.dataBlockOffset, idOffsetMap); + + ostringstream idSetBlock; + WriteIdSet(idSetBlock, idSetHeader, idOffsetMap); + + ostringstream resHeaderBlock; + WriteResHeader(resHeaderBlock, indexHeader); + + out << resHeaderBlock.str(); + out << idSetBlock.str(); + out << dataBlock.str(); + out << dataPool.str(); +} + +uint32_t ResourceTable::SaveToNewResouorceIndex(const map> &configs) const +{ + IndexHeaderV2 indexHeader; + IdSetHeader idSetHeader; + DataHeader dataHeader; + + if (!InitHeader(indexHeader, idSetHeader, dataHeader, configs.size())) { + return false; + } + + ostringstream dataPool; + uint32_t dataPoolLen = 0; + uint32_t configId = 0; + for (const auto &config : configs) { + PrepareKeyConfig(indexHeader, configId, config.first, config.second); + for (const auto &tableData : config.second) { + PrepareResIndex(idSetHeader, tableData); + PrepareResInfo(dataHeader, tableData.id, configId, dataPoolLen); + WriteDataPool(dataPool, tableData.resourceItem, dataPoolLen); + } + configId++; + } + idSetHeader.idCount = dataHeader.idCount; + indexHeader.dataBlockOffset = indexHeader.length + idSetHeader.length; + indexHeader.length += idSetHeader.length + dataHeader.length + dataPoolLen; + + ofstream out(indexFilePath_, ofstream::out | ofstream::binary); + if (!out.is_open()) { + PrintError(GetError(ERR_CODE_OPEN_FILE_ERROR).FormatCause(indexFilePath_.c_str(), strerror(errno))); + return RESTOOL_ERROR; + } + WriteToIndex(indexHeader, idSetHeader, dataHeader, dataPool, out); + return RESTOOL_SUCCESS; +} + bool ResourceTable::InitIndexHeader(IndexHeader &indexHeader, uint32_t count) const { if (memcpy_s(indexHeader.version, VERSION_MAX_LEN, RESTOOL_VERSION, VERSION_MAX_LEN) != EOK) { @@ -519,6 +759,206 @@ bool ResourceTable::ReadDataRecordStart(basic_istream &in, RecordItem &rec return true; } +bool ResourceTable::IsNewModule(const IndexHeader &indexHeader) +{ + string version = string(reinterpret_cast(indexHeader.version), VERSION_MAX_LEN); + if (version.substr(0, version.find(" ")) == "Restool") { + return false; + } + return true; +} + +uint32_t ResourceTable::LoadNewResTable(basic_istream &in, map> &resInfos) +{ + if (!in) { + std::string msg = "file stream bad, state code: " + std::to_string(in.rdstate()); + PrintError(GetError(ERR_CODE_READ_FILE_ERROR).FormatCause(in.rdstate(), msg.c_str())); + return RESTOOL_ERROR; + } + in.seekg(0, ios::end); + int64_t length = in.tellg(); + in.seekg(0, ios::beg); + uint64_t pos = 0; + IndexHeaderV2 indexHeader; + if (!ReadNewFileHeader(in, indexHeader, pos, static_cast(length))) { + return RESTOOL_ERROR; + } + IdSetHeader idSetHeader; + if (!ReadIdSetHeader(in, idSetHeader, pos, static_cast(length))) { + return RESTOOL_ERROR; + } + for (const auto &resType : idSetHeader.resTypes) { + for (const auto &resId : resType.second.resIndexs) { + ReadResources(in, resId.second, resType.second, indexHeader, static_cast(length), resInfos); + } + } + return RESTOOL_SUCCESS; +} + +bool ResourceTable::ReadNewFileHeader(basic_istream &in, IndexHeaderV2 &indexHeader, + uint64_t &pos, uint64_t length) +{ + pos += IndexHeaderV2::INDEX_HEADER_LEN; + if (pos > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("header length error")); + return false; + } + in.read(reinterpret_cast(indexHeader.version), VERSION_MAX_LEN); + in.read(reinterpret_cast(&indexHeader.length), INT_TO_BYTES); + in.read(reinterpret_cast(&indexHeader.keyCount), INT_TO_BYTES); + in.read(reinterpret_cast(&indexHeader.dataBlockOffset), INT_TO_BYTES); + + for (uint32_t key = 0; key < indexHeader.keyCount; key++) { + pos += KeyConfig::KEY_CONFIG_HEADER_LEN; + if (pos > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("KeyConfig header length error")); + return false; + } + KeyConfig keyConfig; + in.read(reinterpret_cast(keyConfig.keyTag), TAG_LEN); + in.read(reinterpret_cast(&keyConfig.configId), INT_TO_BYTES); + in.read(reinterpret_cast(&keyConfig.keyCount), INT_TO_BYTES); + + for (uint32_t keyType = 0; keyType < keyConfig.keyCount; keyType++) { + pos += KeyParam::KEY_PARAM_LEN; + if (pos > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("KeyParam length error")); + return false; + } + KeyParam keyParam; + in.read(reinterpret_cast(&keyParam.keyType), INT_TO_BYTES); + in.read(reinterpret_cast(&keyParam.value), INT_TO_BYTES); + keyConfig.configs.push_back(keyParam); + } + indexHeader.idKeyConfigs[keyConfig.configId] = keyConfig; + } + return true; +} + +bool ResourceTable::ReadIdSetHeader(basic_istream &in, IdSetHeader &idSetHeader, uint64_t &pos, uint64_t length) +{ + pos += IdSetHeader::ID_SET_HEADER_LEN; + if (pos > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("IdSet header length error")); + return false; + } + in.read(reinterpret_cast(idSetHeader.idTag), TAG_LEN); + in.read(reinterpret_cast(&idSetHeader.length), INT_TO_BYTES); + in.read(reinterpret_cast(&idSetHeader.typeCount), INT_TO_BYTES); + in.read(reinterpret_cast(&idSetHeader.idCount), INT_TO_BYTES); + + for (uint32_t resType = 0; resType < idSetHeader.typeCount; resType++) { + pos += ResTypeHeader::RES_TYPE_HEADER_LEN; + if (pos > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("ResType header length error")); + return false; + } + ResTypeHeader resTypeHeader; + in.read(reinterpret_cast(&resTypeHeader.resType), INT_TO_BYTES); + in.read(reinterpret_cast(&resTypeHeader.length), INT_TO_BYTES); + in.read(reinterpret_cast(&resTypeHeader.count), INT_TO_BYTES); + + for (uint32_t resId = 0; resId < resTypeHeader.count; resId++) { + pos += ResIndex::RES_INDEX_LEN; + if (pos > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("ResIndex length error")); + return false; + } + ResIndex resIndex; + in.read(reinterpret_cast(&resIndex.resId), INT_TO_BYTES); + in.read(reinterpret_cast(&resIndex.offset), INT_TO_BYTES); + in.read(reinterpret_cast(&resIndex.length), INT_TO_BYTES); + pos += resIndex.length; + if (pos > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("resource name length error")); + return false; + } + char *name = new char[resIndex.length + 1](); + in.read(name, resIndex.length); + resIndex.name = string(name, resIndex.length); + delete[] name; + + resTypeHeader.resIndexs[resIndex.resId] = resIndex; + } + idSetHeader.resTypes[resTypeHeader.resType] = resTypeHeader; + } + return true; +} + +bool ResourceTable::ReadResources(std::basic_istream &in, const ResIndex &resIndex, + const ResTypeHeader &resTypeHeader, IndexHeaderV2 &indexHeader, uint64_t length, + map> &resInfos) +{ + ResInfo resInfo; + if (!ReadResInfo(in, resInfo, resIndex.offset, length)) { + return RESTOOL_ERROR; + } + uint64_t pos = resIndex.offset + ResInfo::RES_INFO_LEN; + for (uint32_t resConfig = 0; resConfig < resInfo.valueCount; resConfig++) { + uint32_t resConfigId; + uint32_t dataOffset; + if (!ReadResConfig(in, resConfigId, dataOffset, pos, length)) { + return RESTOOL_ERROR; + } + ResourceItem resourceItem(resIndex.name, indexHeader.idKeyConfigs[resConfigId].configs, + resTypeHeader.resType); + resourceItem.SetLimitKey(ResourceUtil::PaserKeyParam(indexHeader.idKeyConfigs[resConfigId].configs)); + if (!ReadResourceItem(in, resourceItem, dataOffset, pos, length)) { + return RESTOOL_ERROR; + } + resInfos[resIndex.resId].push_back(resourceItem); + } + return true; +} + +bool ResourceTable::ReadResInfo(std::basic_istream &in, ResInfo &resInfo, uint32_t offset, uint64_t length) +{ + in.seekg(offset, ios::beg); + if (offset + ResInfo::RES_INFO_LEN > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("ResInfo length error")); + return false; + } + in.read(reinterpret_cast(&resInfo.resId), INT_TO_BYTES); + in.read(reinterpret_cast(&resInfo.length), INT_TO_BYTES); + in.read(reinterpret_cast(&resInfo.valueCount), INT_TO_BYTES); + return true; +} + +bool ResourceTable::ReadResConfig(std::basic_istream &in, uint32_t &resConfigId, uint32_t &dataOffset, + uint64_t &pos, uint64_t length) +{ + in.seekg(pos, ios::beg); + pos += INT_TO_BYTES + INT_TO_BYTES; + if (pos > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("Config id length error")); + return false; + } + in.read(reinterpret_cast(&resConfigId), INT_TO_BYTES); + in.read(reinterpret_cast(&dataOffset), INT_TO_BYTES); + return true; +} + +bool ResourceTable::ReadResourceItem(std::basic_istream &in, ResourceItem &resourceItem, + uint32_t dataOffset, uint64_t &pos, uint64_t length) +{ + if (dataOffset + sizeof(uint16_t) > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("resource length error")); + return false; + } + in.seekg(dataOffset, ios::beg); + uint16_t dataLen; + in.read(reinterpret_cast(&dataLen), sizeof(uint16_t)); + if (dataOffset + sizeof(uint16_t) + dataLen > length) { + PrintError(GetError(ERR_CODE_INVALID_RESOURCE_INDEX).FormatCause("resource length error")); + return false; + } + int8_t data[dataLen + 1]; + in.read(reinterpret_cast(data), dataLen); + + resourceItem.SetData(data, dataLen + 1); + resourceItem.MarkCoverable(); + return true; +} } } } -- Gitee