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