• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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