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