1 /*
2  * Copyright (c) 2021-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 "hap_parser.h"
17 
18 #include <cstdlib>
19 #include <string>
20 #include <fcntl.h>
21 #include <unzip.h>
22 #include <unistd.h>
23 #include <set>
24 #include <sys/stat.h>
25 #include <unordered_map>
26 
27 #include "hilog_wrapper.h"
28 #include "locale_matcher.h"
29 #if defined(__WINNT__)
30 #include <cstring>
31 #else
32 #include "securec.h"
33 #endif
34 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
35 #include "hitrace_meter.h"
36 #endif
37 #include "utils/errors.h"
38 #include "utils/string_utils.h"
39 #include "utils/utils.h"
40 
41 namespace OHOS {
42 namespace Global {
43 namespace Resource {
44 const char *HapParser::RES_FILE_NAME = "/resources.index";
45 const std::string NOT_DEVICE_TYPE = "not_device_type";
46 const std::string DEVICE_DEFAULT = "default";
47 static const std::unordered_map<ResType, uint32_t> TYPE_MAP {
48     {INTEGER, SELECT_INTEGER},
49     {STRING, SELECT_STRING},
50     {STRINGARRAY, SELECT_STRINGARRAY},
51     {INTARRAY, SELECT_INTARRAY},
52     {BOOLEAN, SELECT_BOOLEAN},
53     {COLOR, SELECT_COLOR},
54     {THEME, SELECT_THEME},
55     {PLURALS, SELECT_PLURALS},
56     {FLOAT, SELECT_FLOAT},
57     {MEDIA, SELECT_MEDIA},
58     {PROF, SELECT_PROF},
59     {PATTERN, SELECT_PATTERN},
60     {SYMBOL, SELECT_SYMBOL}
61 };
62 
63 struct SelectOptions {
64     bool match = true;
65     std::shared_ptr<ResConfigImpl> defaultConfig;
66     std::string deviceType;
67     uint32_t selectedTypes = SELECT_ALL;
68 };
69 
LocateFile(unzFile & uf,const char * fileName)70 int32_t LocateFile(unzFile &uf, const char *fileName)
71 {
72     if (unzLocateFile2(uf, fileName, 1)) { // try to locate file inside zip, 1 = case sensitive
73         return UNKNOWN_ERROR;
74     }
75     return OK;
76 }
77 
GetCurrentFileInfo(unzFile & uf,unz_file_info & fileInfo)78 int32_t GetCurrentFileInfo(unzFile &uf, unz_file_info &fileInfo)
79 {
80     // obtained the necessary details about file inside zip
81     char filenameInzip[256];  // for unzGetCurrentFileInfo
82     int err = unzGetCurrentFileInfo(uf, &fileInfo, filenameInzip, sizeof(filenameInzip), nullptr, 0, nullptr, 0);
83     if (err != UNZ_OK) {
84         RESMGR_HILOGE(RESMGR_TAG, "GetCurrentFileInfo failed");
85         return UNKNOWN_ERROR;
86     }
87     return OK;
88 }
89 
ReadCurrentFile(unzFile & uf,unz_file_info & fileInfo,std::unique_ptr<uint8_t[]> & buffer,size_t & bufLen)90 int32_t ReadCurrentFile(unzFile &uf, unz_file_info &fileInfo, std::unique_ptr<uint8_t[]> &buffer,
91     size_t &bufLen)
92 {
93     buffer = std::make_unique<uint8_t[]>(fileInfo.uncompressed_size);
94     bufLen = fileInfo.uncompressed_size;
95     if (buffer == nullptr) {
96         RESMGR_HILOGE(RESMGR_TAG, "Error allocating memory for read buffer");
97         return UNKNOWN_ERROR;
98     }
99 
100     int err = unzOpenCurrentFilePassword(uf, nullptr);
101     if (err != UNZ_OK) {
102         RESMGR_HILOGE(RESMGR_TAG, "Error %d in unzOpenCurrentFilePassword.", err);
103         return UNKNOWN_ERROR;
104     } // file inside the zip is open
105 
106     err = unzReadCurrentFile(uf, buffer.get(), bufLen);
107     if (err < 0) {
108         RESMGR_HILOGE(RESMGR_TAG, "Error %d in unzReadCurrentFile", err);
109         return UNKNOWN_ERROR;
110     }
111 
112     return OK;
113 }
114 
ReadFileFromZip(unzFile & uf,const char * fileName,std::unique_ptr<uint8_t[]> & buffer,size_t & bufLen)115 int32_t HapParser::ReadFileFromZip(unzFile &uf, const char *fileName, std::unique_ptr<uint8_t[]> &buffer,
116     size_t &bufLen)
117 {
118     unz_file_info fileInfo;
119     if (LocateFile(uf, fileName) != OK) {
120         return UNKNOWN_ERROR;
121     }
122     if (GetCurrentFileInfo(uf, fileInfo) != OK) {
123         return UNKNOWN_ERROR;
124     }
125     if (ReadCurrentFile(uf, fileInfo, buffer, bufLen) != OK) {
126         return UNKNOWN_ERROR;
127     }
128     return OK;
129 }
130 
GetModuleName(const char * configStr,size_t len)131 std::string GetModuleName(const char *configStr, size_t len)
132 {
133     if (configStr == nullptr) {
134         return std::string();
135     }
136     std::string config(configStr, len);
137     static const char *key = "\"moduleName\"";
138     auto idx = config.find(key);
139     if (idx == std::string::npos) {
140         return std::string();
141     }
142     auto start = config.find("\"", idx + strlen(key));
143     if (start == std::string::npos) {
144         return std::string();
145     }
146     auto end = config.find("\"", start + 1);
147     if (end == std::string::npos) {
148         return std::string();
149     }
150 
151     if (end < start + 1) {
152         return std::string();
153     }
154     std::string retStr = std::string(configStr + start + 1, end - start - 1);
155     return retStr;
156 }
157 
IsStageMode(unzFile & uf)158 bool HapParser::IsStageMode(unzFile &uf)
159 {
160     // stage mode contains "module.json", The 1 means the case sensitive
161     if (unzLocateFile2(uf, "module.json", 1) != UNZ_OK) {
162         return false;
163     }
164     return true;
165 }
166 
ParseModuleNameFromHap(unzFile & uf)167 std::string ParseModuleNameFromHap(unzFile &uf)
168 {
169     std::unique_ptr<uint8_t[]> tmpBuf;
170     int32_t ret = UNZ_OK;
171     size_t tmpLen;
172     ret = HapParser::ReadFileFromZip(uf, "config.json", tmpBuf, tmpLen);
173     if (ret != OK) {
174         RESMGR_HILOGE(RESMGR_TAG, "read config.json error");
175         return std::string();
176     }
177     // parse config.json
178     std::string mName = GetModuleName(reinterpret_cast<char *>(tmpBuf.get()), tmpLen);
179     if (mName.size() == 0) {
180         RESMGR_HILOGE(RESMGR_TAG, "parse moduleName from config.json error");
181         return std::string();
182     }
183     return mName;
184 }
185 
GetIndexFilePath(unzFile uf)186 std::string GetIndexFilePath(unzFile uf)
187 {
188     std::string mName = ParseModuleNameFromHap(uf);
189     std::string indexFilePath = std::string("assets/");
190     indexFilePath.append(mName);
191     indexFilePath.append("/resources.index");
192     return indexFilePath;
193 }
194 
ReadFileInfoFromZip(unzFile & uf,const char * fileName,std::unique_ptr<uint8_t[]> & buffer,size_t & bufLen)195 int32_t ReadFileInfoFromZip(unzFile &uf, const char *fileName, std::unique_ptr<uint8_t[]> &buffer, size_t &bufLen)
196 {
197     int err = HapParser::ReadFileFromZip(uf, fileName, buffer, bufLen);
198     if (err < 0) {
199         unzClose(uf);
200         return UNKNOWN_ERROR;
201     }
202     unzClose(uf);
203     return OK;
204 }
205 
ReadIndexFromFile(const char * zipFile,std::unique_ptr<uint8_t[]> & buffer,size_t & bufLen)206 int32_t HapParser::ReadIndexFromFile(const char *zipFile, std::unique_ptr<uint8_t[]> &buffer,
207     size_t &bufLen)
208 {
209     unzFile uf = unzOpen64(zipFile);
210     if (uf == nullptr) {
211         RESMGR_HILOGE(RESMGR_TAG, "Error open %{public}s in ReadIndexFromFile %{public}d", zipFile, errno);
212         return UNKNOWN_ERROR;
213     } // file is open
214     if (IsStageMode(uf)) {
215         return ReadFileInfoFromZip(uf, "resources.index", buffer, bufLen);
216     }
217     std::string indexFilePath = GetIndexFilePath(uf);
218     return ReadFileInfoFromZip(uf, indexFilePath.c_str(), buffer, bufLen);
219 }
220 
GetPath(const std::string & filePath,std::string & rawFilePath)221 std::string HapParser::GetPath(const std::string &filePath, std::string &rawFilePath)
222 {
223     std::string tempName = filePath;
224     const std::string rawFileDirName = "rawfile/";
225     if (tempName.length() <= rawFileDirName.length()
226     || (tempName.compare(0, rawFileDirName.length(), rawFileDirName) != 0)) {
227         tempName = rawFileDirName + tempName;
228     }
229     rawFilePath.append(tempName);
230     return rawFilePath;
231 }
232 
233 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
ParseModuleName(std::shared_ptr<AbilityBase::Extractor> & extractor)234 std::string HapParser::ParseModuleName(std::shared_ptr<AbilityBase::Extractor> &extractor)
235 {
236     if (extractor == nullptr) {
237         return std::string();
238     }
239     std::unique_ptr<uint8_t[]> configBuf;
240     size_t len;
241     bool ret = extractor->ExtractToBufByName("config.json", configBuf, len);
242     if (!ret) {
243         RESMGR_HILOGE(RESMGR_TAG, "failed to get config data from ability");
244         return std::string();
245     }
246     // parse config.json
247     std::string mName = GetModuleName(reinterpret_cast<char *>(configBuf.get()), len);
248     if (mName.size() == 0) {
249         RESMGR_HILOGE(RESMGR_TAG, "parse moduleName from config.json error");
250         return std::string();
251     }
252     return mName;
253 }
254 
GetRawFilePathFromFA(std::shared_ptr<AbilityBase::Extractor> & extractor,const std::string & filePath)255 std::string GetRawFilePathFromFA(std::shared_ptr<AbilityBase::Extractor> &extractor,
256     const std::string &filePath)
257 {
258     std::string moduleName = HapParser::ParseModuleName(extractor);
259     std::string rawFilePath("assets/");
260     rawFilePath.append(moduleName);
261     rawFilePath.append("/resources/");
262     HapParser::GetPath(filePath, rawFilePath);
263     return rawFilePath;
264 }
265 
GetRawFilePathFromStage(const std::string & filePath)266 std::string GetRawFilePathFromStage(const std::string &filePath)
267 {
268     std::string rawFilePath("resources/");
269     HapParser::GetPath(filePath, rawFilePath);
270     return rawFilePath;
271 }
272 
GetRawFilePath(std::shared_ptr<AbilityBase::Extractor> & extractor,const std::string & rawFileName)273 std::string HapParser::GetRawFilePath(std::shared_ptr<AbilityBase::Extractor> &extractor,
274     const std::string &rawFileName)
275 {
276     std::string rawfilePath;
277     if (extractor->IsStageModel()) {
278         rawfilePath = GetRawFilePathFromStage(rawFileName);
279     } else {
280         rawfilePath = GetRawFilePathFromFA(extractor, rawFileName);
281     }
282     return rawfilePath;
283 }
284 #endif
285 
ReadRawFileFromHap(const std::string & hapPath,const std::string & rawFileName,size_t & len,std::unique_ptr<uint8_t[]> & outValue)286 RState HapParser::ReadRawFileFromHap(const std::string &hapPath, const std::string &rawFileName, size_t &len,
287     std::unique_ptr<uint8_t[]> &outValue)
288 {
289 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
290     HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
291     bool isNewExtractor = false;
292     auto extractor = AbilityBase::ExtractorUtil::GetExtractor(hapPath, isNewExtractor);
293     if (extractor == nullptr) {
294         RESMGR_HILOGE(RESMGR_TAG, "failed to get extractor hapPath, %{public}s", hapPath.c_str());
295         return NOT_FOUND;
296     }
297     std::string rawfilePath = HapParser::GetRawFilePath(extractor, rawFileName);
298     if (!extractor->HasEntry(rawfilePath)) {
299         RESMGR_HILOGD(RESMGR_TAG,
300             "the rawfile file %{public}s is not exist in %{public}s", rawfilePath.c_str(), hapPath.c_str());
301         return ERROR_CODE_RES_PATH_INVALID;
302     }
303     bool ret = extractor->ExtractToBufByName(rawfilePath, outValue, len);
304     if (!ret) {
305         RESMGR_HILOGE(RESMGR_TAG, "failed to get rawfile data rawfilePath, %{public}s, hapPath, %{public}s",
306             rawfilePath.c_str(), hapPath.c_str());
307         return NOT_FOUND;
308     }
309 #endif
310     return SUCCESS;
311 }
312 
ReadRawFileDescriptor(const char * hapPath,const std::string & rawFileName,ResourceManager::RawFileDescriptor & descriptor)313 RState HapParser::ReadRawFileDescriptor(const char *hapPath, const std::string &rawFileName,
314     ResourceManager::RawFileDescriptor &descriptor)
315 {
316 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
317     HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
318     char outPath[PATH_MAX + 1] = {0};
319     Utils::CanonicalizePath(hapPath, outPath, PATH_MAX);
320     bool isNewExtractor = false;
321     auto extractor = AbilityBase::ExtractorUtil::GetExtractor(outPath, isNewExtractor);
322     if (extractor == nullptr) {
323         RESMGR_HILOGE(RESMGR_TAG, "failed to get extractor in ReadRawFileDescriptor hapPath, %{public}s", outPath);
324         return NOT_FOUND;
325     }
326     std::string rawfilePath = HapParser::GetRawFilePath(extractor, rawFileName);
327     if (!extractor->HasEntry(rawfilePath)) {
328         RESMGR_HILOGD(RESMGR_TAG,
329             "the rawfile file %{public}s is not exist in %{public}s", rawfilePath.c_str(), hapPath);
330         return ERROR_CODE_RES_PATH_INVALID;
331     }
332     AbilityBase::FileInfo fileInfo;
333     bool ret = extractor->GetFileInfo(rawfilePath, fileInfo);
334     if (!ret) {
335         RESMGR_HILOGE(RESMGR_TAG, "failed to get rawFileDescriptor rawfilePath, %{public}s", rawfilePath.c_str());
336         return NOT_FOUND;
337     }
338     int zipFd = open(outPath, O_RDONLY);
339     if (zipFd < 0) {
340         RESMGR_HILOGE(RESMGR_TAG, "failed open file %{public}s", outPath);
341         return NOT_FOUND;
342     }
343     descriptor.offset = static_cast<long>(fileInfo.offset);
344     descriptor.length = static_cast<long>(fileInfo.length);
345     descriptor.fd = zipFd;
346 #endif
347     return SUCCESS;
348 }
349 
GetRawFileList(const std::string & hapPath,const std::string & rawDirPath,std::vector<std::string> & fileList)350 RState HapParser::GetRawFileList(const std::string &hapPath, const std::string &rawDirPath,
351     std::vector<std::string>& fileList)
352 {
353 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
354     HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
355     bool isNewExtractor = false;
356     auto extractor = AbilityBase::ExtractorUtil::GetExtractor(hapPath, isNewExtractor);
357     if (extractor == nullptr) {
358         RESMGR_HILOGE(RESMGR_TAG,
359             "failed to get extractor from ability in GetRawFileList hapPath, %{public}s", hapPath.c_str());
360         return NOT_FOUND;
361     }
362     std::set<std::string> fileSet;
363     std::string rawfilePath = HapParser::GetRawFilePath(extractor, rawDirPath);
364     if (!extractor->IsDirExist(rawfilePath)) {
365         RESMGR_HILOGD(RESMGR_TAG,
366             "the rawfile dir %{public}s is not exist in %{public}s", rawfilePath.c_str(), hapPath.c_str());
367         return ERROR_CODE_RES_PATH_INVALID;
368     }
369     bool ret = extractor->GetFileList(rawfilePath, fileSet);
370     if (!ret) {
371         RESMGR_HILOGE(RESMGR_TAG, "failed to get fileSet from ability rawfilePath, %{public}s", rawfilePath.c_str());
372         return ERROR_CODE_RES_PATH_INVALID;
373     }
374     for (auto it = fileSet.begin(); it != fileSet.end(); it++) {
375         fileList.emplace_back(*it);
376     }
377 #endif
378     return SUCCESS;
379 }
380 
GetRawFileListUnCompressed(const std::string & indexPath,const std::string & rawDirPath,std::vector<std::string> & fileList)381 RState HapParser::GetRawFileListUnCompressed(const std::string &indexPath, const std::string &rawDirPath,
382     std::vector<std::string>& fileList)
383 {
384     auto pos = indexPath.rfind('/');
385     if (pos == std::string::npos) {
386         return ERROR_CODE_RES_PATH_INVALID;
387     }
388     std::string rawFilePath = indexPath.substr(0, pos) + "/resources/";
389     HapParser::GetPath(rawDirPath, rawFilePath);
390     return Utils::GetFiles(rawFilePath, fileList);
391 }
392 /**
393  *
394  * @param buffer
395  * @param offset
396  * @param bufLen
397  * @param id
398  * @param includeTemi dose length include '\0'
399  * @return OK or ERROR
400  */
ParseString(const char * buffer,uint32_t & offset,const size_t & bufLen,std::string & id,bool includeTemi=true)401 int32_t ParseString(const char *buffer, uint32_t &offset, const size_t &bufLen, std::string &id,
402     bool includeTemi = true)
403 {
404     uint16_t strLen;
405     if (offset + IdItem::SIZE_LEN > bufLen) {
406         RESMGR_HILOGE(RESMGR_TAG, "ParseString length failed, the offset will be out of bounds");
407         return SYS_ERROR;
408     }
409     errno_t eret = memcpy_s(&strLen, sizeof(strLen), buffer + offset, IdItem::SIZE_LEN);
410     if (eret != OK || (includeTemi && strLen == 0)) {
411         return SYS_ERROR;
412     }
413     offset += IdItem::SIZE_LEN; // Offset value plus 2
414     if (offset + (includeTemi ? (strLen - 1) : strLen) > bufLen) {
415         RESMGR_HILOGE(RESMGR_TAG, "ParseString value failed, the offset will be out of bounds");
416         return SYS_ERROR;
417     }
418     std::string tmp = std::string(const_cast<char *>(buffer) + offset, includeTemi ? (strLen - 1) : strLen);
419     offset += includeTemi ? strLen : (strLen + 1);
420     id = tmp;
421     return OK;
422 }
423 
424 /**
425  *
426  * @param buffer
427  * @param offset
428  * @param bufLen
429  * @param values
430  * @return
431  */
ParseStringArray(const char * buffer,uint32_t & offset,const size_t & bufLen,std::vector<std::string> & values)432 int32_t ParseStringArray(const char *buffer, uint32_t &offset, const size_t &bufLen, std::vector<std::string> &values)
433 {
434     uint16_t arrLen;
435     if (offset + IdItem::SIZE_LEN > bufLen) {
436         RESMGR_HILOGE(RESMGR_TAG, "ParseStringArray failed, the offset will be out of bounds");
437         return SYS_ERROR;
438     }
439     errno_t eret = memcpy_s(&arrLen, sizeof(arrLen), buffer + offset, IdItem::SIZE_LEN);
440     if (eret != OK) {
441         return SYS_ERROR;
442     }
443     offset += IdItem::SIZE_LEN; // Offset value plus 2
444     // next arrLen bytes are several strings. then after, is one '\0'
445     uint32_t startOffset = offset;
446     std::string value;
447     while (true) {
448         int32_t ret = ParseString(buffer, offset, bufLen, value, false);
449         if (ret != OK) {
450             return ret;
451         }
452         values.push_back(value);
453 
454         uint32_t readSize = offset - startOffset;
455         if (readSize + 1 == arrLen) {
456             offset += 1; // after arrLen, got '\0'
457             break;
458         }
459         if (readSize + 1 > arrLen) {
460             // size not match, cannot > arrLen
461             return SYS_ERROR;
462         }
463     }
464 
465     return OK;
466 }
467 
ConvertType(ResType type)468 uint32_t ConvertType(ResType type)
469 {
470     auto it = TYPE_MAP.find(type);
471     if (it == TYPE_MAP.end()) {
472         return SELECT_ALL;
473     }
474     return it->second;
475 }
476 
ParseIdItem(const char * buffer,uint32_t & offset,const size_t & bufLen,std::shared_ptr<IdItem> idItem,const uint32_t & selectedTypes)477 int32_t ParseIdItem(const char *buffer, uint32_t &offset, const size_t &bufLen, std::shared_ptr<IdItem> idItem,
478     const uint32_t &selectedTypes)
479 {
480     if (offset + IdItem::HEADER_LEN > bufLen) {
481         RESMGR_HILOGE(RESMGR_TAG, "Parse IdItemHeader failed, the offset will be out of bounds");
482         return SYS_ERROR;
483     }
484     errno_t eret = memcpy_s(idItem.get(), sizeof(IdItem), buffer + offset, IdItem::HEADER_LEN);
485     if (eret != OK) {
486         return SYS_ERROR;
487     }
488     if (selectedTypes != SELECT_ALL && (selectedTypes & ConvertType(idItem->resType_)) == 0) {
489         return OK;
490     }
491     offset += IdItem::HEADER_LEN;
492 
493     idItem->JudgeArray();
494     if (idItem->isArray_) {
495         int32_t ret = ParseStringArray(buffer, offset, bufLen, idItem->values_);
496         if (ret != OK) {
497             return ret;
498         }
499     } else {
500         int32_t ret = ParseString(buffer, offset, bufLen, idItem->value_);
501         if (ret != OK) {
502             return ret;
503         }
504         idItem->valueLen_ = idItem->value_.size();
505     }
506     int32_t ret = ParseString(buffer, offset, bufLen, idItem->name_);
507     if (ret != OK) {
508         return ret;
509     }
510     return OK;
511 }
512 
ParseId(const char * buffer,uint32_t & offset,const size_t & bufLen,std::shared_ptr<ResId> id,const uint32_t & selectedTypes)513 int32_t ParseId(const char *buffer, uint32_t &offset, const size_t &bufLen, std::shared_ptr<ResId> id,
514     const uint32_t &selectedTypes)
515 {
516     if (offset + ResId::RESID_HEADER_LEN > bufLen) {
517         RESMGR_HILOGE(RESMGR_TAG, "Parse ResIdHeader failed, the offset will be out of bounds");
518         return SYS_ERROR;
519     }
520     errno_t eret = memcpy_s(id.get(), sizeof(ResId), buffer + offset, ResId::RESID_HEADER_LEN);
521     if (eret != OK) {
522         return SYS_ERROR;
523     }
524     offset += ResId::RESID_HEADER_LEN;
525     if (id->tag_[ArrayIndex::INDEX_ZERO] != 'I' || id->tag_[ArrayIndex::INDEX_ONE] != 'D'
526         || id->tag_[ArrayIndex::INDEX_TWO] != 'S' || id->tag_[ArrayIndex::INDEX_THREE] != 'S') {
527         return -1;
528     }
529     for (uint32_t i = 0; i < id->count_; ++i) {
530         std::shared_ptr<IdParam> ip = std::make_shared<IdParam>();
531         if (ip == nullptr) {
532             RESMGR_HILOGE(RESMGR_TAG, "new IdParam failed when ParseId");
533             return SYS_ERROR;
534         }
535         if (offset + ResId::IDPARAM_HEADER_LEN > bufLen) {
536             RESMGR_HILOGE(RESMGR_TAG, "Parse IdParam failed, the offset will be out of bounds");
537             return SYS_ERROR;
538         }
539         errno_t eret = memcpy_s(ip.get(), sizeof(IdParam), buffer + offset, ResId::IDPARAM_HEADER_LEN);
540         if (eret != OK) {
541             return SYS_ERROR;
542         }
543         offset += ResId::IDPARAM_HEADER_LEN;
544         std::shared_ptr<IdItem> idItem = std::make_shared<IdItem>();
545         if (idItem == nullptr) {
546             RESMGR_HILOGE(RESMGR_TAG, "new IdItem failed when ParseId");
547             return SYS_ERROR;
548         }
549         uint32_t ipOffset = ip->offset_;
550         int32_t ret = ParseIdItem(buffer, ipOffset, bufLen, idItem, selectedTypes);
551         if (ret != OK) {
552             return ret;
553         }
554         ip->idItem_ = idItem;
555         id->idParams_.push_back(ip);
556     }
557 
558     return OK;
559 }
560 
IsLocaleMatch(const std::shared_ptr<ResConfigImpl> defaultConfig,const std::vector<std::shared_ptr<KeyParam>> & keyParams)561 bool IsLocaleMatch(const std::shared_ptr<ResConfigImpl> defaultConfig,
562     const std::vector<std::shared_ptr<KeyParam>> &keyParams)
563 {
564     if (defaultConfig == nullptr) {
565         return true;
566     }
567     auto config = HapParser::CreateResConfigFromKeyParams(keyParams);
568     if (config == nullptr) {
569         return false;
570     }
571     if (LocaleMatcher::Match(defaultConfig->GetResLocale(), config->GetResLocale())) {
572         return true;
573     }
574     RESMGR_HILOGD(RESMGR_TAG, "mismatch, do not parse %s", HapParser::ToFolderPath(keyParams).c_str());
575     return false;
576 }
577 
ParseKeyParam(const char * buffer,uint32_t & offset,const size_t & bufLen,SelectOptions * options,std::shared_ptr<KeyParam> & kp)578 int32_t ParseKeyParam(const char *buffer, uint32_t &offset, const size_t &bufLen,
579     SelectOptions *options, std::shared_ptr<KeyParam> &kp)
580 {
581     kp = std::make_shared<KeyParam>();
582     if (kp == nullptr) {
583         RESMGR_HILOGE(RESMGR_TAG, "ParseKeyParam new KeyParam failed");
584         return SYS_ERROR;
585     }
586     if (offset + ResKey::KEYPARAM_HEADER_LEN > bufLen) {
587         RESMGR_HILOGE(RESMGR_TAG, "ParseKeyParam failed, the offset will be out of bounds");
588         return SYS_ERROR;
589     }
590     errno_t eret = memcpy_s(kp.get(), sizeof(KeyParam), buffer + offset, ResKey::KEYPARAM_HEADER_LEN);
591     if (eret != OK) {
592         return SYS_ERROR;
593     }
594     offset += ResKey::KEYPARAM_HEADER_LEN;
595     kp->InitStr();
596 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
597     auto resDeviceType = kp->GetDeviceTypeStr();
598     if (options->deviceType != DEVICE_DEFAULT && resDeviceType != NOT_DEVICE_TYPE &&
599         resDeviceType != options->deviceType) {
600         options->match = false;
601     }
602 #endif
603     return OK;
604 }
605 
ParseKey(const char * buffer,uint32_t & offset,const size_t & bufLen,std::shared_ptr<ResKey> key,SelectOptions * options)606 int32_t ParseKey(const char *buffer, uint32_t &offset, const size_t &bufLen, std::shared_ptr<ResKey> key,
607     SelectOptions *options)
608 {
609     if (offset + ResKey::RESKEY_HEADER_LEN > bufLen) {
610         RESMGR_HILOGE(RESMGR_TAG, "Parse ResKeyHeader failed, the offset will be out of bounds");
611         return SYS_ERROR;
612     }
613     errno_t eret = memcpy_s(key.get(), sizeof(ResKey), buffer + offset, ResKey::RESKEY_HEADER_LEN);
614     if (eret != OK) {
615         return SYS_ERROR;
616     }
617     offset += ResKey::RESKEY_HEADER_LEN;
618     if (key->tag_[ArrayIndex::INDEX_ZERO] != 'K' || key->tag_[ArrayIndex::INDEX_ONE] != 'E'
619         || key->tag_[ArrayIndex::INDEX_TWO] != 'Y' || key->tag_[ArrayIndex::INDEX_THREE] != 'S') {
620         return -1;
621     }
622     for (uint32_t i = 0; i < key->keyParamsCount_; ++i) {
623         std::shared_ptr<KeyParam> kp;
624         if (ParseKeyParam(buffer, offset, bufLen, options, kp) != OK) {
625             return SYS_ERROR;
626         }
627         if (kp == nullptr) {
628             return SYS_ERROR;
629         }
630         key->keyParams_.push_back(kp);
631     }
632 
633     key->resConfig_ = HapParser::CreateResConfigFromKeyParams(key->keyParams_);
634     if (!options->match || (options->selectedTypes != SELECT_ALL && options->defaultConfig &&
635                             !options->defaultConfig->Match(key->resConfig_, false))) {
636         options->match = false;
637         return OK;
638     }
639 
640     uint32_t idOffset = key->offset_;
641     std::shared_ptr<ResId> id = std::make_shared<ResId>();
642     if (id == nullptr) {
643         RESMGR_HILOGE(RESMGR_TAG, "new ResId failed when ParseKey");
644         return SYS_ERROR;
645     }
646     int32_t ret = ParseId(buffer, idOffset, bufLen, id, options->selectedTypes);
647     if (ret != OK) {
648         return ret;
649     }
650     key->resId_ = id;
651     return OK;
652 }
653 
654 
ParseResHex(const char * buffer,const size_t bufLen,ResDesc & resDesc,const std::shared_ptr<ResConfigImpl> defaultConfig,const uint32_t & selectedTypes)655 int32_t HapParser::ParseResHex(const char *buffer, const size_t bufLen, ResDesc &resDesc,
656                                const std::shared_ptr<ResConfigImpl> defaultConfig, const uint32_t &selectedTypes)
657 {
658 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
659     HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
660 #endif
661     ResHeader *resHeader = new (std::nothrow) ResHeader();
662     if (resHeader == nullptr) {
663         RESMGR_HILOGE(RESMGR_TAG, "new ResHeader failed when ParseResHex");
664         return SYS_ERROR;
665     }
666     uint32_t offset = 0;
667     if (offset + RES_HEADER_LEN > bufLen) {
668         RESMGR_HILOGE(RESMGR_TAG, "Parse ResHeader failed, the offset will be out of bounds");
669         delete (resHeader);
670         return SYS_ERROR;
671     }
672     errno_t eret = memcpy_s(resHeader, sizeof(ResHeader), buffer + offset, RES_HEADER_LEN);
673     if (eret != OK) {
674         delete (resHeader);
675         return SYS_ERROR;
676     }
677     offset += RES_HEADER_LEN;
678     if (resHeader->keyCount_ == 0 || resHeader->length_ == 0) {
679         delete (resHeader);
680         return UNKNOWN_ERROR;
681     }
682 
683     resDesc.resHeader_ = resHeader;
684     const std::string deviceType = resDesc.GetCurrentDeviceType();
685     for (uint32_t i = 0; i < resHeader->keyCount_; i++) {
686         std::shared_ptr<ResKey> key = std::make_shared<ResKey>();
687         if (key == nullptr) {
688             RESMGR_HILOGE(RESMGR_TAG, "new ResKey failed when ParseResHex");
689             return SYS_ERROR;
690         }
691         SelectOptions selectOptions{true, defaultConfig, deviceType, selectedTypes};
692         int32_t ret = ParseKey(buffer, offset, bufLen, key, &selectOptions);
693         if (ret != OK) {
694             return ret;
695         }
696         if (selectOptions.match) {
697             resDesc.keys_.push_back(key);
698         }
699     }
700     return OK;
701 }
702 
CreateResConfigFromKeyParams(const std::vector<std::shared_ptr<KeyParam>> & keyParams)703 std::shared_ptr<ResConfigImpl> HapParser::CreateResConfigFromKeyParams(
704     const std::vector<std::shared_ptr<KeyParam>> &keyParams)
705 {
706     auto resConfig = std::make_shared<ResConfigImpl>();
707     if (resConfig == nullptr) {
708         RESMGR_HILOGE(RESMGR_TAG, "new ResConfigImpl failed when CreateResConfigFromKeyParams");
709         return nullptr;
710     }
711     size_t len = keyParams.size();
712     // default path
713     if (len == 0) {
714         resConfig->SetColorMode(COLOR_MODE_NOT_SET);
715         return resConfig;
716     }
717     size_t i = 0;
718     ResConfigKey configKey;
719     for (i = 0; i < len; ++i) {
720         const std::shared_ptr<KeyParam> kp = keyParams.at(i);
721         if (kp->type_ == LANGUAGES) {
722             configKey.language = kp->GetStr().c_str();
723         } else if (kp->type_ == REGION) {
724             configKey.region = kp->GetStr().c_str();
725         } else if (kp->type_ == SCRIPT) {
726             configKey.script = kp->GetStr().c_str();
727         } else if (kp->type_ == SCREEN_DENSITY) {
728             configKey.screenDensity = GetScreenDensity(kp->value_);
729         } else if (kp->type_ == DEVICETYPE) {
730             configKey.deviceType = GetDeviceType(kp->value_);
731         } else if (kp->type_ == DIRECTION) {
732             if (kp->value_ == 0) {
733                 configKey.direction = DIRECTION_VERTICAL;
734             } else {
735                 configKey.direction = DIRECTION_HORIZONTAL;
736             }
737         } else if (kp->type_ == INPUTDEVICE) {
738             configKey.inputDevice = GetInputDevice(kp->value_);
739         } else if (kp->type_ == COLORMODE) {
740             configKey.colorMode = GetColorMode(kp->value_);
741         } else if (kp->type_ == MCC) {
742             configKey.mcc = GetMcc(kp->value_);
743         } else if (kp->type_ == MNC) {
744             configKey.mnc = GetMnc(kp->value_);
745         }
746     }
747 
748     return BuildResConfig(&configKey);
749 }
750 
BuildResConfig(ResConfigKey * configKey)751 std::shared_ptr<ResConfigImpl> HapParser::BuildResConfig(ResConfigKey *configKey)
752 {
753     if (configKey == nullptr) {
754         RESMGR_HILOGE(RESMGR_TAG, "configKey is null");
755         return nullptr;
756     }
757     auto resConfig = std::make_shared<ResConfigImpl>();
758     if (resConfig == nullptr) {
759         RESMGR_HILOGE(RESMGR_TAG, "new ResConfigImpl failed when BuildResConfig");
760         return nullptr;
761     }
762     resConfig->SetDeviceType(configKey->deviceType);
763     resConfig->SetDirection(configKey->direction);
764     resConfig->SetColorMode(configKey->colorMode);
765     resConfig->SetMcc(configKey->mcc);
766     resConfig->SetMnc(configKey->mnc);
767     resConfig->SetInputDevice(configKey->inputDevice);
768     resConfig->SetScreenDensity((configKey->screenDensity) / Utils::DPI_BASE);
769     RState r = resConfig->SetLocaleInfo(configKey->language, configKey->script, configKey->region);
770     if (r != SUCCESS) {
771         RESMGR_HILOGE(RESMGR_TAG,
772             "error set locale,lang %s,script %s,region %s", configKey->language, configKey->script, configKey->region);
773     }
774 
775     return resConfig;
776 }
777 
GetDeviceType(uint32_t value)778 DeviceType HapParser::GetDeviceType(uint32_t value)
779 {
780     DeviceType deviceType = DEVICE_NOT_SET;
781     if (value == DEVICE_CAR) {
782         deviceType = DEVICE_CAR;
783     } else if (value == DEVICE_PAD) {
784         deviceType = DEVICE_PAD;
785     } else if (value == DEVICE_PHONE) {
786         deviceType = DEVICE_PHONE;
787     } else if (value == DEVICE_TABLET) {
788         deviceType = DEVICE_TABLET;
789     } else if (value == DEVICE_TV) {
790         deviceType = DEVICE_TV;
791     } else if (value == DEVICE_WEARABLE) {
792         deviceType = DEVICE_WEARABLE;
793     } else if (value == DEVICE_TWOINONE) {
794         deviceType = DEVICE_TWOINONE;
795     }
796     return deviceType;
797 }
798 
GetMcc(uint32_t value)799 uint32_t HapParser::GetMcc(uint32_t value)
800 {
801     return value;
802 }
803 
GetMnc(uint32_t value)804 uint32_t HapParser::GetMnc(uint32_t value)
805 {
806     return value;
807 }
808 
GetColorMode(uint32_t value)809 ColorMode HapParser::GetColorMode(uint32_t value)
810 {
811     ColorMode colorMode = COLOR_MODE_NOT_SET;
812     if (value == DARK) {
813         colorMode = DARK;
814     } else {
815         colorMode = LIGHT;
816     }
817     return colorMode;
818 }
819 
GetInputDevice(uint32_t value)820 InputDevice HapParser::GetInputDevice(uint32_t value)
821 {
822     InputDevice inputDevice = INPUTDEVICE_NOT_SET;
823     if (value == INPUTDEVICE_POINTINGDEVICE) {
824         inputDevice = INPUTDEVICE_POINTINGDEVICE;
825     }
826     return inputDevice;
827 }
828 
GetScreenDensity(uint32_t value)829 ScreenDensity HapParser::GetScreenDensity(uint32_t value)
830 {
831     ScreenDensity screenDensity = SCREEN_DENSITY_NOT_SET;
832     if (value == SCREEN_DENSITY_SDPI) {
833         screenDensity = SCREEN_DENSITY_SDPI;
834     } else if (value == SCREEN_DENSITY_MDPI) {
835         screenDensity = SCREEN_DENSITY_MDPI;
836     } else if (value == SCREEN_DENSITY_LDPI) {
837         screenDensity = SCREEN_DENSITY_LDPI;
838     } else if (value == SCREEN_DENSITY_XLDPI) {
839         screenDensity = SCREEN_DENSITY_XLDPI;
840     } else if (value == SCREEN_DENSITY_XXLDPI) {
841         screenDensity = SCREEN_DENSITY_XXLDPI;
842     } else if (value == SCREEN_DENSITY_XXXLDPI) {
843         screenDensity = SCREEN_DENSITY_XXXLDPI;
844     }
845     return screenDensity;
846 }
847 
PathAppend(std::string & path,const std::string & append,const std::string & connector)848 void PathAppend(std::string &path, const std::string &append, const std::string &connector)
849 {
850     if (append.size() > 0) {
851         if (path.size() > 0) {
852             path.append(connector);
853         }
854         path.append(append);
855     }
856 }
857 
ToFolderPath(const std::vector<std::shared_ptr<KeyParam>> & keyParams)858 std::string HapParser::ToFolderPath(const std::vector<std::shared_ptr<KeyParam>> &keyParams)
859 {
860     if (keyParams.size() == 0) {
861         return std::string("default");
862     }
863     // mcc-mnc-language_script_region-direction-deviceType-colorMode-inputDevice-screenDensity
864     Determiner determiner;
865     for (const auto &keyParam : keyParams) {
866         switch (keyParam->type_) {
867             case KeyType::LANGUAGES:
868                 determiner.language = keyParam->GetStr();
869                 break;
870             case KeyType::SCRIPT:
871                 determiner.script = keyParam->GetStr();
872                 break;
873             case KeyType::REGION:
874                 determiner.region = keyParam->GetStr();
875                 break;
876             case KeyType::DIRECTION:
877                 determiner.direction = keyParam->GetStr();
878                 break;
879             case KeyType::DEVICETYPE:
880                 determiner.deviceType = keyParam->GetStr();
881                 break;
882             case KeyType::COLORMODE:
883                 determiner.colorMode = keyParam->GetStr();
884                 break;
885             case KeyType::INPUTDEVICE:
886                 determiner.inputDevice = keyParam->GetStr();
887                 break;
888             case KeyType::MCC:
889                 determiner.mcc = keyParam->GetStr();
890                 break;
891             case KeyType::MNC:
892                 determiner.mnc = keyParam->GetStr();
893                 break;
894             case KeyType::SCREEN_DENSITY:
895                 determiner.screenDensity = keyParam->GetStr();
896                 break;
897             default:
898                 break;
899         }
900     }
901 
902     return BuildFolderPath(&determiner);
903 }
904 
BuildFolderPath(Determiner * determiner)905 std::string HapParser::BuildFolderPath(Determiner *determiner)
906 {
907     std::string path;
908     if (determiner == nullptr) {
909         RESMGR_HILOGE(RESMGR_TAG, "determiner is null");
910         return path;
911     }
912     std::string connecter1("_");
913     std::string connecter2("-");
914     if (determiner->mcc.size() > 0) {
915         path.append(determiner->mcc);
916         if (determiner->mnc.size() > 0) {
917             PathAppend(path, determiner->mnc, connecter1);
918         }
919         if (determiner->language.size() > 0) {
920             PathAppend(path, determiner->language, connecter2);
921         }
922     } else {
923         if (determiner->language.size() > 0) {
924             path.append(determiner->language);
925         }
926     }
927     PathAppend(path, determiner->script, connecter1);
928     PathAppend(path, determiner->region, connecter1);
929     PathAppend(path, determiner->direction, connecter2);
930     PathAppend(path, determiner->deviceType, connecter2);
931     PathAppend(path, determiner->colorMode, connecter2);
932     PathAppend(path, determiner->inputDevice, connecter2);
933     PathAppend(path, determiner->screenDensity, connecter2);
934 
935     return path;
936 }
937 
IsRawDirFromHap(const char * hapPath,const std::string & pathName,bool & outValue)938 RState HapParser::IsRawDirFromHap(const char *hapPath, const std::string &pathName, bool &outValue)
939 {
940 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
941     if (pathName.empty()) {
942         RESMGR_HILOGE(RESMGR_TAG, "the rawfile path is empty");
943         return ERROR_CODE_RES_PATH_INVALID;
944     }
945     bool isNewExtractor = false;
946     auto extractor = AbilityBase::ExtractorUtil::GetExtractor(hapPath, isNewExtractor);
947     if (extractor == nullptr) {
948         RESMGR_HILOGE(RESMGR_TAG, "failed to get extractor hapPath, %{public}s", hapPath);
949         return NOT_FOUND;
950     }
951     std::string rawPath = HapParser::GetRawFilePath(extractor, pathName);
952     if (extractor->HasEntry(rawPath)) {
953         outValue = false;
954     } else if (extractor->IsDirExist(rawPath)) {
955         outValue = true;
956     } else {
957         RESMGR_HILOGD(RESMGR_TAG, "the rawfile file %{public}s is not exist in %{public}s", rawPath.c_str(), hapPath);
958         return ERROR_CODE_RES_PATH_INVALID;
959     }
960 #endif
961     return SUCCESS;
962 }
963 
IsRawDirUnCompressed(const std::string & pathName,bool & outValue)964 RState HapParser::IsRawDirUnCompressed(const std::string &pathName, bool &outValue)
965 {
966     char outPath[PATH_MAX + 1] = {0};
967     Utils::CanonicalizePath(pathName.c_str(), outPath, PATH_MAX);
968     struct stat fileStat {};
969     if (stat(outPath, &fileStat) != 0) {
970         RESMGR_HILOGE(RESMGR_TAG, "failed to get rawfile file info, %{public}s", outPath);
971         return ERROR_CODE_RES_PATH_INVALID;
972     }
973     if ((fileStat.st_mode & S_IFDIR)) {
974         outValue = true;
975     } else if ((fileStat.st_mode & S_IFREG)) {
976         outValue = false;
977     } else {
978         RESMGR_HILOGE(RESMGR_TAG, "the rawfile file %{public}s is not exist", outPath);
979         return ERROR_CODE_RES_PATH_INVALID;
980     }
981     return SUCCESS;
982 }
983 } // namespace Resource
984 } // namespace Global
985 } // namespace OHOS
986