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
get_icu_handle(icu_so_type type, const char *symbol_name)31 static void *get_icu_handle(icu_so_type type, const char *symbol_name)
32 {
33 void *cur_handle;
34 char *cur_so;
35 if (type == ICU_UC) {
36 cur_handle = g_icuuc_handle;
37 cur_so = ICU_UC_SO;
38 } else {
39 cur_handle = g_icui18n_handle;
40 cur_so = ICU_I18N_SO;
41 }
42
43 if (!cur_handle && !dlopen_fail_flag) {
44 cur_handle = dlopen(cur_so, RTLD_LOCAL);
45 }
46 if (!cur_handle) {
47 dlopen_fail_flag = 1;
48 MUSL_LOGE("dlopen icu so for musl locale fail %{public}s", dlerror());
49 return NULL;
50 }
51 return dlsym(cur_handle, symbol_name);
52 }
53
get_icu_version_numnull54 static char *get_icu_version_num()
55 {
56 if (!(g_icu_opt_func.get_icu_version)) {
57 g_icu_opt_func.get_icu_version = get_icu_handle(ICU_UC, ICU_GET_VERSION_NUM_SYMBOL);
58 }
59 if (g_icu_opt_func.get_icu_version) {
60 return g_icu_opt_func.get_icu_version();
61 } else {
62 return "";
63 }
64 }
65
get_icu_symbol(icu_so_type type, void **icu_symbol_handle, const char *symbol_name)66 void get_icu_symbol(icu_so_type type, void **icu_symbol_handle, const char *symbol_name)
67 {
68 if (!(*icu_symbol_handle)) {
69 char *icu_version = get_icu_version_num();
70 char *valid_icu_symbol = malloc(strlen(symbol_name) + strlen(icu_version) + 2);
71 sprintf(valid_icu_symbol, "%s_%s", symbol_name, icu_version);
72 *icu_symbol_handle = get_icu_handle(type, valid_icu_symbol);
73 free(valid_icu_symbol);
74 }
75 }
76
set_icu_directorynull77 void set_icu_directory()
78 {
79 if (!(g_icu_opt_func.set_data_directory)) {
80 g_icu_opt_func.set_data_directory = get_icu_handle(ICU_UC, ICU_SET_DATA_DIRECTORY_SYMBOL);
81 if (g_icu_opt_func.set_data_directory) {
82 g_icu_opt_func.set_data_directory();
83 }
84 }
85 }
86
87 /* 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)88 void get_valid_icu_locale_name(const char *name, const char *icu_name, int icu_name_len)
89 {
90 char *pos = memchr(name, '.', strlen(name));
91 int valid_len;
92 if (pos) {
93 valid_len = pos - name;
94 } else {
95 valid_len = strlen(name);
96 }
97 if (icu_name_len > valid_len) {
98 strncpy(icu_name, name, valid_len);
99 }
100 }
101 #endif
102