diff --git a/libc-test/src/functional/iconv_joint_icu_test.c b/libc-test/src/functional/iconv_joint_icu_test.c index ee4a5b561658cb61b144efc10e914fc24397ffe0..fd00ab0c4498c5e44b7e473b84788d5825512ce4 100644 --- a/libc-test/src/functional/iconv_joint_icu_test.c +++ b/libc-test/src/functional/iconv_joint_icu_test.c @@ -30,6 +30,8 @@ #define BUFFER_SIZE 1024 #define IGNORE_SIZE 9 +int set_iconv_icu_enable(); + typedef struct StatefulCombined { unsigned sign; const unsigned char* to; @@ -364,6 +366,16 @@ void test_large_string(void) int main(void) { + int icu_res = set_iconv_icu_enable(); + if (icu_res != 0) { + t_error("set_iconv_icu_enable failed, error: %d \n", icu_res); + return t_status; + } + icu_res = set_iconv_icu_enable(); + if (icu_res != 0) { + t_error("set_iconv_icu_enable twice failed, error: %d \n", icu_res); + return t_status; + } g_ins_zh_len = strlen(g_ins_zh); for (int i = 0; i < g_target_num; i++) { diff --git a/src/internal/locale_impl.c b/src/internal/locale_impl.c index cae0c1fdfad11b3e2abb3865c5272c718959509e..012e335bc2a0ee1e6e785217be94577af75fd1e2 100644 --- a/src/internal/locale_impl.c +++ b/src/internal/locale_impl.c @@ -27,7 +27,7 @@ static void *g_icuuc_handle = NULL; static void *g_icui18n_handle = NULL; hidden struct icu_opt_func g_icu_opt_func = { NULL }; static int dlopen_fail_flag = 0; -static int icuuc_handle_init_fail = 0; +static int icuuc_handle_init_succeed = 0; static void *get_icu_handle(icu_so_type type, const char *symbol_name) { @@ -107,8 +107,8 @@ void get_valid_icu_locale_name(const char *name, const char *icu_name, int icu_n bool icuuc_handle_init() { - if (icuuc_handle_init_fail) { - return false; + if (icuuc_handle_init_succeed) { + return true; } if (!g_icu_opt_func.set_data_directory) { @@ -116,46 +116,40 @@ bool icuuc_handle_init() if (g_icu_opt_func.set_data_directory) { g_icu_opt_func.set_data_directory(); } else { - icuuc_handle_init_fail = 1; return false; } } if (!g_icu_opt_func.ucnv_open) { get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_open), ICU_UCNV_OPEN_SYMBOL); if (!g_icu_opt_func.ucnv_open) { - icuuc_handle_init_fail = 1; return false; } } if (!g_icu_opt_func.ucnv_setToUCallBack) { get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_setToUCallBack), ICU_UCNV_SETTOUCALLBACK_SYMBOL); if (!g_icu_opt_func.ucnv_setToUCallBack) { - icuuc_handle_init_fail = 1; return false; } } if (!g_icu_opt_func.ucnv_setFromUCallBack) { get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_setFromUCallBack), ICU_UCNV_SETFROMUCALLBACK_SYMBOL); if (!g_icu_opt_func.ucnv_setFromUCallBack) { - icuuc_handle_init_fail = 1; return false; } } if (!g_icu_opt_func.ucnv_convertEx) { get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_convertEx), ICU_UCNV_CONVERTEX_SYMBOL); if (!g_icu_opt_func.ucnv_convertEx) { - icuuc_handle_init_fail = 1; return false; } } if (!g_icu_opt_func.ucnv_close) { get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_close), ICU_UCNV_CLOSE_SYMBOL); if (!g_icu_opt_func.ucnv_close) { - icuuc_handle_init_fail = 1; return false; } } - + icuuc_handle_init_succeed = 1; errno = 0; return true; } diff --git a/src/locale/iconv.c b/src/locale/iconv.c index d43bac2270bb83587f438ce3a69ab29f90ec002d..7c869593d987ceb867f9ea673cc47de5dde84f8e 100644 --- a/src/locale/iconv.c +++ b/src/locale/iconv.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "locale_impl.h" #ifndef __LITEOS__ #ifdef FEATURE_ICU_LOCALE @@ -35,12 +36,13 @@ #ifndef __LITEOS__ #ifdef FEATURE_ICU_LOCALE #define ICU_ZERO_ERROR 0 +#define ICU_SYMBOL_LOAD_ERROR (-1) #define ICU_IVALID_CHAR_ERROR 10 #define ICU_TRUNCATED_CHAR_ERROR 11 #define ICU_ILLEGAL_CHAR_ERROR 12 #define ICU_BUFFER_OVERFLOW_ERROR 15 #define ICU_SKIP_THRESHOLD 2 -#define DEVICE_VERSION_THRESHOLD 18 +#define DEVICE_VERSION_THRESHOLD 20 #define TYPE_FLAG_POS 1 #define TO_IGNORE_FLAG_POS 2 #define FROM_IGNORE_FLAG_POS 3 @@ -288,6 +290,33 @@ static bool deal_with_tail(const char* ins, unsigned* sign, const unsigned char* free(ins_tmp); return true; } + +int icu_first_init = 0; + +bool icu_locale_enable = false; + +pthread_mutex_t icu_init_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** +* @Description: The set_icu_enable function is used to set the internal implementation of iconv to the implementation of the ICU library. +* The iconv internal implementation may have been set to the ICU library implementation before the function was executed. In this case, +* the function also returns success. +* @return:If the function call is successful, the returned value will be zero; otherwise, the returned value will be a non-zero error code. +*/ + +int set_iconv_icu_enable() +{ + pthread_mutex_lock(&icu_init_mutex); + if (!icuuc_handle_init()) { + pthread_mutex_unlock(&icu_init_mutex); + return ICU_SYMBOL_LOAD_ERROR; + } + + icu_locale_enable = true; + pthread_mutex_unlock(&icu_init_mutex); + return ICU_ZERO_ERROR; +} + #endif #endif @@ -298,19 +327,21 @@ iconv_t iconv_open(const char *to, const char *from) #ifndef __LITEOS__ #ifdef FEATURE_ICU_LOCALE bool is_basic_open = false; - if (get_device_api_version_inner() < DEVICE_VERSION_THRESHOLD) { - is_basic_open = true; - } else { - for (const char* s = "iso885916\0iso2022jp\0\0"; *s;) { // icu not support - if (!fuzzycmp((void*)to, (void*)s) || !fuzzycmp((void*)from, (void*)s)) { - is_basic_open = true; - } - s += strlen(s) + 1; + + if ((get_device_api_version_inner() >= DEVICE_VERSION_THRESHOLD) && (icu_first_init == 0)) + { + set_iconv_icu_enable(); + icu_first_init++; + } + for (const char* s = "iso885916\0iso2022jp\0\0"; *s;) { // icu not support + if (!fuzzycmp((void*)to, (void*)s) || !fuzzycmp((void*)from, (void*)s)) { + is_basic_open = true; } + s += strlen(s) + 1; } // icu open - if (!is_basic_open && icuuc_handle_init()) { + if (!is_basic_open && icu_locale_enable) { scd = malloc(sizeof *scd); if (!scd) {return (iconv_t)-1;} scd->sign = 0;