1 /*
2 * Copyright (c) 2025 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_v2.h"
17
18 #include <fcntl.h>
19 #include <fstream>
20 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23 #endif
24 #include <unistd.h>
25
26 #if defined(__WINNT__)
27 #include <cstring>
28 #else
29 #include "securec.h"
30 #endif
31
32 #include "hilog_wrapper.h"
33 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
34 #include "hitrace_meter.h"
35 #endif
36
37 #include "utils/errors.h"
38 #include "utils/utils.h"
39
40 namespace OHOS {
41 namespace Global {
42 namespace Resource {
HapParserV2()43 HapParserV2::HapParserV2()
44 {}
45
~HapParserV2()46 HapParserV2::~HapParserV2()
47 {}
48
Init(const char * path)49 bool HapParserV2::Init(const char *path)
50 {
51 mMapFile_ = std::make_shared<MmapFile>();
52 if (mMapFile_ == nullptr) {
53 RESMGR_HILOGE(RESMGR_TAG, "Init mmap file failed");
54 return false;
55 }
56
57 if (!this->GetIndexMmap(path)) {
58 RESMGR_HILOGE(RESMGR_TAG, "GetIndexMmap failed when construct hapParser");
59 return false;
60 }
61
62 int32_t out = this->ParseResHex();
63 if (out != OK) {
64 RESMGR_HILOGE(RESMGR_TAG, "ParseResHex failed! retcode:%d", out);
65 return false;
66 }
67 return true;
68 }
69
ParseResHex()70 int32_t HapParserV2::ParseResHex()
71 {
72 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
73 HITRACE_METER_NAME_EX(HITRACE_LEVEL_INFO, HITRACE_TAG_APP, __PRETTY_FUNCTION__, nullptr);
74 #endif
75 uint32_t offset = 0;
76 int32_t ret = this->ParseHeader(offset);
77 if (ret != OK) {
78 return ret;
79 }
80
81 ret = this->ParseKeys(offset);
82 if (ret != OK) {
83 return ret;
84 }
85
86 ret = this->ParseIds(offset);
87 if (ret != OK) {
88 return ret;
89 }
90
91 if (offset != resHeader_.dataBlockOffset_) {
92 RESMGR_HILOGE(RESMGR_TAG, "Parse ResHeader failed, resource data error.");
93 return UNKNOWN_ERROR;
94 }
95 return OK;
96 }
97
ParseHeader(uint32_t & offset)98 int32_t HapParserV2::ParseHeader(uint32_t &offset)
99 {
100 if (offset + ResIndexHeader::RES_HEADER_LEN > mMapFile_->mmapLen_) {
101 RESMGR_HILOGE(RESMGR_TAG, "Parse ResHeader failed, the offset will be out of bounds.");
102 return SYS_ERROR;
103 }
104 errno_t eret = memcpy_s(&resHeader_, sizeof(ResIndexHeader),
105 mMapFile_->mmap_ + offset, ResIndexHeader::RES_HEADER_LEN);
106 if (eret != OK) {
107 RESMGR_HILOGE(RESMGR_TAG, "Parse ResHeader failed, memory copy failed.");
108 return SYS_ERROR;
109 }
110 if (resHeader_.keyCount_ == 0 || resHeader_.length_ == 0 || resHeader_.dataBlockOffset_ > mMapFile_->mmapLen_) {
111 RESMGR_HILOGE(RESMGR_TAG, "Parse ResHeader failed, ResHeader data error.");
112 return UNKNOWN_ERROR;
113 }
114 offset += ResIndexHeader::RES_HEADER_LEN;
115 keys_.reserve(resHeader_.keyCount_);
116 return OK;
117 }
118
ParseKeys(uint32_t & offset)119 int32_t HapParserV2::ParseKeys(uint32_t &offset)
120 {
121 for (uint32_t i = 0; i < resHeader_.keyCount_; i++) {
122 std::shared_ptr<KeyInfo> key = std::make_shared<KeyInfo>();
123 if (key == nullptr) {
124 RESMGR_HILOGE(RESMGR_TAG, "new ResKey failed when ParseResHex");
125 return SYS_ERROR;
126 }
127 int32_t ret = this->ParseKey(offset, key);
128 if (ret != OK) {
129 return ret;
130 }
131 keys_[key->resConfigId_] = HapParser::CreateResConfigFromKeyParams(key->params_);
132 if (keys_[key->resConfigId_]->GetColorMode() == ColorMode::DARK) {
133 hasDarkRes_ = true;
134 }
135 }
136 return OK;
137 }
138
ParseIds(uint32_t & offset)139 int32_t HapParserV2::ParseIds(uint32_t &offset)
140 {
141 if (offset + IdsHeader::IDS_HEADER_LEN > mMapFile_->mmapLen_) {
142 RESMGR_HILOGE(RESMGR_TAG, "Parse IdsHeader failed, the offset will be out of bounds.");
143 return SYS_ERROR;
144 }
145 errno_t eret = memcpy_s(&idsHeader_, sizeof(IdsHeader), mMapFile_->mmap_ + offset, IdsHeader::IDS_HEADER_LEN);
146 if (eret != OK) {
147 RESMGR_HILOGE(RESMGR_TAG, "Parse IdsHeader failed, memory copy failed.");
148 return SYS_ERROR;
149 }
150 if (idsHeader_.tag_[ArrayIndex::INDEX_ZERO] != 'I' || idsHeader_.tag_[ArrayIndex::INDEX_ONE] != 'D' ||
151 idsHeader_.tag_[ArrayIndex::INDEX_TWO] != 'S' || idsHeader_.tag_[ArrayIndex::INDEX_THREE] != 'S' ||
152 offset + idsHeader_.length_ > resHeader_.dataBlockOffset_ ||
153 idsHeader_.typeCount_ == 0 || idsHeader_.idCount_ == 0) {
154 RESMGR_HILOGE(RESMGR_TAG, "Parse IdsHeader failed, IdsHeader data error.");
155 return UNKNOWN_ERROR;
156 }
157 offset += IdsHeader::IDS_HEADER_LEN;
158 idMap_.reserve(idsHeader_.idCount_);
159 typeNameMap_.reserve(idsHeader_.typeCount_);
160
161 for (uint32_t i = 0; i < idsHeader_.typeCount_; i++) {
162 int32_t ret = ParseType(offset);
163 if (ret != OK) {
164 return ret;
165 }
166 }
167 return OK;
168 }
169
ParseType(uint32_t & offset)170 int32_t HapParserV2::ParseType(uint32_t &offset)
171 {
172 if (offset + TypeInfo::TYPE_INFO_LEN > mMapFile_->mmapLen_) {
173 RESMGR_HILOGE(RESMGR_TAG, "Parse TypeInfo failed, the offset will be out of bounds.");
174 return SYS_ERROR;
175 }
176 TypeInfo typeInfo;
177 errno_t eret = memcpy_s(&typeInfo, sizeof(TypeInfo), mMapFile_->mmap_ + offset, TypeInfo::TYPE_INFO_LEN);
178 if (eret != OK) {
179 RESMGR_HILOGE(RESMGR_TAG, "Parse TypeInfo failed, memory copy failed.");
180 return SYS_ERROR;
181 }
182 if (typeInfo.type_ >= ResType::MAX_RES_TYPE || offset + typeInfo.length_ > resHeader_.dataBlockOffset_ ||
183 typeInfo.count_ > idsHeader_.idCount_) {
184 RESMGR_HILOGE(RESMGR_TAG, "Parse TypeInfo failed, TypeInfo data error.");
185 return UNKNOWN_ERROR;
186 }
187 offset += TypeInfo::TYPE_INFO_LEN;
188 typeNameMap_[typeInfo.type_].reserve(typeInfo.count_);
189
190 for (uint32_t i = 0; i < typeInfo.count_; i++) {
191 int32_t ret = this->ParseItem(offset, typeInfo);
192 if (ret != OK) {
193 return ret;
194 }
195 }
196 return OK;
197 }
198
ParseItem(uint32_t & offset,const TypeInfo & typeInfo)199 int32_t HapParserV2::ParseItem(uint32_t &offset, const TypeInfo &typeInfo)
200 {
201 if (offset + ResItem::RES_ITEM_LEN > mMapFile_->mmapLen_) {
202 RESMGR_HILOGE(RESMGR_TAG, "Parse ResItem failed, the offset will be out of bounds.");
203 return SYS_ERROR;
204 }
205 ResItem resItem;
206 errno_t eret = memcpy_s(&resItem, sizeof(ResItem), mMapFile_->mmap_ + offset, ResItem::RES_ITEM_LEN);
207 if (eret != OK) {
208 RESMGR_HILOGE(RESMGR_TAG, "Parse ResItem failed, memory copy failed.");
209 return SYS_ERROR;
210 }
211 offset += ResItem::RES_ITEM_LEN;
212 resItem.name_ = std::string(reinterpret_cast<const char *>(mMapFile_->mmap_) + offset, resItem.length_);
213 offset += resItem.length_;
214
215 std::shared_ptr<IdValuesV2> idValues =
216 std::make_shared<IdValuesV2>((ResType)typeInfo.type_, resItem.resId_, resItem.offset_, resItem.name_);
217 idValues->SetMMap(mMapFile_);
218 typeNameMap_[typeInfo.type_][resItem.name_] = idValues;
219 idMap_[resItem.resId_] = idValues;
220 return OK;
221 }
222
ParseStringArray(uint32_t & offset,std::vector<std::string> & values,size_t bufLen,uint8_t * buf)223 int32_t HapParserV2::ParseStringArray(uint32_t &offset, std::vector<std::string> &values, size_t bufLen, uint8_t *buf)
224 {
225 uint16_t arrLen;
226 if (offset + ValueUnderQualifierDirV2::DATA_HEAD_LEN > bufLen) {
227 RESMGR_HILOGE(RESMGR_TAG, "ParseStringArray failed, the offset will be out of bounds.");
228 return SYS_ERROR;
229 }
230 errno_t eret = memcpy_s(&arrLen, sizeof(uint16_t), buf + offset, ValueUnderQualifierDirV2::DATA_HEAD_LEN);
231 if (eret != OK) {
232 RESMGR_HILOGE(RESMGR_TAG, "ParseStringArray failed, memory copy failed.");
233 return SYS_ERROR;
234 }
235 offset += ValueUnderQualifierDirV2::DATA_HEAD_LEN;
236
237 uint32_t startOffset = offset;
238 std::string value;
239 while (true) {
240 int32_t ret = ParseString(offset, value, bufLen, buf);
241 if (ret != OK) {
242 return ret;
243 }
244 values.push_back(value);
245 offset++;
246
247 uint32_t readSize = offset - startOffset;
248 if (readSize == arrLen) {
249 break;
250 }
251 if (readSize > arrLen) {
252 RESMGR_HILOGE(RESMGR_TAG, "ParseStringArray failed, the read size out of bounds.");
253 return SYS_ERROR;
254 }
255 }
256 return OK;
257 }
258
ParseString(uint32_t & offset,std::string & id,size_t bufLen,uint8_t * buf)259 int32_t HapParserV2::ParseString(uint32_t &offset, std::string &id, size_t bufLen, uint8_t *buf)
260 {
261 uint16_t strLen;
262 if (offset + ValueUnderQualifierDirV2::DATA_HEAD_LEN > bufLen) {
263 RESMGR_HILOGE(RESMGR_TAG, "ParseString failed, the offset will be out of bounds.");
264 return SYS_ERROR;
265 }
266 errno_t eret = memcpy_s(&strLen, sizeof(uint16_t), buf + offset, ValueUnderQualifierDirV2::DATA_HEAD_LEN);
267 if (eret != OK) {
268 RESMGR_HILOGE(RESMGR_TAG, "ParseString failed, memory copy failed.");
269 return SYS_ERROR;
270 }
271 offset += ValueUnderQualifierDirV2::DATA_HEAD_LEN;
272
273 if (offset + strLen > bufLen) {
274 RESMGR_HILOGE(RESMGR_TAG, "ParseString failed, the string offset will be out of bounds");
275 return SYS_ERROR;
276 }
277 std::string tmp = std::string(reinterpret_cast<char *>(buf) + offset, strLen);
278 offset += strLen;
279 id = tmp;
280 return OK;
281 }
282
ParseResInfo(uint32_t & offset,ResInfo & resInfo,const size_t bufLen,const uint8_t * buf)283 int32_t HapParserV2::ParseResInfo(uint32_t &offset, ResInfo &resInfo, const size_t bufLen, const uint8_t *buf)
284 {
285 if (offset + ResInfo::RES_INFO_LEN > bufLen) {
286 RESMGR_HILOGE(RESMGR_TAG, "Parse ResInfo failed, the offset will be out of bounds.");
287 return SYS_ERROR;
288 }
289 errno_t eret = memcpy_s(&resInfo, sizeof(ResInfo), buf + offset, ResInfo::RES_INFO_LEN);
290 if (eret != OK) {
291 RESMGR_HILOGE(RESMGR_TAG, "Parse ResInfo failed, memory copy failed.");
292 return SYS_ERROR;
293 }
294 offset += ResInfo::RES_INFO_LEN;
295 return OK;
296 }
297
ParseConfigItem(uint32_t & offset,ConfigItem & configItem,const size_t bufLen,const uint8_t * buf)298 int32_t HapParserV2::ParseConfigItem(uint32_t &offset, ConfigItem &configItem, const size_t bufLen, const uint8_t *buf)
299 {
300 if (offset + ConfigItem::CONFIG_ITEM_LEN > bufLen) {
301 RESMGR_HILOGE(RESMGR_TAG, "Parse ConfigItem failed, the offset will be out of bounds.");
302 return SYS_ERROR;
303 }
304 errno_t eret = memcpy_s(&configItem, sizeof(ConfigItem), buf + offset, ConfigItem::CONFIG_ITEM_LEN);
305 if (eret != OK) {
306 RESMGR_HILOGE(RESMGR_TAG, "Parse ConfigItem failed, memory copy failed.");
307 return SYS_ERROR;
308 }
309 offset += ConfigItem::CONFIG_ITEM_LEN;
310 return OK;
311 }
312
ParseKey(uint32_t & offset,std::shared_ptr<KeyInfo> key)313 int32_t HapParserV2::ParseKey(uint32_t &offset, std::shared_ptr<KeyInfo> key)
314 {
315 if (offset + KeyInfo::RESKEY_HEADER_LEN > mMapFile_->mmapLen_) {
316 RESMGR_HILOGE(RESMGR_TAG, "Parse ResKey failed, the offset will be out of bounds.");
317 return SYS_ERROR;
318 }
319 errno_t eret = memcpy_s(key.get(), sizeof(KeyInfo), mMapFile_->mmap_ + offset, KeyInfo::RESKEY_HEADER_LEN);
320 if (eret != OK) {
321 RESMGR_HILOGE(RESMGR_TAG, "Parse ResKey failed, memory copy failed.");
322 return SYS_ERROR;
323 }
324 if (key->tag_[ArrayIndex::INDEX_ZERO] != 'K' || key->tag_[ArrayIndex::INDEX_ONE] != 'E' ||
325 key->tag_[ArrayIndex::INDEX_TWO] != 'Y' || key->tag_[ArrayIndex::INDEX_THREE] != 'S') {
326 RESMGR_HILOGE(RESMGR_TAG, "Parse ResKey failed, ResKey data error.");
327 return UNKNOWN_ERROR;
328 }
329 offset += KeyInfo::RESKEY_HEADER_LEN;
330
331 std::string locale;
332 bool isLocale = false;
333 for (uint32_t i = 0; i < key->keyParamsCount_; i++) {
334 std::shared_ptr<KeyParam> keyParam = std::make_shared<KeyParam>();
335 if (keyParam == nullptr) {
336 RESMGR_HILOGE(RESMGR_TAG, "new KeyParam failed when ParseResHex");
337 return SYS_ERROR;
338 }
339 int32_t ret = this->ParseKeyParam(offset, keyParam);
340 GetKeyParamsLocales(keyParam, locale, isLocale);
341 if (ret != OK) {
342 return ret;
343 }
344 key->params_.push_back(keyParam);
345 }
346 if (isLocale) {
347 locales_.emplace(locale);
348 }
349 return OK;
350 }
351
ParseKeyParam(uint32_t & offset,std::shared_ptr<KeyParam> keyParam)352 int32_t HapParserV2::ParseKeyParam(uint32_t &offset, std::shared_ptr<KeyParam> keyParam)
353 {
354 if (offset + KeyParam::KEYPARAM_LEN > mMapFile_->mmapLen_) {
355 RESMGR_HILOGE(RESMGR_TAG, "Parse KeyParam failed, the offset will be out of bounds.");
356 return SYS_ERROR;
357 }
358 errno_t eret = memcpy_s(keyParam.get(), sizeof(KeyParam), mMapFile_->mmap_ + offset, KeyParam::KEYPARAM_LEN);
359 if (eret != OK) {
360 RESMGR_HILOGE(RESMGR_TAG, "Parse KeyParam failed, memory copy failed.");
361 return SYS_ERROR;
362 }
363 offset += KeyParam::KEYPARAM_LEN;
364 keyParam->InitStr();
365
366 this->GetLimitKeyValue(keyParam->type_);
367 return OK;
368 }
369
GetLimitKeyValue(KeyType type)370 void HapParserV2::GetLimitKeyValue(KeyType type)
371 {
372 const uint32_t limitKeysBase = 0x00000001;
373 if (type < KeyType::KEY_TYPE_MAX) {
374 uint32_t typeValue = static_cast<uint32_t>(type);
375 limitKeyValue_ |= limitKeysBase << typeValue;
376 }
377 }
378
GetHapResource(const char * path,bool isSystem,bool isOverlay)379 std::shared_ptr<HapResource> HapParserV2::GetHapResource(const char *path, bool isSystem, bool isOverlay)
380 {
381 if (keys_.size() == 0 || idMap_.size() == 0 || typeNameMap_.size() == 0) {
382 RESMGR_HILOGE(RESMGR_TAG, "Get Hap resource failed, parse data is empty.");
383 return nullptr;
384 }
385
386 std::shared_ptr<HapResourceV2> pResource = nullptr;
387 if (isSystem && isOverlay) {
388 pResource = std::make_shared<SystemOverlayResource>(path, 0);
389 } else if (isSystem) {
390 pResource = std::make_shared<SystemResource>(path, 0);
391 } else if (isOverlay) {
392 pResource = std::make_shared<OverlayResource>(path, 0);
393 } else {
394 pResource = std::make_shared<HapResourceV2>(path, 0, hasDarkRes_);
395 }
396
397 if (pResource == nullptr || !pResource->Init(keys_, idMap_, typeNameMap_, mMapFile_)) {
398 RESMGR_HILOGE(RESMGR_TAG, "Get Hap resource failed, HapResource init failed.");
399 return nullptr;
400 }
401
402 pResource->SetLimitKeysValue(limitKeyValue_);
403 pResource->SetLocales(locales_);
404 pResource->InitThemeSystemRes();
405 return pResource;
406 }
407
GetIndexMmap(const char * path)408 bool HapParserV2::GetIndexMmap(const char *path)
409 {
410 if (Utils::ContainsTail(path, Utils::tailSet)) {
411 return this->GetIndexMmapFromHap(path);
412 } else {
413 return this->GetIndexMmapFromIndex(path);
414 }
415 }
416
GetIndexMmapFromHap(const char * path)417 bool HapParserV2::GetIndexMmapFromHap(const char *path)
418 {
419 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
420 HITRACE_METER_NAME_EX(HITRACE_LEVEL_INFO, HITRACE_TAG_APP, __PRETTY_FUNCTION__, nullptr);
421 bool isNewExtractor = false;
422 mMapFile_->extractor_ = AbilityBase::ExtractorUtil::GetExtractor(path, isNewExtractor);
423 if (mMapFile_->extractor_ == nullptr) {
424 return false;
425 }
426 std::string indexFilePath;
427 if (mMapFile_->extractor_->IsStageModel()) {
428 indexFilePath = "resources.index";
429 } else {
430 indexFilePath = HapParser::GetIndexFilePath(mMapFile_->extractor_);
431 }
432 mMapFile_->mapper_ = mMapFile_->extractor_->GetMmapData(indexFilePath);
433 if (mMapFile_->mapper_ == nullptr) {
434 RESMGR_HILOGE(RESMGR_TAG, "failed to get mmap data indexFilePath from hap");
435 return false;
436 }
437 mMapFile_->mmapLen_ = mMapFile_->mapper_->GetDataLen();
438 mMapFile_->mmap_ = mMapFile_->mapper_->GetDataPtr();
439 #endif
440 return true;
441 }
442
GetIndexMmapFromIndex(const char * path)443 bool HapParserV2::GetIndexMmapFromIndex(const char *path)
444 {
445 char indexPath[PATH_MAX + 1] = {0};
446 Utils::CanonicalizePath(path, indexPath, PATH_MAX);
447 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
448 mMapFile_->fd_ = open(indexPath, O_RDONLY);
449 if (mMapFile_->fd_ <= 0) {
450 return false;
451 }
452 struct stat fileStat;
453 fstat(mMapFile_->fd_, &fileStat);
454 mMapFile_->mmapLen_ = static_cast<size_t>(fileStat.st_size);
455 mMapFile_->mmap_ = (uint8_t*)mmap(nullptr, mMapFile_->mmapLen_, PROT_READ, MAP_PRIVATE, mMapFile_->fd_, 0);
456 if (mMapFile_->mmap_ == MAP_FAILED) {
457 RESMGR_HILOGE(RESMGR_TAG, "failed to get mmap data indexFilePath from index");
458 return false;
459 }
460 #else
461 std::ifstream inFile(indexPath, std::ios::binary | std::ios::in);
462 if (!inFile.good()) {
463 return false;
464 }
465 inFile.seekg(0, std::ios::end);
466 int fileLen = inFile.tellg();
467 if (fileLen <= 0) {
468 RESMGR_HILOGE(RESMGR_TAG, "file size is zero");
469 inFile.close();
470 return false;
471 }
472 mMapFile_->mmapLen_ = static_cast<size_t>(fileLen);
473 mMapFile_->mmap_ = new uint8_t[fileLen + 1];
474 inFile.seekg(0, std::ios::beg);
475 inFile.read(reinterpret_cast<char*>(mMapFile_->mmap_), fileLen);
476 inFile.close();
477 RESMGR_HILOGD(RESMGR_TAG, "extract success, bufLen:%d", fileLen);
478 #endif
479 return true;
480 }
481 } // namespace Resource
482 } // namespace Global
483 } // namespace OHOS
484