1 /*
2 * Copyright (c) 2021 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.h"
16 #include <algorithm>
17 #include <bitset>
18 #include <cerrno>
19 #include <climits>
20 #include <filesystem>
21 #include <fstream>
22 #include <iomanip>
23 #include <mutex>
24 #include <sstream>
25 #include <stdexcept>
26 #include <string>
27 #include <sys/stat.h>
28 #include <vector>
29 #include "accesstoken_kit.h"
30 #include "i18n_hilog.h"
31 #include "ipc_skeleton.h"
32 #include "locale_config.h"
33 #include "parameter.h"
34 #include "tokenid_kit.h"
35 #include "unicode/localebuilder.h"
36
37 namespace OHOS {
38 namespace Global {
39 namespace I18n {
40 using namespace std;
41 static const std::string PSEUDO_LOCALE_TAG = "en-XA";
42 static const std::string PSEUDO_START_TAG = "{";
43 static const std::string PSEUDO_END_TAG = "}";
44 static const char CHAR_A = 'A';
45 static const int32_t CHAR2INT_SIZE = 2;
46 constexpr const char *TIMEZONE_LIST_CONFIG_PATH = "/system/etc/zoneinfo/timezone_list.cfg";
47 constexpr const char *DISTRO_TIMEZONE_LIST_CONFIG = "/system/etc/tzdata_distro/timezone_list.cfg";
48 static std::mutex validLocaleMutex;
49
Split(const string & src,const string & sep,vector<string> & dest)50 void Split(const string &src, const string &sep, vector<string> &dest)
51 {
52 if (src.empty()) {
53 return;
54 }
55 string::size_type begin = 0;
56 string::size_type end = src.find(sep);
57 while (end != string::npos) {
58 dest.push_back(src.substr(begin, end - begin));
59 begin = end + sep.size();
60 end = src.find(sep, begin);
61 }
62 if (begin != src.size()) {
63 dest.push_back(src.substr(begin));
64 }
65 }
66
Split(const std::string & src,const std::string & sep,std::unordered_set<std::string> & dest)67 void Split(const std::string& src, const std::string& sep, std::unordered_set<std::string>& dest)
68 {
69 dest.clear();
70 if (src.empty()) {
71 return;
72 }
73 std::string::size_type begin = 0;
74 std::string::size_type end = src.find(sep);
75 while (end != string::npos) {
76 dest.insert(src.substr(begin, end - begin));
77 begin = end + sep.size();
78 end = src.find(sep, begin);
79 }
80 if (begin != src.size()) {
81 dest.insert(src.substr(begin));
82 }
83 }
84
Merge(const std::vector<std::string> & src,const std::string & sep,std::string & dest)85 void Merge(const std::vector<std::string>& src, const std::string& sep, std::string& dest)
86 {
87 if (src.size() == 0) {
88 dest = "";
89 return;
90 }
91 dest = src[0];
92 for (size_t i = 1; i < src.size(); ++i) {
93 dest += sep;
94 dest += src[i];
95 }
96 }
97
ReadSystemParameter(const char * paramKey,const int paramLength)98 std::string ReadSystemParameter(const char *paramKey, const int paramLength)
99 {
100 char param[paramLength];
101 int status = GetParameter(paramKey, "", param, paramLength);
102 if (status > 0) {
103 return param;
104 }
105 return "";
106 }
107
ConvertString2Int(const string & numberStr,int32_t & status,int base)108 int32_t ConvertString2Int(const string &numberStr, int32_t& status, int base)
109 {
110 if (!numberStr.empty() && std::all_of(numberStr.begin(), numberStr.end(), ::isdigit)) {
111 try {
112 return std::stoi(numberStr, nullptr, base);
113 } catch (const std::invalid_argument &except) {
114 status = -1;
115 return -1;
116 } catch (const std::out_of_range &except) {
117 status = -1;
118 return -1;
119 } catch (...) {
120 status = -1;
121 HILOG_ERROR_I18N("ConvertString2Int: unknow error. numberStr: %{public}s.", numberStr.c_str());
122 return -1;
123 }
124 } else {
125 status = -1;
126 return -1;
127 }
128 }
129
ConvertString2Double(const string & numberStr,int32_t & status)130 double ConvertString2Double(const string &numberStr, int32_t& status)
131 {
132 try {
133 return std::stod(numberStr);
134 } catch (const std::invalid_argument &except) {
135 status = -1;
136 return -1;
137 } catch (const std::out_of_range &except) {
138 status = -1;
139 return -1;
140 } catch (...) {
141 status = -1;
142 HILOG_ERROR_I18N("ConvertString2Double: unknow error. numberStr: %{public}s.", numberStr.c_str());
143 return -1;
144 }
145 }
146
IsValidLocaleTag(icu::Locale & locale)147 bool IsValidLocaleTag(icu::Locale &locale)
148 {
149 static std::unordered_set<std::string> allValidLocalesLanguageTag;
150 GetAllValidLocalesTag(allValidLocalesLanguageTag);
151 std::string languageTag = locale.getLanguage() == nullptr ? "" : locale.getLanguage();
152 if (allValidLocalesLanguageTag.find(languageTag) == allValidLocalesLanguageTag.end()) {
153 HILOG_ERROR_I18N("GetTimePeriodName does not support this languageTag: %{public}s", languageTag.c_str());
154 return false;
155 }
156 return true;
157 }
158
GetAllValidLocalesTag(std::unordered_set<std::string> & allValidLocalesLanguageTag)159 void GetAllValidLocalesTag(std::unordered_set<std::string>& allValidLocalesLanguageTag)
160 {
161 static bool init = false;
162 if (init) {
163 return;
164 }
165 std::lock_guard<std::mutex> matchLocaleLock(validLocaleMutex);
166 if (init) {
167 return;
168 }
169 int32_t validCount = 1;
170 const icu::Locale *validLocales = icu::Locale::getAvailableLocales(validCount);
171 if (validLocales == nullptr) {
172 return;
173 }
174 for (int i = 0; i < validCount; i++) {
175 const char* language = validLocales[i].getLanguage();
176 if (language != nullptr) {
177 allValidLocalesLanguageTag.insert(language);
178 }
179 }
180 init = true;
181 }
182
GetAbsoluteFilePath(const std::string & filePath)183 std::string GetAbsoluteFilePath(const std::string &filePath)
184 {
185 if (filePath.empty()) {
186 HILOG_ERROR_I18N("utils::GetAbsoluteFilePath: input param filePath is empty");
187 return "";
188 }
189 char* result = realpath(filePath.c_str(), nullptr);
190 if (result == nullptr) {
191 HILOG_ERROR_I18N("utils::GetAbsoluteFilePath realpath error, error message: %{public}s.", strerror(errno));
192 return "";
193 }
194 std::ifstream file(result);
195 if (!file.good()) {
196 free(result);
197 HILOG_ERROR_I18N("utils::GetAbsoluteFilePath file open is not good.");
198 return "";
199 }
200 std::string absolutePath(result);
201 free(result);
202 result = nullptr;
203 return absolutePath;
204 }
205
StrReplaceAll(const std::string & str,const std::string & target,const std::string & replace)206 std::string StrReplaceAll(const std::string& str,
207 const std::string& target, const std::string& replace)
208 {
209 std::string::size_type pos = 0;
210 std::string result = str;
211 if (replace.empty() || target.compare(replace) == 0) {
212 return result;
213 }
214 while ((pos = result.find(target)) != std::string::npos) {
215 result.replace(pos, target.length(), replace);
216 }
217 return result;
218 }
219
GetISO3Language(const string & language)220 std::string GetISO3Language(const string& language)
221 {
222 UErrorCode icuStatus = U_ZERO_ERROR;
223 icu::Locale locale = icu::Locale::forLanguageTag(language.data(), icuStatus);
224 if (U_FAILURE(icuStatus) || !IsValidLocaleTag(locale)) {
225 return "";
226 }
227 return locale.getISO3Language();
228 }
229
GetISO3Country(const string & country)230 std::string GetISO3Country(const string& country)
231 {
232 UErrorCode icuStatus = U_ZERO_ERROR;
233 icu::Locale locale;
234 if (LocaleConfig::IsValidRegion(country)) {
235 locale = icu::LocaleBuilder().setLanguage("zh").setRegion(country).build(icuStatus);
236 } else if (LocaleConfig::IsValidTag(country)) {
237 locale = icu::Locale::forLanguageTag(country.data(), icuStatus);
238 } else {
239 return "";
240 }
241 if (U_FAILURE(icuStatus) || !IsValidLocaleTag(locale)) {
242 return "";
243 }
244 return locale.getISO3Country();
245 }
246
FileExist(const std::string & path)247 bool FileExist(const std::string& path)
248 {
249 bool status = false;
250 try {
251 status = std::filesystem::exists(path.c_str());
252 } catch (const std::filesystem::filesystem_error &except) {
253 HILOG_ERROR_I18N("utils: FileExist failed because filesystem_error, error message: %{public}s.",
254 except.code().message().c_str());
255 return false;
256 } catch (const std::__h::__fs::filesystem::filesystem_error &except) {
257 HILOG_ERROR_I18N("utils: FileExist failed because filesystem_error, error message: %{public}s.",
258 except.code().message().c_str());
259 return false;
260 } catch (const std::bad_alloc &except) {
261 HILOG_ERROR_I18N("utils: FileExist failed because bad_alloc, error message: %{public}s.",
262 except.what());
263 return false;
264 }
265 return status;
266 }
267
FileCopy(const std::string & srcPath,const std::string & dstPath)268 bool FileCopy(const std::string& srcPath, const std::string& dstPath)
269 {
270 try {
271 std::filesystem::copy(srcPath.c_str(), dstPath.c_str());
272 return true;
273 } catch (const std::filesystem::filesystem_error &except) {
274 HILOG_ERROR_I18N("utils: FileCopy failed because filesystem_error, error message: %{public}s.",
275 except.code().message().c_str());
276 } catch (const std::__h::__fs::filesystem::filesystem_error &except) {
277 HILOG_ERROR_I18N("utils: FileCopy failed because filesystem_error, error message: %{public}s.",
278 except.code().message().c_str());
279 } catch (const std::bad_alloc &except) {
280 HILOG_ERROR_I18N("utils: FileCopy failed because bad_alloc, error message: %{public}s.",
281 except.what());
282 }
283 return false;
284 }
285
IsLegalPath(const std::string & path)286 bool IsLegalPath(const std::string& path)
287 {
288 if (path.find("./") != std::string::npos ||
289 path.find("../") != std::string::npos) {
290 return false;
291 }
292 return true;
293 }
294
IsDirExist(const char * path)295 bool IsDirExist(const char *path)
296 {
297 if (!(path && *path)) {
298 return false;
299 }
300 size_t length = strlen(path);
301 if (length > PATH_MAX) {
302 return false;
303 }
304 char resolvedPath[PATH_MAX];
305 if (realpath(path, resolvedPath) == nullptr) {
306 return false;
307 }
308 struct stat buf;
309 return stat(resolvedPath, &buf) == 0 && S_ISDIR(buf.st_mode);
310 }
311
ClearDir(const std::filesystem::path & dirPath)312 void ClearDir(const std::filesystem::path& dirPath)
313 {
314 std::error_code errCode;
315 for (const auto& entry : std::filesystem::directory_iterator(dirPath)) {
316 std::filesystem::remove_all(entry.path(), errCode);
317 if (errCode) {
318 HILOG_ERROR_I18N("ClearDir: Error removing file: %{public}s, Error: %{public}s", entry.path().c_str(),
319 errCode.message().c_str());
320 }
321 }
322 }
323
trim(std::string & s)324 std::string trim(std::string &s)
325 {
326 if (s.empty()) {
327 return s;
328 }
329 s.erase(0, s.find_first_not_of(" "));
330 s.erase(s.find_last_not_of(" ") + 1);
331 return s;
332 }
333
GetPseudoLocalizationEnforce()334 bool GetPseudoLocalizationEnforce()
335 {
336 std::string systemLocale = LocaleConfig::GetSystemLocale();
337 if (systemLocale.compare(PSEUDO_LOCALE_TAG) == 0) {
338 return true;
339 }
340 return false;
341 }
342
PseudoLocalizationProcessor(const std::string & input)343 std::string PseudoLocalizationProcessor(const std::string &input)
344 {
345 return PseudoLocalizationProcessor(input, GetPseudoLocalizationEnforce());
346 }
347
PseudoLocalizationProcessor(const std::string & input,bool ifEnforce)348 std::string PseudoLocalizationProcessor(const std::string &input, bool ifEnforce)
349 {
350 if (ifEnforce) {
351 return PSEUDO_START_TAG + input + PSEUDO_END_TAG;
352 }
353 return input;
354 }
355
CheckSystemPermission()356 bool CheckSystemPermission()
357 {
358 uint64_t tokenId = IPCSkeleton::GetCallingFullTokenID();
359 uint32_t callerToken = IPCSkeleton::GetCallingTokenID();
360 bool isSystemApp = Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(tokenId);
361 Security::AccessToken::ATokenTypeEnum tokenType =
362 Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callerToken);
363 bool isShell = tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_SHELL;
364 bool isNative = tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE;
365 if (!isSystemApp && !isShell && !isNative) {
366 HILOG_ERROR_I18N("CheckSystemPermission failed, because current app is not system app.");
367 return false;
368 }
369 return true;
370 }
371
GetTimeZoneAvailableIDs(I18nErrorCode & errorCode)372 std::set<std::string> GetTimeZoneAvailableIDs(I18nErrorCode &errorCode)
373 {
374 if (availableIDs.size() != 0) {
375 return availableIDs;
376 }
377 struct stat s;
378 const char *tzIdConfigPath = stat(DISTRO_TIMEZONE_LIST_CONFIG, &s) == 0 ?
379 DISTRO_TIMEZONE_LIST_CONFIG : TIMEZONE_LIST_CONFIG_PATH;
380 std::string absolutePath = GetAbsoluteFilePath(tzIdConfigPath);
381 if (absolutePath.empty()) {
382 HILOG_ERROR_I18N("GetTimeZoneAvailableIDs: check file %{public}s failed.", tzIdConfigPath);
383 return availableIDs;
384 }
385 std::unique_ptr<char[]> resolvedPath = std::make_unique<char[]>(PATH_MAX + 1);
386 if (realpath(tzIdConfigPath, resolvedPath.get()) == nullptr) {
387 HILOG_ERROR_I18N("Get realpath failed, errno: %{public}d.", errno);
388 return availableIDs;
389 }
390 std::ifstream file(resolvedPath.get());
391 if (!file.good()) {
392 HILOG_ERROR_I18N("Open timezone list config file failed.");
393 return availableIDs;
394 }
395 std::string line;
396 while (std::getline(file, line)) {
397 if (line.length() == 0) {
398 break;
399 }
400 line.resize(line.find_last_not_of("\r\n") + 1);
401 availableIDs.insert(line);
402 }
403 file.close();
404 return availableIDs;
405 }
406
RegexSearchNoExcept(const std::string & str,std::smatch & match,const std::regex & regex)407 bool RegexSearchNoExcept(const std::string& str, std::smatch& match, const std::regex& regex)
408 {
409 try {
410 return std::regex_search(str, match, regex);
411 } catch (const std::regex_error &except) {
412 HILOG_ERROR_I18N("RegexSearchNoExcept: regex_error caught %{public}s.", except.what());
413 return false;
414 }
415 }
416
LocaleEncode(const std::string & locale)417 std::string LocaleEncode(const std::string& locale)
418 {
419 std::stringstream ss;
420 for (auto& c : locale) {
421 int32_t number = (c == '-') ? 0 : static_cast<int32_t>(c) - static_cast<int32_t>(CHAR_A) + 1;
422 ss << std::setw(CHAR2INT_SIZE) << std::setfill('0') << number;
423 }
424 return ss.str();
425 }
426
Eq(double a,double b)427 bool Eq(double a, double b)
428 {
429 return fabs(a - b) < 1e-6;
430 }
431
Geq(double a,double b)432 bool Geq(double a, double b)
433 {
434 return a > b || Eq(a, b);
435 }
436
Leq(double a,double b)437 bool Leq(double a, double b)
438 {
439 return a < b || Eq(a, b);
440 }
441
StrToHex(const std::string & text,size_t num)442 std::string StrToHex(const std::string& text, size_t num)
443 {
444 std::string binary;
445 for (auto i : text) {
446 // 8-bit binary.
447 bitset<8> bs(i);
448 binary += bs.to_string();
449 }
450 int32_t status = 0;
451 // 2 means binary.
452 int32_t convertNum = ConvertString2Int(binary, status, 2);
453 if (status != 0) {
454 HILOG_ERROR_I18N("StrToHex: convert %{public}s to number error", binary.c_str());
455 return "";
456 }
457 std::stringstream ss;
458 ss << std::hex << std::setw(num) << std::setfill('0') << convertNum;
459 std::string hex;
460 ss >> hex;
461 return hex;
462 }
463
HexToStr(const std::string & hex)464 std::string HexToStr(const std::string& hex)
465 {
466 // The length of hex must be a multiple of 2.
467 size_t len = 2;
468 if (hex.length() % len != 0) {
469 return "";
470 }
471
472 bool flag = true;
473 std::string result;
474 for (size_t i = 0; i < hex.length(); i += len) {
475 std::string hexStr = hex.substr(i, len);
476 if (flag && hexStr.compare("00") == 0) {
477 continue;
478 }
479 flag = false;
480 int32_t value = 0;
481 try {
482 value = std::stoi(hexStr, nullptr, 16); // 16 represents hexadecimal.
483 } catch (const std::invalid_argument &except) {
484 HILOG_ERROR_I18N("HexToStr: invalid_argument, hexStr: %{public}s.", hexStr.c_str());
485 return "";
486 } catch (const std::out_of_range &except) {
487 HILOG_ERROR_I18N("HexToStr: out_of_range, hexStr: %{public}s.", hexStr.c_str());
488 return "";
489 } catch (...) {
490 HILOG_ERROR_I18N("HexToStr: unknow error, hexStr: %{public}s.", hexStr.c_str());
491 return "";
492 }
493 result += char(value);
494 }
495 return result;
496 }
497 } // namespace I18n
498 } // namespace Global
499 } // namespace OHOS