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