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