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 16#include <cerrno> 17#include <algorithm> 18#include <climits> 19#include <filesystem> 20#include <fstream> 21#include <dirent.h> 22#include <mutex> 23#include <stdexcept> 24#include <string> 25#include <sys/stat.h> 26#include <vector> 27#include "accesstoken_kit.h" 28#include "i18n_hilog.h" 29#include "ipc_skeleton.h" 30#include "locale_config.h" 31#include "parameter.h" 32#include "tokenid_kit.h" 33#include "unicode/localebuilder.h" 34#include "utils.h" 35 36namespace OHOS { 37namespace Global { 38namespace I18n { 39using namespace std; 40static const std::string PSEUDO_LOCALE_TAG = "en-XA"; 41static const std::string PSEUDO_START_TAG = "{"; 42static const std::string PSEUDO_END_TAG = "}"; 43constexpr const char *TIMEZONE_LIST_CONFIG_PATH = "/system/etc/zoneinfo/timezone_list.cfg"; 44constexpr const char *DISTRO_TIMEZONE_LIST_CONFIG = "/system/etc/tzdata_distro/timezone_list.cfg"; 45static std::mutex validLocaleMutex; 46 47void Split(const string &src, const string &sep, vector<string> &dest) 48{ 49 if (src == "") { 50 return; 51 } 52 string::size_type begin = 0; 53 string::size_type end = src.find(sep); 54 while (end != string::npos) { 55 dest.push_back(src.substr(begin, end - begin)); 56 begin = end + sep.size(); 57 end = src.find(sep, begin); 58 } 59 if (begin != src.size()) { 60 dest.push_back(src.substr(begin)); 61 } 62} 63 64void Merge(const std::vector<std::string>& src, const std::string& sep, std::string& dest) 65{ 66 if (src.size() == 0) { 67 dest = ""; 68 return; 69 } 70 dest = src[0]; 71 for (size_t i = 1; i < src.size(); ++i) { 72 dest += sep; 73 dest += src[i]; 74 } 75} 76 77std::string ReadSystemParameter(const char *paramKey, const int paramLength) 78{ 79 char param[paramLength]; 80 int status = GetParameter(paramKey, "", param, paramLength); 81 if (status > 0) { 82 return param; 83 } 84 return ""; 85} 86 87int32_t ConvertString2Int(const string &numberStr, int32_t& status) 88{ 89 if (!numberStr.empty() && std::all_of(numberStr.begin(), numberStr.end(), ::isdigit)) { 90 try { 91 return std::stoi(numberStr); 92 } catch (const std::invalid_argument &except) { 93 status = -1; 94 return -1; 95 } catch (const std::out_of_range &except) { 96 status = -1; 97 return -1; 98 } catch (...) { 99 status = -1; 100 HILOG_ERROR_I18N("ConvertString2Int: unknow error. numberStr: %{public}s.", numberStr.c_str()); 101 return -1; 102 } 103 } else { 104 status = -1; 105 return -1; 106 } 107} 108 109bool IsValidLocaleTag(icu::Locale &locale) 110{ 111 static std::unordered_set<std::string> allValidLocalesLanguageTag; 112 GetAllValidLocalesTag(allValidLocalesLanguageTag); 113 std::string languageTag = locale.getLanguage() == nullptr ? "" : locale.getLanguage(); 114 if (allValidLocalesLanguageTag.find(languageTag) == allValidLocalesLanguageTag.end()) { 115 HILOG_ERROR_I18N("GetTimePeriodName does not support this languageTag: %{public}s", languageTag.c_str()); 116 return false; 117 } 118 return true; 119} 120 121void GetAllValidLocalesTag(std::unordered_set<std::string>& allValidLocalesLanguageTag) 122{ 123 static bool init = false; 124 if (init) { 125 return; 126 } 127 std::lock_guard<std::mutex> matchLocaleLock(validLocaleMutex); 128 if (init) { 129 return; 130 } 131 int32_t validCount = 1; 132 const icu::Locale *validLocales = icu::Locale::getAvailableLocales(validCount); 133 for (int i = 0; i < validCount; i++) { 134 const char* language = validLocales[i].getLanguage(); 135 if (language != nullptr) { 136 allValidLocalesLanguageTag.insert(language); 137 } 138 } 139 init = true; 140} 141 142bool CheckTzDataFilePath(const std::string &filePath) 143{ 144 char *realpathRes = nullptr; 145 realpathRes = realpath(filePath.c_str(), nullptr); 146 if (realpathRes == nullptr) { 147 return false; 148 } 149 std::ifstream file(filePath.c_str()); 150 if (!file.good()) { 151 file.close(); 152 free(realpathRes); 153 return false; 154 } 155 file.close(); 156 free(realpathRes); 157 realpathRes = nullptr; 158 return true; 159} 160 161std::string StrReplaceAll(const std::string& str, 162 const std::string& target, const std::string& replace) 163{ 164 std::string::size_type pos = 0; 165 std::string result = str; 166 if (replace.empty() || target.compare(replace) == 0) { 167 return result; 168 } 169 while ((pos = result.find(target)) != std::string::npos) { 170 result.replace(pos, target.length(), replace); 171 } 172 return result; 173} 174 175std::string GetISO3Language(const string& language) 176{ 177 UErrorCode icuStatus = U_ZERO_ERROR; 178 icu::Locale locale = icu::Locale::forLanguageTag(language.data(), icuStatus); 179 if (U_FAILURE(icuStatus) || !IsValidLocaleTag(locale)) { 180 return ""; 181 } 182 return locale.getISO3Language(); 183} 184 185std::string GetISO3Country(const string& country) 186{ 187 UErrorCode icuStatus = U_ZERO_ERROR; 188 icu::Locale locale; 189 if (LocaleConfig::IsValidRegion(country)) { 190 locale = icu::LocaleBuilder().setLanguage("zh").setRegion(country).build(icuStatus); 191 } else if (LocaleConfig::IsValidTag(country)) { 192 locale = icu::Locale::forLanguageTag(country.data(), icuStatus); 193 } else { 194 return ""; 195 } 196 if (U_FAILURE(icuStatus) || !IsValidLocaleTag(locale)) { 197 return ""; 198 } 199 return locale.getISO3Country(); 200} 201 202bool FileExist(const std::string& path) 203{ 204 bool status = false; 205 try { 206 status = std::filesystem::exists(path.c_str()); 207 } catch (const std::filesystem::filesystem_error &except) { 208 HILOG_ERROR_I18N("utils: FileExist failed because filesystem_error, error message: %{public}s.", 209 except.code().message().c_str()); 210 return false; 211 } catch (const std::__h::__fs::filesystem::filesystem_error &except) { 212 HILOG_ERROR_I18N("utils: FileExist failed because filesystem_error, error message: %{public}s.", 213 except.code().message().c_str()); 214 return false; 215 } catch (const std::bad_alloc &except) { 216 HILOG_ERROR_I18N("utils: FileExist failed because bad_alloc, error message: %{public}s.", 217 except.what()); 218 return false; 219 } 220 return status; 221} 222 223bool FileCopy(const std::string& srcPath, const std::string& dstPath) 224{ 225 try { 226 std::filesystem::copy(srcPath.c_str(), dstPath.c_str()); 227 return true; 228 } catch (const std::filesystem::filesystem_error &except) { 229 HILOG_ERROR_I18N("utils: FileCopy failed because filesystem_error, error message: %{public}s.", 230 except.code().message().c_str()); 231 } catch (const std::__h::__fs::filesystem::filesystem_error &except) { 232 HILOG_ERROR_I18N("utils: FileCopy failed because filesystem_error, error message: %{public}s.", 233 except.code().message().c_str()); 234 } catch (const std::bad_alloc &except) { 235 HILOG_ERROR_I18N("utils: FileCopy failed because bad_alloc, error message: %{public}s.", 236 except.what()); 237 } 238 return false; 239} 240 241bool IsLegalPath(const std::string& path) 242{ 243 if (path.find("./") != std::string::npos || 244 path.find("../") != std::string::npos) { 245 return false; 246 } 247 return true; 248} 249 250bool IsDirExist(const char *path) 251{ 252 if (!(path && *path)) { 253 return false; 254 } 255 size_t length = strlen(path); 256 if (length > PATH_MAX) { 257 return false; 258 } 259 char resolvedPath[PATH_MAX]; 260 if (realpath(path, resolvedPath) == nullptr) { 261 return false; 262 } 263 struct stat buf; 264 return stat(resolvedPath, &buf) == 0 && S_ISDIR(buf.st_mode); 265} 266 267std::string trim(std::string &s) 268{ 269 if (s.empty()) { 270 return s; 271 } 272 s.erase(0, s.find_first_not_of(" ")); 273 s.erase(s.find_last_not_of(" ") + 1); 274 return s; 275} 276 277bool GetPseudoLocalizationEnforce() 278{ 279 std::string systemLocale = LocaleConfig::GetSystemLocale(); 280 if (systemLocale.compare(PSEUDO_LOCALE_TAG) == 0) { 281 return true; 282 } 283 return false; 284} 285 286std::string PseudoLocalizationProcessor(const std::string &input) 287{ 288 return PseudoLocalizationProcessor(input, GetPseudoLocalizationEnforce()); 289} 290 291std::string PseudoLocalizationProcessor(const std::string &input, bool ifEnforce) 292{ 293 if (ifEnforce) { 294 return PSEUDO_START_TAG + input + PSEUDO_END_TAG; 295 } 296 return input; 297} 298 299bool CheckSystemPermission() 300{ 301 uint64_t tokenId = IPCSkeleton::GetCallingFullTokenID(); 302 uint32_t callerToken = IPCSkeleton::GetCallingTokenID(); 303 bool isSystemApp = Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(tokenId); 304 Security::AccessToken::ATokenTypeEnum tokenType = 305 Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callerToken); 306 bool isShell = tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_SHELL; 307 bool isNative = tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE; 308 if (!isSystemApp && !isShell && !isNative) { 309 HILOG_ERROR_I18N("CheckSystemPermission failed, because current app is not system app."); 310 return false; 311 } 312 return true; 313} 314 315std::set<std::string> GetTimeZoneAvailableIDs(I18nErrorCode &errorCode) 316{ 317 if (availableIDs.size() != 0) { 318 return availableIDs; 319 } 320 struct stat s; 321 const char *tzIdConfigPath = stat(DISTRO_TIMEZONE_LIST_CONFIG, &s) == 0 ? 322 DISTRO_TIMEZONE_LIST_CONFIG : TIMEZONE_LIST_CONFIG_PATH; 323 std::unique_ptr<char[]> resolvedPath = std::make_unique<char[]>(PATH_MAX + 1); 324 if (realpath(tzIdConfigPath, resolvedPath.get()) == nullptr) { 325 HILOG_ERROR_I18N("Get realpath failed, errno: %{public}d.", errno); 326 return availableIDs; 327 } 328 std::ifstream file(resolvedPath.get()); 329 if (!file.good()) { 330 HILOG_ERROR_I18N("Open timezone list config file failed."); 331 return availableIDs; 332 } 333 std::string line; 334 while (std::getline(file, line)) { 335 if (line.length() == 0) { 336 break; 337 } 338 line.resize(line.find_last_not_of("\r\n") + 1); 339 availableIDs.insert(line); 340 } 341 file.close(); 342 return availableIDs; 343} 344 345bool RegexSearchNoExcept(const std::string& str, std::smatch& match, const std::regex& regex) 346{ 347 try { 348 return std::regex_search(str, match, regex); 349 } catch (const std::regex_error &except) { 350 return false; 351 } 352} 353} // namespace I18n 354} // namespace Global 355} // namespace OHOS