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