• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef ECMASCRIPT_BASE_LOCALE_HELPER_H
17 #define ECMASCRIPT_BASE_LOCALE_HELPER_H
18 
19 #include "ecmascript/js_handle.h"
20 #include "ecmascript/js_locale.h"
21 
22 namespace panda::ecmascript::intl {
23 constexpr uint8_t INTL_INDEX_TWO = 2;
24 constexpr uint8_t INTL_INDEX_THREE = 3;
25 constexpr uint8_t INTL_INDEX_FOUR = 4;
26 constexpr uint8_t INTL_INDEX_FIVE = 5;
27 constexpr uint8_t INTL_INDEX_EIGHT = 8;
28 class LocaleHelper {
29 public:
30     struct ParsedLocale {
31         std::string base;
32         std::string extension;
33     };
34     static JSHandle<EcmaString> UStringToString(JSThread *thread, const icu::UnicodeString &string);
35     static JSHandle<EcmaString> UStringToString(JSThread *thread, const icu::UnicodeString &string, int32_t begin,
36                                                 int32_t end);
37 
38     // 9.2.1 CanonicalizeLocaleList ( locales )
39     static JSHandle<TaggedArray> CanonicalizeLocaleList(JSThread *thread, const JSHandle<JSTaggedValue> &locales);
40     // 6.2.3 CanonicalizeUnicodeLocaleId ( locale )
41     static JSHandle<EcmaString> CanonicalizeUnicodeLocaleId(JSThread *thread, const JSHandle<EcmaString> &locale);
42     static std::string ToStdStringLanguageTag(JSThread *thread, const icu::Locale &locale);
43     static JSHandle<EcmaString> ToLanguageTag(JSThread *thread, const icu::Locale &locale);
44     static std::vector<std::string> GetAvailableLocales(JSThread *thread, const char *key, const char *path);
45     static bool IsStructurallyValidLanguageTag(const JSHandle<EcmaString> &tag);
46     // 9.2.2 BestAvailableLocale ( availableLocales, locale )
47     static std::string BestAvailableLocale(const std::vector<std::string> &availableLocales,
48                                            const std::string &locale);
49     static const std::string& StdStringDefaultLocale(JSThread *thread);
50     static JSHandle<EcmaString> DefaultLocale(JSThread *thread);
51     static LocaleHelper::ParsedLocale HandleLocale(const JSHandle<EcmaString> &localeString);
52     static LocaleHelper::ParsedLocale HandleLocale(const std::string &localeString);
53     static void HandleLocaleExtension(size_t &start, size_t &extensionEnd, const std::string result, size_t len);
54     static std::string ConvertToStdString(const JSHandle<EcmaString> &ecmaStr);
55 private:
56     template<typename T>
57     static JSHandle<TaggedArray> CanonicalizeHelper(JSThread *thread, JSHandle<T> &obj, JSHandle<TaggedArray> &seen);
58     static bool DealwithLanguageTag(const std::vector<std::string> &containers, size_t &address);
59 
AsciiAlphaToLower(uint32_t c)60     static inline constexpr int AsciiAlphaToLower(uint32_t c)
61     {
62         constexpr uint32_t FLAG = 0x20;
63         return static_cast<int>(c | FLAG);
64     }
65 
IsLanguageSubtag(const std::string & value)66     static bool IsLanguageSubtag(const std::string &value)
67     {
68         return IsAlpha(value, INTL_INDEX_TWO, INTL_INDEX_THREE) || IsAlpha(value, INTL_INDEX_FIVE, INTL_INDEX_EIGHT);
69     }
70 
IsScriptSubtag(const std::string & value)71     static bool IsScriptSubtag(const std::string &value)
72     {
73         return IsAlpha(value, INTL_INDEX_FOUR, INTL_INDEX_FOUR);
74     }
75 
IsRegionSubtag(const std::string & value)76     static bool IsRegionSubtag(const std::string &value)
77     {
78         return IsAlpha(value, INTL_INDEX_TWO, INTL_INDEX_TWO) || IsDigit(value, INTL_INDEX_THREE, INTL_INDEX_THREE);
79     }
80 
IsVariantSubtag(const std::string & value)81     static bool IsVariantSubtag(const std::string &value)
82     {
83         return IsThirdDigitAlphanum(value) || IsAlphanum(value, INTL_INDEX_FIVE, INTL_INDEX_EIGHT);
84     }
85 
IsThirdDigitAlphanum(const std::string & value)86     static bool IsThirdDigitAlphanum(const std::string &value)
87     {
88         return InRange(value[0], '0', '9') && value.length() == INTL_INDEX_FOUR &&
89             IsAlphanum(value.substr(1), INTL_INDEX_THREE, INTL_INDEX_THREE);
90     }
91 
IsExtensionSingleton(const std::string & value)92     static bool IsExtensionSingleton(const std::string &value)
93     {
94         return IsAlphanum(value, 1, 1);
95     }
96 
IsPrivateSubTag(std::string result,size_t len)97     static bool IsPrivateSubTag(std::string result, size_t len)
98     {
99         if ((len > 1) && (result[1] == '-')) {
100             ASSERT(result[0] == 'x' || result[0] == 'i');
101             return true;
102         }
103         return false;
104     }
105 
106     template<typename T, typename U>
InRange(T value,U start,U end)107     static bool InRange(T value, U start, U end)
108     {
109         ASSERT(start <= end);
110         ASSERT(sizeof(T) >= sizeof(U));
111         return (value >= static_cast<T>(start)) && (value <= static_cast<T>(end));
112     }
113 
IsAsciiAlpha(char ch)114     static bool IsAsciiAlpha(char ch)
115     {
116         return InRange(ch, 'A', 'Z') || InRange(ch, 'a', 'z');
117     }
118 
IsAlpha(const std::string & str,size_t min,size_t max)119     static bool IsAlpha(const std::string &str, size_t min, size_t max)
120     {
121         if (!InRange(str.length(), min, max)) {
122             return false;
123         }
124         for (char c : str) {
125             if (!IsAsciiAlpha(c)) {
126                 return false;
127             }
128         }
129         return true;
130     }
131 
IsDigit(const std::string & str,size_t min,size_t max)132     static bool IsDigit(const std::string &str, size_t min, size_t max)
133     {
134         if (!InRange(str.length(), min, max)) {
135             return false;
136         }
137         for (char i : str) {
138             if (!InRange(i, '0', '9')) {
139                 return false;
140             }
141         }
142         return true;
143     }
144 
IsAlphanum(const std::string & str,size_t min,size_t max)145     static bool IsAlphanum(const std::string &str, size_t min, size_t max)
146     {
147         if (!InRange(str.length(), min, max)) {
148             return false;
149         }
150         for (char i : str) {
151             if (!IsAsciiAlpha(i) && !InRange(i, '0', '9')) {
152                 return false;
153             }
154         }
155         return true;
156     }
157 
ValidateOtherTags(const icu::Locale & locale,const char * packageName,const char * key,bool & res)158     static bool ValidateOtherTags(const icu::Locale &locale, const char *packageName, const char *key, bool &res)
159     {
160         const char *localeCountry = locale.getCountry();
161         const char *localeScript = locale.getScript();
162         if (localeCountry[0] != '\0' && localeScript[0] != '\0') {
163             std::string removeCountry = locale.getLanguage();
164             removeCountry.append("-");
165             removeCountry.append(localeScript);
166             return CheckLocales(removeCountry.c_str(), key, packageName, res);
167         }
168         if (localeCountry[0] != '\0' || localeScript[0] != '\0') {
169             std::string language = locale.getLanguage();
170             return CheckLocales(language.c_str(), key, packageName, res);
171         }
172         return res;
173     }
174 
CheckLocales(const icu::Locale & locale,const char * key,const char * packageName,bool & res)175     static bool CheckLocales(const icu::Locale &locale, const char *key, const char *packageName, bool &res)
176     {
177         res = false;
178         UErrorCode status = U_ZERO_ERROR;
179         const char *formalLocale = locale.getName();
180         UResourceBundle *localeRes = ures_open(packageName, formalLocale, &status);
181         if (localeRes != nullptr && status == U_ZERO_ERROR) {
182             if (key == nullptr) {
183                 res = true;
184             } else {
185                 UResourceBundle *keyRes = ures_getByKey(localeRes, key, nullptr, &status);
186                 if (keyRes != nullptr && status == U_ZERO_ERROR) {
187                     res = true;
188                 }
189                 ures_close(keyRes);
190             }
191         }
192         ures_close(localeRes);
193         if (res) {
194             return res;
195         } else {
196             ValidateOtherTags(locale, packageName, key, res);
197         }
198         return res;
199     }
200 
201     static bool IsVariantSubtag(std::string substring, std::vector<std::string> containers);
202 };
203 }
204 #endif  // ECMASCRIPT_BASE_LOCALE_HELPER_H