• 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 
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