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