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_v1.h"
17
18 #include <cstdlib>
19 #include <fcntl.h>
20 #include <fstream>
21 #include <unistd.h>
22 #include <sys/stat.h>
23 #include <unordered_map>
24
25 #include "hap_resource_manager.h"
26 #include "hap_resource_v1.h"
27 #include "hilog_wrapper.h"
28 #include "locale_matcher.h"
29 #include "utils/errors.h"
30 #include "utils/string_utils.h"
31 #include "utils/utils.h"
32
33 #if defined(__WINNT__)
34 #include <cstring>
35 #else
36 #include "securec.h"
37 #endif
38
39 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
40 #include "hitrace_meter.h"
41 #include "file_mapper.h"
42 #include "extractor.h"
43 #endif
44
45 namespace OHOS {
46 namespace Global {
47 namespace Resource {
48 const std::string NOT_DEVICE_TYPE = "not_device_type";
49 const std::string DEVICE_DEFAULT = "default";
50 static const std::unordered_map<ResType, uint32_t> TYPE_MAP {
51 {INTEGER, SELECT_INTEGER},
52 {STRING, SELECT_STRING},
53 {STRINGARRAY, SELECT_STRINGARRAY},
54 {INTARRAY, SELECT_INTARRAY},
55 {BOOLEAN, SELECT_BOOLEAN},
56 {COLOR, SELECT_COLOR},
57 {THEME, SELECT_THEME},
58 {PLURALS, SELECT_PLURALS},
59 {FLOAT, SELECT_FLOAT},
60 {MEDIA, SELECT_MEDIA},
61 {PROF, SELECT_PROF},
62 {PATTERN, SELECT_PATTERN},
63 {SYMBOL, SELECT_SYMBOL}
64 };
65
HapParserV1()66 HapParserV1::HapParserV1() : deviceType_(DEVICE_DEFAULT)
67 {}
68
HapParserV1(std::shared_ptr<ResConfigImpl> & defaultConfig,uint32_t selectedTypes,bool loadAll,bool isUpdate)69 HapParserV1::HapParserV1(std::shared_ptr<ResConfigImpl> &defaultConfig, uint32_t selectedTypes,
70 bool loadAll, bool isUpdate) : defaultConfig_(defaultConfig), selectedTypes_(selectedTypes),
71 deviceType_(DEVICE_DEFAULT), loadAll_(loadAll), isUpdate_(isUpdate)
72 {}
73
~HapParserV1()74 HapParserV1::~HapParserV1()
75 {}
76
SetResDesc(std::shared_ptr<ResDesc> & resDesc)77 void HapParserV1::SetResDesc(std::shared_ptr<ResDesc> &resDesc)
78 {
79 resDesc_ = resDesc;
80 }
81
Init(const char * path)82 bool HapParserV1::Init(const char *path)
83 {
84 if (resDesc_ == nullptr) {
85 return false;
86 }
87
88 if (!GetIndexData(path, buffer_, bufLen_)) {
89 return false;
90 }
91
92 int32_t out = this->ParseResHex();
93 if (out != OK) {
94 RESMGR_HILOGE(RESMGR_TAG, "ParseResHex failed! retcode:%d", out);
95 return false;
96 }
97 return true;
98 }
99
ParseResHex()100 int32_t HapParserV1::ParseResHex()
101 {
102 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
103 HITRACE_METER_NAME_EX(HITRACE_LEVEL_INFO, HITRACE_TAG_APP, __PRETTY_FUNCTION__, nullptr);
104 #endif
105 ResHeader resHeader;
106 uint32_t offset = 0;
107 if (offset + ResHeader::RES_HEADER_LEN > bufLen_) {
108 RESMGR_HILOGE(RESMGR_TAG, "Parse ResHeader failed, the offset will be out of bounds");
109 return SYS_ERROR;
110 }
111 errno_t eret = memcpy_s(&resHeader, sizeof(ResHeader), buffer_.get() + offset, ResHeader::RES_HEADER_LEN);
112 if (eret != OK) {
113 return SYS_ERROR;
114 }
115 offset += ResHeader::RES_HEADER_LEN;
116 if (resHeader.keyCount_ == 0 || resHeader.length_ == 0) {
117 return UNKNOWN_ERROR;
118 }
119 deviceType_ = ResConfigImpl::GetCurrentDeviceType();
120 if (deviceType_ == std::string(TABLET_STR) || deviceType_ == std::string(TWOINONE_STR)) {
121 deviceTypes_ = ResConfigImpl::GetAppSupportDeviceTypes();
122 }
123 std::vector<bool> keyTypes(KeyType::KEY_TYPE_MAX, false);
124 for (uint32_t i = 0; i < resHeader.keyCount_; i++) {
125 std::shared_ptr<ResKey> key = std::make_shared<ResKey>();
126 if (key == nullptr) {
127 RESMGR_HILOGE(RESMGR_TAG, "new ResKey failed when ParseResHex");
128 return SYS_ERROR;
129 }
130 bool match = true;
131 int32_t ret = ParseKey(offset, key, match, keyTypes);
132 if (ret != OK) {
133 return ret;
134 }
135 if (match) {
136 resDesc_->keys_.push_back(key);
137 }
138 }
139 return OK;
140 }
141
ParseKey(uint32_t & offset,std::shared_ptr<ResKey> key,bool & match,std::vector<bool> & keyTypes)142 int32_t HapParserV1::ParseKey(uint32_t &offset, std::shared_ptr<ResKey> key, bool &match, std::vector<bool> &keyTypes)
143 {
144 if (offset + ResKey::RESKEY_HEADER_LEN > bufLen_) {
145 RESMGR_HILOGE(RESMGR_TAG, "Parse ResKeyHeader failed, the offset will be out of bounds");
146 return SYS_ERROR;
147 }
148 errno_t eret = memcpy_s(key.get(), sizeof(ResKey), buffer_.get() + offset, ResKey::RESKEY_HEADER_LEN);
149 if (eret != OK) {
150 return SYS_ERROR;
151 }
152 offset += ResKey::RESKEY_HEADER_LEN;
153 if (key->tag_[ArrayIndex::INDEX_ZERO] != 'K' || key->tag_[ArrayIndex::INDEX_ONE] != 'E' ||
154 key->tag_[ArrayIndex::INDEX_TWO] != 'Y' || key->tag_[ArrayIndex::INDEX_THREE] != 'S') {
155 return -1;
156 }
157
158 std::vector<std::shared_ptr<KeyParam>> keyParams;
159 if (!this->getKeyParams(offset, key->keyParamsCount_, match, keyTypes, keyParams)) {
160 return SYS_ERROR;
161 }
162 key->resConfig_ = HapParser::CreateResConfigFromKeyParams(keyParams);
163 if (SkipParseItem(key, match)) {
164 match = false;
165 return OK;
166 }
167
168 uint32_t idOffset = key->offset_;
169 std::shared_ptr<ResId> id = std::make_shared<ResId>();
170 if (id == nullptr) {
171 RESMGR_HILOGE(RESMGR_TAG, "new ResId failed when ParseKey");
172 return SYS_ERROR;
173 }
174 int32_t ret = ParseId(idOffset, id);
175 if (ret != OK) {
176 return ret;
177 }
178 key->resId_ = id;
179 return OK;
180 }
181
getKeyParams(uint32_t & offset,uint32_t paramsCount,bool & match,std::vector<bool> & keyTypes,std::vector<std::shared_ptr<KeyParam>> & keyParams)182 bool HapParserV1::getKeyParams(uint32_t &offset, uint32_t paramsCount, bool &match, std::vector<bool> &keyTypes,
183 std::vector<std::shared_ptr<KeyParam>> &keyParams)
184 {
185 std::string locale;
186 bool isLocale = false;
187 for (uint32_t i = 0; i < paramsCount; ++i) {
188 std::shared_ptr<KeyParam> kp;
189 if (ParseKeyParam(offset, match, kp) != OK) {
190 return false;
191 }
192 if (kp == nullptr) {
193 return false;
194 }
195 GetLimitKeyValue(kp->type_, keyTypes);
196 GetKeyParamsLocales(kp, locale, isLocale);
197 keyParams.push_back(kp);
198 }
199 if (isLocale) {
200 locales_.emplace(locale);
201 }
202 return true;
203 }
204
ParseKeyParam(uint32_t & offset,bool & match,std::shared_ptr<KeyParam> & kp)205 int32_t HapParserV1::ParseKeyParam(uint32_t &offset, bool &match, std::shared_ptr<KeyParam> &kp)
206 {
207 kp = std::make_shared<KeyParam>();
208 if (kp == nullptr) {
209 RESMGR_HILOGE(RESMGR_TAG, "ParseKeyParam new KeyParam failed");
210 return SYS_ERROR;
211 }
212 if (offset + KeyParam::KEYPARAM_LEN > bufLen_) {
213 RESMGR_HILOGE(RESMGR_TAG, "ParseKeyParam failed, the offset will be out of bounds");
214 return SYS_ERROR;
215 }
216 errno_t eret = memcpy_s(kp.get(), sizeof(KeyParam), buffer_.get() + offset, KeyParam::KEYPARAM_LEN);
217 if (eret != OK) {
218 return SYS_ERROR;
219 }
220 offset += KeyParam::KEYPARAM_LEN;
221 kp->InitStr();
222 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
223 auto resDeviceType = kp->GetDeviceTypeStr();
224 deviceTypes_.push_back(deviceType_);
225 if (deviceType_ != DEVICE_DEFAULT && resDeviceType != NOT_DEVICE_TYPE &&
226 find(deviceTypes_.begin(), deviceTypes_.end(), resDeviceType) == deviceTypes_.end()) {
227 match = false;
228 }
229 #endif
230 return OK;
231 }
232
GetLimitKeyValue(KeyType type,std::vector<bool> & keyTypes)233 void HapParserV1::GetLimitKeyValue(KeyType type, std::vector<bool> &keyTypes)
234 {
235 const uint32_t limitKeysBase = 0x00000001;
236 uint32_t typeValue = static_cast<uint32_t>(type);
237 if (type < KeyType::KEY_TYPE_MAX && !keyTypes[typeValue]) {
238 keyTypes[typeValue] = true;
239 limitKeyValue_ |= limitKeysBase << typeValue;
240 }
241 }
242
SkipParseItem(const std::shared_ptr<ResKey> & key,bool & match)243 bool HapParserV1::SkipParseItem(const std::shared_ptr<ResKey> &key, bool &match)
244 {
245 if (!match || (selectedTypes_ != SELECT_ALL &&
246 defaultConfig_ != nullptr && !defaultConfig_->Match(key->resConfig_, false))) {
247 return true;
248 }
249
250 if (loadAll_) {
251 return false;
252 }
253
254 if (!key->resConfig_->GetLocaleInfo()) {
255 return isUpdate_;
256 }
257
258 if (defaultConfig_ != nullptr && defaultConfig_->MatchLocal(*key->resConfig_)) {
259 return false;
260 }
261 return true;
262 }
263
ParseId(uint32_t & offset,std::shared_ptr<ResId> id)264 int32_t HapParserV1::ParseId(uint32_t &offset, std::shared_ptr<ResId> id)
265 {
266 if (offset + ResId::RESID_HEADER_LEN > bufLen_) {
267 RESMGR_HILOGE(RESMGR_TAG, "Parse ResIdHeader failed, the offset will be out of bounds");
268 return SYS_ERROR;
269 }
270 errno_t eret = memcpy_s(id.get(), sizeof(ResId), buffer_.get() + offset, ResId::RESID_HEADER_LEN);
271 if (eret != OK) {
272 return SYS_ERROR;
273 }
274 offset += ResId::RESID_HEADER_LEN;
275 if (id->tag_[ArrayIndex::INDEX_ZERO] != 'I' || id->tag_[ArrayIndex::INDEX_ONE] != 'D'
276 || id->tag_[ArrayIndex::INDEX_TWO] != 'S' || id->tag_[ArrayIndex::INDEX_THREE] != 'S') {
277 return -1;
278 }
279 for (uint32_t i = 0; i < id->count_; ++i) {
280 std::shared_ptr<IdParam> ip = std::make_shared<IdParam>();
281 if (ip == nullptr) {
282 RESMGR_HILOGE(RESMGR_TAG, "new IdParam failed when ParseId");
283 return SYS_ERROR;
284 }
285 if (offset + ResId::IDPARAM_HEADER_LEN > bufLen_) {
286 RESMGR_HILOGE(RESMGR_TAG, "Parse IdParam failed, the offset will be out of bounds");
287 return SYS_ERROR;
288 }
289 errno_t eret = memcpy_s(ip.get(), sizeof(IdParam), buffer_.get() + offset, ResId::IDPARAM_HEADER_LEN);
290 if (eret != OK) {
291 return SYS_ERROR;
292 }
293 offset += ResId::IDPARAM_HEADER_LEN;
294 std::shared_ptr<IdItem> idItem = std::make_shared<IdItem>();
295 if (idItem == nullptr) {
296 RESMGR_HILOGE(RESMGR_TAG, "new IdItem failed when ParseId");
297 return SYS_ERROR;
298 }
299 uint32_t ipOffset = ip->offset_;
300 int32_t ret = ParseIdItem(ipOffset, idItem);
301 if (ret != OK) {
302 return ret;
303 }
304 ip->idItem_ = idItem;
305 id->idParams_.push_back(ip);
306 }
307 return OK;
308 }
309
ConvertType(ResType type)310 uint32_t ConvertType(ResType type)
311 {
312 auto it = TYPE_MAP.find(type);
313 if (it == TYPE_MAP.end()) {
314 return SELECT_ALL;
315 }
316 return it->second;
317 }
318
ParseIdItem(uint32_t & offset,std::shared_ptr<IdItem> idItem)319 int32_t HapParserV1::ParseIdItem(uint32_t &offset, std::shared_ptr<IdItem> idItem)
320 {
321 if (offset + IdItem::HEADER_LEN > bufLen_) {
322 RESMGR_HILOGE(RESMGR_TAG, "Parse IdItemHeader failed, the offset will be out of bounds");
323 return SYS_ERROR;
324 }
325 errno_t eret = memcpy_s(idItem.get(), sizeof(IdItem), buffer_.get() + offset, IdItem::HEADER_LEN);
326 if (eret != OK) {
327 return SYS_ERROR;
328 }
329 if (selectedTypes_ != SELECT_ALL && (selectedTypes_ & ConvertType(idItem->resType_)) == 0) {
330 return OK;
331 }
332 offset += IdItem::HEADER_LEN;
333
334 idItem->JudgeArray();
335 if (idItem->isArray_) {
336 int32_t ret = ParseStringArray(offset, idItem->values_);
337 if (ret != OK) {
338 return ret;
339 }
340 } else {
341 int32_t ret = ParseString(offset, idItem->value_);
342 if (ret != OK) {
343 return ret;
344 }
345 idItem->valueLen_ = idItem->value_.size();
346 }
347 int32_t ret = ParseString(offset, idItem->name_);
348 if (ret != OK) {
349 return ret;
350 }
351 return OK;
352 }
353
ParseStringArray(uint32_t & offset,std::vector<std::string> & values)354 int32_t HapParserV1::ParseStringArray(uint32_t &offset, std::vector<std::string> &values)
355 {
356 uint16_t arrLen;
357 if (offset + IdItem::SIZE_LEN > bufLen_) {
358 RESMGR_HILOGE(RESMGR_TAG, "ParseStringArray failed, the offset will be out of bounds");
359 return SYS_ERROR;
360 }
361 errno_t eret = memcpy_s(&arrLen, sizeof(arrLen), buffer_.get() + offset, IdItem::SIZE_LEN);
362 if (eret != OK) {
363 return SYS_ERROR;
364 }
365 offset += IdItem::SIZE_LEN; // Offset value plus 2
366 // next arrLen bytes are several strings. then after, is one '\0'
367 uint32_t startOffset = offset;
368 std::string value;
369 while (true) {
370 int32_t ret = ParseString(offset, value, false);
371 if (ret != OK) {
372 return ret;
373 }
374 values.push_back(value);
375
376 uint32_t readSize = offset - startOffset;
377 if (readSize + 1 == arrLen) {
378 offset += 1; // after arrLen, got '\0'
379 break;
380 }
381 if (readSize + 1 > arrLen) {
382 // size not match, cannot > arrLen
383 return SYS_ERROR;
384 }
385 }
386 return OK;
387 }
388
ParseString(uint32_t & offset,std::string & id,bool includeTemi)389 int32_t HapParserV1::ParseString(uint32_t &offset, std::string &id, bool includeTemi)
390 {
391 uint16_t strLen;
392 if (offset + IdItem::SIZE_LEN > bufLen_) {
393 RESMGR_HILOGE(RESMGR_TAG, "ParseString length failed, the offset will be out of bounds");
394 return SYS_ERROR;
395 }
396 errno_t eret = memcpy_s(&strLen, sizeof(strLen), buffer_.get() + offset, IdItem::SIZE_LEN);
397 if (eret != OK || (includeTemi && strLen == 0)) {
398 return SYS_ERROR;
399 }
400 offset += IdItem::SIZE_LEN; // Offset value plus 2
401 if (offset + (includeTemi ? (strLen - 1) : strLen) > bufLen_) {
402 RESMGR_HILOGE(RESMGR_TAG, "ParseString value failed, the offset will be out of bounds");
403 return SYS_ERROR;
404 }
405 std::string tmp = std::string(reinterpret_cast<char *>(buffer_.get()) + offset,
406 includeTemi ? (strLen - 1) : strLen);
407 offset += includeTemi ? strLen : (strLen + 1);
408 id = tmp;
409 return OK;
410 }
411
GetHapResource(const char * path,bool isSystem,bool isOverlay)412 std::shared_ptr<HapResource> HapParserV1::GetHapResource(const char *path, bool isSystem, bool isOverlay)
413 {
414 std::shared_ptr<HapResourceV1> pResource = std::make_shared<HapResourceV1>(path, 0, resDesc_, isSystem, isOverlay);
415 if (pResource == nullptr || !pResource->Init(defaultConfig_)) {
416 return nullptr;
417 }
418 pResource->SetLimitKeysValue(limitKeyValue_);
419 pResource->SetLocales(locales_);
420 pResource->SetSelectedType(selectedTypes_);
421 return pResource;
422 }
423 } // namespace Resource
424 } // namespace Global
425 } // namespace OHOS
426