1 /* 2 * Copyright (c) 2021 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 "resource_table.h" 17 #include "cmd_parser.h" 18 #include "file_entry.h" 19 #include "file_manager.h" 20 #include "resource_util.h" 21 #include "securec.h" 22 23 namespace OHOS { 24 namespace Global { 25 namespace Restool { 26 using namespace std; ResourceTable()27 ResourceTable::ResourceTable() 28 { 29 auto &parser = CmdParser<PackageParser>::GetInstance(); 30 auto &packageParser = parser.GetCmdParser(); 31 indexFilePath_ = FileEntry::FilePath(packageParser.GetOutput()).Append(RESOURCE_INDEX_FILE).GetPath(); 32 } 33 ~ResourceTable()34 ResourceTable::~ResourceTable() 35 { 36 } 37 CreateResourceTable()38 uint32_t ResourceTable::CreateResourceTable() 39 { 40 FileManager &fileManager = FileManager::GetInstance(); 41 auto &allResource = fileManager.GetResources(); 42 map<string, vector<TableData>> configs; 43 for (const auto &item : allResource) { 44 for (const auto &resourceItem : item.second) { 45 if (resourceItem.GetResType() == ResType::ID) { 46 break; 47 } 48 TableData tableData; 49 tableData.id = item.first; 50 tableData.resourceItem = resourceItem; 51 configs[resourceItem.GetLimitKey()].push_back(tableData); 52 } 53 } 54 55 if (SaveToResouorceIndex(configs) != RESTOOL_SUCCESS) { 56 return RESTOOL_ERROR; 57 } 58 return RESTOOL_SUCCESS; 59 } 60 CreateResourceTable(const map<int32_t,vector<shared_ptr<ResourceItem>>> & items)61 uint32_t ResourceTable::CreateResourceTable(const map<int32_t, vector<shared_ptr<ResourceItem>>> &items) 62 { 63 map<string, vector<TableData>> configs; 64 for (const auto &item : items) { 65 for (const auto &resourceItemPtr : item.second) { 66 if (resourceItemPtr->GetResType() == ResType::ID) { 67 break; 68 } 69 TableData tableData; 70 tableData.id = item.first; 71 tableData.resourceItem = *resourceItemPtr; 72 configs[resourceItemPtr->GetLimitKey()].push_back(tableData); 73 } 74 } 75 76 if (SaveToResouorceIndex(configs) != RESTOOL_SUCCESS) { 77 return RESTOOL_ERROR; 78 } 79 return RESTOOL_SUCCESS; 80 } 81 LoadResTable(const string path,map<int32_t,vector<ResourceItem>> & resInfos)82 uint32_t ResourceTable::LoadResTable(const string path, map<int32_t, vector<ResourceItem>> &resInfos) 83 { 84 ifstream in(path, ios::binary); 85 if (!in.is_open()) { 86 cerr << "Error: open failed." << NEW_LINE_PATH << path <<endl; 87 return RESTOOL_ERROR; 88 } 89 90 in.seekg(0, ios::end); 91 int32_t length = in.tellg(); 92 if (length <= 0) { 93 in.close(); 94 return RESTOOL_ERROR; 95 } 96 in.seekg(0, ios::beg); 97 98 int32_t pos = 0; 99 IndexHeader indexHeader; 100 if (!ReadFileHeader(in, indexHeader, pos, length)) { 101 in.close(); 102 return RESTOOL_ERROR; 103 } 104 105 map<int32_t, vector<KeyParam>> limitKeys; 106 if (!ReadLimitKeys(in, limitKeys, indexHeader.limitKeyConfigSize, pos, length)) { 107 in.close(); 108 return RESTOOL_ERROR; 109 } 110 111 map<int32_t, pair<int32_t, int32_t>> datas; 112 if (!ReadIdTables(in, datas, indexHeader.limitKeyConfigSize, pos, length)) { 113 in.close(); 114 return RESTOOL_ERROR; 115 } 116 117 while (in.tellg() < length) { 118 RecordItem record; 119 if (!ReadDataRecordPrepare(in, record, pos, length) || 120 !ReadDataRecordStart(in, record, limitKeys, datas, resInfos)) { 121 in.close(); 122 return RESTOOL_ERROR; 123 } 124 } 125 in.close(); 126 return RESTOOL_SUCCESS; 127 } 128 // below private SaveToResouorceIndex(const map<string,vector<TableData>> & configs) const129 uint32_t ResourceTable::SaveToResouorceIndex(const map<string, vector<TableData>> &configs) const 130 { 131 uint32_t pos = 0; 132 IndexHeader indexHeader; 133 if (!InitIndexHeader(indexHeader, configs.size())) { 134 return RESTOOL_ERROR; 135 } 136 pos += sizeof(IndexHeader); 137 138 map<string, LimitKeyConfig> limitKeyConfigs; 139 map<string, IdSet> idSets; 140 if (!Prepare(configs, limitKeyConfigs, idSets, pos)) { 141 return RESTOOL_ERROR; 142 } 143 144 ofstream out(indexFilePath_, ofstream::out | ofstream::binary); 145 if (!out.is_open()) { 146 cerr << "Error: open failed '" << indexFilePath_ << "', reason: " << strerror(errno) << endl; 147 return RESTOOL_ERROR; 148 } 149 150 ostringstream outStreamData; 151 if (!SaveRecordItem(configs, outStreamData, idSets, pos)) { 152 return RESTOOL_ERROR; 153 } 154 155 ostringstream outStreamHeader; 156 indexHeader.fileSize = pos; 157 SaveHeader(indexHeader, outStreamHeader); 158 SaveLimitKeyConfigs(limitKeyConfigs, outStreamHeader); 159 SaveIdSets(idSets, outStreamHeader); 160 out << outStreamHeader.str(); 161 out << outStreamData.str(); 162 return RESTOOL_SUCCESS; 163 } 164 InitIndexHeader(IndexHeader & indexHeader,uint32_t count) const165 bool ResourceTable::InitIndexHeader(IndexHeader &indexHeader, uint32_t count) const 166 { 167 if (memcpy_s(indexHeader.version, VERSION_MAX_LEN, RESTOOL_VERSION, VERSION_MAX_LEN) != EOK) { 168 cerr << "Error: InitIndexHeader memcpy_s fail." << endl; 169 return false; 170 } 171 indexHeader.limitKeyConfigSize = count; 172 return true; 173 } 174 Prepare(const map<string,vector<TableData>> & configs,map<string,LimitKeyConfig> & limitKeyConfigs,map<string,IdSet> & idSets,uint32_t & pos) const175 bool ResourceTable::Prepare(const map<string, vector<TableData>> &configs, 176 map<string, LimitKeyConfig> &limitKeyConfigs, 177 map<string, IdSet> &idSets, uint32_t &pos) const 178 { 179 for (const auto &config : configs) { 180 LimitKeyConfig limitKeyConfig; 181 const auto &keyParams = config.second.at(0).resourceItem.GetKeyParam(); 182 limitKeyConfig.keyCount = keyParams.size(); 183 pos += sizeof(limitKeyConfig.keyTag) + sizeof(limitKeyConfig.offset) + sizeof(limitKeyConfig.keyCount); 184 for (const auto &keyParam : keyParams) { 185 limitKeyConfig.data.push_back(static_cast<int32_t>(keyParam.keyType)); 186 limitKeyConfig.data.push_back(static_cast<int32_t>(keyParam.value)); 187 pos += sizeof(KeyParam); 188 } 189 limitKeyConfigs.emplace(config.first, limitKeyConfig); 190 } 191 192 for (const auto &config : configs) { 193 auto limitKeyConfig = limitKeyConfigs.find(config.first); 194 if (limitKeyConfig == limitKeyConfigs.end()) { 195 cerr << "Error: limit key config don't find '" << config.first << "'." << endl; 196 return false; 197 } 198 limitKeyConfig->second.offset = pos; 199 200 IdSet idSet; 201 idSet.idCount = config.second.size(); 202 pos += sizeof(idSet.idTag) + sizeof(idSet.idCount); 203 for (const auto &tableData : config.second) { 204 idSet.data.emplace(tableData.id, 0); 205 pos += sizeof(uint32_t) + sizeof(uint32_t); 206 } 207 idSets.emplace(config.first, idSet); 208 } 209 return true; 210 } 211 SaveRecordItem(const map<string,vector<TableData>> & configs,ostringstream & out,map<string,IdSet> & idSets,uint32_t & pos) const212 bool ResourceTable::SaveRecordItem(const map<string, vector<TableData>> &configs, 213 ostringstream &out, map<string, IdSet> &idSets, uint32_t &pos) const 214 { 215 for (const auto &config : configs) { 216 auto idSet = idSets.find(config.first); 217 if (idSet == idSets.end()) { 218 cerr << "Error: id set don't find '" << config.first << "'." << endl; 219 return false; 220 } 221 222 for (const auto &tableData : config.second) { 223 if (idSet->second.data.find(tableData.id) == idSet->second.data.end()) { 224 cerr << "Error: resource table don't find id '" << tableData.id << "'." << endl; 225 return false; 226 } 227 idSet->second.data[tableData.id] = pos; 228 RecordItem recordItem; 229 recordItem.id = tableData.id; 230 recordItem.resType = static_cast<int32_t>(tableData.resourceItem.GetResType()); 231 vector<string> contents; 232 string value(reinterpret_cast<const char *>(tableData.resourceItem.GetData()), 233 tableData.resourceItem.GetDataLength()); 234 contents.push_back(value); 235 string name = ResourceUtil::GetIdName(tableData.resourceItem.GetName(), 236 tableData.resourceItem.GetResType()); 237 contents.push_back(name); 238 string data = ResourceUtil::ComposeStrings(contents, true); 239 recordItem.size = sizeof(RecordItem) + data.length() - sizeof(uint32_t); 240 pos += recordItem.size + sizeof(uint32_t); 241 242 out.write(reinterpret_cast<const char *>(&recordItem.size), sizeof(uint32_t)); 243 out.write(reinterpret_cast<const char *>(&recordItem.resType), sizeof(uint32_t)); 244 out.write(reinterpret_cast<const char *>(&recordItem.id), sizeof(uint32_t)); 245 out.write(reinterpret_cast<const char *>(data.c_str()), data.length()); 246 } 247 } 248 return true; 249 } 250 SaveHeader(const IndexHeader & indexHeader,ostringstream & out) const251 void ResourceTable::SaveHeader(const IndexHeader &indexHeader, ostringstream &out) const 252 { 253 out.write(reinterpret_cast<const char *>(&indexHeader.version), VERSION_MAX_LEN); 254 out.write(reinterpret_cast<const char *>(&indexHeader.fileSize), sizeof(uint32_t)); 255 out.write(reinterpret_cast<const char *>(&indexHeader.limitKeyConfigSize), sizeof(uint32_t)); 256 } 257 SaveLimitKeyConfigs(const map<string,LimitKeyConfig> & limitKeyConfigs,ostringstream & out) const258 void ResourceTable::SaveLimitKeyConfigs(const map<string, LimitKeyConfig> &limitKeyConfigs, ostringstream &out) const 259 { 260 for (const auto &iter : limitKeyConfigs) { 261 out.write(reinterpret_cast<const char *>(iter.second.keyTag), TAG_LEN); 262 out.write(reinterpret_cast<const char *>(&iter.second.offset), sizeof(uint32_t)); 263 out.write(reinterpret_cast<const char *>(&iter.second.keyCount), sizeof(uint32_t)); 264 for (const auto &value : iter.second.data) { 265 out.write(reinterpret_cast<const char *>(&value), sizeof(int32_t)); 266 } 267 } 268 } 269 SaveIdSets(const map<string,IdSet> & idSets,ostringstream & out) const270 void ResourceTable::SaveIdSets(const map<string, IdSet> &idSets, ostringstream &out) const 271 { 272 for (const auto &iter : idSets) { 273 out.write(reinterpret_cast<const char *>(iter.second.idTag), TAG_LEN); 274 out.write(reinterpret_cast<const char *>(&iter.second.idCount), sizeof(uint32_t)); 275 for (const auto &keyValue : iter.second.data) { 276 out.write(reinterpret_cast<const char *>(&keyValue.first), sizeof(uint32_t)); 277 out.write(reinterpret_cast<const char *>(&keyValue.second), sizeof(uint32_t)); 278 } 279 } 280 } 281 ReadFileHeader(ifstream & in,IndexHeader & indexHeader,int32_t & pos,int32_t length) const282 bool ResourceTable::ReadFileHeader(ifstream &in, IndexHeader &indexHeader, int32_t &pos, int32_t length) const 283 { 284 pos += sizeof(indexHeader); 285 if (pos > length) { 286 cerr << "Error: invalid resources.index File Header." << endl; 287 return false; 288 } 289 in.read(reinterpret_cast<char *>(indexHeader.version), VERSION_MAX_LEN); 290 in.read(reinterpret_cast<char *>(&indexHeader.fileSize), INT_TO_BYTES); 291 in.read(reinterpret_cast<char *>(&indexHeader.limitKeyConfigSize), INT_TO_BYTES); 292 return true; 293 } 294 ReadLimitKeys(ifstream & in,map<int32_t,vector<KeyParam>> & limitKeys,uint32_t count,int32_t & pos,int32_t length) const295 bool ResourceTable::ReadLimitKeys(ifstream &in, map<int32_t, vector<KeyParam>> &limitKeys, 296 uint32_t count, int32_t &pos, int32_t length) const 297 { 298 for (uint32_t i = 0; i< count; i++) { 299 pos = pos + TAG_LEN + INT_TO_BYTES + INT_TO_BYTES; 300 if (pos > length) { 301 cerr << "Error: invalid resources.index KEYS." << endl; 302 return false; 303 } 304 LimitKeyConfig limitKey; 305 in.read(reinterpret_cast<char *>(limitKey.keyTag), TAG_LEN); 306 string keyTag(reinterpret_cast<const char *>(limitKey.keyTag), TAG_LEN); 307 if (keyTag != "KEYS") { 308 cerr << "Error: invalid resources.index key tag = " << keyTag << endl; 309 return false; 310 } 311 in.read(reinterpret_cast<char *>(&limitKey.offset), INT_TO_BYTES); 312 in.read(reinterpret_cast<char *>(&limitKey.keyCount), INT_TO_BYTES); 313 314 vector<KeyParam> keyParams; 315 for (uint32_t j = 0; j < limitKey.keyCount; j++) { 316 pos = pos + INT_TO_BYTES + INT_TO_BYTES; 317 if (pos > length) { 318 cerr << "Error: invalid resources.index keyParams." << endl; 319 return false; 320 } 321 KeyParam keyParam; 322 in.read(reinterpret_cast<char *>(&keyParam.keyType), INT_TO_BYTES); 323 in.read(reinterpret_cast<char *>(&keyParam.value), INT_TO_BYTES); 324 keyParams.push_back(keyParam); 325 } 326 limitKeys[limitKey.offset] = keyParams; 327 } 328 return true; 329 } 330 ReadIdTables(std::ifstream & in,std::map<int32_t,std::pair<int32_t,int32_t>> & datas,uint32_t count,int32_t & pos,int32_t length) const331 bool ResourceTable::ReadIdTables(std::ifstream &in, std::map<int32_t, std::pair<int32_t, int32_t>> &datas, 332 uint32_t count, int32_t &pos, int32_t length) const 333 { 334 for (uint32_t i = 0; i< count; i++) { 335 pos = pos + TAG_LEN + INT_TO_BYTES; 336 if (pos > length) { 337 cerr << "Error: invalid resources.index IDSS." << endl; 338 return false; 339 } 340 IdSet idss; 341 int32_t offset = in.tellg(); 342 in.read(reinterpret_cast<char *>(idss.idTag), TAG_LEN); 343 string idTag(reinterpret_cast<const char *>(idss.idTag), TAG_LEN); 344 if (idTag != "IDSS") { 345 cerr << "Error: invalid resources.index id tag = " << idTag << endl; 346 return false; 347 } 348 in.read(reinterpret_cast<char *>(&idss.idCount), INT_TO_BYTES); 349 350 for (uint32_t j = 0; j < idss.idCount; j++) { 351 pos = pos + INT_TO_BYTES + INT_TO_BYTES; 352 if (pos > length) { 353 cerr << "Error: invalid resources.index id data." << endl; 354 return false; 355 } 356 IdData data; 357 in.read(reinterpret_cast<char *>(&data.id), INT_TO_BYTES); 358 in.read(reinterpret_cast<char *>(&data.dataOffset), INT_TO_BYTES); 359 datas[data.dataOffset] = make_pair(data.id, offset); 360 } 361 } 362 return true; 363 } 364 ReadDataRecordPrepare(ifstream & in,RecordItem & record,int32_t & pos,int32_t length) const365 bool ResourceTable::ReadDataRecordPrepare(ifstream &in, RecordItem &record, int32_t &pos, int32_t length) const 366 { 367 pos = pos + INT_TO_BYTES; 368 if (pos > length) { 369 cerr << "Error: invalid resources.index data record." << endl; 370 return false; 371 } 372 in.read(reinterpret_cast<char *>(&record.size), INT_TO_BYTES); 373 pos = pos + record.size; 374 if (pos > length) { 375 cerr << "Error: invalid resources.index record.size." << endl; 376 return false; 377 } 378 in.read(reinterpret_cast<char *>(&record.resType), INT_TO_BYTES); 379 in.read(reinterpret_cast<char *>(&record.id), INT_TO_BYTES); 380 return true; 381 } 382 ReadDataRecordStart(std::ifstream & in,RecordItem & record,const std::map<int32_t,std::vector<KeyParam>> & limitKeys,const std::map<int32_t,std::pair<int32_t,int32_t>> & datas,std::map<int32_t,std::vector<ResourceItem>> & resInfos) const383 bool ResourceTable::ReadDataRecordStart(std::ifstream &in, RecordItem &record, 384 const std::map<int32_t, std::vector<KeyParam>> &limitKeys, 385 const std::map<int32_t, std::pair<int32_t, int32_t>> &datas, 386 std::map<int32_t, std::vector<ResourceItem>> &resInfos) const 387 { 388 int32_t offset = in.tellg(); 389 offset = offset - INT_TO_BYTES - INT_TO_BYTES - INT_TO_BYTES; 390 uint16_t value_size = 0; 391 in.read(reinterpret_cast<char *>(&value_size), sizeof(uint16_t)); 392 if (value_size + sizeof(uint16_t) > record.size) { 393 cerr << "Error: invalid resources.index value size." << endl; 394 return false; 395 } 396 int8_t values[value_size]; 397 in.read(reinterpret_cast<char *>(&values), value_size); 398 399 uint16_t name_size = 0; 400 in.read(reinterpret_cast<char *>(&name_size), sizeof(uint16_t)); 401 if (value_size + sizeof(uint16_t) + name_size + sizeof(uint16_t) > record.size) { 402 cerr << "Error: invalid resources.index name size." << endl; 403 return false; 404 } 405 int8_t name[name_size]; 406 in.read(reinterpret_cast<char *>(name), name_size); 407 string filename(reinterpret_cast<char *>(name)); 408 409 auto idTableOffset = datas.find(offset); 410 if (idTableOffset == datas.end()) { 411 cerr << "Error: invalid resources.index id offset." << endl; 412 return false; 413 } 414 415 if (idTableOffset->second.first != record.id) { 416 cerr << "Error: invalid resources.index id." << endl; 417 return false; 418 } 419 420 if (limitKeys.find(idTableOffset->second.second) == limitKeys.end()) { 421 cerr << "Error: invalid resources.index limit key offset." << endl; 422 return false; 423 } 424 const vector<KeyParam> &keyparams = limitKeys.find(datas.find(offset)->second.second)->second; 425 ResourceItem resourceitem(filename, keyparams, g_resTypeMap.find(record.resType)->second); 426 resourceitem.SetLimitKey(ResourceUtil::PaserKeyParam(keyparams)); 427 resourceitem.SetData(values, value_size); 428 resInfos[record.id].push_back(resourceitem); 429 return true; 430 } 431 432 } 433 } 434 } 435