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