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