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