• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #include <regex>
16 #include "accesstoken_kit.h"
17 #ifdef TEL_CORE_SERVICE_EXISTS
18 #include "core_service_client.h"
19 #endif
20 #include <cctype>
21 #include "hilog/log.h"
22 #include "ipc_skeleton.h"
23 #include "libxml/parser.h"
24 #include "locale_info.h"
25 #include "localebuilder.h"
26 #include "locid.h"
27 #include "ohos/init_data.h"
28 #include "parameter.h"
29 #include "securec.h"
30 #include "string_ex.h"
31 #include "ucase.h"
32 #include "ulocimp.h"
33 #include "unistr.h"
34 #include "ureslocs.h"
35 #include "ustring.h"
36 #include "ustr_imp.h"
37 #include "locale_config.h"
38 
39 namespace OHOS {
40 namespace Global {
41 namespace I18n {
42 using namespace std;
43 using namespace OHOS::HiviewDFX;
44 
45 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001E00, "LocaleConfig" };
46 const char *LocaleConfig::LANGUAGE_KEY = "persist.global.language";
47 const char *LocaleConfig::LOCALE_KEY = "persist.global.locale";
48 const char *LocaleConfig::HOUR_KEY = "persist.global.is24Hour";
49 const char *LocaleConfig::DEFAULT_LOCALE_KEY = "const.global.locale";
50 const char *LocaleConfig::DEFAULT_LANGUAGE_KEY = "const.global.language";
51 const char *LocaleConfig::DEFAULT_REGION_KEY = "const.global.region";
52 const char *LocaleConfig::SUPPORTED_LOCALES_NAME = "supported_locales";
53 const char *LocaleConfig::SUPPORTED_REGIONS_NAME = "supported_regions";
54 const char *LocaleConfig::WHITE_LANGUAGES_NAME = "white_languages";
55 const char *LocaleConfig::FORBIDDEN_LANGUAGES_NAME = "forbidden_languages";
56 const char *LocaleConfig::FORBIDDEN_REGIONS_NAME = "forbidden_regions";
57 const char *LocaleConfig::FORBIDDEN_LANGUAGES_PATH = "/system/usr/ohos_locale_config/forbidden_languages.xml";
58 const char *LocaleConfig::FORBIDDEN_REGIONS_PATH = "/system/usr/ohos_locale_config/forbidden_regions.xml";
59 const char *LocaleConfig::SUPPORTED_LOCALES_PATH = "/system/usr/ohos_locale_config/supported_locales.xml";
60 const char *LocaleConfig::SUPPORTED_REGIONS_PATH = "/system/usr/ohos_locale_config/supported_regions.xml";
61 const char *LocaleConfig::WHITE_LANGUAGES_PATH = "/system/usr/ohos_locale_config/white_languages.xml";
62 const char *LocaleConfig::SUPPORT_LOCALES_PATH = "/etc/ohos_lang_config/supported_locales.xml";
63 const char *LocaleConfig::DEFAULT_LOCALE = "en-Latn";
64 const char *LocaleConfig::supportLocalesTag = "supported_locales";
65 const char *LocaleConfig::LANG_PATH = "/etc/ohos_lang_config/";
66 const char *LocaleConfig::rootTag = "languages";
67 const char *LocaleConfig::secondRootTag = "lang";
68 unordered_set<string> LocaleConfig::supportedLocales;
69 unordered_set<string> LocaleConfig::supportedRegions;
70 unordered_set<string> LocaleConfig::whiteLanguages;
71 unordered_map<string, string> LocaleConfig::dialectMap {
72     { "es-Latn-419", "es-Latn-419" },
73     { "es-Latn-BO", "es-Latn-419" },
74     { "es-Latn-BR", "es-Latn-419" },
75     { "es-Latn-BZ", "es-Latn-419" },
76     { "es-Latn-CL", "es-Latn-419" },
77     { "es-Latn-CO", "es-Latn-419" },
78     { "es-Latn-CR", "es-Latn-419" },
79     { "es-Latn-CU", "es-Latn-419" },
80     { "es-Latn-DO", "es-Latn-419" },
81     { "es-Latn-EC", "es-Latn-419" },
82     { "es-Latn-GT", "es-Latn-419" },
83     { "es-Latn-HN", "es-Latn-419" },
84     { "es-Latn-MX", "es-Latn-419" },
85     { "es-Latn-NI", "es-Latn-419" },
86     { "es-Latn-PA", "es-Latn-419" },
87     { "es-Latn-PE", "es-Latn-419" },
88     { "es-Latn-PR", "es-Latn-419" },
89     { "es-Latn-PY", "es-Latn-419" },
90     { "es-Latn-SV", "es-Latn-419" },
91     { "es-Latn-US", "es-Latn-419" },
92     { "es-Latn-UY", "es-Latn-419" },
93     { "es-Latn-VE", "es-Latn-419" },
94     { "pt-Latn-PT", "pt-Latn-PT" },
95     { "en-Latn-US", "en-Latn-US" }
96 };
97 
98 std::map<std::string, std::string> LocaleConfig::supportedDialectLocales;
99 std::map<string, string> LocaleConfig::locale2DisplayName {};
100 std::string LocaleConfig::currentDialectLocale = "";
101 
102 set<std::string> LocaleConfig::validCaTag {
103     "buddhist",
104     "chinese",
105     "coptic",
106     "dangi",
107     "ethioaa",
108     "ethiopic",
109     "gregory",
110     "hebrew",
111     "indian",
112     "islamic",
113     "islamic-umalqura",
114     "islamic-tbla",
115     "islamic-civil",
116     "islamic-rgsa",
117     "iso8601",
118     "japanese",
119     "persian",
120     "roc",
121     "islamicc",
122 };
123 set<std::string> LocaleConfig::validCoTag {
124     "big5han",
125     "compat",
126     "dict",
127     "direct",
128     "ducet",
129     "eor",
130     "gb2312",
131     "phonebk",
132     "phonetic",
133     "pinyin",
134     "reformed",
135     "searchjl",
136     "stroke",
137     "trad",
138     "unihan",
139     "zhuyin",
140 };
141 set<std::string> LocaleConfig::validKnTag {
142     "true",
143     "false",
144 };
145 set<std::string> LocaleConfig::validKfTag {
146     "upper",
147     "lower",
148     "false",
149 };
150 set<std::string> LocaleConfig::validNuTag {
151     "adlm", "ahom", "arab", "arabext", "bali", "beng",
152     "bhks", "brah", "cakm", "cham", "deva", "diak",
153     "fullwide", "gong", "gonm", "gujr", "guru", "hanidec",
154     "hmng", "hmnp", "java", "kali", "khmr", "knda",
155     "lana", "lanatham", "laoo", "latn", "lepc", "limb",
156     "mathbold", "mathdbl", "mathmono", "mathsanb", "mathsans", "mlym",
157     "modi", "mong", "mroo", "mtei", "mymr", "mymrshan",
158     "mymrtlng", "newa", "nkoo", "olck", "orya", "osma",
159     "rohg", "saur", "segment", "shrd", "sind", "sinh",
160     "sora", "sund", "takr", "talu", "tamldec", "telu",
161     "thai", "tibt", "tirh", "vaii", "wara", "wcho",
162 };
163 set<std::string> LocaleConfig::validHcTag {
164     "h12",
165     "h23",
166     "h11",
167     "h24",
168 };
169 set<std::string> LocaleConfig::dialectLang {
170     "zh",
171     "ro",
172     "fa",
173 };
174 
175 static unordered_map<string, string> g_languageMap = {
176     { "zh-Hans", "zh-Hans" },
177     { "zh-Hant", "zh-Hant" },
178     { "my-Qaag", "my-Qaag" },
179     { "es-Latn-419", "es-419" },
180     { "es-Latn-US", "es-419" },
181     { "az-Latn", "az-Latn" },
182     { "bs-Latn", "bs-Latn" },
183     { "en-Qaag", "en-Qaag" },
184     { "uz-Latn", "uz-Latn" },
185     { "sr-Latn", "sr-Latn" },
186     { "jv-Latn", "jv-Latn" },
187     { "pt-Latn-BR", "pt-BR" },
188     { "pa-Guru", "pa-Guru" },
189     { "mai-Deva", "mai-Deva" }
190 };
191 
Adjust(const string & origin)192 string Adjust(const string &origin)
193 {
194     for (auto iter = g_languageMap.begin(); iter != g_languageMap.end(); ++iter) {
195         string key = iter->first;
196         if (!origin.compare(0, key.length(), key)) {
197             return iter->second;
198         }
199     }
200     return origin;
201 }
202 
GetDialectName(const char * localeName,char * name,size_t nameCapacity,UErrorCode & status)203 int32_t GetDialectName(const char *localeName, char *name, size_t nameCapacity, UErrorCode &status)
204 {
205     icu::Locale locale = icu::Locale::forLanguageTag(localeName, status);
206     if (status != U_ZERO_ERROR) {
207         return 0;
208     }
209     const char *lang = locale.getLanguage();
210     const char *script = locale.getScript();
211     const char *country = locale.getCountry();
212     bool hasScript = (script != nullptr) && strlen(script) > 0;
213     bool hasCountry = (country != nullptr) && strlen(country) > 0;
214     string temp = lang;
215     if (hasScript && hasCountry) {
216         temp.append("_");
217         temp.append(script);
218         temp.append("_");
219         temp.append(country);
220     } else if (hasScript) {
221         temp.append("_");
222         temp.append(script);
223     } else if (hasCountry) {
224         temp.append("_");
225         temp.append(country);
226     }
227     if (strcpy_s(name, nameCapacity, temp.data()) != EOK) {
228         return 0;
229     }
230     return temp.size();
231 }
232 
GetDisplayName(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode & status)233 int32_t GetDisplayName(const char *locale, const char *displayLocale, UChar *dest, int32_t destCapacity,
234     UErrorCode &status)
235 {
236     if (status != U_ZERO_ERROR) {
237         return 0;
238     }
239     if ((destCapacity < 0) || (destCapacity > 0  && !dest)) {
240         status = U_ILLEGAL_ARGUMENT_ERROR;
241         return 0;
242     }
243     char localeBuffer[ULOC_FULLNAME_CAPACITY];
244     int32_t length = GetDialectName(locale, localeBuffer, sizeof(localeBuffer), status);
245     if (status != U_ZERO_ERROR || !length) {
246         status = U_ILLEGAL_ARGUMENT_ERROR;
247         return 0;
248     }
249     const UChar *str = uloc_getTableStringWithFallback(U_ICUDATA_LANG, displayLocale, "Languages",
250         nullptr, localeBuffer, &length, &status);
251     if (status <= U_ZERO_ERROR) {
252         int32_t len = (length < destCapacity) ? length : destCapacity;
253         if ((len > 0) && (str != nullptr)) {
254             u_memcpy(dest, str, len);
255         }
256     } else {
257         status = U_USING_DEFAULT_WARNING;
258         return 0;
259     }
260     return u_terminateUChars(dest, destCapacity, length, &status);
261 }
262 
GetDisplayLanguageImpl(const char * locale,const char * displayLocale,icu::UnicodeString & result)263 void GetDisplayLanguageImpl(const char *locale, const char *displayLocale, icu::UnicodeString &result)
264 {
265     UChar *buffer = result.getBuffer(50);  // size 50 is enough to hold language name
266     if (!buffer) {
267         result.truncate(0);
268         return;
269     }
270     UErrorCode status = U_ZERO_ERROR;
271     int32_t length = GetDisplayName(locale, displayLocale, buffer, result.getCapacity(), status);
272     result.releaseBuffer(U_SUCCESS(status) ? length : 0);
273 }
274 
GetDisplayLanguageInner(const string & language,const string & displayLocale,bool sentenceCase)275 string GetDisplayLanguageInner(const string &language, const string &displayLocale, bool sentenceCase)
276 {
277     icu::UnicodeString unistr;
278     // 0 is the start position of language, 2 is the length of zh and fa
279     if (!language.compare(0, 2, "zh") || !language.compare(0, 2, "fa")) {
280         UErrorCode error = U_ZERO_ERROR;
281         icu::Locale disLocale = icu::Locale::forLanguageTag(displayLocale, error);
282         if (error != U_ZERO_ERROR) {
283             return language;
284         }
285         const char *name = disLocale.getName();
286         if (!name) {
287             return language;
288         }
289         GetDisplayLanguageImpl(language.c_str(), name, unistr);
290     } else {
291         UErrorCode status = U_ZERO_ERROR;
292         icu::Locale displayLoc = icu::Locale::forLanguageTag(displayLocale, status);
293         if (status != U_ZERO_ERROR) {
294             return "";
295         }
296         icu::Locale locale = icu::Locale::forLanguageTag(language, status);
297         if (status != U_ZERO_ERROR) {
298             return "";
299         }
300         locale.getDisplayName(displayLoc, unistr);
301     }
302     if (sentenceCase) {
303         UChar32 ch = ucase_toupper(unistr.char32At(0));
304         unistr.replace(0, 1, ch);
305     }
306     string out;
307     unistr.toUTF8String(out);
308     return out;
309 }
310 
311 bool LocaleConfig::listsInitialized = LocaleConfig::InitializeLists();
312 
GetSystemLanguage()313 string LocaleConfig::GetSystemLanguage()
314 {
315     char value[CONFIG_LEN];
316     int code = GetParameter(LANGUAGE_KEY, "", value, CONFIG_LEN);
317     if (code > 0) {
318         return value;
319     }
320     code = GetParameter(DEFAULT_LANGUAGE_KEY, "", value, CONFIG_LEN);
321     if (code > 0) {
322         return value;
323     }
324     return "";
325 }
326 
GetSystemRegion()327 string LocaleConfig::GetSystemRegion()
328 {
329     string locale = GetSystemLocale();
330     char value[CONFIG_LEN];
331     int code = GetParameter(LOCALE_KEY, "", value, CONFIG_LEN);
332     if (code > 0) {
333         string tag(value, code);
334         UErrorCode status = U_ZERO_ERROR;
335         icu::Locale origin = icu::Locale::forLanguageTag(tag, status);
336         if (status == U_ZERO_ERROR) {
337             const char *country = origin.getCountry();
338             if (country != nullptr) {
339                 return country;
340             }
341         }
342     }
343     code = GetParameter(DEFAULT_REGION_KEY, "", value, CONFIG_LEN);
344     if (code > 0) {
345         return value;
346     }
347     return "";
348 }
349 
GetSystemLocale()350 string LocaleConfig::GetSystemLocale()
351 {
352     char value[CONFIG_LEN];
353     int code = GetParameter(LOCALE_KEY, "", value, CONFIG_LEN);
354     if (code > 0) {
355         return value;
356     }
357     code = GetParameter(DEFAULT_LOCALE_KEY, "", value, CONFIG_LEN);
358     if (code > 0) {
359         return value;
360     }
361     return "";
362 }
363 
CheckPermission()364 bool LocaleConfig::CheckPermission()
365 {
366     Security::AccessToken::AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();
367     int result = Security::AccessToken::PermissionState::PERMISSION_GRANTED;
368     if (Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callerToken)
369         == Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE) {
370         result = Security::AccessToken::AccessTokenKit::VerifyNativeToken(callerToken,
371                                                                           "ohos.permission.UPDATE_CONFIGURATION");
372     } else if (Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callerToken)
373         == Security::AccessToken::ATokenTypeEnum::TOKEN_HAP) {
374         result = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callerToken,
375                                                                           "ohos.permission.UPDATE_CONFIGURATION");
376     } else {
377         HiLog::Info(LABEL, "Invlid tokenID");
378         return false;
379     }
380     if (result != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
381         HiLog::Info(LABEL, "Verify permission failed");
382         return false;
383     }
384     return true;
385 }
386 
SetSystemLanguage(const string & language)387 bool LocaleConfig::SetSystemLanguage(const string &language)
388 {
389     if (!CheckPermission()) {
390         return false;
391     }
392     if (!IsValidTag(language)) {
393         return false;
394     }
395     return SetParameter(LANGUAGE_KEY, language.data()) == 0;
396 }
397 
SetSystemRegion(const string & region)398 bool LocaleConfig::SetSystemRegion(const string &region)
399 {
400     if (!CheckPermission()) {
401         return false;
402     }
403     if (!IsValidRegion(region)) {
404         return false;
405     }
406     char value[CONFIG_LEN];
407     int code = GetParameter(LOCALE_KEY, "", value, CONFIG_LEN);
408     string newLocale;
409     if (code > 0) {
410         string tag(value, code);
411         newLocale = GetRegionChangeLocale(tag, region);
412         if (newLocale == "") {
413             return false;
414         }
415     } else {
416         icu::Locale temp("", region.c_str());
417         UErrorCode status = U_ZERO_ERROR;
418         temp.addLikelySubtags(status);
419         if (status != U_ZERO_ERROR) {
420             return false;
421         }
422         newLocale = temp.toLanguageTag<string>(status);
423         if (status != U_ZERO_ERROR) {
424             return false;
425         }
426     }
427     return SetParameter(LOCALE_KEY, newLocale.data()) == 0;
428 }
429 
SetSystemLocale(const string & locale)430 bool LocaleConfig::SetSystemLocale(const string &locale)
431 {
432     if (!CheckPermission()) {
433         return false;
434     }
435     if (!IsValidTag(locale)) {
436         return false;
437     }
438     return SetParameter(LOCALE_KEY, locale.data()) == 0;
439 }
440 
IsValidLanguage(const string & language)441 bool LocaleConfig::IsValidLanguage(const string &language)
442 {
443     string::size_type size = language.size();
444     if ((size != LANGUAGE_LEN) && (size != LANGUAGE_LEN + 1)) {
445         return false;
446     }
447     for (size_t i = 0; i < size; ++i) {
448         if ((language[i] > 'z') || (language[i] < 'a')) {
449             return false;
450         }
451     }
452     return true;
453 }
454 
IsValidScript(const string & script)455 bool LocaleConfig::IsValidScript(const string &script)
456 {
457     string::size_type size = script.size();
458     if (size != LocaleInfo::SCRIPT_LEN) {
459         return false;
460     }
461     char first = script[0];
462     if ((first < 'A') || (first > 'Z')) {
463         return false;
464     }
465     for (string::size_type i = 1; i < LocaleInfo::SCRIPT_LEN; ++i) {
466         if ((script[i] > 'z') || (script[i] < 'a')) {
467             return false;
468         }
469     }
470     return true;
471 }
472 
IsValidRegion(const string & region)473 bool LocaleConfig::IsValidRegion(const string &region)
474 {
475     string::size_type size = region.size();
476     if (size != LocaleInfo::REGION_LEN) {
477         return false;
478     }
479     for (size_t i = 0; i < LocaleInfo::REGION_LEN; ++i) {
480         if ((region[i] > 'Z') || (region[i] < 'A')) {
481             return false;
482         }
483     }
484     return true;
485 }
486 
IsValidTag(const string & tag)487 bool LocaleConfig::IsValidTag(const string &tag)
488 {
489     if (!tag.size()) {
490         return false;
491     }
492     vector<string> splits;
493     Split(tag, "-", splits);
494     if (!IsValidLanguage(splits[0])) {
495         return false;
496     }
497     return true;
498 }
499 
Split(const string & src,const string & sep,vector<string> & dest)500 void LocaleConfig::Split(const string &src, const string &sep, vector<string> &dest)
501 {
502     string::size_type begin = 0;
503     string::size_type end = src.find(sep);
504     while (end != string::npos) {
505         dest.push_back(src.substr(begin, end - begin));
506         begin = end + sep.size();
507         end = src.find(sep, begin);
508     }
509     if (begin != src.size()) {
510         dest.push_back(src.substr(begin));
511     }
512 }
513 
514 // language in white languages should have script.
GetSystemLanguages(vector<string> & ret)515 void LocaleConfig::GetSystemLanguages(vector<string> &ret)
516 {
517     for (auto item : whiteLanguages) {
518         ret.push_back(item);
519     }
520 }
521 
GetSupportedLocales()522 const unordered_set<string>& LocaleConfig::GetSupportedLocales()
523 {
524     return supportedLocales;
525 }
526 
GetSupportedRegions()527 const unordered_set<string>& LocaleConfig::GetSupportedRegions()
528 {
529     return supportedRegions;
530 }
531 
GetSystemCountries(vector<string> & ret)532 void LocaleConfig::GetSystemCountries(vector<string> &ret)
533 {
534     for (auto item : supportedRegions) {
535         ret.push_back(item);
536     }
537 }
538 
IsSuggested(const string & language)539 bool LocaleConfig::IsSuggested(const string &language)
540 {
541     unordered_set<string> relatedLocales;
542     vector<string> simCountries;
543     GetCountriesFromSim(simCountries);
544     GetRelatedLocales(relatedLocales, simCountries);
545     for (auto iter = relatedLocales.begin(); iter != relatedLocales.end();) {
546         if (whiteLanguages.find(*iter) == whiteLanguages.end()) {
547             iter = relatedLocales.erase(iter);
548         } else {
549             ++iter;
550         }
551     }
552     string mainLanguage = GetMainLanguage(language);
553     return relatedLocales.find(mainLanguage) != relatedLocales.end();
554 }
555 
IsSuggested(const std::string & language,const std::string & region)556 bool LocaleConfig::IsSuggested(const std::string &language, const std::string &region)
557 {
558     unordered_set<string> relatedLocales;
559     vector<string> countries { region };
560     GetRelatedLocales(relatedLocales, countries);
561     for (auto iter = relatedLocales.begin(); iter != relatedLocales.end();) {
562         if (whiteLanguages.find(*iter) == whiteLanguages.end()) {
563             iter = relatedLocales.erase(iter);
564         } else {
565             ++iter;
566         }
567     }
568     string mainLanguage = GetMainLanguage(language);
569     return relatedLocales.find(mainLanguage) != relatedLocales.end();
570 }
571 
GetRelatedLocales(unordered_set<string> & relatedLocales,vector<string> countries)572 void LocaleConfig::GetRelatedLocales(unordered_set<string> &relatedLocales, vector<string> countries)
573 {
574     // remove unsupported countries
575     const unordered_set<string> &regions = GetSupportedRegions();
576     for (auto iter = countries.begin(); iter != countries.end();) {
577         if (regions.find(*iter) == regions.end()) {
578             iter = countries.erase(iter);
579         } else {
580             ++iter;
581         }
582     }
583     const unordered_set<string> &locales = GetSupportedLocales();
584     for (string locale : locales) {
585         bool find = false;
586         for (string country : countries) {
587             if (locale.find(country) != string::npos) {
588                 find = true;
589                 break;
590             }
591         }
592         if (!find) {
593             continue;
594         }
595         string mainLanguage = GetMainLanguage(locale);
596         if (mainLanguage != "") {
597             relatedLocales.insert(mainLanguage);
598         }
599     }
600 }
601 
GetCountriesFromSim(vector<string> & simCountries)602 void LocaleConfig::GetCountriesFromSim(vector<string> &simCountries)
603 {
604     simCountries.push_back(GetSystemRegion());
605 #ifdef TEL_CORE_SERVICE_EXISTS
606     simCountries.push_back(Str16ToStr8(
607         DelayedRefSingleton<Telephony::CoreServiceClient>::GetInstance().GetISOCountryCodeForSim(0)));
608 #endif
609 }
610 
GetListFromFile(const char * path,const char * resourceName,unordered_set<string> & ret)611 void LocaleConfig::GetListFromFile(const char *path, const char *resourceName, unordered_set<string> &ret)
612 {
613     xmlKeepBlanksDefault(0);
614     if (!path) {
615         return;
616     }
617     xmlDocPtr doc = xmlParseFile(path);
618     if (!doc) {
619         return;
620     }
621     xmlNodePtr cur = xmlDocGetRootElement(doc);
622     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(resourceName))) {
623         xmlFreeDoc(doc);
624         return;
625     }
626     cur = cur->xmlChildrenNode;
627     xmlChar *content = nullptr;
628     while (cur != nullptr) {
629         content = xmlNodeGetContent(cur);
630         if (content != nullptr) {
631             ret.insert(reinterpret_cast<const char*>(content));
632             xmlFree(content);
633             cur = cur->next;
634         } else {
635             break;
636         }
637     }
638     xmlFreeDoc(doc);
639 }
640 
Expunge(unordered_set<string> & src,const unordered_set<string> & another)641 void LocaleConfig::Expunge(unordered_set<string> &src, const unordered_set<string> &another)
642 {
643     for (auto iter = src.begin(); iter != src.end();) {
644         if (another.find(*iter) != another.end()) {
645             iter = src.erase(iter);
646         } else {
647             ++iter;
648         }
649     }
650 }
651 
InitializeLists()652 bool LocaleConfig::InitializeLists()
653 {
654     SetHwIcuDirectory();
655     GetListFromFile(SUPPORTED_REGIONS_PATH, SUPPORTED_REGIONS_NAME, supportedRegions);
656     unordered_set<string> forbiddenRegions;
657     GetListFromFile(FORBIDDEN_REGIONS_PATH, FORBIDDEN_REGIONS_NAME, forbiddenRegions);
658     Expunge(supportedRegions, forbiddenRegions);
659     GetListFromFile(WHITE_LANGUAGES_PATH, WHITE_LANGUAGES_NAME, whiteLanguages);
660     unordered_set<string> forbiddenLanguages;
661     GetListFromFile(FORBIDDEN_LANGUAGES_PATH, FORBIDDEN_LANGUAGES_NAME, forbiddenLanguages);
662     Expunge(whiteLanguages, forbiddenLanguages);
663     GetListFromFile(SUPPORTED_LOCALES_PATH, SUPPORTED_LOCALES_NAME, supportedLocales);
664     return true;
665 }
666 
GetRegionChangeLocale(const string & languageTag,const string & region)667 string LocaleConfig::GetRegionChangeLocale(const string &languageTag, const string &region)
668 {
669     UErrorCode status = U_ZERO_ERROR;
670     const icu::Locale origin = icu::Locale::forLanguageTag(languageTag, status);
671     if (status != U_ZERO_ERROR) {
672         return "";
673     }
674     icu::LocaleBuilder builder = icu::LocaleBuilder().setLanguage(origin.getLanguage()).
675         setScript(origin.getScript()).setRegion(region);
676     icu::Locale temp = builder.setExtension('u', "").build(status);
677     if (status != U_ZERO_ERROR) {
678         return "";
679     }
680     string ret = temp.toLanguageTag<string>(status);
681     return (status != U_ZERO_ERROR) ? "" : ret;
682 }
683 
GetMainLanguage(const string & language)684 string LocaleConfig::GetMainLanguage(const string &language)
685 {
686     UErrorCode status = U_ZERO_ERROR;
687     icu::Locale origin = icu::Locale::forLanguageTag(language, status);
688     if (status != U_ZERO_ERROR) {
689         return "";
690     }
691     origin.addLikelySubtags(status);
692     if (status != U_ZERO_ERROR) {
693         return "";
694     }
695     icu::LocaleBuilder builder = icu::LocaleBuilder().setLanguage(origin.getLanguage()).
696         setScript(origin.getScript()).setRegion(origin.getCountry());
697     icu::Locale temp = builder.setExtension('u', "").build(status);
698     string fullLanguage = temp.toLanguageTag<string>(status);
699     if (status != U_ZERO_ERROR) {
700         return "";
701     }
702     if (dialectMap.find(fullLanguage) != dialectMap.end()) {
703         return dialectMap[fullLanguage];
704     }
705     builder.setRegion("");
706     temp = builder.build(status);
707     fullLanguage = temp.toLanguageTag<string>(status);
708     if (status != U_ZERO_ERROR) {
709         return "";
710     }
711     return fullLanguage;
712 }
713 
GetDisplayLanguage(const string & language,const string & displayLocale,bool sentenceCase)714 string LocaleConfig::GetDisplayLanguage(const string &language, const string &displayLocale, bool sentenceCase)
715 {
716     string adjust = Adjust(language);
717     if (adjust == language) {
718         UErrorCode status = U_ZERO_ERROR;
719         icu::Locale displayLoc = icu::Locale::forLanguageTag(displayLocale, status);
720         if (status != U_ZERO_ERROR) {
721             return "";
722         }
723         icu::Locale locale = icu::Locale::forLanguageTag(language, status);
724         if (status != U_ZERO_ERROR) {
725             return "";
726         }
727         icu::UnicodeString unistr;
728         std::string lang(locale.getLanguage());
729         std::string result;
730         if (dialectLang.find(lang) != dialectLang.end()) {
731             result = GetDsiplayLanguageWithDialect(language, displayLocale);
732         } else {
733             locale.getDisplayLanguage(displayLoc, unistr);
734             unistr.toUTF8String(result);
735         }
736         if (sentenceCase) {
737             char ch = static_cast<char>(toupper(result[0]));
738             return result.replace(0, 1, 1, ch);
739         }
740         return result;
741     }
742     return GetDisplayLanguageInner(adjust, displayLocale, sentenceCase);
743 }
744 
ComputeLocale(const std::string & displayLocale)745 std::string LocaleConfig::ComputeLocale(const std::string &displayLocale)
746 {
747     if (supportedDialectLocales.size() == 0) {
748         xmlKeepBlanksDefault(0);
749         xmlDocPtr doc = xmlParseFile(SUPPORT_LOCALES_PATH);
750         if (!doc) {
751             return DEFAULT_LOCALE;
752         }
753         xmlNodePtr cur = xmlDocGetRootElement(doc);
754         if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(supportLocalesTag))) {
755             xmlFreeDoc(doc);
756             HiLog::Info(LABEL, "can not parse language supported locale file");
757             return DEFAULT_LOCALE;
758         }
759         cur = cur->xmlChildrenNode;
760         while (cur != nullptr) {
761             xmlChar *content = xmlNodeGetContent(cur);
762             if (content == nullptr) {
763                 HiLog::Info(LABEL, "get xml node content failed");
764                 break;
765             }
766             std::map<std::string, std::string> localeInfoConfigs = {};
767             LocaleInfo localeinfo(reinterpret_cast<const char*>(content), localeInfoConfigs);
768             std::string language = localeinfo.GetLanguage();
769             std::string script = localeinfo.GetScript();
770             std::string languageAndScript = (script.length() == 0) ? language : language + "-" + script;
771             LocaleInfo newLocaleInfo(languageAndScript, localeInfoConfigs);
772             std::string maximizeLocale = newLocaleInfo.Maximize();
773             supportedDialectLocales.insert(
774                 std::make_pair<std::string, std::string>(maximizeLocale.c_str(),
775                                                          reinterpret_cast<const char*>(content)));
776             xmlFree(content);
777             cur = cur->next;
778         }
779     }
780     std::map<std::string, std::string> configs = {};
781     LocaleInfo localeinfo(displayLocale, configs);
782     std::string language = localeinfo.GetLanguage();
783     std::string script = localeinfo.GetScript();
784     std::string languageAndScript = (script.length() == 0) ? language : language + "-" + script;
785     LocaleInfo newLocaleInfo(languageAndScript, configs);
786     std::string maximizeLocale = newLocaleInfo.Maximize();
787     if (supportedDialectLocales.find(maximizeLocale) != supportedDialectLocales.end()) {
788         return supportedDialectLocales.at(maximizeLocale);
789     }
790     return DEFAULT_LOCALE;
791 }
792 
ReadLangData(const char * langDataPath)793 void LocaleConfig::ReadLangData(const char *langDataPath)
794 {
795     xmlKeepBlanksDefault(0);
796     if (langDataPath == nullptr) {
797         return;
798     }
799     xmlDocPtr doc = xmlParseFile(langDataPath);
800     if (!doc) {
801         HiLog::Info(LABEL, "can not open language data file");
802         return;
803     }
804     xmlNodePtr cur = xmlDocGetRootElement(doc);
805     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(rootTag))) {
806         xmlFreeDoc(doc);
807         HiLog::Info(LABEL, "parse language data file failed");
808         return;
809     }
810     cur = cur->xmlChildrenNode;
811     while (cur != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(secondRootTag))) {
812         xmlChar *langContents[ELEMENT_NUM] = { 0 }; // 2 represent langid, displayname;
813         xmlNodePtr langValue = cur->xmlChildrenNode;
814         for (size_t i = 0; i < ELEMENT_NUM; i++) {
815             if (langValue != nullptr) {
816                 langContents[i] = xmlNodeGetContent(langValue);
817                 langValue = langValue->next;
818             } else {
819                 break;
820             }
821         }
822         // 0 represents langid index, 1 represents displayname index
823         locale2DisplayName.insert(
824             std::make_pair<std::string, std::string>(reinterpret_cast<const char *>(langContents[0]),
825                                                      reinterpret_cast<const char *>(langContents[1])));
826         for (size_t i = 0; i < ELEMENT_NUM; i++) {
827             if (langContents[i] != nullptr) {
828                 xmlFree(langContents[i]);
829             }
830         }
831         cur = cur->next;
832     }
833     xmlFreeDoc(doc);
834 }
835 
GetDsiplayLanguageWithDialect(const std::string & localeStr,const std::string & displayLocale)836 string LocaleConfig::GetDsiplayLanguageWithDialect(const std::string &localeStr, const std::string &displayLocale)
837 {
838     std::string finalLocale = ComputeLocale(displayLocale);
839     if (finalLocale.compare(currentDialectLocale) != 0) {
840         std::string xmlPath = LANG_PATH + finalLocale + ".xml";
841         locale2DisplayName.clear();
842         ReadLangData(xmlPath.c_str());
843         currentDialectLocale = finalLocale;
844     }
845     if (locale2DisplayName.find(localeStr) != locale2DisplayName.end()) {
846         return locale2DisplayName.at(localeStr);
847     }
848     std::map<std::string, std::string> configs = {};
849     LocaleInfo locale(localeStr, configs);
850     std::string language = locale.GetLanguage();
851     std::string scripts = locale.GetScript();
852     std::string region = locale.GetRegion();
853     if (scripts.length() != 0) {
854         std::string languageAndScripts = language + "-" + scripts;
855         if (locale2DisplayName.find(languageAndScripts) != locale2DisplayName.end()) {
856             return locale2DisplayName.at(languageAndScripts);
857         }
858     }
859     if (region.length() != 0) {
860         std::string languageAndRegion = language + "-" + region;
861         if (locale2DisplayName.find(languageAndRegion) != locale2DisplayName.end()) {
862             return locale2DisplayName.at(languageAndRegion);
863         }
864     }
865     if (locale2DisplayName.find(language) != locale2DisplayName.end()) {
866         return locale2DisplayName.at(language);
867     }
868     return "";
869 }
870 
GetDisplayRegion(const string & region,const string & displayLocale,bool sentenceCase)871 string LocaleConfig::GetDisplayRegion(const string &region, const string &displayLocale, bool sentenceCase)
872 {
873     UErrorCode status = U_ZERO_ERROR;
874     icu::Locale originLocale;
875     if (IsValidRegion(region)) {
876         icu::LocaleBuilder builder = icu::LocaleBuilder().setRegion(region);
877         originLocale = builder.build(status);
878     } else {
879         originLocale = icu::Locale::forLanguageTag(region, status);
880     }
881     std::string country(originLocale.getCountry());
882     if (country.length() == 0) {
883         return "";
884     }
885     if (status != U_ZERO_ERROR) {
886         return "";
887     }
888     icu::Locale locale = icu::Locale::forLanguageTag(displayLocale, status);
889     if (status != U_ZERO_ERROR) {
890         return "";
891     }
892     icu::UnicodeString displayRegion;
893     originLocale.getDisplayCountry(locale, displayRegion);
894     if (sentenceCase) {
895         UChar32 ch = ucase_toupper(displayRegion.char32At(0));
896         displayRegion.replace(0, 1, ch);
897     }
898     string temp;
899     displayRegion.toUTF8String(temp);
900     return temp;
901 }
902 
IsRTL(const string & locale)903 bool LocaleConfig::IsRTL(const string &locale)
904 {
905     icu::Locale curLocale(locale.c_str());
906     return curLocale.isRightToLeft();
907 }
908 
ContainTag(std::string & localeTag,std::string & defaultLocaleTag,const std::string & extensionTag)909 std::string ContainTag(std::string &localeTag, std::string &defaultLocaleTag,
910     const std::string &extensionTag)
911 {
912     std::string tag = localeTag;
913     std::size_t found = tag.find(extensionTag);
914     if (found == std::string::npos) {
915         tag = defaultLocaleTag;
916         found = tag.find(extensionTag);
917     }
918     if (found == std::string::npos) {
919         return "";
920     }
921 
922     std::size_t start = found + 4;  // 4 is the tag length
923     std::size_t end = tag.find("-", start);
924 
925     return tag.substr(start, end - start);
926 }
927 
parseExtension(const std::string & extension,std::map<std::string,std::string> & map)928 void parseExtension(const std::string &extension, std::map<std::string, std::string> &map)
929 {
930     std::string pattern = "-..-";
931     std::regex express(pattern);
932 
933     std::regex_token_iterator<std::string::const_iterator> begin1(extension.cbegin(), extension.cend(), express);
934     std::regex_token_iterator<std::string::const_iterator> begin2(extension.cbegin(), extension.cend(), express, -1);
935     begin2++;
936     for (; begin1 != std::sregex_token_iterator() && begin2 != std::sregex_token_iterator(); begin1++, begin2++) {
937         map.insert(std::pair<std::string, std::string>(begin1->str(), begin2->str()));
938     }
939 }
940 
setExtension(std::string & extension,const std::string & tag,const std::set<string> & validValue,const std::map<std::string,std::string> & extensionMap,const std::map<std::string,std::string> & defaultExtensionMap)941 void setExtension(std::string &extension, const std::string &tag, const std::set<string> &validValue,
942     const std::map<std::string, std::string> &extensionMap,
943     const std::map<std::string, std::string> &defaultExtensionMap)
944 {
945     std::string value = "";
946     auto it = extensionMap.find(tag);
947     if (it != extensionMap.end()) {
948         value = it->second;
949         if (validValue.find(value) == validValue.end()) {
950             return;
951         } else {
952             extension += tag;
953             extension += value;
954         }
955     } else {
956         it = defaultExtensionMap.find(tag);
957         if (it != defaultExtensionMap.end()) {
958             value = it->second;
959             if (validValue.find(value) == validValue.end()) {
960                 return;
961             } else {
962                 extension += tag;
963                 extension += value;
964             }
965         }
966     }
967 }
968 
setOtherExtension(std::string & extension,std::map<std::string,std::string> & extensionMap,std::map<std::string,std::string> & defaultExtensionMap)969 void setOtherExtension(std::string &extension, std::map<std::string, std::string> &extensionMap,
970     std::map<std::string, std::string> &defaultExtensionMap)
971 {
972     std::set<std::string> tags;
973     tags.insert("-ca-");
974     tags.insert("-co-");
975     tags.insert("-kn-");
976     tags.insert("-kf-");
977     tags.insert("-nu-");
978     tags.insert("-hc-");
979 
980     for (auto it = tags.begin(); it != tags.end(); it++) {
981         extensionMap.erase(*it);
982         defaultExtensionMap.erase(*it);
983     }
984 
985     for (auto it = defaultExtensionMap.begin(); it != defaultExtensionMap.end(); it++) {
986         extensionMap.insert(std::pair<std::string, std::string>(it->first, it->second));
987     }
988 
989     for (auto it = extensionMap.begin(); it != extensionMap.end(); it++) {
990         extension += it->first;
991         extension += it->second;
992     }
993 }
994 
GetValidLocale(const std::string & localeTag)995 std::string LocaleConfig::GetValidLocale(const std::string &localeTag)
996 {
997     std::string baseLocale = "";
998     std::string extension = "";
999     std::size_t found = localeTag.find("-u-");
1000     baseLocale = localeTag.substr(0, found);
1001     if (found != std::string::npos) {
1002         extension = localeTag.substr(found);
1003     }
1004     std::map<std::string, std::string> extensionMap;
1005     if (extension != "") {
1006         parseExtension(extension, extensionMap);
1007     }
1008 
1009     std::string systemLocaleTag = GetSystemLocale();
1010     std::string defaultExtension = "";
1011     found = systemLocaleTag.find("-u-");
1012     if (found != std::string::npos) {
1013         defaultExtension = systemLocaleTag.substr(found);
1014     }
1015     std::map<std::string, std::string> defaultExtensionMap;
1016     if (defaultExtension != "") {
1017         parseExtension(defaultExtension, defaultExtensionMap);
1018     }
1019 
1020     std::string ext = "";
1021     setExtension(ext, "-ca-", validCaTag, extensionMap, defaultExtensionMap);
1022     setExtension(ext, "-co-", validCoTag, extensionMap, defaultExtensionMap);
1023     setExtension(ext, "-kn-", validKnTag, extensionMap, defaultExtensionMap);
1024     setExtension(ext, "-kf-", validKfTag, extensionMap, defaultExtensionMap);
1025     setExtension(ext, "-nu-", validNuTag, extensionMap, defaultExtensionMap);
1026     setExtension(ext, "-hc-", validHcTag, extensionMap, defaultExtensionMap);
1027 
1028     std::string otherExt = "";
1029     setOtherExtension(otherExt, extensionMap, defaultExtensionMap);
1030     if (ext != "" || otherExt != "") {
1031         return baseLocale + "-u" + ext + otherExt;
1032     } else {
1033         return baseLocale;
1034     }
1035 }
1036 
Is24HourClock()1037 bool LocaleConfig::Is24HourClock()
1038 {
1039     char value[CONFIG_LEN];
1040     int code = GetParameter(HOUR_KEY, "", value, CONFIG_LEN);
1041     if (code <= 0) {
1042         return false;
1043     }
1044     if (!strcmp(value, "true")) {
1045         return true;
1046     }
1047     return false;
1048 }
1049 
Set24HourClock(bool option)1050 bool LocaleConfig::Set24HourClock(bool option)
1051 {
1052     if (!CheckPermission()) {
1053         return false;
1054     }
1055     std::string optionStr = "";
1056     if (option) {
1057         optionStr = "true";
1058     } else {
1059         optionStr = "false";
1060     }
1061     return SetParameter(HOUR_KEY, optionStr.data()) == 0;
1062 }
1063 } // namespace I18n
1064 } // namespace Global
1065 } // namespace OHOS
1066