• 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_pack.h"
17 #include<algorithm>
18 #include<iomanip>
19 #include "file_entry.h"
20 #include "file_manager.h"
21 #include "header.h"
22 #include "increment_manager.h"
23 #include "resource_merge.h"
24 #include "resource_table.h"
25 
26 #include "preview_manager.h"
27 
28 namespace OHOS {
29 namespace Global {
30 namespace Restool {
31 using namespace std;
ResourcePack(const PackageParser & packageParser)32 ResourcePack::ResourcePack(const PackageParser &packageParser):packageParser_(packageParser)
33 {
34 }
35 
Package()36 uint32_t ResourcePack::Package()
37 {
38     if (packageParser_.GetPreviewMode()) {
39         PreviewManager preview;
40         preview.SetPriority(packageParser_.GetPriority());
41         return preview.ScanModules(packageParser_.GetInputs(), packageParser_.GetOutput());
42     }
43     if (Init() != RESTOOL_SUCCESS) {
44         return RESTOOL_ERROR;
45     }
46 
47     ResourceMerge resourceMerge;
48     if (resourceMerge.Init() != RESTOOL_SUCCESS) {
49         return RESTOOL_ERROR;
50     }
51 
52     if (ScanResources(resourceMerge.GetInputs(), packageParser_.GetOutput()) != RESTOOL_SUCCESS) {
53         return RESTOOL_ERROR;
54     }
55 
56     if (GenerateHeader() != RESTOOL_SUCCESS) {
57         return RESTOOL_ERROR;
58     }
59 
60     if (CopyRawFile(resourceMerge.GetInputs()) != RESTOOL_SUCCESS) {
61         return RESTOOL_ERROR;
62     }
63 
64     if (GenerateConfigJson() != RESTOOL_SUCCESS) {
65         return RESTOOL_ERROR;
66     }
67 
68     ResourceTable resourceTable;
69     if (!packageParser_.GetDependEntry().empty()) {
70         if (HandleFeature() != RESTOOL_SUCCESS) {
71             return RESTOOL_ERROR;
72         }
73         if (GenerateHeader() != RESTOOL_SUCCESS) {
74             return RESTOOL_ERROR;
75         }
76     }
77 
78     if (resourceTable.CreateResourceTable() != RESTOOL_SUCCESS) {
79         return RESTOOL_ERROR;
80     }
81     return RESTOOL_SUCCESS;
82 }
83 
84 // below private founction
Init()85 uint32_t ResourcePack::Init()
86 {
87     InitHeaderCreater();
88     if (InitOutput() != RESTOOL_SUCCESS) {
89         return RESTOOL_ERROR;
90     }
91 
92     if (InitConfigJson() != RESTOOL_SUCCESS) {
93         return RESTOOL_ERROR;
94     }
95 
96     if (InitModule() != RESTOOL_SUCCESS) {
97         return RESTOOL_ERROR;
98     }
99     return RESTOOL_SUCCESS;
100 }
101 
InitModule()102 uint32_t ResourcePack::InitModule()
103 {
104     IdWorker::ResourceIdCluster hapType = IdWorker::ResourceIdCluster::RES_ID_APP;
105     string packageName = packageParser_.GetPackageName();
106     if (packageName == "ohos.global.systemres") {
107         hapType = IdWorker::ResourceIdCluster::RES_ID_SYS;
108     }
109 
110     moduleName_ = configJson_.GetModuleName();
111     vector<string> moduleNames = packageParser_.GetModuleNames();
112     IdWorker &idWorker = IdWorker::GetInstance();
113     int32_t startId = packageParser_.GetStartId();
114     if (startId > 0) {
115         return idWorker.Init(hapType, startId);
116     }
117 
118     if (moduleNames.empty()) {
119         return idWorker.Init(hapType);
120     } else {
121         sort(moduleNames.begin(), moduleNames.end());
122         auto it = find_if(moduleNames.begin(), moduleNames.end(), [this](auto iter) {
123                 return moduleName_ == iter;
124             });
125         if (it == moduleNames.end()) {
126             string buffer(" ");
127             for_each(moduleNames.begin(), moduleNames.end(), [&buffer](auto &iter) {
128                     buffer.append(" " + iter + " ");
129                 });
130             cerr << "Error: module name '" << moduleName_ << "' not in [" << buffer << "]" << endl;
131             return RESTOOL_ERROR;
132         }
133 
134         int32_t startId = ((it - moduleNames.begin()) + 1) * 0x01000000;
135         if (startId >= 0x07000000) {
136             startId = startId + 0x01000000;
137         }
138         return idWorker.Init(hapType, startId);
139     }
140     return RESTOOL_SUCCESS;
141 }
142 
InitHeaderCreater()143 void ResourcePack::InitHeaderCreater()
144 {
145     using namespace placeholders;
146     headerCreaters_.emplace(".txt", bind(&ResourcePack::GenerateTextHeader, this, _1));
147     headerCreaters_.emplace(".js", bind(&ResourcePack::GenerateJsHeader, this, _1));
148     headerCreaters_.emplace(".h", bind(&ResourcePack::GenerateCplusHeader, this, _1));
149 }
150 
InitOutput() const151 uint32_t ResourcePack::InitOutput() const
152 {
153     string cachePath = packageParser_.GetCachePath();
154     string indexPath = FileEntry::FilePath(cachePath).Append(IncrementManager::ID_JSON_FILE).GetPath();
155     if (!cachePath.empty() && ResourceUtil::FileExist(indexPath)) {
156         return RESTOOL_SUCCESS;
157     }
158 
159     bool forceWrite = packageParser_.GetForceWrite();
160     string output = packageParser_.GetOutput();
161     string resourcesPath = FileEntry::FilePath(output).Append(RESOURCES_DIR).GetPath();
162     if (ResourceUtil::FileExist(resourcesPath)) {
163         if (!forceWrite) {
164             cerr << "Error: output path '" << resourcesPath << "' exists." << endl;
165             return RESTOOL_ERROR;
166         }
167 
168         if (!ResourceUtil::RmoveAllDir(resourcesPath)) {
169             return RESTOOL_ERROR;
170         }
171     }
172     return RESTOOL_SUCCESS;
173 }
174 
GenerateHeader() const175 uint32_t ResourcePack::GenerateHeader() const
176 {
177     auto headerPaths = packageParser_.GetResourceHeaders();
178     string textPath = FileEntry::FilePath(packageParser_.GetOutput()).Append("ResourceTable.txt").GetPath();
179     headerPaths.push_back(textPath);
180     for (const auto &headerPath : headerPaths) {
181         string extension = FileEntry::FilePath(headerPath).GetExtension();
182         auto it = headerCreaters_.find(extension);
183         if (it == headerCreaters_.end()) {
184             cout << "Warning: don't support header file format '" << headerPath << "'" << endl;
185             continue;
186         }
187         if (it->second(headerPath) != RESTOOL_SUCCESS) {
188             return RESTOOL_ERROR;
189         }
190     }
191     return RESTOOL_SUCCESS;
192 }
193 
InitConfigJson()194 uint32_t ResourcePack::InitConfigJson()
195 {
196     string config = packageParser_.GetConfig();
197     if (config.empty()) {
198         if (packageParser_.GetInputs().size() > 1) {
199             cerr << "Error: more input path, -j config.json empty" << endl;
200             return RESTOOL_ERROR;
201         }
202         config = FileEntry::FilePath(packageParser_.GetInputs()[0]).Append(CONFIG_JSON).GetPath();
203         if (!ResourceUtil::FileExist(config)) {
204             config = FileEntry::FilePath(packageParser_.GetInputs()[0]).Append(MODULE_JSON).GetPath();
205         }
206     }
207 
208     if (FileEntry::FilePath(config).GetFilename() == MODULE_JSON) {
209         ConfigParser::SetUseModule();
210     }
211     configJson_ = ConfigParser(config);
212     if (configJson_.Init() != RESTOOL_SUCCESS) {
213         return RESTOOL_ERROR;
214     }
215     return RESTOOL_SUCCESS;
216 }
217 
GenerateTextHeader(const string & headerPath) const218 uint32_t ResourcePack::GenerateTextHeader(const string &headerPath) const
219 {
220     Header textHeader(headerPath);
221     bool first = true;
222     uint32_t result = textHeader.Create([](stringstream &buffer) {},
223         [&first](stringstream &buffer, const IdWorker::ResourceId& resourceId) {
224             if (first) {
225                 first = false;
226             } else {
227                 buffer << "\n";
228             }
229             buffer << resourceId.type << " " << resourceId.name;
230             buffer << " 0x" << hex << setw(8)  << setfill('0') << resourceId.id;
231         }, [](stringstream &buffer) {});
232     if (result != RESTOOL_SUCCESS) {
233         return RESTOOL_ERROR;
234     }
235     return RESTOOL_SUCCESS;
236 }
237 
GenerateCplusHeader(const string & headerPath) const238 uint32_t ResourcePack::GenerateCplusHeader(const string &headerPath) const
239 {
240     Header cplusHeader(headerPath);
241     uint32_t result = cplusHeader.Create([](stringstream &buffer) {
242         buffer << Header::LICENSE_HEADER << "\n";
243         buffer << "#ifndef RESOURCE_TABLE_H\n";
244         buffer << "#define RESOURCE_TABLE_H\n\n";
245         buffer << "#include<stdint.h>\n\n";
246         buffer << "namespace OHOS {\n";
247     }, [](stringstream &buffer, const IdWorker::ResourceId& resourceId) {
248         string name = resourceId.type + "_" + resourceId.name;
249         transform(name.begin(), name.end(), name.begin(), ::toupper);
250         buffer << "const int32_t " << name << " = ";
251         buffer << "0x" << hex << setw(8)  << setfill('0') << resourceId.id << ";\n";
252     }, [](stringstream &buffer){
253         buffer << "}\n";
254         buffer << "#endif";
255     });
256     return result;
257 }
258 
GenerateJsHeader(const std::string & headerPath) const259 uint32_t ResourcePack::GenerateJsHeader(const std::string &headerPath) const
260 {
261     Header JsHeader(headerPath);
262     string itemType;
263     uint32_t result = JsHeader.Create([](stringstream &buffer) {
264         buffer << Header::LICENSE_HEADER << "\n";
265         buffer << "export default {\n";
266     }, [&itemType](stringstream &buffer, const IdWorker::ResourceId& resourceId) {
267         if (itemType != resourceId.type) {
268             if (!itemType.empty()) {
269                 buffer << "\n" << "    " << "},\n";
270             }
271             buffer << "    " << resourceId.type << " : {\n";
272             itemType = resourceId.type;
273         } else {
274             buffer << ",\n";
275         }
276         buffer << "        " << resourceId.name << " : " << resourceId.id;
277     }, [](stringstream &buffer){
278         buffer << "\n" << "    " << "}\n";
279         buffer << "}\n";
280     });
281     return result;
282 }
283 
CopyRawFile(const vector<string> & inputs) const284 uint32_t ResourcePack::CopyRawFile(const vector<string> &inputs) const
285 {
286     for (const auto &input : inputs) {
287         string rawfilePath = FileEntry::FilePath(input).Append(RAW_FILE_DIR).GetPath();
288         if (!ResourceUtil::FileExist(rawfilePath)) {
289             continue;
290         }
291 
292         if (!FileEntry::IsDirectory(rawfilePath)) {
293             cerr << "Error: '" << rawfilePath << "' not directory." << endl;
294             return RESTOOL_ERROR;
295         }
296 
297         string dst = FileEntry::FilePath(packageParser_.GetOutput())
298             .Append(RESOURCES_DIR).Append(RAW_FILE_DIR).GetPath();
299         if (CopyRawFileImpl(rawfilePath, dst) != RESTOOL_SUCCESS) {
300             return RESTOOL_ERROR;
301         }
302     }
303     return RESTOOL_SUCCESS;
304 }
305 
CopyRawFileImpl(const string & src,const string & dst) const306 uint32_t ResourcePack::CopyRawFileImpl(const string &src, const string &dst) const
307 {
308     if (!ResourceUtil::CreateDirs(dst)) {
309         return RESTOOL_ERROR;
310     }
311 
312     FileEntry f(src);
313     if (!f.Init()) {
314         return RESTOOL_ERROR;
315     }
316     for (const auto &entry : f.GetChilds()) {
317         string filename = entry->GetFilePath().GetFilename();
318         if (ResourceUtil::IsIgnoreFile(filename, entry->IsFile())) {
319             continue;
320         }
321 
322         string subPath = FileEntry::FilePath(dst).Append(filename).GetPath();
323         if (!entry->IsFile()) {
324             if (CopyRawFileImpl(entry->GetFilePath().GetPath(), subPath) != RESTOOL_SUCCESS) {
325                 return RESTOOL_ERROR;
326             }
327         } else {
328             if (ResourceUtil::FileExist(subPath)) {
329                 continue;
330             }
331             if (!ResourceUtil::CopyFleInner(entry->GetFilePath().GetPath(), subPath)) {
332                 return RESTOOL_ERROR;
333             }
334         }
335     }
336     return RESTOOL_SUCCESS;
337 }
338 
GenerateConfigJson()339 uint32_t ResourcePack::GenerateConfigJson()
340 {
341     if (configJson_.ParseRefence() != RESTOOL_SUCCESS) {
342         return RESTOOL_ERROR;
343     }
344     string outputPath = FileEntry::FilePath(packageParser_.GetOutput())
345         .Append(ConfigParser::GetConfigName()).GetPath();
346     return configJson_.Save(outputPath);
347 }
348 
ScanResources(const vector<string> & inputs,const string & output)349 uint32_t ResourcePack::ScanResources(const vector<string> &inputs, const string &output)
350 {
351     auto &fileManager = FileManager::GetInstance();
352     fileManager.SetModuleName(moduleName_);
353     string cachePath = packageParser_.GetCachePath();
354     if (cachePath.empty()) {
355         if (fileManager.ScanModules(inputs, output) != RESTOOL_SUCCESS) {
356             return RESTOOL_ERROR;
357         }
358         return RESTOOL_SUCCESS;
359     }
360 
361     auto &incrementManager = IncrementManager::GetInstance();
362     if (incrementManager.Init(cachePath, inputs, output, moduleName_) != RESTOOL_SUCCESS) {
363         return RESTOOL_ERROR;
364     }
365     if (fileManager.ScanIncrement(output) != RESTOOL_SUCCESS) {
366         return RESTOOL_ERROR;
367     }
368     return RESTOOL_SUCCESS;
369 }
370 
HandleFeature()371 uint32_t ResourcePack::HandleFeature()
372 {
373     string output = packageParser_.GetOutput();
374     string featureDependEntry = packageParser_.GetDependEntry();
375     if (featureDependEntry.empty()) {
376         return RESTOOL_SUCCESS;
377     }
378     string jsonFile = FileEntry::FilePath(featureDependEntry).Append(CONFIG_JSON).GetPath();
379     ConfigParser entryJson(jsonFile);
380     entryJson.SetDependEntry(true);
381     if (entryJson.Init() != RESTOOL_SUCCESS) {
382         cerr << "Error: config json invalid. at " << jsonFile << endl;
383         return RESTOOL_ERROR;
384     }
385 
386     int32_t labelId = entryJson.GetAbilityLabelId();
387     int32_t iconId = entryJson.GetAbilityIconId();
388     if (labelId <= 0 || iconId <= 0) {
389         cerr << "Error: Entry MainAbility must have 'icon' and 'label'." << endl;
390         return RESTOOL_ERROR;
391     }
392     string path = FileEntry::FilePath(featureDependEntry).Append(RESOURCE_INDEX_FILE).GetPath();
393     map<int32_t, vector<ResourceItem>> resInfoLocal;
394     ResourceTable resourceTable;
395     if (resourceTable.LoadResTable(path, resInfoLocal) != RESTOOL_SUCCESS) {
396         cerr << "Error: LoadResTable fail." << endl;
397         return RESTOOL_ERROR;
398     }
399     jsonFile = FileEntry::FilePath(output).Append(CONFIG_JSON).GetPath();
400     ConfigParser config(jsonFile);
401     if (config.Init() != RESTOOL_SUCCESS) {
402         cerr << "Error: config json invalid. at " << jsonFile << endl;
403         return RESTOOL_ERROR;
404     }
405     vector<ResourceItem> items;
406     if (FindResourceItems(resInfoLocal, items, labelId) != RESTOOL_SUCCESS ||
407         HandleLabel(items, config) != RESTOOL_SUCCESS) {
408         return RESTOOL_ERROR;
409     }
410     items.clear();
411     if (FindResourceItems(resInfoLocal, items, iconId) != RESTOOL_SUCCESS ||
412         HandleIcon(items, config) != RESTOOL_SUCCESS) {
413         return RESTOOL_ERROR;
414     }
415     string outputPath = FileEntry::FilePath(output).Append(ConfigParser::GetConfigName()).GetPath();
416     if (config.Save(outputPath) != RESTOOL_SUCCESS) {
417         return RESTOOL_ERROR;
418     }
419     entryJson.SetDependEntry(false);
420     return RESTOOL_SUCCESS;
421 }
422 
FindResourceItems(const map<int32_t,vector<ResourceItem>> & resInfoLocal,vector<ResourceItem> & items,int32_t id) const423 uint32_t ResourcePack::FindResourceItems(const map<int32_t, vector<ResourceItem>> &resInfoLocal,
424                                          vector<ResourceItem> &items, int32_t id) const
425 {
426     auto ret = resInfoLocal.find(id);
427     if (ret == resInfoLocal.end()) {
428         cerr << "Error: FindResourceItems don't found '" << id << "'." << endl;
429         return RESTOOL_ERROR;
430     }
431     ResType type = ResType::INVALID_RES_TYPE;
432     items = ret->second;
433     if (items.empty()) {
434         cerr << "Error: FindResourceItems resource item empty '" << id << "'." << endl;
435         return RESTOOL_ERROR;
436     }
437     for (auto &it : items) {
438         if (type == ResType::INVALID_RES_TYPE) {
439             type = it.GetResType();
440         }
441         if (type != it.GetResType()) {
442             cerr << "Error: FindResourceItems invalid restype '" << ResourceUtil::ResTypeToString(type);
443             cerr << "' vs '"  << ResourceUtil::ResTypeToString(it.GetResType()) << "'." << endl;
444             return RESTOOL_ERROR;
445         }
446     }
447     return RESTOOL_SUCCESS;
448 }
449 
HandleLabel(vector<ResourceItem> & items,ConfigParser & config) const450 uint32_t ResourcePack::HandleLabel(vector<ResourceItem> &items, ConfigParser &config) const
451 {
452     int32_t nextId = 0;
453     string idName;
454     for (auto it : items) {
455         if (it.GetResType() != ResType::STRING) {
456             cerr << "Error: HandleLabel invalid restype '";
457             cerr << ResourceUtil::ResTypeToString(it.GetResType()) << "'." << endl;
458             return RESTOOL_ERROR;
459         }
460         idName = it.GetName() + "_entry";
461         it.SetName(idName);
462         string data(reinterpret_cast<const char *>(it.GetData()));
463         if (!it.SetData(reinterpret_cast<const int8_t *>(data.c_str()), it.GetDataLength()-1)) {
464             return RESTOOL_ERROR;
465         }
466         if (nextId <= 0) {
467             nextId = IdWorker::GetInstance().GenerateId(ResType::STRING, idName);
468         }
469         SaveResourceItem(it, nextId);
470     }
471     string label = "$string:" +idName;
472     config.SetAppLabel(label, nextId);
473     return RESTOOL_SUCCESS;
474 }
475 
CopyIcon(string & dataPath,const string & idName,string & fileName) const476 bool ResourcePack::CopyIcon(string &dataPath, const string &idName, string &fileName) const
477 {
478     string featureDependEntry = packageParser_.GetDependEntry();
479     string source = FileEntry::FilePath(featureDependEntry).Append(dataPath).GetPath();
480     string suffix = FileEntry::FilePath(source).GetExtension();
481     fileName = idName + suffix;
482     string output = packageParser_.GetOutput();
483 #ifdef _WIN32
484     ResourceUtil::StringReplace(dataPath, SEPARATOR, WIN_SEPARATOR);
485 #endif
486     string dstDir = FileEntry::FilePath(output).Append(dataPath).GetParent().GetPath();
487     string dst = FileEntry::FilePath(dstDir).Append(fileName).GetPath();
488     if (!ResourceUtil::CreateDirs(dstDir)) {
489         cerr << "Error: Create Dirs fail '" << dstDir << "'."<< endl;
490         return false;
491     }
492     if (!ResourceUtil::CopyFleInner(source, dst)) {
493         cerr << "Error: copy file fail from '" << source << "' to '" << dst << "'." << endl;
494         return false;
495     }
496     return true;
497 }
498 
HandleIcon(vector<ResourceItem> & items,ConfigParser & config) const499 uint32_t ResourcePack::HandleIcon(vector<ResourceItem> &items, ConfigParser &config) const
500 {
501     int32_t nextId = 0;
502     string idName;
503     for (auto it : items) {
504         if (it.GetResType() != ResType::MEDIA) {
505             cerr << "Error: HandleLabel invalid restype '";
506             cerr << ResourceUtil::ResTypeToString(it.GetResType()) << "'." << endl;
507             return RESTOOL_ERROR;
508         }
509         string dataPath(reinterpret_cast<const char *>(it.GetData()));
510         string::size_type pos = dataPath.find_first_of(SEPARATOR);
511         if (pos == string::npos) {
512             cerr << "Error: HandleIcon invalid '" << dataPath << "'."<< endl;
513             return RESTOOL_ERROR;
514         }
515         dataPath = dataPath.substr(pos + 1);
516         idName = it.GetName() + "_entry";
517         string fileName;
518         if (!CopyIcon(dataPath, idName, fileName)) {
519             return RESTOOL_ERROR;
520         }
521         string data = FileEntry::FilePath(moduleName_).Append(dataPath).GetParent().Append(fileName).GetPath();
522         ResourceUtil::StringReplace(data, WIN_SEPARATOR, SEPARATOR);
523         ResourceItem resourceItem(fileName, it.GetKeyParam(), ResType::MEDIA);
524         resourceItem.SetLimitKey(it.GetLimitKey());
525         if (!resourceItem.SetData(reinterpret_cast<const int8_t *>(data.c_str()), data.length())) {
526             return RESTOOL_ERROR;
527         }
528         if (nextId <= 0) {
529             nextId = IdWorker::GetInstance().GenerateId(ResType::MEDIA, idName);
530         }
531         SaveResourceItem(resourceItem, nextId);
532     }
533     string icon = "$media:" + idName;
534     config.SetAppIcon(icon, nextId);
535     return RESTOOL_SUCCESS;
536 }
537 
SaveResourceItem(const ResourceItem & resourceItem,int32_t nextId) const538 void ResourcePack::SaveResourceItem(const ResourceItem &resourceItem, int32_t nextId) const
539 {
540     map<int32_t, vector<ResourceItem>> resInfo;
541     vector<ResourceItem> vet;
542     vet.push_back(resourceItem);
543     resInfo.insert(make_pair(nextId, vet));
544     FileManager &fileManager = FileManager::GetInstance();
545     fileManager.MergeResourceItem(resInfo);
546 }
547 
548 }
549 }
550 }