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