-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
pal_icushim_static.c
249 lines (204 loc) · 5.73 KB
/
pal_icushim_static.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "pal_icushim_internal.h"
#include "pal_icushim.h"
#include <unicode/putil.h>
#include <unicode/uversion.h>
#include <unicode/localpointer.h>
#include <unicode/utrace.h>
#if defined(TARGET_UNIX)
#include <strings.h>
#elif defined(TARGET_WINDOWS)
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#endif
static int32_t isLoaded = 0;
static int32_t isDataSet = 0;
static void log_shim_error(const char* format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
fputc('\n', stderr);
va_end(args);
}
static void log_icu_error(const char* name, UErrorCode status)
{
const char * statusText = u_errorName(status);
log_shim_error("ICU call %s failed with error #%d '%s'.", name, status, statusText);
}
#if defined(ICU_TRACING)
static void U_CALLCONV icu_trace_data(const void* context, int32_t fnNumber, int32_t level, const char* fmt, va_list args)
{
char buf[1000];
utrace_vformat(buf, sizeof(buf), 0, fmt, args);
printf("[ICUDT] %s: %s\n", utrace_functionName(fnNumber), buf);
}
#endif
static int32_t load_icu_data(const void* pData);
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE int32_t mono_wasm_load_icu_data(const void* pData);
EMSCRIPTEN_KEEPALIVE int32_t mono_wasm_load_icu_data(const void* pData)
{
return load_icu_data(pData);
}
/*
* driver.c calls this to make sure this file is linked, otherwise
* its not, meaning the EMSCRIPTEN_KEEPALIVE functions above
* are not kept.
*/
void mono_wasm_link_icu_shim(void);
void mono_wasm_link_icu_shim(void)
{
}
#endif
int32_t mono_wasi_load_icu_data(const void* pData);
int32_t mono_wasi_load_icu_data(const void* pData)
{
return load_icu_data(pData);
}
static int32_t load_icu_data(const void* pData)
{
UErrorCode status = 0;
udata_setCommonData(pData, &status);
if (U_FAILURE(status))
{
log_icu_error("udata_setCommonData", status);
return 0;
}
else
{
#if defined(ICU_TRACING)
// see https://github.com/unicode-org/icu/blob/master/docs/userguide/icu_data/tracing.md
utrace_setFunctions(0, 0, 0, icu_trace_data);
utrace_setLevel(UTRACE_VERBOSE);
#endif
isDataSet = 1;
return 1;
}
}
static const char *
cstdlib_load_icu_data(const char *path)
{
char *file_buf = NULL;
FILE *fp = fopen(path, "rb");
if (fp == NULL)
{
log_shim_error("Unable to load ICU dat file '%s'.", path);
goto error;
}
if (fseek(fp, 0L, SEEK_END) != 0)
{
log_shim_error("Unable to determine size of the dat file");
goto error;
}
long file_buf_size = ftell(fp);
if (file_buf_size == -1)
{
log_shim_error("Unable to determine size of the ICU dat file.");
goto error;
}
file_buf = malloc(sizeof(char) * (unsigned long)(file_buf_size + 1));
if (file_buf == NULL)
{
log_shim_error("Unable to allocate enough to read the ICU dat file");
goto error;
}
if (fseek(fp, 0L, SEEK_SET) != 0)
{
log_shim_error("Unable to seek ICU dat file.");
goto error;
}
fread(file_buf, sizeof(char), (unsigned long)file_buf_size, fp);
if (ferror( fp ) != 0)
{
log_shim_error("Unable to read ICU dat file");
goto error;
}
fclose(fp);
fp = NULL;
return file_buf;
error:
if (fp != NULL)
{
fclose(fp);
}
if (file_buf != NULL)
{
free(file_buf);
}
return NULL;
}
int32_t
GlobalizationNative_LoadICUData(const char* path)
{
#if defined(TARGET_MACCATALYST) || defined(TARGET_IOS) || defined(TARGET_TVOS)
if (path && path[0] != '/')
{
// if the path is relative, prepend the app bundle root
path = GlobalizationNative_GetICUDataPathRelativeToAppBundleRoot(path);
}
if (!path)
{
// fallback to icudt.dat in the app bundle resources in case the path isn't set
path = GlobalizationNative_GetICUDataPathFallback();
}
#endif
const char *icu_data = cstdlib_load_icu_data(path);
if (icu_data == NULL)
{
log_shim_error("Failed to load ICU data.");
return 0;
}
if (load_icu_data(icu_data) == 0)
{
log_shim_error("ICU BAD EXIT.");
return 0;
}
return GlobalizationNative_LoadICU();
}
int32_t GlobalizationNative_LoadICU(void)
{
#if !defined(LOCAL_BUILD)
// Static NativeAOT compilation does not have
// GlobalizationNative_LoadICUData() as entrypoint
if (!isDataSet)
{
// don't try to locate icudt.dat automatically if mono_wasm_load_icu_data wasn't called
// and fallback to invariant mode
return 0;
}
#endif
UErrorCode status = 0;
UVersionInfo version;
// Request the CLDR version to perform basic ICU initialization and find out
// whether it worked.
ulocdata_getCLDRVersion(version, &status);
if (U_FAILURE(status))
{
log_icu_error("ulocdata_getCLDRVersion", status);
return 0;
}
isLoaded = 1;
return 1;
}
void GlobalizationNative_InitICUFunctions(void* icuuc, void* icuin, const char* version, const char* suffix)
{
// no-op for static
}
int32_t GlobalizationNative_GetICUVersion(void)
{
// this method is only used from our tests
// this way we ensure we're testing on the right mode
// even though we can call u_getVersion without loading since it is statically linked.
if (!isLoaded)
return 0;
UVersionInfo versionInfo;
u_getVersion(versionInfo);
return (versionInfo[0] << 24) + (versionInfo[1] << 16) + (versionInfo[2] << 8) + versionInfo[3];
}