• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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