From da10dd87fed72fc06621719b7acbf835dec16915 Mon Sep 17 00:00:00 2001 From: wuyuanchao Date: Fri, 5 Sep 2025 19:59:29 +0800 Subject: [PATCH] [cherry pick 0728] add verify BCP47 LanguageTag Issue:https://gitee.com/openharmony/arkcompiler_runtime_core/issues/ICWEM5 Signed-off-by: wuyuanchao --- .../plugins/ets/runtime/CMakeLists.txt | 1 + .../plugins/ets/stdlib/native/core/Intl.cpp | 2 + .../stdlib/native/core/IntlLocaleHelper.cpp | 50 +++++++++++++++ .../ets/stdlib/native/core/IntlLocaleHelper.h | 32 ++++++++++ .../ets/stdlib/std/core/LocaleMatch.ets | 6 ++ static_core/plugins/ets/subproject_sources.gn | 1 + .../core/IntlLocalesToLanguageTagsTest.ets | 63 +++++++++++++++++++ .../core/IntlNumberFormatNumberingSystem.ets | 4 +- 8 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 static_core/plugins/ets/stdlib/native/core/IntlLocaleHelper.cpp create mode 100644 static_core/plugins/ets/stdlib/native/core/IntlLocaleHelper.h create mode 100644 static_core/plugins/ets/tests/ets_func_tests/std/core/IntlLocalesToLanguageTagsTest.ets diff --git a/static_core/plugins/ets/runtime/CMakeLists.txt b/static_core/plugins/ets/runtime/CMakeLists.txt index 5c9a3ab390..f7ba1d969a 100644 --- a/static_core/plugins/ets/runtime/CMakeLists.txt +++ b/static_core/plugins/ets/runtime/CMakeLists.txt @@ -138,6 +138,7 @@ set(ETS_RUNTIME_SOURCES ${PANDA_ETS_PLUGIN_SOURCE}/stdlib/native/core/IntlLocaleMatch.cpp ${PANDA_ETS_PLUGIN_SOURCE}/stdlib/native/core/IntlCollator.cpp ${PANDA_ETS_PLUGIN_SOURCE}/stdlib/native/core/IntlLocale.cpp + ${PANDA_ETS_PLUGIN_SOURCE}/stdlib/native/core/IntlLocaleHelper.cpp ${PANDA_ETS_PLUGIN_SOURCE}/stdlib/native/core/IntlPluralRules.cpp ${PANDA_ETS_PLUGIN_SOURCE}/stdlib/native/core/IntlSegmenter.cpp ${PANDA_ETS_PLUGIN_SOURCE}/stdlib/native/core/stdlib_ani_helpers.cpp diff --git a/static_core/plugins/ets/stdlib/native/core/Intl.cpp b/static_core/plugins/ets/stdlib/native/core/Intl.cpp index 54d73226fd..e2a127f49d 100644 --- a/static_core/plugins/ets/stdlib/native/core/Intl.cpp +++ b/static_core/plugins/ets/stdlib/native/core/Intl.cpp @@ -21,6 +21,7 @@ #include "plugins/ets/stdlib/native/core/IntlSegmenter.h" #include "plugins/ets/stdlib/native/core/IntlCommon.h" #include "plugins/ets/stdlib/native/core/IntlLocale.h" +#include "plugins/ets/stdlib/native/core/IntlLocaleHelper.h" #include "plugins/ets/stdlib/native/core/IntlPluralRules.h" #include "plugins/ets/stdlib/native/core/IntlDateTimeFormat.h" #include "plugins/ets/stdlib/native/core/IntlListFormat.h" @@ -40,6 +41,7 @@ ani_status InitCoreIntl(ani_env *env) // Register Native methods. Stop if an error occurred ani_status err = RegisterIntlNumberFormatNativeMethods(env); err = err == ANI_OK ? RegisterIntlLocaleMatch(env) : err; + err = err == ANI_OK ? RegisterIntlLocaleHelper(env) : err; err = err == ANI_OK ? RegisterIntlCollator(env) : err; err = err == ANI_OK ? RegisterIntlLocaleNativeMethods(env) : err; err = err == ANI_OK ? RegisterIntlPluralRules(env) : err; diff --git a/static_core/plugins/ets/stdlib/native/core/IntlLocaleHelper.cpp b/static_core/plugins/ets/stdlib/native/core/IntlLocaleHelper.cpp new file mode 100644 index 0000000000..3bc5f3ed8d --- /dev/null +++ b/static_core/plugins/ets/stdlib/native/core/IntlLocaleHelper.cpp @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "plugins/ets/stdlib/native/core/IntlLocaleHelper.h" +#include "plugins/ets/stdlib/native/core/IntlLanguageTag.h" +#include "stdlib_ani_helpers.h" + +#include +#include + +namespace ark::ets::stdlib::intl { + +void StdCoreVerifyBCP47LanguageTag(ani_env *env, [[maybe_unused]] ani_class klass, ani_string locale) +{ + auto localeCStr = ConvertFromAniString(env, locale); + if (localeCStr.length() == 0) { + std::string message = "Incorrect locale information provided"; + ThrowNewError(env, "std.core.RangeError", message.c_str(), "C{std.core.String}:"); + } + if (!intl::IsStructurallyValidLanguageTag(localeCStr)) { + std::string message = "Incorrect locale information provided"; + ThrowNewError(env, "std.core.RangeError", message.c_str(), "C{std.core.String}:"); + } + + return; +} + +ani_status RegisterIntlLocaleHelper(ani_env *env) +{ + const auto methods = std::array {ani_native_function { + "verifyBCP47LanguageTag", "C{std.core.String}:", reinterpret_cast(StdCoreVerifyBCP47LanguageTag)}}; + + ani_class localeHelperClass; + ANI_FATAL_IF_ERROR(env->FindClass("std.core.LocaleHelper", &localeHelperClass)); + + return env->Class_BindStaticNativeMethods(localeHelperClass, methods.data(), methods.size()); +} + +} // namespace ark::ets::stdlib::intl \ No newline at end of file diff --git a/static_core/plugins/ets/stdlib/native/core/IntlLocaleHelper.h b/static_core/plugins/ets/stdlib/native/core/IntlLocaleHelper.h new file mode 100644 index 0000000000..240f16e880 --- /dev/null +++ b/static_core/plugins/ets/stdlib/native/core/IntlLocaleHelper.h @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PANDA_PLUGINS_ETS_STDLIB_NATIVE_CORE_INTLLOCALEHELPER_H +#define PANDA_PLUGINS_ETS_STDLIB_NATIVE_CORE_INTLLOCALEHELPER_H + +#include "stdlib_ani_helpers.h" + +#include +#include + +namespace ark::ets::stdlib::intl { + +ani_status RegisterIntlLocaleHelper(ani_env *env); + +void StdCoreVerifyBCP47LanguageTag(ani_env *env, [[maybe_unused]] ani_class klass, ani_string locale); + +} // namespace ark::ets::stdlib::intl + +#endif // PANDA_PLUGINS_ETS_STDLIB_NATIVE_CORE_INTLLOCALEHELPER_H diff --git a/static_core/plugins/ets/stdlib/std/core/LocaleMatch.ets b/static_core/plugins/ets/stdlib/std/core/LocaleMatch.ets index 616bb80fb5..68622ab247 100644 --- a/static_core/plugins/ets/stdlib/std/core/LocaleMatch.ets +++ b/static_core/plugins/ets/stdlib/std/core/LocaleMatch.ets @@ -22,6 +22,10 @@ export class LocaleMatch { static native lookupLocales(locale: string[]): string[] } +class LocaleHelper { + static native verifyBCP47LanguageTag(locale: string): void +} + export function intlLookUpLocale(locale: Intl.BCP47LanguageTag | Intl.BCP47LanguageTag[]): string { const tagList = locale instanceof Intl.BCP47LanguageTag ? [locale] : locale return LocaleMatch.lookupLocale(tagList) @@ -48,6 +52,8 @@ export function intlLocalesToLanguageTags(locales: string | Intl.Locale | Readon } if (locales instanceof string) { + const locale = locales as string + LocaleHelper.verifyBCP47LanguageTag(locale) return [locales] } else if (locales instanceof Intl.Locale) { return [locales.toString()] diff --git a/static_core/plugins/ets/subproject_sources.gn b/static_core/plugins/ets/subproject_sources.gn index 07480231de..4b4c4dcebc 100644 --- a/static_core/plugins/ets/subproject_sources.gn +++ b/static_core/plugins/ets/subproject_sources.gn @@ -214,6 +214,7 @@ srcs_runtime = [ "stdlib/native/core/IntlNumberFormatters.cpp", "stdlib/native/core/IntlFormattersCache.cpp", "stdlib/native/core/IntlLocale.cpp", + "stdlib/native/core/IntlLocaleHelper.cpp", "stdlib/native/core/IntlLocaleMatch.cpp", "stdlib/native/core/IntlCollator.cpp", "stdlib/native/core/IntlPluralRules.cpp", diff --git a/static_core/plugins/ets/tests/ets_func_tests/std/core/IntlLocalesToLanguageTagsTest.ets b/static_core/plugins/ets/tests/ets_func_tests/std/core/IntlLocalesToLanguageTagsTest.ets new file mode 100644 index 0000000000..6165640e60 --- /dev/null +++ b/static_core/plugins/ets/tests/ets_func_tests/std/core/IntlLocalesToLanguageTagsTest.ets @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function main(): int { + const suite = new arktest.ArkTestsuite('IntlLocalesToLanguageTags Tests'); + suite.addTest('testEmptyStringInvalid', testEmptyStringInvalid); + suite.addTest('testNumericInvalid', testNumericInvalid); + suite.addTest('testDoubleHyphenInvalid', testDoubleHyphenInvalid); + suite.addTest('testValidSimpleTag', testValidSimpleTag); + suite.addTest('testValidWithRegion', testValidWithRegion); + suite.addTest('testGrandfatheredInvalidTag1', testGrandfatheredInvalidTag1); + suite.addTest('testGrandfatheredInvalidTag2', testGrandfatheredInvalidTag2); + return suite.run(); +} + +function testEmptyStringInvalid() { + const loc = ''; + arktest.expectError((): void => { intlLocalesToLanguageTags(loc) }); +} + +function testNumericInvalid() { + const loc = '123'; + arktest.expectError((): void => { intlLocalesToLanguageTags(loc) }); +} + +function testDoubleHyphenInvalid() { + const loc = 'en--US'; + arktest.expectError((): void => { intlLocalesToLanguageTags(loc) }); +} + +function testValidSimpleTag() { + const loc = 'en'; + const result = intlLocalesToLanguageTags(loc); + arktest.assertEQ(result.toString(), 'en'); +} + +function testValidWithRegion() { + const loc = 'zh-CN'; + const result = intlLocalesToLanguageTags(loc); + arktest.assertEQ(result.toString(), 'zh-CN'); +} + +function testGrandfatheredInvalidTag1() { + const loc = 'i-enochian'; + arktest.expectError((): void => { intlLocalesToLanguageTags(loc) }); +} + +function testGrandfatheredInvalidTag2() { + const loc = 'sgn-BE-FR'; + arktest.expectError((): void => { intlLocalesToLanguageTags(loc) }); +} diff --git a/static_core/plugins/ets/tests/ets_func_tests/std/core/IntlNumberFormatNumberingSystem.ets b/static_core/plugins/ets/tests/ets_func_tests/std/core/IntlNumberFormatNumberingSystem.ets index 33dfd7f43e..dad8add427 100644 --- a/static_core/plugins/ets/tests/ets_func_tests/std/core/IntlNumberFormatNumberingSystem.ets +++ b/static_core/plugins/ets/tests/ets_func_tests/std/core/IntlNumberFormatNumberingSystem.ets @@ -20,8 +20,8 @@ function main(): int { } function testNumberingSystem() { - const locales: string[] = [ "en-US", "zh", "ar-SA", ""]; - const expected: string[] = [ "latn", "latn", "arab", "latn"]; + const locales: string[] = [ "en-US", "zh", "ar-SA"]; + const expected: string[] = [ "latn", "latn", "arab"]; let i: int = 0; for (const l of locales) { const nf = new Intl.NumberFormat(l); -- Gitee