• 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