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