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 #include "utils/utils.h"
16 
17 #include <fstream>
18 #include <vector>
19 #include <sys/stat.h>
20 #include "hilog_wrapper.h"
21 #ifdef __LINUX__
22 #include <cstring>
23 #endif
24 
25 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
26 #include "hitrace_meter.h"
27 #endif
28 
29 #ifdef __WINNT__
30 #include <shlwapi.h>
31 #include <windows.h>
32 #undef ERROR
33 #endif
34 
35 namespace OHOS {
36 namespace Global {
37 namespace Resource {
38 constexpr int ERROR_RESULT = -1;
39 
40 const std::set<std::string> Utils::tailSet {
41     ".hap",
42     ".hsp",
43 };
44 
45 std::vector<char> g_codes = {
46     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
47     'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
48     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
49     'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
50     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
51 };
52 
GetMediaBase64Data(const std::string& iconPath, std::string &base64Data)53 RState Utils::GetMediaBase64Data(const std::string& iconPath, std::string &base64Data)
54 {
55     size_t len = 0;
56     auto tempData = Utils::LoadResourceFile(iconPath, len);
57     if (tempData == nullptr) {
58         RESMGR_HILOGE(RESMGR_TAG, "get the tempData error");
59         return NOT_FOUND;
60     }
61     auto pos = iconPath.find_last_of('.');
62     std::string imgType;
63     if (pos != std::string::npos) {
64         imgType = iconPath.substr(pos + 1);
65     }
66     Utils::EncodeBase64(tempData, len, imgType, base64Data);
67     return SUCCESS;
68 }
69 
LoadResourceFile(const std::string &path, size_t &len)70 std::unique_ptr<uint8_t[]> Utils::LoadResourceFile(const std::string &path, size_t &len)
71 {
72     std::ifstream mediaStream(path, std::ios::binary);
73     if (!mediaStream.is_open()) {
74         return nullptr;
75     }
76     mediaStream.seekg(0, std::ios::end);
77     int length = mediaStream.tellg();
78     if (length == ERROR_RESULT) {
79         RESMGR_HILOGE(RESMGR_TAG, "failed to get the file length");
80         return nullptr;
81     } else {
82         len = static_cast<size_t>(length);
83     }
84     std::unique_ptr<uint8_t[]> tempData = std::make_unique<uint8_t[]>(len);
85     if (tempData == nullptr) {
86         return nullptr;
87     }
88     mediaStream.seekg(0, std::ios::beg);
89     mediaStream.read(reinterpret_cast<char *>(tempData.get()), len);
90     return tempData;
91 }
92 
EncodeBase64(std::unique_ptr<uint8_t[]> &data, int srcLen, const std::string &imgType, std::string &dstData)93 RState Utils::EncodeBase64(std::unique_ptr<uint8_t[]> &data, int srcLen,
94     const std::string &imgType, std::string &dstData)
95 {
96     const unsigned char *srcData = data.get();
97     if (srcData == nullptr) {
98         return ERROR;
99     }
100     std::string base64data;
101     base64data += "data:image/" + imgType + ";base64,";
102     int i = 0;
103     // encode in groups of every 3 bytes
104     for (; i <= srcLen - 3; i += 3) {
105         unsigned char byte1 = static_cast<unsigned char>(srcData[i]);
106         unsigned char byte2 = static_cast<unsigned char>(srcData[i + 1]);
107         unsigned char byte3 = static_cast<unsigned char>(srcData[i + 2]);
108         base64data += g_codes[byte1 >> BitOperatorNum::BIT_TWO];
109         base64data += g_codes[((byte1 & 0x3) << BitOperatorNum::BIT_FOUR) | (byte2 >> BitOperatorNum::BIT_FOUR)];
110         base64data += g_codes[((byte2 & 0xF) << BitOperatorNum::BIT_TWO) | (byte3 >> BitOperatorNum::BIT_SIX)];
111         base64data += g_codes[byte3 & 0x3F];
112     }
113 
114     if (i >= srcLen) {
115         dstData = base64data;
116         return SUCCESS;
117     }
118 
119     // Handle the case where there is one element left
120     if (srcLen % ArrayLen::LEN_THREE == 1) {
121         unsigned char byte1 = static_cast<unsigned char>(srcData[i]);
122         base64data += g_codes[byte1 >> BitOperatorNum::BIT_TWO];
123         base64data += g_codes[(byte1 & 0x3) << BitOperatorNum::BIT_FOUR];
124         base64data += '=';
125         base64data += '=';
126     } else if (srcLen % ArrayLen::LEN_THREE == ArrayIndex::INDEX_TWO) {
127         unsigned char byte1 = static_cast<unsigned char>(srcData[i]);
128         unsigned char byte2 = static_cast<unsigned char>(srcData[i + 1]);
129         base64data += g_codes[byte1 >> BitOperatorNum::BIT_TWO];
130         base64data += g_codes[((byte1 & 0x3) << BitOperatorNum::BIT_FOUR) | (byte2 >> BitOperatorNum::BIT_FOUR)];
131         base64data += g_codes[(byte2 & 0xF) << BitOperatorNum::BIT_TWO];
132         base64data += '=';
133     }
134     dstData = base64data;
135     return SUCCESS;
136 }
137 
IsAlphaString(const char *s, int32_t len)138 bool Utils::IsAlphaString(const char *s, int32_t len)
139 {
140     if (s == nullptr) {
141         return false;
142     }
143     int32_t i;
144     for (i = 0; i < len; i++) {
145         char c = *(s + i);
146         if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
147             return false;
148         }
149     }
150     return true;
151 }
152 
IsNumericString(const char *s, int32_t len)153 bool Utils::IsNumericString(const char *s, int32_t len)
154 {
155     if (s == nullptr) {
156         return false;
157     }
158     int32_t i;
159     for (i = 0; i < len; i++) {
160         char c = *(s + i);
161         if (!(c >= '0' && c <= '9')) {
162             return false;
163         }
164     }
165 
166     return true;
167 }
168 
169 /**
170  * @brief decode 32 bits as script array.
171  * 31-24 bits is script[0]
172  * 23-16 bits is script[1]
173  * 15-8 bits is script[2]
174  * 0-7 bits is script[3]
175  *
176  * @param encodeScript
177  * @param outValue
178  */
DecodeScript(uint32_t encodeScript, char *outValue)179 void Utils::DecodeScript(uint32_t encodeScript, char *outValue)
180 {
181     if (outValue == nullptr) {
182         return;
183     }
184     outValue[ArrayIndex::INDEX_ZERO] = (encodeScript & 0xFF000000) >> BitOperatorNum::BIT_TWENTY_FOUR;
185     outValue[ArrayIndex::INDEX_ONE] = (encodeScript & 0x00FF0000) >> BitOperatorNum::BIT_SIXTEEN;
186     outValue[ArrayIndex::INDEX_TWO] = (encodeScript & 0x0000FF00) >> BitOperatorNum::BIT_EIGHT;
187     outValue[ArrayIndex::INDEX_THREE] = (encodeScript & 0x000000FF);
188 }
189 
IsStrEmpty(const char *s)190 bool Utils::IsStrEmpty(const char *s)
191 {
192     return (s == nullptr || *s == '\0');
193 }
194 
StrLen(const char *s)195 size_t Utils::StrLen(const char *s)
196 {
197     if (s == nullptr) {
198         return 0;
199     }
200     return strlen(s);
201 }
202 
EncodeLanguage(const char *language)203 uint16_t Utils::EncodeLanguage(const char *language)
204 {
205     if (Utils::IsStrEmpty(language)) {
206         return NULL_LANGUAGE;
207     }
208     return Utils::EncodeLanguageOrRegion(language, 'a');
209 }
210 
211 /**
212  * @brief  locale compose of language,script and region,encode as 64bits.
213  * 63-48 bits represent language,detail format see EncodeLanguageOrRegion method
214  * 47-16 bits represent script,detail format see EncodeScript method
215  * 15-0 bits represent region,detail format see EncodeLanguageOrRegion method
216  *
217  * @param language
218  * @param script
219  * @param region
220  * @return uint64_t
221  */
EncodeLocale(const char *language, const char *script, const char *region)222 uint64_t Utils::EncodeLocale(const char *language,
223                              const char *script,
224                              const char *region)
225 {
226     uint16_t languageData = Utils::EncodeLanguage(language);
227     uint32_t scriptData = Utils::EncodeScript(script);
228     uint16_t regionData = Utils::EncodeRegion(region);
229 
230     return (uint64_t)(0xffff000000000000 & (((uint64_t)languageData) << BitOperatorNum::BIT_FORTY_EIGHT)) |
231            (0x0000ffffffff0000 & (((uint64_t)scriptData) << BitOperatorNum::BIT_SIXTEEN)) |
232            (0x000000000000ffff & (uint64_t)(regionData));
233 }
234 
EncodeRegionByResLocale(const ResLocale *locale)235 uint16_t Utils::EncodeRegionByResLocale(const ResLocale *locale)
236 {
237     if (locale == nullptr) {
238         return NULL_REGION;
239     }
240     return Utils::EncodeRegion(locale->GetRegion());
241 }
242 
EncodeLanguageByResLocale(const ResLocale *locale)243 uint16_t Utils::EncodeLanguageByResLocale(const ResLocale *locale)
244 {
245     if (locale == nullptr) {
246         return NULL_LANGUAGE;
247     }
248     return Utils::EncodeLanguage(locale->GetLanguage());
249 }
250 
EncodeScriptByResLocale(const ResLocale *locale)251 uint32_t Utils::EncodeScriptByResLocale(const ResLocale *locale)
252 {
253     if (locale == nullptr) {
254         return NULL_SCRIPT;
255     }
256     return Utils::EncodeScript(locale->GetScript());
257 }
258 
EncodeRegion(const char *region)259 uint16_t Utils::EncodeRegion(const char *region)
260 {
261     if (Utils::IsStrEmpty(region)) {
262         return NULL_REGION;
263     }
264     if (region[0] >= '0' && region[0] <= '9') {
265         return Utils::EncodeLanguageOrRegion(region, '0');
266     }
267     return Utils::EncodeLanguageOrRegion(region, 'A');
268 }
269 
270 /**
271  * @brief script is four letter array.encode script array as four bytes.Encode format.
272  * 31-24 bits represent script[0]
273  * 23-16 bits represent script[1]
274  * 15-8 bits represent script[2]
275  * 0-7 bits represent script[3]
276  *
277  * @param script
278  * @return uint32_t
279  */
EncodeScript(const char *script)280 uint32_t Utils::EncodeScript(const char *script)
281 {
282     if (Utils::IsStrEmpty(script)) {
283         return NULL_SCRIPT;
284     }
285     return ((uint8_t)script[ArrayIndex::INDEX_ZERO] << BitOperatorNum::BIT_TWENTY_FOUR) |
286         ((uint8_t)script[ArrayIndex::INDEX_ONE] << BitOperatorNum::BIT_SIXTEEN) |
287         ((uint8_t)script[ArrayIndex::INDEX_TWO] << BitOperatorNum::BIT_EIGHT) |
288         (uint8_t)script[ArrayIndex::INDEX_THREE];
289 }
290 
291 /**
292  * @brief encode language or region str as two byte.
293  * language is two or three lowercase.
294  * region is two capital  letter or three digit.
295  *
296  * two char,encode format
297  * 15-8 bits is the first char
298  * 7-0 bits is the second char
299  *
300  * three chars,encode format
301  * 15 bit is 1
302  * 14-10 bits represent the value of  the first char subtract base char,
303  * 9-5 bits represent the value of the second char subtract base char  .
304  * 4-0 bits represent the value of the third char subtract base char.
305  * base char is 'a','A','0'.
306  * example when base is 'a',max value('z' - 'a') is 26,so five bits can represent a char.
307  *
308  * @param str
309  * @param base is '0' or 'a' or 'A'
310  * @return uint16_t
311  */
EncodeLanguageOrRegion(const char *str, char base)312 uint16_t Utils::EncodeLanguageOrRegion(const char *str, char base)
313 {
314     if (str[ArrayIndex::INDEX_TWO] == 0 || str[ArrayIndex::INDEX_TWO] == '-' || str[ArrayIndex::INDEX_TWO] == '_') {
315         return ((uint8_t)str[ArrayIndex::INDEX_ZERO] << BitOperatorNum::BIT_EIGHT) |
316             ((uint8_t)str[ArrayIndex::INDEX_ONE]);
317     }
318     uint8_t first = ((uint8_t)(str[ArrayIndex::INDEX_ZERO] - base)) & 0x7f;
319     uint8_t second = ((uint8_t)(str[ArrayIndex::INDEX_ONE] - base)) & 0x7f;
320     uint8_t third = ((uint8_t)(str[ArrayIndex::INDEX_TWO] - base)) & 0x7f;
321     return ((0x80 | (first << BitOperatorNum::BIT_TWO) | (second >> BitOperatorNum::BIT_THREE)) <<
322         BitOperatorNum::BIT_EIGHT) | ((second << BitOperatorNum::BIT_FIVE) | third);
323 };
324 
325 /**
326  * @brief convert hex char as int value
327  *
328  * @param c
329  * @param state
330  * @return uint32_t
331  */
ParseHex(char c, RState &state)332 static uint32_t ParseHex(char c, RState &state)
333 {
334     if (c >= '0' && c <= '9') {
335         return (c - '0');
336     } else if (c >= 'a' && c <= 'f') {
337         return (c - 'a' + 0xa);
338     } else if (c >= 'A' && c <= 'F') {
339         return (c - 'A' + 0xa);
340     }
341     state = INVALID_FORMAT;
342     return -1;
343 }
344 
ConvertColorRgbToUInt32(const char *s, uint32_t &color, RState &parseState)345 void ConvertColorRgbToUInt32(const char *s, uint32_t &color, RState &parseState)
346 {
347     color |= 0xFF000000;
348     color |= ParseHex(s[ArrayIndex::INDEX_ONE], parseState) << BitOperatorNum::BIT_TWENTY;
349     color |= ParseHex(s[ArrayIndex::INDEX_ONE], parseState) << BitOperatorNum::BIT_SIXTEEN;
350     color |= ParseHex(s[ArrayIndex::INDEX_TWO], parseState) << BitOperatorNum::BIT_TWELVE;
351     color |= ParseHex(s[ArrayIndex::INDEX_TWO], parseState) << BitOperatorNum::BIT_EIGHT;
352     color |= ParseHex(s[ArrayIndex::INDEX_THREE], parseState) << BitOperatorNum::BIT_FOUR;
353     color |= ParseHex(s[ArrayIndex::INDEX_THREE], parseState);
354 }
355 
ConvertColorArgbToUInt32(const char *s, uint32_t &color, RState &parseState)356 void ConvertColorArgbToUInt32(const char *s, uint32_t &color, RState &parseState)
357 {
358     color |= ParseHex(s[ArrayIndex::INDEX_ONE], parseState) << BitOperatorNum::BIT_TWENTY_EIGHT;
359     color |= ParseHex(s[ArrayIndex::INDEX_ONE], parseState) << BitOperatorNum::BIT_TWENTY_FOUR;
360     color |= ParseHex(s[ArrayIndex::INDEX_TWO], parseState) << BitOperatorNum::BIT_TWENTY;
361     color |= ParseHex(s[ArrayIndex::INDEX_TWO], parseState) << BitOperatorNum::BIT_SIXTEEN;
362     color |= ParseHex(s[ArrayIndex::INDEX_THREE], parseState) << BitOperatorNum::BIT_TWELVE;
363     color |= ParseHex(s[ArrayIndex::INDEX_THREE], parseState) << BitOperatorNum::BIT_EIGHT;
364     color |= ParseHex(s[ArrayIndex::INDEX_FOUR], parseState) << BitOperatorNum::BIT_FOUR;
365     color |= ParseHex(s[ArrayIndex::INDEX_FOUR], parseState);
366 }
367 
ConvertColorSixRgbToUInt32(const char *s, uint32_t &color, RState &parseState)368 void ConvertColorSixRgbToUInt32(const char *s, uint32_t &color, RState &parseState)
369 {
370     color |= 0xFF000000;
371     color |= ParseHex(s[ArrayIndex::INDEX_ONE], parseState) << BitOperatorNum::BIT_TWENTY;
372     color |= ParseHex(s[ArrayIndex::INDEX_TWO], parseState) << BitOperatorNum::BIT_SIXTEEN;
373     color |= ParseHex(s[ArrayIndex::INDEX_THREE], parseState) << BitOperatorNum::BIT_TWELVE;
374     color |= ParseHex(s[ArrayIndex::INDEX_FOUR], parseState) << BitOperatorNum::BIT_EIGHT;
375     color |= ParseHex(s[ArrayIndex::INDEX_FIVE], parseState) << BitOperatorNum::BIT_FOUR;
376     color |= ParseHex(s[ArrayIndex::INDEX_SIX], parseState);
377 }
378 
ConvertColorEightRgbToUInt32(const char *s, uint32_t &color, RState &parseState)379 void ConvertColorEightRgbToUInt32(const char *s, uint32_t &color, RState &parseState)
380 {
381     color |= ParseHex(s[ArrayIndex::INDEX_ONE], parseState) << BitOperatorNum::BIT_TWENTY_EIGHT;
382     color |= ParseHex(s[ArrayIndex::INDEX_TWO], parseState) << BitOperatorNum::BIT_TWENTY_FOUR;
383     color |= ParseHex(s[ArrayIndex::INDEX_THREE], parseState) << BitOperatorNum::BIT_TWENTY;
384     color |= ParseHex(s[ArrayIndex::INDEX_FOUR], parseState) << BitOperatorNum::BIT_SIXTEEN;
385     color |= ParseHex(s[ArrayIndex::INDEX_FIVE], parseState) << BitOperatorNum::BIT_TWELVE;
386     color |= ParseHex(s[ArrayIndex::INDEX_SIX], parseState) << BitOperatorNum::BIT_EIGHT;
387     color |= ParseHex(s[ArrayIndex::INDEX_SEVEN], parseState) << BitOperatorNum::BIT_FOUR;
388     color |= ParseHex(s[ArrayIndex::INDEX_EIGHT], parseState);
389 }
390 
391 /**
392  * @brief  convert color string to 32 bits value 0xaarrggbb.
393  * color string format is
394  * #rgb  red (0-f) greed(0-f) blue(0-f)
395  * #argb transparency(0-f)  red (0-f) greed(0-f) blue(0-f)
396  * #rrggbb red (00-ff) greed(00-ff) blue(00-ff)
397  * #aarrggbb transparency(00-ff) red (00-ff) greed(00-ff) blue(00-ff)
398  *
399  * @param s
400  * @param outValue
401  * @return RState
402  */
ConvertColorToUInt32(const char *s, uint32_t &outValue)403 RState Utils::ConvertColorToUInt32(const char *s, uint32_t &outValue)
404 {
405     if (s == nullptr) {
406         return INVALID_FORMAT;
407     }
408     uint32_t color = 0;
409     RState parseState = SUCCESS;
410     size_t len = strlen(s);
411     if (*s == '#') {
412         if (len == ArrayLen::LEN_FOUR) {
413             ConvertColorRgbToUInt32(s, color, parseState);
414         } else if (len == ArrayLen::LEN_FIVE) {
415             ConvertColorArgbToUInt32(s, color, parseState);
416         } else if (len == ArrayLen::LEN_SEVEN) {
417             ConvertColorSixRgbToUInt32(s, color, parseState);
418         } else if (len == ArrayLen::LEN_NINE) {
419             ConvertColorEightRgbToUInt32(s, color, parseState);
420         } else {
421             return INVALID_FORMAT;
422         }
423     } else {
424         parseState = INVALID_FORMAT;
425     }
426     outValue = color;
427     return parseState;
428 }
429 
endWithTail(const std::string& path, const std::string& tail)430 bool Utils::endWithTail(const std::string& path, const std::string& tail)
431 {
432     if (path.size() < tail.size()) {
433         RESMGR_HILOGE(RESMGR_TAG, "the path is shorter than tail");
434         return false;
435     }
436     return path.compare(path.size() - tail.size(), tail.size(), tail) == 0;
437 }
438 
IsFileExist(const std::string& filePath)439 bool Utils::IsFileExist(const std::string& filePath)
440 {
441     struct stat buffer;
442     return (stat(filePath.c_str(), &buffer) == 0);
443 }
444 
ContainsTail(std::string hapPath, std::set<std::string> tailSet)445 bool Utils::ContainsTail(std::string hapPath, std::set<std::string> tailSet)
446 {
447     for (auto tail : tailSet) {
448         if (Utils::endWithTail(hapPath, tail)) {
449             return true;
450         }
451     }
452     return false;
453 }
454 
CanonicalizePath(const char *path, char *outPath, size_t len)455 void Utils::CanonicalizePath(const char *path, char *outPath, size_t len)
456 {
457 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
458     HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
459 #endif
460     if (path == nullptr) {
461         RESMGR_HILOGE(RESMGR_TAG, "path is null");
462         return;
463     }
464     if (strlen(path) >= len) {
465         RESMGR_HILOGE(RESMGR_TAG, "the length of path longer than len");
466         return;
467     }
468 #ifdef __WINNT__
469     if (!PathCanonicalizeA(outPath, path)) {
470         RESMGR_HILOGE(RESMGR_TAG, "failed to canonicalize the path");
471         return;
472     }
473 #else
474     if (realpath(path, outPath) == nullptr) {
475         RESMGR_HILOGE(RESMGR_TAG, "failed to realpath the path, %{public}s, errno:%{public}d", path, errno);
476         return;
477     }
478 #endif
479 }
480 
GetFiles(const std::string &strCurrentDir, std::vector<std::string> &vFiles)481 RState Utils::GetFiles(const std::string &strCurrentDir, std::vector<std::string> &vFiles)
482 {
483 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__)
484     char outPath[PATH_MAX + 1] = {0};
485     Utils::CanonicalizePath(strCurrentDir.c_str(), outPath, PATH_MAX);
486     if (outPath[0] == '\0') {
487         RESMGR_HILOGE(RESMGR_TAG, "invalid path, %{public}s", strCurrentDir.c_str());
488         return ERROR_CODE_RES_PATH_INVALID;
489     }
490     DIR *dir;
491     struct dirent *pDir;
492     if ((dir = opendir(strCurrentDir.c_str())) == nullptr) {
493         RESMGR_HILOGE(RESMGR_TAG, "opendir failed strCurrentDir = %{public}s", strCurrentDir.c_str());
494         return ERROR_CODE_RES_PATH_INVALID;
495     }
496     while ((pDir = readdir(dir)) != nullptr) {
497         if (strcmp(pDir->d_name, ".") == 0 || strcmp(pDir->d_name, "..") == 0) {
498             continue;
499         }
500         if (pDir->d_type != DT_REG && pDir->d_type != DT_DIR) {
501             continue;
502         }
503         vFiles.emplace_back(pDir->d_name);
504     }
505     closedir(dir);
506 #endif
507     return SUCCESS;
508 }
509 } // namespace Resource
510 } // namespace Global
511 } // namespace OHOS
512