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