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 static int icuuc_wctype_handle_init_succeed = 0;
32 bool icu_locale_wctype_enable = false;
33 pthread_mutex_t icu_wctype_init_mutex = PTHREAD_MUTEX_INITIALIZER;
34
get_icu_handle(icu_so_type type,const char * symbol_name)35 static void *get_icu_handle(icu_so_type type, const char *symbol_name)
36 {
37 void *cur_handle;
38 char *cur_so;
39 if (type == ICU_UC) {
40 cur_handle = g_icuuc_handle;
41 cur_so = ICU_UC_SO;
42 } else {
43 cur_handle = g_icui18n_handle;
44 cur_so = ICU_I18N_SO;
45 }
46
47 if (!cur_handle && !dlopen_fail_flag) {
48 cur_handle = dlopen(cur_so, RTLD_LOCAL);
49 if (type == ICU_UC) {
50 g_icuuc_handle = cur_handle;
51 } else {
52 g_icui18n_handle = cur_handle;
53 }
54 }
55 if (!cur_handle) {
56 dlopen_fail_flag = 1;
57 MUSL_LOGE("dlopen icu so for musl locale fail %{public}s", dlerror());
58 return NULL;
59 }
60 return dlsym(cur_handle, symbol_name);
61 }
62
get_icu_version_num()63 static char *get_icu_version_num()
64 {
65 if (!(g_icu_opt_func.get_icu_version)) {
66 g_icu_opt_func.get_icu_version = get_icu_handle(ICU_UC, ICU_GET_VERSION_NUM_SYMBOL);
67 }
68 if (g_icu_opt_func.get_icu_version) {
69 return g_icu_opt_func.get_icu_version();
70 } else {
71 return "";
72 }
73 }
74
get_icu_symbol(icu_so_type type,void ** icu_symbol_handle,const char * symbol_name)75 void get_icu_symbol(icu_so_type type, void **icu_symbol_handle, const char *symbol_name)
76 {
77 if (!(*icu_symbol_handle)) {
78 char *icu_version = get_icu_version_num();
79 char *valid_icu_symbol = malloc(strlen(symbol_name) + strlen(icu_version) + 2);
80 sprintf(valid_icu_symbol, "%s_%s", symbol_name, icu_version);
81 *icu_symbol_handle = get_icu_handle(type, valid_icu_symbol);
82 free(valid_icu_symbol);
83 }
84 }
85
set_icu_directory()86 void set_icu_directory()
87 {
88 if (!(g_icu_opt_func.set_data_directory)) {
89 g_icu_opt_func.set_data_directory = get_icu_handle(ICU_UC, ICU_SET_DATA_DIRECTORY_SYMBOL);
90 if (g_icu_opt_func.set_data_directory) {
91 g_icu_opt_func.set_data_directory();
92 }
93 }
94 }
95
96 /* 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)97 void get_valid_icu_locale_name(const char *name, const char *icu_name, int icu_name_len)
98 {
99 char *pos = memchr(name, '.', strlen(name));
100 int valid_len;
101 if (pos) {
102 valid_len = pos - name;
103 } else {
104 valid_len = strlen(name);
105 }
106 if (icu_name_len > valid_len) {
107 strncpy((char *)icu_name, name, valid_len);
108 }
109 }
110
set_wctype_icu_enable()111 int set_wctype_icu_enable()
112 {
113 pthread_mutex_lock(&icu_wctype_init_mutex);
114 if (!icuuc_wctype_handle_init()){
115 pthread_mutex_unlock(&icu_wctype_init_mutex);
116 return ICU_SYMBOL_LOAD_ERROR;
117 }
118
119 icu_locale_wctype_enable = true;
120 pthread_mutex_unlock(&icu_wctype_init_mutex);
121 return ICU_ZERO_ERROR;
122 }
123
icuuc_wctype_handle_init()124 bool icuuc_wctype_handle_init()
125 {
126 if (icuuc_wctype_handle_init_succeed) {
127 return true;
128 }
129 if (!g_icu_opt_func.u_isalnum) {
130 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_isalnum), ICU_UCHAR_ISALNUM_SYMBOL);
131 if (!g_icu_opt_func.u_isalnum) {
132 return false;
133 }
134 }
135 if (!g_icu_opt_func.u_isalpha) {
136 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_isalpha), ICU_UCHAR_ISALPHA_SYMBOL);
137 if (!g_icu_opt_func.u_isalpha) {
138 return false;
139 }
140 }
141 if (!g_icu_opt_func.u_isblank) {
142 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_isblank), ICU_UCHAR_ISBLANK_SYMBOL);
143 if (!g_icu_opt_func.u_isblank) {
144 return false;
145 }
146 }
147 if (!g_icu_opt_func.u_iscntrl) {
148 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_iscntrl), ICU_UCHAR_ISCNTRL_SYMBOL);
149 if (!g_icu_opt_func.u_iscntrl) {
150 return false;
151 }
152 }
153 if (!g_icu_opt_func.u_isdigit) {
154 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_isdigit), ICU_UCHAR_ISDIGIT_SYMBOL);
155 if (!g_icu_opt_func.u_isdigit) {
156 return false;
157 }
158 }
159 if (!g_icu_opt_func.u_isgraph) {
160 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_isgraph), ICU_UCHAR_ISGRAPH_SYMBOL);
161 if (!g_icu_opt_func.u_isgraph) {
162 return false;
163 }
164 }
165 if (!g_icu_opt_func.u_islower) {
166 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_islower), ICU_UCHAR_ISLOWER_SYMBOL);
167 if (!g_icu_opt_func.u_islower) {
168 return false;
169 }
170 }
171 if (!g_icu_opt_func.u_isprint) {
172 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_isprint), ICU_UCHAR_ISPRINT_SYMBOL);
173 if (!g_icu_opt_func.u_isprint) {
174 return false;
175 }
176 }
177 if (!g_icu_opt_func.u_ispunct) {
178 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_ispunct), ICU_UCHAR_ISPUNCT_SYMBOL);
179 if (!g_icu_opt_func.u_ispunct) {
180 return false;
181 }
182 }
183 if (!g_icu_opt_func.u_isspace) {
184 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_isspace), ICU_UCHAR_ISSPACE_SYMBOL);
185 if (!g_icu_opt_func.u_isspace) {
186 return false;
187 }
188 }
189 if (!g_icu_opt_func.u_isupper) {
190 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_isupper), ICU_UCHAR_ISUPPER_SYMBOL);
191 if (!g_icu_opt_func.u_isupper) {
192 return false;
193 }
194 }
195 if (!g_icu_opt_func.u_isxdigit) {
196 get_icu_symbol(ICU_I18N, (void **)&(g_icu_opt_func.u_isxdigit), ICU_UCHAR_ISXDIGIT_SYMBOL);
197 if (!g_icu_opt_func.u_isxdigit) {
198 return false;
199 }
200 }
201 if (!g_icu_opt_func.u_tolower) {
202 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.u_tolower), ICU_UCHAR_TOLOWER_SYMBOL);
203 if (!g_icu_opt_func.u_tolower) {
204 return false;
205 }
206 }
207 if (!g_icu_opt_func.u_toupper) {
208 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.u_toupper), ICU_UCHAR_TOUPPER_SYMBOL);
209 if (!g_icu_opt_func.u_toupper) {
210 return false;
211 }
212 }
213 icuuc_wctype_handle_init_succeed = true;
214 return true;
215 }
216
icuuc_handle_init()217 bool icuuc_handle_init()
218 {
219 if (icuuc_handle_init_succeed) {
220 return true;
221 }
222
223 if (!g_icu_opt_func.set_data_directory) {
224 g_icu_opt_func.set_data_directory = get_icu_handle(ICU_UC, ICU_SET_DATA_DIRECTORY_SYMBOL);
225 if (g_icu_opt_func.set_data_directory) {
226 g_icu_opt_func.set_data_directory();
227 } else {
228 return false;
229 }
230 }
231 if (!g_icu_opt_func.ucnv_open) {
232 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_open), ICU_UCNV_OPEN_SYMBOL);
233 if (!g_icu_opt_func.ucnv_open) {
234 return false;
235 }
236 }
237 if (!g_icu_opt_func.ucnv_setToUCallBack) {
238 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_setToUCallBack), ICU_UCNV_SETTOUCALLBACK_SYMBOL);
239 if (!g_icu_opt_func.ucnv_setToUCallBack) {
240 return false;
241 }
242 }
243 if (!g_icu_opt_func.ucnv_setFromUCallBack) {
244 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_setFromUCallBack), ICU_UCNV_SETFROMUCALLBACK_SYMBOL);
245 if (!g_icu_opt_func.ucnv_setFromUCallBack) {
246 return false;
247 }
248 }
249 if (!g_icu_opt_func.ucnv_convertEx) {
250 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_convertEx), ICU_UCNV_CONVERTEX_SYMBOL);
251 if (!g_icu_opt_func.ucnv_convertEx) {
252 return false;
253 }
254 }
255 if (!g_icu_opt_func.ucnv_close) {
256 get_icu_symbol(ICU_UC, (void **)&(g_icu_opt_func.ucnv_close), ICU_UCNV_CLOSE_SYMBOL);
257 if (!g_icu_opt_func.ucnv_close) {
258 return false;
259 }
260 }
261 icuuc_handle_init_succeed = 1;
262 errno = 0;
263 return true;
264 }
265 #endif
266