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
LoadResTable(const string path,map<int32_t,vector<ResourceItem>> & resInfos)61 uint32_t ResourceTable::LoadResTable(const string path, map<int32_t, vector<ResourceItem>> &resInfos)
62 {
63 ifstream in(path, ios::binary);
64 if (!in.is_open()) {
65 cerr << "Error: open failed. at" << path <<endl;
66 return RESTOOL_ERROR;
67 }
68
69 in.seekg(0, ios::end);
70 int32_t length = in.tellg();
71 if (length <= 0) {
72 in.close();
73 return RESTOOL_ERROR;
74 }
75 in.seekg(0, ios::beg);
76
77 int32_t pos = 0;
78 IndexHeader indexHeader;
79 if (!ReadFileHeader(in, indexHeader, pos, length)) {
80 in.close();
81 return RESTOOL_ERROR;
82 }
83
84 map<int32_t, vector<KeyParam>> limitKeys;
85 if (!ReadLimitKeys(in, limitKeys, indexHeader.limitKeyConfigSize, pos, length)) {
86 in.close();
87 return RESTOOL_ERROR;
88 }
89
90 map<int32_t, pair<int32_t, int32_t>> datas;
91 if (!ReadIdTables(in, datas, indexHeader.limitKeyConfigSize, pos, length)) {
92 in.close();
93 return RESTOOL_ERROR;
94 }
95
96 while (in.tellg() < length) {
97 RecordItem record;
98 if (!ReadDataRecordPrepare(in, record, pos, length) ||
99 !ReadDataRecordStart(in, record, limitKeys, datas, resInfos)) {
100 in.close();
101 return RESTOOL_ERROR;
102 }
103 }
104 in.close();
105 return RESTOOL_SUCCESS;
106 }
107 // below private
SaveToResouorceIndex(const map<string,vector<TableData>> & configs) const108 uint32_t ResourceTable::SaveToResouorceIndex(const map<string, vector<TableData>> &configs) const
109 {
110 uint32_t pos = 0;
111 IndexHeader indexHeader;
112 if (!InitIndexHeader(indexHeader, configs.size())) {
113 return RESTOOL_ERROR;
114 }
115 pos += sizeof(IndexHeader);
116
117 map<string, LimitKeyConfig> limitKeyConfigs;
118 map<string, IdSet> idSets;
119 if (!Prepare(configs, limitKeyConfigs, idSets, pos)) {
120 return RESTOOL_ERROR;
121 }
122
123 ofstream out(indexFilePath_, ofstream::out | ofstream::binary);
124 if (!out.is_open()) {
125 cerr << "Error: open fail " << indexFilePath_ << endl;
126 return RESTOOL_ERROR;
127 }
128
129 if (!SaveRecordItem(configs, out, idSets, pos)) {
130 return RESTOOL_ERROR;
131 }
132
133 indexHeader.fileSize = pos;
134 SaveHeader(indexHeader, out);
135 SaveLimitKeyConfigs(limitKeyConfigs, out);
136 SaveIdSets(idSets, out);
137 return RESTOOL_SUCCESS;
138 }
139
InitIndexHeader(IndexHeader & indexHeader,uint32_t count) const140 bool ResourceTable::InitIndexHeader(IndexHeader &indexHeader, uint32_t count) const
141 {
142 if (memcpy_s(indexHeader.version, VERSION_MAX_LEN, RESTOOL_VERSION, VERSION_MAX_LEN) != EOK) {
143 cerr << "Error: InitIndexHeader memcpy_s fail." << endl;
144 return false;
145 }
146 indexHeader.limitKeyConfigSize = count;
147 return true;
148 }
149
Prepare(const map<string,vector<TableData>> & configs,map<string,LimitKeyConfig> & limitKeyConfigs,map<string,IdSet> & idSets,uint32_t & pos) const150 bool ResourceTable::Prepare(const map<string, vector<TableData>> &configs,
151 map<string, LimitKeyConfig> &limitKeyConfigs,
152 map<string, IdSet> &idSets, uint32_t &pos) const
153 {
154 for (const auto &config : configs) {
155 LimitKeyConfig limitKeyConfig;
156 const auto &keyParams = config.second.at(0).resourceItem.GetKeyParam();
157 limitKeyConfig.keyCount = keyParams.size();
158 pos += sizeof(limitKeyConfig.keyTag) + sizeof(limitKeyConfig.offset) + sizeof(limitKeyConfig.keyCount);
159 for (const auto &keyParam : keyParams) {
160 limitKeyConfig.data.push_back(static_cast<int32_t>(keyParam.keyType));
161 limitKeyConfig.data.push_back(static_cast<int32_t>(keyParam.value));
162 pos += sizeof(KeyParam);
163 }
164 limitKeyConfigs.emplace(config.first, limitKeyConfig);
165 }
166
167 for (const auto &config : configs) {
168 auto limitKeyConfig = limitKeyConfigs.find(config.first);
169 if (limitKeyConfig == limitKeyConfigs.end()) {
170 cerr << "Error: limit key config don't find '" << config.first << "'" << endl;
171 return false;
172 }
173 limitKeyConfig->second.offset = pos;
174
175 IdSet idSet;
176 idSet.idCount = config.second.size();
177 pos += sizeof(idSet.idTag) + sizeof(idSet.idCount);
178 for (const auto &tableData : config.second) {
179 idSet.data.emplace(tableData.id, 0);
180 pos += sizeof(uint32_t) + sizeof(uint32_t);
181 }
182 idSets.emplace(config.first, idSet);
183 }
184 return true;
185 }
186
SaveRecordItem(const map<string,vector<TableData>> & configs,ofstream & out,map<string,IdSet> & idSets,uint32_t & pos) const187 bool ResourceTable::SaveRecordItem(const map<string, vector<TableData>> &configs,
188 ofstream &out, map<string, IdSet> &idSets, uint32_t &pos) const
189 {
190 out.seekp(pos);
191 for (const auto &config : configs) {
192 auto idSet = idSets.find(config.first);
193 if (idSet == idSets.end()) {
194 cerr << "Error: id set don't find '" << config.first << "'" << endl;
195 return false;
196 }
197
198 for (const auto &tableData : config.second) {
199 if (idSet->second.data.find(tableData.id) == idSet->second.data.end()) {
200 cerr << "Error: resource table don't find id '" << tableData.id << "'" << endl;
201 return false;
202 }
203 idSet->second.data[tableData.id] = pos;
204 RecordItem recordItem;
205 recordItem.id = tableData.id;
206 recordItem.resType = static_cast<int32_t>(tableData.resourceItem.GetResType());
207 vector<string> contents;
208 string value(reinterpret_cast<const char *>(tableData.resourceItem.GetData()),
209 tableData.resourceItem.GetDataLength());
210 contents.push_back(value);
211 string name = ResourceUtil::GetIdName(tableData.resourceItem.GetName(),
212 tableData.resourceItem.GetResType());
213 contents.push_back(name);
214 string data = ResourceUtil::ComposeStrings(contents, true);
215 recordItem.size = sizeof(RecordItem) + data.length() - sizeof(uint32_t);
216 pos += recordItem.size + sizeof(uint32_t);
217
218 out.write(reinterpret_cast<const char *>(&recordItem.size), sizeof(uint32_t));
219 out.write(reinterpret_cast<const char *>(&recordItem.resType), sizeof(uint32_t));
220 out.write(reinterpret_cast<const char *>(&recordItem.id), sizeof(uint32_t));
221 out.write(reinterpret_cast<const char *>(data.c_str()), data.length());
222 }
223 }
224 return true;
225 }
226
SaveHeader(const IndexHeader & indexHeader,std::ofstream & out) const227 void ResourceTable::SaveHeader(const IndexHeader &indexHeader, std::ofstream &out) const
228 {
229 out.seekp(0);
230 out.write(reinterpret_cast<const char *>(&indexHeader.version), VERSION_MAX_LEN);
231 out.write(reinterpret_cast<const char *>(&indexHeader.fileSize), sizeof(uint32_t));
232 out.write(reinterpret_cast<const char *>(&indexHeader.limitKeyConfigSize), sizeof(uint32_t));
233 }
234
SaveLimitKeyConfigs(const map<string,LimitKeyConfig> & limitKeyConfigs,ofstream & out) const235 void ResourceTable::SaveLimitKeyConfigs(const map<string, LimitKeyConfig> &limitKeyConfigs, ofstream &out) const
236 {
237 for (const auto &iter : limitKeyConfigs) {
238 out.write(reinterpret_cast<const char *>(iter.second.keyTag), TAG_LEN);
239 out.write(reinterpret_cast<const char *>(&iter.second.offset), sizeof(uint32_t));
240 out.write(reinterpret_cast<const char *>(&iter.second.keyCount), sizeof(uint32_t));
241 for (const auto &value : iter.second.data) {
242 out.write(reinterpret_cast<const char *>(&value), sizeof(int32_t));
243 }
244 }
245 }
246
SaveIdSets(const map<string,IdSet> & idSets,ofstream & out) const247 void ResourceTable::SaveIdSets(const map<string, IdSet> &idSets, ofstream &out) const
248 {
249 for (const auto &iter : idSets) {
250 out.write(reinterpret_cast<const char *>(iter.second.idTag), TAG_LEN);
251 out.write(reinterpret_cast<const char *>(&iter.second.idCount), sizeof(uint32_t));
252 for (const auto &keyValue : iter.second.data) {
253 out.write(reinterpret_cast<const char *>(&keyValue.first), sizeof(uint32_t));
254 out.write(reinterpret_cast<const char *>(&keyValue.second), sizeof(uint32_t));
255 }
256 }
257 }
258
ReadFileHeader(ifstream & in,IndexHeader & indexHeader,int32_t & pos,int32_t length) const259 bool ResourceTable::ReadFileHeader(ifstream &in, IndexHeader &indexHeader, int32_t &pos, int32_t length) const
260 {
261 pos += sizeof(indexHeader);
262 if (pos > length) {
263 cerr << "Error: invalid resources.index File Header." << endl;
264 return false;
265 }
266 in.read(reinterpret_cast<char *>(indexHeader.version), VERSION_MAX_LEN);
267 in.read(reinterpret_cast<char *>(&indexHeader.fileSize), INT_TO_BYTES);
268 in.read(reinterpret_cast<char *>(&indexHeader.limitKeyConfigSize), INT_TO_BYTES);
269 return true;
270 }
271
ReadLimitKeys(ifstream & in,map<int32_t,vector<KeyParam>> & limitKeys,uint32_t count,int32_t & pos,int32_t length) const272 bool ResourceTable::ReadLimitKeys(ifstream &in, map<int32_t, vector<KeyParam>> &limitKeys,
273 uint32_t count, int32_t &pos, int32_t length) const
274 {
275 for (uint32_t i = 0; i< count; i++) {
276 pos = pos + TAG_LEN + INT_TO_BYTES + INT_TO_BYTES;
277 if (pos > length) {
278 cerr << "Error: invalid resources.index KEYS." << endl;
279 return false;
280 }
281 LimitKeyConfig limitKey;
282 in.read(reinterpret_cast<char *>(limitKey.keyTag), TAG_LEN);
283 string keyTag(reinterpret_cast<const char *>(limitKey.keyTag), TAG_LEN);
284 if (keyTag != "KEYS") {
285 cerr << "Error: invalid resources.index key tag = " << keyTag << endl;
286 return false;
287 }
288 in.read(reinterpret_cast<char *>(&limitKey.offset), INT_TO_BYTES);
289 in.read(reinterpret_cast<char *>(&limitKey.keyCount), INT_TO_BYTES);
290
291 vector<KeyParam> keyParams;
292 for (uint32_t j = 0; j < limitKey.keyCount; j++) {
293 pos = pos + INT_TO_BYTES + INT_TO_BYTES;
294 if (pos > length) {
295 cerr << "Error: invalid resources.index keyParams." << endl;
296 return false;
297 }
298 KeyParam keyParam;
299 in.read(reinterpret_cast<char *>(&keyParam.keyType), INT_TO_BYTES);
300 in.read(reinterpret_cast<char *>(&keyParam.value), INT_TO_BYTES);
301 keyParams.push_back(keyParam);
302 }
303 limitKeys[limitKey.offset] = keyParams;
304 }
305 return true;
306 }
307
ReadIdTables(std::ifstream & in,std::map<int32_t,std::pair<int32_t,int32_t>> & datas,uint32_t count,int32_t & pos,int32_t length) const308 bool ResourceTable::ReadIdTables(std::ifstream &in, std::map<int32_t, std::pair<int32_t, int32_t>> &datas,
309 uint32_t count, int32_t &pos, int32_t length) const
310 {
311 for (uint32_t i = 0; i< count; i++) {
312 pos = pos + TAG_LEN + INT_TO_BYTES;
313 if (pos > length) {
314 cerr << "Error: invalid resources.index IDSS." << endl;
315 return false;
316 }
317 IdSet idss;
318 int32_t offset = in.tellg();
319 in.read(reinterpret_cast<char *>(idss.idTag), TAG_LEN);
320 string idTag(reinterpret_cast<const char *>(idss.idTag), TAG_LEN);
321 if (idTag != "IDSS") {
322 cerr << "Error: invalid resources.index id tag = " << idTag << endl;
323 return false;
324 }
325 in.read(reinterpret_cast<char *>(&idss.idCount), INT_TO_BYTES);
326
327 for (uint32_t j = 0; j < idss.idCount; j++) {
328 pos = pos + INT_TO_BYTES + INT_TO_BYTES;
329 if (pos > length) {
330 cerr << "Error: invalid resources.index id data." << endl;
331 return false;
332 }
333 IdData data;
334 in.read(reinterpret_cast<char *>(&data.id), INT_TO_BYTES);
335 in.read(reinterpret_cast<char *>(&data.dataOffset), INT_TO_BYTES);
336 datas[data.dataOffset] = make_pair(data.id, offset);
337 }
338 }
339 return true;
340 }
341
ReadDataRecordPrepare(ifstream & in,RecordItem & record,int32_t & pos,int32_t length) const342 bool ResourceTable::ReadDataRecordPrepare(ifstream &in, RecordItem &record, int32_t &pos, int32_t length) const
343 {
344 pos = pos + INT_TO_BYTES;
345 if (pos > length) {
346 cerr << "Error: invalid resources.index data record." << endl;
347 return false;
348 }
349 in.read(reinterpret_cast<char *>(&record.size), INT_TO_BYTES);
350 pos = pos + record.size;
351 if (pos > length) {
352 cerr << "Error: invalid resources.index record.size." << endl;
353 return false;
354 }
355 in.read(reinterpret_cast<char *>(&record.resType), INT_TO_BYTES);
356 in.read(reinterpret_cast<char *>(&record.id), INT_TO_BYTES);
357 return true;
358 }
359
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) const360 bool ResourceTable::ReadDataRecordStart(std::ifstream &in, RecordItem &record,
361 const std::map<int32_t, std::vector<KeyParam>> &limitKeys,
362 const std::map<int32_t, std::pair<int32_t, int32_t>> &datas,
363 std::map<int32_t, std::vector<ResourceItem>> &resInfos) const
364 {
365 int32_t offset = in.tellg();
366 offset = offset - INT_TO_BYTES - INT_TO_BYTES - INT_TO_BYTES;
367 uint16_t value_size = 0;
368 in.read(reinterpret_cast<char *>(&value_size), sizeof(uint16_t));
369 if (value_size + sizeof(uint16_t) > record.size) {
370 cerr << "Error: invalid resources.index value size." << endl;
371 return false;
372 }
373 int8_t values[value_size];
374 in.read(reinterpret_cast<char *>(&values), value_size);
375
376 uint16_t name_size = 0;
377 in.read(reinterpret_cast<char *>(&name_size), sizeof(uint16_t));
378 if (value_size + sizeof(uint16_t) + name_size + sizeof(uint16_t) > record.size) {
379 cerr << "Error: invalid resources.index name size." << endl;
380 return false;
381 }
382 int8_t name[name_size];
383 in.read(reinterpret_cast<char *>(name), name_size);
384 string filename(reinterpret_cast<char *>(name));
385
386 auto idTableOffset = datas.find(offset);
387 if (idTableOffset == datas.end()) {
388 cerr << "Error: invalid resources.index id offset." << endl;
389 return false;
390 }
391
392 if (idTableOffset->second.first != record.id) {
393 cerr << "Error: invalid resources.index id." << endl;
394 return false;
395 }
396
397 if (limitKeys.find(idTableOffset->second.second) == limitKeys.end()) {
398 cerr << "Error: invalid resources.index limit key offset." << endl;
399 return false;
400 }
401 const vector<KeyParam> &keyparams = limitKeys.find(datas.find(offset)->second.second)->second;
402 ResourceItem resourceitem(filename, keyparams, g_resTypeMap.find(record.resType)->second);
403 resourceitem.SetLimitKey(ResourceUtil::PaserKeyParam(keyparams));
404 resourceitem.SetData(values, value_size);
405 resInfos[record.id].push_back(resourceitem);
406 return true;
407 }
408
409 }
410 }
411 }
412