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