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