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 <algorithm>
19 #include <cstdlib>
20 #include <iostream>
21 #include <string>
22 #include <unzip.h>
23 #include <zip.h>
24 #include <zlib.h>
25
26 #include "hilog_wrapper.h"
27 #include "locale_matcher.h"
28 #include "securec.h"
29 #include "utils/common.h"
30 #include "utils/errors.h"
31 #include "utils/string_utils.h"
32
33 namespace OHOS {
34 namespace Global {
35 namespace Resource {
36 const char *HapParser::RES_FILE_NAME = "/resources.index";
37
UnzCloseFileAndLog(unzFile uf,const char * zipFile)38 void UnzCloseFileAndLog(unzFile uf, const char *zipFile)
39 {
40 int err = unzCloseCurrentFile(uf); // close the zipfile
41 if (err != UNZ_OK) {
42 HILOG_ERROR("Error %d with zipfile %s in unzCloseCurrentFile", err, zipFile);
43 }
44 }
45
ReadFileFromZip(const char * zipFile,const char * fileName,void ** buffer,size_t & bufLen,std::string & errInfo)46 int32_t HapParser::ReadFileFromZip(const char *zipFile, const char *fileName, void **buffer, size_t &bufLen,
47 std::string &errInfo)
48 {
49 int err = UNZ_OK; // error status
50 char filenameInzip[256]; // for unzGetCurrentFileInfo
51 unz_file_info fileInfo; // for unzGetCurrentFileInfo
52
53 unzFile uf = unzOpen64(zipFile); // open zipfile stream
54 if (uf == nullptr) {
55 errInfo = FormatString("Cannot open %s", zipFile);
56 return UNKNOWN_ERROR;
57 } // file is open
58
59 if (unzLocateFile(uf, fileName, 1)) { // try to locate file inside zip
60 // second argument of unzLocateFile: 1 = case sensitive, 0 = case-insensitive
61 unzClose(uf);
62 errInfo = FormatString("File %s not found in %s", fileName, zipFile);
63 return UNKNOWN_ERROR;
64 } // file inside zip found
65
66 if (unzGetCurrentFileInfo(uf, &fileInfo, filenameInzip, sizeof(filenameInzip), nullptr, 0, nullptr, 0)) {
67 unzClose(uf);
68 errInfo = FormatString("Error %d with zipfile %s in unzGetCurrentFileInfo.", err, zipFile);
69 return UNKNOWN_ERROR;
70 } // obtained the necessary details about file inside zip
71
72 *buffer = static_cast<void *>(malloc(fileInfo.uncompressed_size)); // setup buffer
73 bufLen = fileInfo.uncompressed_size;
74 if ((*buffer) == nullptr) {
75 unzClose(uf);
76 errInfo = FormatString("Error allocating memory for read buffer");
77 return UNKNOWN_ERROR;
78 } // buffer ready
79
80 err = unzOpenCurrentFilePassword(uf, nullptr); // Open the file inside the zip (password = NULL)
81 if (err != UNZ_OK) {
82 errInfo = FormatString("Error %d with zipfile %s in unzOpenCurrentFilePassword.", err, zipFile);
83 free(*buffer);
84 *buffer = nullptr;
85 unzClose(uf);
86 return UNKNOWN_ERROR;
87 } // file inside the zip is open
88 // Copy contents of the file inside the zip to the buffer
89 HILOG_DEBUG("Extracting: %s from %s, file size: %lu", filenameInzip, zipFile, fileInfo.uncompressed_size);
90 err = unzReadCurrentFile(uf, *buffer, bufLen);
91 if (err < 0) {
92 errInfo = FormatString("Error %d with zipfile %s in unzReadCurrentFile", err, zipFile);
93 free(*buffer);
94 *buffer = nullptr;
95 UnzCloseFileAndLog(uf, zipFile); // close the zipfile
96 unzClose(uf);
97 return UNKNOWN_ERROR;
98 }
99
100 UnzCloseFileAndLog(uf, zipFile); // close the zipfile
101 unzClose(uf);
102 return OK;
103 }
104
GetModuleName(const char * configStr)105 std::string GetModuleName(const char *configStr)
106 {
107 std::string config(configStr);
108 static const char *key = "\"moduleName\"";
109 auto idx = config.find(key);
110 if (idx == std::string::npos) {
111 return std::string();
112 }
113 auto start = config.find("\"", idx + strlen(key));
114 if (start == std::string::npos) {
115 return std::string();
116 }
117 auto end = config.find("\"", start + 1);
118 if (end == std::string::npos) {
119 return std::string();
120 }
121
122 std::string retStr = std::string(configStr + start + 1, end - start - 1);
123 return retStr;
124 }
125
ReadIndexFromFile(const char * zipFile,void ** buffer,size_t & bufLen,std::string & errInfo)126 int32_t HapParser::ReadIndexFromFile(const char *zipFile, void **buffer,
127 size_t &bufLen, std::string &errInfo)
128 {
129 void *tmpBuf = nullptr;
130 size_t tmpLen;
131 std::string tmp;
132 int32_t ret = ReadFileFromZip(zipFile, "config.json", &tmpBuf, tmpLen, tmp);
133 if (ret != OK) {
134 errInfo = "read config.json error";
135 HILOG_ERROR("read config.json error");
136 return ret;
137 }
138
139 // parse config.json
140 std::string mName = GetModuleName(static_cast<char *>(tmpBuf));
141 if (mName.size() == 0) {
142 errInfo = "parse moduleName from config.json error";
143 free(tmpBuf);
144 return UNKNOWN_ERROR;
145 }
146 free(tmpBuf);
147 std::string indexFilePath = std::string("assets/");
148 indexFilePath.append(mName);
149 indexFilePath.append(RES_FILE_NAME);
150
151 return ReadFileFromZip(zipFile, indexFilePath.c_str(), buffer, bufLen, errInfo);
152 }
153
154 /**
155 *
156 * @param buffer
157 * @param offset
158 * @param id
159 * @param includeTemi dose length include '\0'
160 * @return OK or ERROR
161 */
ParseString(const char * buffer,uint32_t & offset,std::string & id,bool includeTemi=true)162 int32_t ParseString(const char *buffer, uint32_t &offset, std::string &id, bool includeTemi = true)
163 {
164 uint16_t strLen;
165 errno_t eret = memcpy_s(&strLen, sizeof(strLen), buffer + offset, 2);
166 if (eret != EOK) {
167 return SYS_ERROR;
168 }
169 offset += 2;
170 std::string tmp = std::string(const_cast<char *>(buffer) + offset, includeTemi ? (strLen - 1) : strLen);
171 offset += includeTemi ? strLen : (strLen + 1);
172 id = tmp;
173 return OK;
174 }
175
176 /**
177 *
178 * @param buffer
179 * @param offset
180 * @param values
181 * @return
182 */
ParseStringArray(const char * buffer,uint32_t & offset,std::vector<std::string> & values)183 int32_t ParseStringArray(const char *buffer, uint32_t &offset, std::vector<std::string> &values)
184 {
185 uint16_t arrLen;
186 errno_t eret = memcpy_s(&arrLen, sizeof(arrLen), buffer + offset, 2);
187 if (eret != EOK) {
188 return SYS_ERROR;
189 }
190 offset += 2;
191 // next arrLen bytes are several strings. then after, is one '\0'
192 uint32_t startOffset = offset;
193 while (true) {
194 std::string value;
195 int32_t ret = ParseString(buffer, offset, value, false);
196 if (ret != OK) {
197 return ret;
198 }
199 values.push_back(value);
200
201 uint32_t readSize = offset - startOffset;
202 if (readSize + 1 == arrLen) {
203 offset += 1; // after arrLen, got '\0'
204 break;
205 }
206 if (readSize + 1 > arrLen) {
207 // size not match, cannot > arrLen
208 return SYS_ERROR;
209 }
210 }
211
212 return OK;
213 }
214
ParseIdItem(const char * buffer,uint32_t & offset,IdItem * idItem)215 int32_t ParseIdItem(const char *buffer, uint32_t &offset, IdItem *idItem)
216 {
217 errno_t eret = memcpy_s(idItem, sizeof(IdItem), buffer + offset, IdItem::HEADER_LEN);
218 if (eret != EOK) {
219 return SYS_ERROR;
220 }
221 offset += IdItem::HEADER_LEN;
222
223 idItem->JudgeArray();
224 if (idItem->isArray_) {
225 int32_t ret = ParseStringArray(buffer, offset, idItem->values_);
226 if (ret != OK) {
227 return ret;
228 }
229 } else {
230 std::string value;
231 int32_t ret = ParseString(buffer, offset, value);
232 if (ret != OK) {
233 return ret;
234 }
235 idItem->value_ = std::string(value);
236 idItem->valueLen_ = value.size();
237 }
238 std::string name;
239 int32_t ret = ParseString(buffer, offset, name);
240 if (ret != OK) {
241 return ret;
242 }
243 idItem->name_ = std::string(name);
244 return OK;
245 }
246
ParseId(const char * buffer,uint32_t & offset,ResId * id)247 int32_t ParseId(const char *buffer, uint32_t &offset, ResId *id)
248 {
249 errno_t eret = memcpy_s(id, sizeof(ResId), buffer + offset, ResId::RESID_HEADER_LEN);
250 if (eret != EOK) {
251 return SYS_ERROR;
252 }
253 offset += ResId::RESID_HEADER_LEN;
254 if (id->tag_[0] != 'I' || id->tag_[1] != 'D'
255 || id->tag_[2] != 'S' || id->tag_[3] != 'S') {
256 return -1;
257 }
258 for (uint32_t i = 0; i < id->count_; ++i) {
259 IdParam *ip = new (std::nothrow) IdParam();
260 if (ip == nullptr) {
261 HILOG_ERROR("new IdParam failed when ParseId");
262 return SYS_ERROR;
263 }
264 errno_t eret = memcpy_s(ip, sizeof(IdParam), buffer + offset, ResId::IDPARAM_HEADER_LEN);
265 if (eret != EOK) {
266 delete (ip);
267 return SYS_ERROR;
268 }
269 offset += ResId::IDPARAM_HEADER_LEN;
270 IdItem *idItem = new (std::nothrow) IdItem();
271 if (idItem == nullptr) {
272 HILOG_ERROR("new IdItem failed when ParseId");
273 delete (ip);
274 return SYS_ERROR;
275 }
276 uint32_t ipOffset = ip->offset_;
277 int32_t ret = ParseIdItem(buffer, ipOffset, idItem);
278 if (ret != OK) {
279 delete (ip);
280 delete (idItem);
281 return ret;
282 }
283 ip->idItem_ = idItem;
284 id->idParams_.push_back(ip);
285 }
286
287 return OK;
288 }
289
IsLocaleMatch(const ResConfigImpl * defaultConfig,const std::vector<KeyParam * > & keyParams)290 bool IsLocaleMatch(const ResConfigImpl *defaultConfig, const std::vector<KeyParam *> &keyParams)
291 {
292 if (defaultConfig != nullptr) {
293 ResConfigImpl *config = HapParser::CreateResConfigFromKeyParams(keyParams);
294 if (config == nullptr) {
295 return SYS_ERROR;
296 }
297 if (!LocaleMatcher::Match(defaultConfig->GetResLocale(), config->GetResLocale())) {
298 HILOG_DEBUG("mismatch, do not parse %s", HapParser::ToFolderPath(keyParams).c_str());
299 delete (config);
300 return false;
301 }
302 delete (config);
303 }
304 return true;
305 }
306
ParseKey(const char * buffer,uint32_t & offset,ResKey * key,bool & match,const ResConfigImpl * defaultConfig)307 int32_t ParseKey(const char *buffer, uint32_t &offset, ResKey *key,
308 bool &match, const ResConfigImpl *defaultConfig)
309 {
310 errno_t eret = memcpy_s(key, sizeof(ResKey), buffer + offset, ResKey::RESKEY_HEADER_LEN);
311 if (eret != EOK) {
312 return SYS_ERROR;
313 }
314 offset += ResKey::RESKEY_HEADER_LEN;
315 if (key->tag_[0] != 'K' || key->tag_[1] != 'E'
316 || key->tag_[2] != 'Y' || key->tag_[3] != 'S') {
317 return -1;
318 }
319 for (uint32_t i = 0; i < key->keyParamsCount_; ++i) {
320 KeyParam *kp = new (std::nothrow) KeyParam();
321 if (kp == nullptr) {
322 HILOG_ERROR("new KeyParam failed when ParseKey");
323 return SYS_ERROR;
324 }
325 errno_t eret = memcpy_s(kp, sizeof(KeyParam), buffer + offset, ResKey::KEYPARAM_HEADER_LEN);
326 if (eret != EOK) {
327 delete (kp);
328 return SYS_ERROR;
329 }
330 offset += ResKey::KEYPARAM_HEADER_LEN;
331 kp->InitStr();
332 key->keyParams_.push_back(kp);
333 }
334 match = IsLocaleMatch(defaultConfig, key->keyParams_);
335 if (!match) {
336 return OK;
337 }
338 uint32_t idOffset = key->offset_;
339 ResId *id = new (std::nothrow) ResId();
340 if (id == nullptr) {
341 HILOG_ERROR("new ResId failed when ParseKey");
342 return SYS_ERROR;
343 }
344 int32_t ret = ParseId(buffer, idOffset, id);
345 if (ret != OK) {
346 delete (id);
347 return ret;
348 }
349 key->resId_ = id;
350 return OK;
351 }
352
353
ParseResHex(const char * buffer,const size_t bufLen,ResDesc & resDesc,const ResConfigImpl * defaultConfig)354 int32_t HapParser::ParseResHex(const char *buffer, const size_t bufLen, ResDesc &resDesc,
355 const ResConfigImpl *defaultConfig)
356 {
357 ResHeader *resHeader = new (std::nothrow) ResHeader();
358 if (resHeader == nullptr) {
359 HILOG_ERROR("new ResHeader failed when ParseResHex");
360 return SYS_ERROR;
361 }
362 uint32_t offset = 0;
363 errno_t eret = memcpy_s(resHeader, sizeof(ResHeader), buffer + offset, RES_HEADER_LEN);
364 if (eret != EOK) {
365 delete (resHeader);
366 return SYS_ERROR;
367 }
368 offset += RES_HEADER_LEN;
369 if (resHeader->keyCount_ == 0 || resHeader->length_ == 0) {
370 delete (resHeader);
371 return UNKNOWN_ERROR;
372 }
373
374 resDesc.resHeader_ = resHeader;
375 for (uint32_t i = 0; i < resHeader->keyCount_; i++) {
376 ResKey *key = new (std::nothrow) ResKey();
377 if (key == nullptr) {
378 HILOG_ERROR("new ResKey failed when ParseResHex");
379 return SYS_ERROR;
380 }
381 bool match = true;
382 int32_t ret = ParseKey(buffer, offset, key, match, defaultConfig);
383 if (ret != OK) {
384 delete (key);
385 return ret;
386 }
387 if (match) {
388 resDesc.keys_.push_back(key);
389 } else {
390 delete (key);
391 }
392 }
393 return OK;
394 }
395
CreateResConfigFromKeyParams(const std::vector<KeyParam * > & keyParams)396 ResConfigImpl *HapParser::CreateResConfigFromKeyParams(const std::vector<KeyParam *> &keyParams)
397 {
398 ResConfigImpl *resConfig = new (std::nothrow) ResConfigImpl;
399 if (resConfig == nullptr) {
400 HILOG_ERROR("new ResConfigImpl failed when CreateResConfigFromKeyParams");
401 return nullptr;
402 }
403 size_t len = keyParams.size();
404 // default path
405 if (len == 0) {
406 return resConfig;
407 }
408 size_t i = 0;
409 const char *language = nullptr;
410 const char *script = nullptr;
411 const char *region = nullptr;
412 ScreenDensity screenDensity = SCREEN_DENSITY_NOT_SET;
413 Direction direction = DIRECTION_NOT_SET;
414 DeviceType deviceType = DEVICE_NOT_SET;
415
416 for (i = 0; i < len; ++i) {
417 const KeyParam *kp = keyParams.at(i);
418 if (kp->type_ == LANGUAGES) {
419 language = kp->GetStr().c_str();
420 } else if (kp->type_ == REGION) {
421 region = kp->GetStr().c_str();
422 } else if (kp->type_ == SCRIPT) {
423 script = kp->GetStr().c_str();
424 } else if (kp->type_ == SCREEN_DENSITY) {
425 screenDensity = GetScreenDensity(kp->value_);
426 } else if (kp->type_ == DEVICETYPE) {
427 deviceType = GetDeviceType(kp->value_);
428 } else if (kp->type_ == DIRECTION) {
429 if (kp->value_ == 0) {
430 direction = DIRECTION_VERTICAL;
431 } else {
432 direction = DIRECTION_HORIZONTAL;
433 }
434 }
435 }
436 resConfig->SetDeviceType(deviceType);
437 resConfig->SetDirection(direction);
438 resConfig->SetScreenDensity(screenDensity);
439 RState r = resConfig->SetLocaleInfo(language, script, region);
440 if (r != SUCCESS) {
441 HILOG_ERROR("error set locale,lang %s,script %s,region %s", language, script,
442 region);
443 }
444
445 return resConfig;
446 }
447
GetDeviceType(uint32_t value)448 DeviceType HapParser::GetDeviceType(uint32_t value)
449 {
450 DeviceType deviceType = DEVICE_NOT_SET;
451 if (value == DEVICE_CAR) {
452 deviceType = DEVICE_CAR;
453 } else if (value == DEVICE_PAD) {
454 deviceType = DEVICE_PAD;
455 } else if (value == DEVICE_PHONE) {
456 deviceType = DEVICE_PHONE;
457 } else if (value == DEVICE_TABLET) {
458 deviceType = DEVICE_TABLET;
459 } else if (value == DEVICE_TV) {
460 deviceType = DEVICE_TV;
461 } else if (value == DEVICE_WEARABLE) {
462 deviceType = DEVICE_WEARABLE;
463 }
464 return deviceType;
465 }
466
GetScreenDensity(uint32_t value)467 ScreenDensity HapParser::GetScreenDensity(uint32_t value)
468 {
469 ScreenDensity screenDensity = SCREEN_DENSITY_NOT_SET;
470 if (value == SCREEN_DENSITY_SDPI) {
471 screenDensity = SCREEN_DENSITY_SDPI;
472 } else if (value == SCREEN_DENSITY_MDPI) {
473 screenDensity = SCREEN_DENSITY_MDPI;
474 } else if (value == SCREEN_DENSITY_LDPI) {
475 screenDensity = SCREEN_DENSITY_LDPI;
476 } else if (value == SCREEN_DENSITY_XLDPI) {
477 screenDensity = SCREEN_DENSITY_XLDPI;
478 } else if (value == SCREEN_DENSITY_XXLDPI) {
479 screenDensity = SCREEN_DENSITY_XXLDPI;
480 } else if (value == SCREEN_DENSITY_XXXLDPI) {
481 screenDensity = SCREEN_DENSITY_XXXLDPI;
482 }
483 return screenDensity;
484 }
485
PathAppend(std::string & path,const std::string & append,const std::string & connector)486 void PathAppend(std::string &path, const std::string &append, const std::string &connector)
487 {
488 if (append.size() > 0) {
489 if (path.size() > 0) {
490 path.append(connector);
491 }
492 path.append(append);
493 }
494 }
495
ToFolderPath(const std::vector<KeyParam * > & keyParams)496 std::string HapParser::ToFolderPath(const std::vector<KeyParam *> &keyParams)
497 {
498 if (keyParams.size() == 0) {
499 return std::string("default");
500 }
501 // language_script_region-direction-deviceType-screenDensity
502 std::string language;
503 std::string script;
504 std::string region;
505 std::string direction;
506 std::string deviceType;
507 std::string screenDensity;
508 for (size_t i = 0; i < keyParams.size(); ++i) {
509 KeyParam *keyParam = keyParams[i];
510 switch (keyParam->type_) {
511 case KeyType::LANGUAGES:
512 language = keyParam->GetStr();
513 break;
514 case KeyType::SCRIPT:
515 script = keyParam->GetStr();
516 break;
517 case KeyType::REGION:
518 region = keyParam->GetStr();
519 break;
520 case KeyType::DIRECTION:
521 direction = keyParam->GetStr();
522 break;
523 case KeyType::DEVICETYPE:
524 deviceType = keyParam->GetStr();
525 break;
526 case KeyType::SCREEN_DENSITY:
527 screenDensity = keyParam->GetStr();
528 break;
529 default:
530 break;
531 }
532 }
533 std::string path;
534 if (language.size() > 0) {
535 path.append(language);
536 }
537 std::string c1("_");
538 std::string c2("-");
539 PathAppend(path, script, c1);
540 PathAppend(path, region, c1);
541 PathAppend(path, direction, c2);
542 PathAppend(path, deviceType, c2);
543 PathAppend(path, screenDensity, c2);
544
545 return path;
546 }
547 } // namespace Resource
548 } // namespace Global
549 } // namespace OHOS