1 /*
2 * Copyright (c) 2024 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 #ifdef FEATURE_ICU_LOCALE
17 #include <stdio.h>
18 #include <dlfcn.h>
19 #include <musl_log.h>
20 #include <string.h>
21 #include "locale_impl.h"
22
23 #define ICU_UC_SO "libhmicuuc.z.so"
24 #define ICU_I18N_SO "libhmicui18n.z.so"
25
26 static void *g_icuuc_handle = NULL;
27 static void *g_icui18n_handle = NULL;
28 hidden struct icu_opt_func g_icu_opt_func = { NULL };
29 static int dlopen_fail_flag = 0;
30 static int icuuc_handle_init_succeed = 0;
31
get_icu_handle(icu_so_type type,const char * symbol_name)32 static void *get_icu_handle(icu_so_type type, const char *symbol_name)
33 {
34 void *cur_handle;
35 char *cur_so;
36 if (type == ICU_UC) {
37 cur_handle = g_icuuc_handle;
38 cur_so = ICU_UC_SO;
39 } else {
40 cur_handle = g_icui18n_handle;
41 cur_so = ICU_I18N_SO;
42 }
43
44 if (!cur_handle && !dlopen_fail_flag) {
45 cur_handle = dlopen(cur_so, RTLD_LOCAL);
46 if (type == ICU_UC) {
47 g_icuuc_handle = cur_handle;
48 } else {
49 g_icui18n_handle = cur_handle;
50 }
51 }
52 if (!cur_handle) {
53 dlopen_fail_flag = 1;
54 MUSL_LOGE("dlopen icu so for musl locale fail %{public}s", dlerror());
55 return NULL;
56 }
57 return dlsym(cur_handle, symbol_name);
58 }
59
get_icu_version_num()60 static char *get_icu_version_num()
61 {
62 if (!(g_icu_opt_func.get_icu_version)) {
63 g_icu_opt_func.get_icu_version = get_icu_handle(ICU_UC, ICU_GET_VERSION_NUM_SYMBOL);
64 }
65 if (g_icu_opt_func.get_icu_version) {
66 return g_icu_opt_func.get_icu_version();
67 } else {
68 return "";
69 }
70 }
71
get_icu_symbol(icu_so_type type,void ** icu_symbol_handle,const char * symbol_name)72 void get_icu_symbol(icu_so_type type, void **icu_symbol_handle, const char *symbol_name)
73 {
74 if (!(*icu_symbol_handle)) {
75 char *icu_version = get_icu_version_num();
76 char *valid_icu_symbol = malloc(strlen(symbol_name) + strlen(icu_version) + 2);
77 sprintf(valid_icu_symbol, "%s_%s", symbol_name, icu_version);
78 *icu_symbol_handle = get_icu_handle(type, valid_icu_symbol);
79 free(valid_icu_symbol);
80 }
81 }
82
set_icu_directory()83 void set_icu_directory()
84 {
85 if (!(g_icu_opt_func.set_data_directory)) {
86 g_icu_opt_func.set_data_directory = get_icu_handle(ICU_UC, ICU_SET_DATA_DIRECTORY_SYMBOL);
87 if (g_icu_opt_func.set_data_directory) {
88 g_icu_opt_func.set_data_directory();
89 }
90 }
91 }
92
93 /* ICU methods don't need charset for locale, process the given locale name */
get_valid_icu_locale_name(const char * name,const char * icu_name,int icu_name_len)94 void get_valid_icu_locale_name(const char *name, const char *icu_name, int icu_name_len)
95 {
96 char *pos = memchr(name, '.', strlen(name));
97 int valid_len;
98 if (pos) {
99 valid_len = pos - name;
100 } else {
101 valid_len = strlen(name);
102 }
103 if (icu_name_len > valid_len) {
104 strncpy((char *)icu_name, name, valid_len);
105 }
106 }
107
icuuc_handle_init()108 bool icuuc_handle_init()
109 {
110 if (icuuc_handle_init_succeed) {
111 return true;
112 }
113
114 if (!g_icu_opt_func.set_data_directory) {
115 g_icu_opt_func.set_data_directory = get_icu_handle(ICU_UC, ICU_SET_DATA_DIRECTORY_SYMBOL);
116 if (g_icu_opt_func.set_data_directory) {
117 g_icu_opt_func.set_data_directory();
118 } else {
119 return false;
120 }
121 }
122 if (!g_icu_opt_func.ucnv_open) {
123 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_open), ICU_UCNV_OPEN_SYMBOL);
124 if (!g_icu_opt_func.ucnv_open) {
125 return false;
126 }
127 }
128 if (!g_icu_opt_func.ucnv_setToUCallBack) {
129 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_setToUCallBack), ICU_UCNV_SETTOUCALLBACK_SYMBOL);
130 if (!g_icu_opt_func.ucnv_setToUCallBack) {
131 return false;
132 }
133 }
134 if (!g_icu_opt_func.ucnv_setFromUCallBack) {
135 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_setFromUCallBack), ICU_UCNV_SETFROMUCALLBACK_SYMBOL);
136 if (!g_icu_opt_func.ucnv_setFromUCallBack) {
137 return false;
138 }
139 }
140 if (!g_icu_opt_func.ucnv_convertEx) {
141 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_convertEx), ICU_UCNV_CONVERTEX_SYMBOL);
142 if (!g_icu_opt_func.ucnv_convertEx) {
143 return false;
144 }
145 }
146 if (!g_icu_opt_func.ucnv_close) {
147 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_close), ICU_UCNV_CLOSE_SYMBOL);
148 if (!g_icu_opt_func.ucnv_close) {
149 return false;
150 }
151 }
152 icuuc_handle_init_succeed = 1;
153 errno = 0;
154 return true;
155 }
156 #endif
157