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
36 namespace OHOS {
37 namespace Global {
38 namespace I18n {
39 using namespace std;
40 static const std::string PSEUDO_LOCALE_TAG = "en-XA";
41 static const std::string PSEUDO_START_TAG = "{";
42 static const std::string PSEUDO_END_TAG = "}";
43 constexpr const char *TIMEZONE_LIST_CONFIG_PATH = "/system/etc/zoneinfo/timezone_list.cfg";
44 constexpr const char *DISTRO_TIMEZONE_LIST_CONFIG = "/system/etc/tzdata_distro/timezone_list.cfg";
45 static std::mutex validLocaleMutex;
46
Split(const string &src, const string &sep, vector<string> &dest)47 void 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
Merge(const std::vector<std::string>& src, const std::string& sep, std::string& dest)64 void 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
ReadSystemParameter(const char *paramKey, const int paramLength)77 std::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
ConvertString2Int(const string &numberStr, int32_t& status)87 int32_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
IsValidLocaleTag(icu::Locale &locale)109 bool 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
GetAllValidLocalesTag(std::unordered_set<std::string>& allValidLocalesLanguageTag)121 void 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
CheckTzDataFilePath(const std::string &filePath)142 bool 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
StrReplaceAll(const std::string& str, const std::string& target, const std::string& replace)161 std::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
GetISO3Language(const string& language)175 std::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
GetISO3Country(const string& country)185 std::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
FileExist(const std::string& path)202 bool 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
FileCopy(const std::string& srcPath, const std::string& dstPath)223 bool 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
IsLegalPath(const std::string& path)241 bool 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
IsDirExist(const char *path)250 bool 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
trim(std::string &s)267 std::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
GetPseudoLocalizationEnforce()277 bool 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
PseudoLocalizationProcessor(const std::string &input)286 std::string PseudoLocalizationProcessor(const std::string &input)
287 {
288 return PseudoLocalizationProcessor(input, GetPseudoLocalizationEnforce());
289 }
290
PseudoLocalizationProcessor(const std::string &input, bool ifEnforce)291 std::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
CheckSystemPermission()299 bool 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
GetTimeZoneAvailableIDs(I18nErrorCode &errorCode)315 std::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
RegexSearchNoExcept(const std::string& str, std::smatch& match, const std::regex& regex)345 bool 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