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