• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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