xref: /base/global/i18n/frameworks/intl/src/utils.cpp (revision 9596a2c1)
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