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