1 /*
2 * Copyright (c) 2022 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_append.h"
17 #include <algorithm>
18 #include <iomanip>
19 #include <iostream>
20 #include <regex>
21 #include "config_parser.h"
22 #include "header.h"
23 #include "id_worker.h"
24 #include "key_parser.h"
25 #include "reference_parser.h"
26 #include "resource_table.h"
27 #include "resource_util.h"
28 #include "select_compile_parse.h"
29 #ifdef __WIN32
30 #include "windows.h"
31 #endif
32 #include "securec.h"
33
34 namespace OHOS {
35 namespace Global {
36 namespace Restool {
37 using namespace std;
38
ResourceAppend(const PackageParser & packageParser)39 ResourceAppend::ResourceAppend(const PackageParser &packageParser) : packageParser_(packageParser)
40 {
41 }
42
Append()43 uint32_t ResourceAppend::Append()
44 {
45 string outputPath = packageParser_.GetOutput();
46 for (const auto &iter : packageParser_.GetAppend()) {
47 if (!ScanResources(iter, outputPath)) {
48 return RESTOOL_ERROR;
49 }
50 }
51 return RESTOOL_SUCCESS;
52 }
53
Combine()54 uint32_t ResourceAppend::Combine()
55 {
56 vector<pair<ResType, string>> noBaseResource;
57 for (const auto &iter : packageParser_.GetInputs()) {
58 if (!Combine(iter)) {
59 return RESTOOL_ERROR;
60 }
61 CheckAllItems(noBaseResource);
62 }
63 if (!noBaseResource.empty()) {
64 ResourceUtil::PrintWarningMsg(noBaseResource);
65 }
66
67 if (!ParseRef()) {
68 return RESTOOL_ERROR;
69 }
70
71 ResourceTable resourceTable;
72 if (resourceTable.CreateResourceTable(items_) != RESTOOL_SUCCESS) {
73 return RESTOOL_ERROR;
74 }
75 return RESTOOL_SUCCESS;
76 }
77
78 // private
Combine(const string & folderPath)79 bool ResourceAppend::Combine(const string &folderPath)
80 {
81 FileEntry entry(folderPath);
82 if (!entry.Init()) {
83 return false;
84 }
85
86 itemsForModule_.clear();
87 for (const auto &child : entry.GetChilds()) {
88 if (!child->IsFile()) {
89 PrintError(GetError(ERR_CODE_INVALID_RESOURCE_PATH)
90 .FormatCause(child->GetFilePath().GetPath().c_str(), "not a file"));
91 return false;
92 }
93 const std::string fileName = child->GetFilePath().GetFilename();
94 if (fileName == ID_DEFINED_FILE) {
95 continue;
96 }
97 if (fileName.find('.') == 0) {
98 // The file starts with '.' is invalid
99 continue;
100 }
101 if (!LoadResourceItem(child->GetFilePath().GetPath())) {
102 return false;
103 }
104 }
105 return true;
106 }
107
ParseRef()108 bool ResourceAppend::ParseRef()
109 {
110 for (auto &iter : refs_) {
111 ReferenceParser ref;
112 if (iter->GetResType() == ResType::PROF || iter->GetResType() == ResType::MEDIA) {
113 if (ref.ParseRefInJsonFile(*iter, packageParser_.GetOutput(), true) != RESTOOL_SUCCESS) {
114 return false;
115 }
116 } else if (ref.ParseRefInResourceItem(*iter) != RESTOOL_SUCCESS) {
117 return false;
118 }
119 }
120 return true;
121 }
122
ScanResources(const string & resourcePath,const string & outputPath)123 bool ResourceAppend::ScanResources(const string &resourcePath, const string &outputPath)
124 {
125 if (!ResourceUtil::FileExist(resourcePath)) {
126 string filePath = FileEntry::FilePath(outputPath).Append(ResourceUtil::GenerateHash(resourcePath)).GetPath();
127 if (remove(filePath.c_str()) != 0) {
128 PrintError(GetError(ERR_CODE_REMOVE_FILE_ERROR).FormatCause(filePath.c_str(), strerror(errno)));
129 return false;
130 }
131 return true;
132 }
133
134 FileEntry entry(resourcePath);
135 if (!entry.Init()) {
136 return false;
137 }
138
139 if (entry.IsFile()) {
140 return ScanSingleFile(resourcePath, outputPath);
141 }
142
143 return ScanSubResources(entry, resourcePath, outputPath);
144 }
145
ScanSubResources(const FileEntry entry,const string & resourcePath,const string & outputPath)146 bool ResourceAppend::ScanSubResources(const FileEntry entry, const string &resourcePath, const string &outputPath)
147 {
148 vector<KeyParam> keyParams;
149 if (KeyParser::Parse(entry.GetFilePath().GetFilename(), keyParams)) {
150 for (const auto &child : entry.GetChilds()) {
151 if (!ResourceUtil::IslegalPath(child->GetFilePath().GetFilename())) {
152 continue;
153 }
154 if (!ScanIegalResources(child->GetFilePath().GetPath(), outputPath)) {
155 return false;
156 }
157 }
158 return true;
159 }
160
161 if (ResourceUtil::IslegalPath(entry.GetFilePath().GetFilename())) {
162 return ScanIegalResources(resourcePath, outputPath);
163 }
164
165 return ScanSubLimitkeyResources(entry, resourcePath, outputPath);
166 }
167
ScanSubLimitkeyResources(const FileEntry entry,const string & resourcePath,const string & outputPath)168 bool ResourceAppend::ScanSubLimitkeyResources(const FileEntry entry, const string &resourcePath,
169 const string &outputPath)
170 {
171 for (const auto &child : entry.GetChilds()) {
172 string limitKey = child->GetFilePath().GetFilename();
173 if (ResourceUtil::IsIgnoreFile(limitKey, child->IsFile())) {
174 continue;
175 }
176
177 if (limitKey == RAW_FILE_DIR || limitKey == RES_FILE_DIR) {
178 if (!ScanRawFilesOrResFiles(child->GetFilePath().GetPath(), outputPath, limitKey)) {
179 return false;
180 }
181 continue;
182 }
183
184 if (child->IsFile()) {
185 PrintError(GetError(ERR_CODE_INVALID_RESOURCE_PATH)
186 .FormatCause(child->GetFilePath().GetPath().c_str(), "not a directory"));
187 return false;
188 }
189
190 if (!ScanLimitKey(child, limitKey, outputPath)) {
191 return false;
192 }
193 }
194 return true;
195 }
196
ScanIegalResources(const string & resourcePath,const string & outputPath)197 bool ResourceAppend::ScanIegalResources(const string &resourcePath, const string &outputPath)
198 {
199 FileEntry entry(resourcePath);
200 if (!entry.Init()) {
201 return false;
202 }
203 for (const auto &child : entry.GetChilds()) {
204 if (!ScanSingleFile(child->GetFilePath().GetPath(), outputPath)) {
205 return false;
206 }
207 }
208 return true;
209 }
ScanLimitKey(const unique_ptr<FileEntry> & entry,const string & limitKey,const string outputPath)210 bool ResourceAppend::ScanLimitKey(const unique_ptr<FileEntry> &entry,
211 const string &limitKey, const string outputPath)
212 {
213 vector<KeyParam> keyParams;
214 if (!KeyParser::Parse(limitKey, keyParams)) {
215 PrintError(GetError(ERR_CODE_INVALID_LIMIT_KEY).FormatCause(limitKey.c_str())
216 .SetPosition(entry->GetFilePath().GetPath().c_str()));
217 return false;
218 }
219
220 for (const auto &child : entry->GetChilds()) {
221 string fileCuster = child->GetFilePath().GetFilename();
222 if (ResourceUtil::IsIgnoreFile(fileCuster, child->IsFile())) {
223 continue;
224 }
225
226 if (child->IsFile()) {
227 PrintError(GetError(ERR_CODE_INVALID_RESOURCE_PATH)
228 .FormatCause(child->GetFilePath().GetPath().c_str(), "not a directory"));
229 return false;
230 }
231
232 ResType resType = ResourceUtil::GetResTypeByDir(fileCuster);
233 if (resType == ResType::INVALID_RES_TYPE) {
234 PrintError(GetError(ERR_CODE_INVALID_RESOURCE_DIR)
235 .FormatCause(fileCuster.c_str(), ResourceUtil::GetAllResTypeDirs().c_str())
236 .SetPosition(child->GetFilePath().GetPath().c_str()));
237 return false;
238 }
239
240 DirectoryInfo directoryInfo = { limitKey, fileCuster, child->GetFilePath().GetPath(), keyParams, resType};
241 if (!ScanFiles(child, directoryInfo, outputPath)) {
242 return false;
243 }
244 }
245 return true;
246 }
247
248
ScanFiles(const unique_ptr<FileEntry> & entry,const DirectoryInfo & directoryInfo,const string & outputPath)249 bool ResourceAppend::ScanFiles(const unique_ptr<FileEntry> &entry,
250 const DirectoryInfo &directoryInfo, const string &outputPath)
251 {
252 for (const auto &child : entry->GetChilds()) {
253 string filename = child->GetFilePath().GetFilename();
254 if (ResourceUtil::IsIgnoreFile(filename, child->IsFile())) {
255 continue;
256 }
257
258 if (!child->IsFile()) {
259 PrintError(GetError(ERR_CODE_INVALID_RESOURCE_PATH)
260 .FormatCause(child->GetFilePath().GetPath().c_str(), "not a file"));
261 return false;
262 }
263
264 FileInfo fileInfo = {directoryInfo, child->GetFilePath().GetPath(), filename};
265 if (!ScanFile(fileInfo, outputPath)) {
266 return false;
267 }
268 }
269 return true;
270 }
271
ScanFile(const FileInfo & fileInfo,const string & outputPath)272 bool ResourceAppend::ScanFile(const FileInfo &fileInfo, const string &outputPath)
273 {
274 if (ResourceAppend::IsBaseIdDefined(fileInfo)) {
275 cout << "Warning: id_defined.json does not compile to generate intermediate files" << endl;
276 FileEntry::FilePath outPath(outputPath);
277 return ResourceUtil::CopyFileInner(fileInfo.filePath, outPath.Append(ID_DEFINED_FILE).GetPath());
278 }
279
280 unique_ptr<IResourceCompiler> resourceCompiler =
281 ResourceCompilerFactory::CreateCompilerForAppend(fileInfo.dirType, outputPath);
282 if (resourceCompiler == nullptr) {
283 return true;
284 }
285
286 if (resourceCompiler->CompileForAppend(fileInfo) != RESTOOL_SUCCESS) {
287 return false;
288 }
289
290 ostringstream outStream;
291 const auto &items = resourceCompiler->GetResourceItems();
292 for (const auto &item : items) {
293 for (const auto &resourceItem : item.second) {
294 if (!WriteResourceItem(resourceItem, outStream)) {
295 return false;
296 }
297 }
298 }
299
300 string hash = ResourceUtil::GenerateHash(fileInfo.filePath);
301 FileEntry::FilePath output(outputPath);
302 if (!WriteFileInner(outStream, output.Append(hash).GetPath())) {
303 return false;
304 }
305 return true;
306 }
307
ScanSingleFile(const string & filePath,const string & outputPath)308 bool ResourceAppend::ScanSingleFile(const string &filePath, const string &outputPath)
309 {
310 if (filePath.find(RAW_FILE_DIR) != string::npos) {
311 return WriteRawFilesOrResFiles(filePath, outputPath, RAW_FILE_DIR);
312 }
313
314 if (filePath.find(RES_FILE_DIR) != string::npos) {
315 return WriteRawFilesOrResFiles(filePath, outputPath, RES_FILE_DIR);
316 }
317
318 FileEntry::FilePath path(filePath);
319 string fileCuster = path.GetParent().GetFilename();
320 ResType resType = ResourceUtil::GetResTypeByDir(fileCuster);
321 if (resType == ResType::INVALID_RES_TYPE) {
322 PrintError(GetError(ERR_CODE_INVALID_RESOURCE_DIR)
323 .FormatCause(fileCuster.c_str(), ResourceUtil::GetAllResTypeDirs().c_str())
324 .SetPosition(filePath));
325 return false;
326 }
327
328 string limitKey = path.GetParent().GetParent().GetFilename();
329 vector<KeyParam> keyParams;
330 if (!KeyParser::Parse(limitKey, keyParams)) {
331 PrintError(GetError(ERR_CODE_INVALID_LIMIT_KEY).FormatCause(limitKey.c_str()).SetPosition(filePath));
332 return false;
333 }
334
335 DirectoryInfo directoryInfo = {limitKey, fileCuster, path.GetParent().GetPath(), keyParams, resType};
336 FileInfo fileInfo = {directoryInfo, filePath, path.GetFilename() };
337 if (!ScanFile(fileInfo, outputPath)) {
338 return false;
339 }
340 return true;
341 }
342
WriteFileInner(ostringstream & outStream,const string & outputPath) const343 bool ResourceAppend::WriteFileInner(ostringstream &outStream, const string &outputPath) const
344 {
345 #ifdef __WIN32
346 HANDLE hWriteFile = CreateFile(outputPath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
347 nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
348 if (hWriteFile == INVALID_HANDLE_VALUE) {
349 PrintError(GetError(ERR_CODE_CREATE_FILE_ERROR)
350 .FormatCause(outputPath.c_str(), to_string(GetLastError()).c_str()));
351 return false;
352 }
353
354 DWORD writeBytes;
355 if (!WriteFile(hWriteFile, outStream.str().c_str(), outStream.tellp(), &writeBytes, nullptr)) {
356 PrintError(GetError(ERR_CODE_OPEN_FILE_ERROR)
357 .FormatCause(outputPath.c_str(), to_string(GetLastError()).c_str()));
358 CloseHandle(hWriteFile);
359 return false;
360 }
361 CloseHandle(hWriteFile);
362 #else
363 ofstream out(outputPath, ofstream::out | ofstream::binary);
364 if (!out.is_open()) {
365 PrintError(GetError(ERR_CODE_OPEN_FILE_ERROR).FormatCause(outputPath.c_str(), strerror(errno)));
366 return false;
367 }
368 out << outStream.str();
369 #endif
370 return true;
371 }
372
WriteResourceItem(const ResourceItem & resourceItem,ostringstream & out)373 bool ResourceAppend::WriteResourceItem(const ResourceItem &resourceItem, ostringstream &out)
374 {
375 uint32_t size = resourceItem.GetName().length();
376 out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
377 out.write(reinterpret_cast<const char *>(resourceItem.GetName().c_str()), size);
378
379 size = resourceItem.GetLimitKey().length();
380 out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
381 out.write(reinterpret_cast<const char *>(resourceItem.GetLimitKey().c_str()), size);
382
383 size = resourceItem.GetFilePath().length();
384 out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
385 out.write(reinterpret_cast<const char *>(resourceItem.GetFilePath().c_str()), size);
386
387 int32_t type = static_cast<int32_t>(resourceItem.GetResType());
388 out.write(reinterpret_cast<const char *>(&type), sizeof(int32_t));
389
390 size = resourceItem.GetKeyParam().size();
391 out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
392 for (const auto &keyParam : resourceItem.GetKeyParam()) {
393 out.write(reinterpret_cast<const char *>(&keyParam.keyType), sizeof(int32_t));
394 out.write(reinterpret_cast<const char *>(&keyParam.value), sizeof(int32_t));
395 }
396
397 size = resourceItem.GetDataLength();
398 out.write(reinterpret_cast<const char *>(&size), sizeof(int32_t));
399 out.write(reinterpret_cast<const char *>(resourceItem.GetData()), size);
400 return true;
401 }
402
LoadResourceItem(const string & filePath)403 bool ResourceAppend::LoadResourceItem(const string &filePath)
404 {
405 #ifdef __WIN32
406 return LoadResourceItemWin(filePath);
407 #else
408 ifstream in(filePath, ifstream::in | ifstream::binary);
409 if (!in.is_open()) {
410 PrintError(GetError(ERR_CODE_OPEN_FILE_ERROR).FormatCause(filePath.c_str(), strerror(errno)));
411 return false;
412 }
413
414 in.seekg(0, in.end);
415 int32_t length = in.tellg();
416 in.seekg(0, in.beg);
417 if (length <= 0) {
418 PrintError(GetError(ERR_CODE_READ_FILE_ERROR).FormatCause(filePath.c_str(), "file is empty"));
419 return false;
420 }
421 char buffer[length];
422 in.read(buffer, length);
423 return LoadResourceItemFromMem(buffer, length);
424 #endif
425 }
426
ScanRawFilesOrResFiles(const string & path,const string & outputPath,const string & limit)427 bool ResourceAppend::ScanRawFilesOrResFiles(const string &path, const string &outputPath, const string &limit)
428 {
429 FileEntry entry(path);
430 if (!entry.Init()) {
431 return false;
432 }
433
434 for (const auto &child : entry.GetChilds()) {
435 string filename = child->GetFilePath().GetFilename();
436 if (ResourceUtil::IsIgnoreFile(filename, child->IsFile())) {
437 continue;
438 }
439
440 bool ret = false;
441 if (child->IsFile()) {
442 ret = WriteRawFilesOrResFiles(child->GetFilePath().GetPath(), outputPath, limit);
443 } else {
444 ret = ScanRawFilesOrResFiles(child->GetFilePath().GetPath(), outputPath, limit);
445 }
446
447 if (!ret) {
448 return false;
449 }
450 }
451 return true;
452 }
453
WriteRawFilesOrResFiles(const string & filePath,const string & outputPath,const string & limit)454 bool ResourceAppend::WriteRawFilesOrResFiles(const string &filePath, const string &outputPath, const string &limit)
455 {
456 string::size_type pos = filePath.find(limit);
457 if (pos == string::npos) {
458 PrintError(GetError(ERR_CODE_INVALID_RESOURCE_PATH).FormatCause(filePath.c_str(), "missing separator"));
459 return false;
460 }
461
462 string sub = filePath.substr(pos);
463 sub = FileEntry::FilePath(RESOURCES_DIR).Append(sub).GetPath();
464 vector<KeyParam> keyParams;
465 auto iter = g_copyFileMap.find(limit);
466 ResourceItem resourceItem("", keyParams, iter->second);
467 resourceItem.SetData(sub);
468 resourceItem.SetFilePath(filePath);
469 resourceItem.SetLimitKey("");
470
471 ostringstream outStream;
472 if (!WriteResourceItem(resourceItem, outStream)) {
473 return false;
474 }
475
476 string hash = ResourceUtil::GenerateHash(filePath);
477 FileEntry::FilePath output(outputPath);
478 if (!WriteFileInner(outStream, output.Append(hash).GetPath())) {
479 return false;
480 }
481 return true;
482 }
483
Push(const shared_ptr<ResourceItem> & resourceItem)484 bool ResourceAppend::Push(const shared_ptr<ResourceItem> &resourceItem)
485 {
486 string idName = ResourceUtil::GetIdName(resourceItem->GetName(), resourceItem->GetResType());
487 int64_t id = IdWorker::GetInstance().GenerateId(resourceItem->GetResType(), idName);
488 if (id < 0) {
489 PrintError(GetError(ERR_CODE_RESOURCE_ID_NOT_DEFINED)
490 .FormatCause(resourceItem->GetName().c_str(),
491 ResourceUtil::ResTypeToString(resourceItem->GetResType()).c_str()));
492 return false;
493 }
494
495 if (!CheckModuleResourceItem(resourceItem, id)) {
496 return false;
497 }
498
499 const auto &result = items_.find(id);
500 if (result == items_.end()) {
501 items_[id].push_back(resourceItem);
502 AddRef(resourceItem);
503 return true;
504 }
505
506 if (find_if(result->second.begin(), result->second.end(), [resourceItem](auto &iter) {
507 return resourceItem->GetLimitKey() == iter->GetLimitKey();
508 }) != result->second.end()) {
509 return true;
510 }
511
512 items_[id].push_back(resourceItem);
513 AddRef(resourceItem);
514 return true;
515 }
516
AddRef(const shared_ptr<ResourceItem> & resourceItem)517 void ResourceAppend::AddRef(const shared_ptr<ResourceItem> &resourceItem)
518 {
519 string data(reinterpret_cast<const char *>(resourceItem->GetData()), resourceItem->GetDataLength());
520 ResType resType = resourceItem->GetResType();
521 if (resType == ResType::MEDIA) {
522 if (FileEntry::FilePath(resourceItem->GetFilePath()).GetExtension() == JSON_EXTENSION) {
523 refs_.push_back(resourceItem);
524 }
525 return;
526 }
527
528 if (resType == ResType::PROF) {
529 if (resourceItem->GetLimitKey() != "base" ||
530 FileEntry::FilePath(resourceItem->GetFilePath()).GetExtension() != JSON_EXTENSION) {
531 return;
532 }
533 refs_.push_back(resourceItem);
534 return;
535 }
536
537 if (regex_match(data, regex(".*\\$.+:.*"))) {
538 refs_.push_back(resourceItem);
539 }
540 }
541
LoadResourceItemFromMem(const char buffer[],int32_t length)542 bool ResourceAppend::LoadResourceItemFromMem(const char buffer[], int32_t length)
543 {
544 int32_t offset = 0;
545 do {
546 // name
547 string nameStr = ParseString(buffer, length, offset);
548 // limit key
549 string limitKeyStr = ParseString(buffer, length, offset);
550 // file path
551 string filePathStr = ParseString(buffer, length, offset);
552 // ResType
553 int32_t type = ParseInt32(buffer, length, offset);
554 ResType resType = static_cast<ResType>(type);
555 // keyParam
556 int32_t keyParamSize = ParseInt32(buffer, length, offset);
557 vector<KeyParam> keyParams;
558 for (int i = 0; i < keyParamSize; i++) {
559 KeyParam keyParam;
560 keyParam.keyType = static_cast<KeyType>(ParseInt32(buffer, length, offset));
561 int32_t value = ParseInt32(buffer, length, offset);
562 if (value == -1) {
563 return false;
564 }
565 keyParam.value = static_cast<uint32_t>(value);
566 keyParams.push_back(keyParam);
567 }
568 if (limitKeyStr != "base" && !limitKeyStr.empty() && !SelectCompileParse::IsSelectCompile(keyParams)) {
569 return true;
570 }
571 // data
572 string data = ParseString(buffer, length, offset);
573 if (resType == ResType::RAW || resType == ResType::RES) {
574 FileEntry::FilePath outPath(packageParser_.GetOutput());
575 if (ResourceUtil::FileExist(outPath.Append(data).GetPath())) {
576 continue;
577 }
578 if (!ResourceUtil::CreateDirs(outPath.Append(data).GetParent().GetPath())) {
579 return false;
580 }
581
582 if (!ResourceUtil::FileExist(filePathStr)) {
583 continue;
584 }
585
586 if (!ResourceUtil::CopyFileInner(filePathStr, outPath.Append(data).GetPath())) {
587 return false;
588 }
589 continue;
590 }
591
592 shared_ptr<ResourceItem> resourceItem = make_shared<ResourceItem>(nameStr, keyParams, resType);
593 resourceItem->SetData(reinterpret_cast<const int8_t *>(data.c_str()), data.length());
594 resourceItem->SetLimitKey(limitKeyStr);
595 resourceItem->SetFilePath(filePathStr);
596 if (!Push(resourceItem)) {
597 return false;
598 }
599 } while (offset < length);
600 return true;
601 }
602
ParseString(const char buffer[],int32_t length,int32_t & offset) const603 string ResourceAppend::ParseString(const char buffer[], int32_t length, int32_t &offset) const
604 {
605 int32_t size = ParseInt32(buffer, length, offset);
606 if (size < 0 || offset + size > length) {
607 offset = length;
608 return "";
609 }
610
611 if (size == 0) {
612 return "";
613 }
614
615 string value(buffer + offset, size);
616 offset += size;
617 return value;
618 }
619
ParseInt32(const char buffer[],int32_t length,int32_t & offset) const620 int32_t ResourceAppend::ParseInt32(const char buffer[], int32_t length, int32_t &offset) const
621 {
622 if (offset + static_cast<int32_t>(sizeof(int32_t)) > length) {
623 offset = length;
624 return -1;
625 }
626
627 int32_t size = 0;
628 if (memcpy_s(&size, sizeof(int32_t), buffer + offset, sizeof(int32_t)) != EOK) {
629 offset = length;
630 return -1;
631 }
632 offset += sizeof(int32_t);
633 return size;
634 }
635
CheckModuleResourceItem(const shared_ptr<ResourceItem> & resourceItem,int64_t id)636 bool ResourceAppend::CheckModuleResourceItem(const shared_ptr<ResourceItem> &resourceItem, int64_t id)
637 {
638 const auto &result = itemsForModule_.find(id);
639 if (result == itemsForModule_.end()) {
640 itemsForModule_[id].push_back(resourceItem);
641 return true;
642 }
643
644 const auto &ret = find_if(result->second.begin(), result->second.end(), [resourceItem](auto iter) {
645 return resourceItem->GetLimitKey() == iter->GetLimitKey();
646 });
647
648 if (ret != result->second.end()) {
649 PrintError(GetError(ERR_CODE_RESOURCE_DUPLICATE)
650 .FormatCause(resourceItem->GetName().c_str(), (*ret)->GetFilePath().c_str(),
651 resourceItem->GetFilePath().c_str()));
652 return false;
653 }
654
655 itemsForModule_[id].push_back(resourceItem);
656 return true;
657 }
658
659 #ifdef __WIN32
LoadResourceItemWin(const string & filePath)660 bool ResourceAppend::LoadResourceItemWin(const string &filePath)
661 {
662 bool result = false;
663 HANDLE hReadFile = CreateFile(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
664 FILE_ATTRIBUTE_READONLY | FILE_FLAG_RANDOM_ACCESS, nullptr);
665 if (hReadFile == INVALID_HANDLE_VALUE) {
666 PrintError(GetError(ERR_CODE_CREATE_FILE_ERROR)
667 .FormatCause(filePath.c_str(), to_string(GetLastError()).c_str()).SetPosition(filePath));
668 return result;
669 }
670
671 DWORD fileSize = GetFileSize(hReadFile, nullptr);
672 HANDLE hFileMap = CreateFileMapping(hReadFile, nullptr, PAGE_READONLY, 0, fileSize, nullptr);
673 if (hFileMap == INVALID_HANDLE_VALUE) {
674 string errMsg = "create mapping error: " + to_string(GetLastError());
675 PrintError(GetError(ERR_CODE_READ_FILE_ERROR).FormatCause(filePath.c_str(), errMsg.c_str()));
676 CloseHandle(hReadFile);
677 return result;
678 }
679
680 void* pBuffer = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
681 if (pBuffer == nullptr) {
682 string errMsg = "map view of file error: " + to_string(GetLastError());
683 PrintError(GetError(ERR_CODE_READ_FILE_ERROR).FormatCause(filePath.c_str(), errMsg.c_str()));
684 CloseHandle(hReadFile);
685 return result;
686 }
687
688 char* buffer = reinterpret_cast<char *>(pBuffer);
689 result = LoadResourceItemFromMem(buffer, fileSize);
690 UnmapViewOfFile(hFileMap);
691 CloseHandle(hReadFile);
692 return result;
693 }
694 #endif
695
IsBaseIdDefined(const FileInfo & fileInfo)696 bool ResourceAppend::IsBaseIdDefined(const FileInfo &fileInfo)
697 {
698 FileEntry::FilePath filePath(fileInfo.filePath);
699 return filePath.GetParent().GetParent().GetFilename() == "base" &&
700 filePath.GetParent().GetFilename() == "element" &&
701 fileInfo.filename == ID_DEFINED_FILE;
702 }
703
CheckAllItems(vector<pair<ResType,string>> & noBaseResource)704 void ResourceAppend::CheckAllItems(vector<pair<ResType, string>> &noBaseResource)
705 {
706 for (const auto &item : items_) {
707 bool found = any_of(item.second.begin(), item.second.end(), [](const auto &iter) {
708 return iter->GetLimitKey() == "base";
709 });
710 if (!found) {
711 auto firstItem = item.second.front();
712 bool ret = any_of(noBaseResource.begin(), noBaseResource.end(), [firstItem](const auto &iterItem) {
713 return (firstItem->GetResType() == iterItem.first) &&
714 (firstItem->GetName() == iterItem.second);
715 });
716 if (!ret) {
717 noBaseResource.push_back(make_pair(firstItem->GetResType(), firstItem->GetName()));
718 }
719 }
720 }
721 }
722 }
723 }
724 }