1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 #ifndef __LITEOS__
23 #include "test.h"
24 #include <errno.h>
25 #include <iconv.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #define EXTRA_LARGE_SIZE (30*1024*1024)
30 #define BUFFER_SIZE 1024
31 #define IGNORE_SIZE 9
32
33 int set_iconv_icu_enable(void);
34
35 typedef struct StatefulCombined {
36 unsigned sign;
37 const unsigned char* to;
38 const unsigned char* from;
39 iconv_t base_cd;
40 unsigned state;
41 } StatefulCombined;
42
43 typedef struct NameMap {
44 const char* source;
45 const char* target;
46 } NameMap;
47
48
49 // Global Variables
50 static NameMap g_mappings[] = {
51 {"utf8\0char\0\0", "UTF-8"},
52 {"utf7\0\0", "UTF-7"},
53 {"ucs2\0utf16\0ucs2be\0utf16be\0\0", "UTF-16BE"},
54 {"ucs2le\0utf16le\0\0", "UTF-16LE"},
55 {"ucs4\0utf32\0ucs4be\0utf32be\0\0", "UTF-32BE"},
56 {"wchart\0ucs4le\0utf32le\0\0", "UTF-32LE"},
57 {"ascii\0usascii\0""20127\0iso646\0iso646us\0\0", "US-ASCII"},
58 {"eucjp\0eucjp2007\0\0", "euc-jp-2007"},
59 {"shiftjis\0sjis\0cp932\0ibm943p15a2003\0\0", "ibm-943_P15A-2003"},
60 {"gb18030\0\0", "gb18030"},
61 {"gbk\0""54936\0windows9362000\0\0", "windows-936-2000"},
62 {"gb2312\0""52936\0ibm1383p1101999\0\0", "ibm-1383_P110-1999"},
63 {"big5\0""950\0bigfive\0cp950\0windows9502000\0\0", "windows-950-2000"},
64 {"big5hk\0big5hkscs\0""951\0ibm1375p1002008\0\0", "ibm-1375_P100-2008"},
65 {"euckr\0ibm970p110p1102006u2\0\0", "ibm-970_P110_P110-2006_U2"},
66 {"ksc5601\0ksx1001\0cp949\0windows9492000\0\0", "windows-949-2000"},
67 {"iso88591\0latin1\0\0", "ISO-8859-1"},
68 {"iso88592\0ibm912p1001995\0\0", "ibm-912_P100-1995"},
69 {"iso88593\0ibm913p1002000\0\0", "ibm-913_P100-2000"},
70 {"iso88594\0ibm914p1001995\0\0", "ibm-914_P100-1995"},
71 {"iso88595\0ibm915p1001995\0\0", "ibm-915_P100-1995"},
72 {"iso88596\0ibm1089p1001995\0\0", "ibm-1089_P100-1995"},
73 {"iso88597\0ibm9005x1102007\0\0", "ibm-9005_X110-2007"},
74 {"iso88598\0ibm5012p1001999\0\0", "ibm-5012_P100-1999"},
75 {"iso88599\0ibm920p1001995\0\0", "ibm-920_P100-1995"},
76 {"iso885910\0iso8859101998\0\0", "iso-8859_10-1998"},
77 {"iso885911\0iso8859112001\0\0", "iso-8859_11-2001"},
78 {"tis620\0windows8742000\0\0", "windows-874-2000"},
79 {"iso885913\0ibm921p1001995\0\0", "ibm-921_P100-1995"},
80 {"iso885914\0iso8859141998\0\0", "iso-8859_14-1998"},
81 {"iso885915\0latin9\0ibm923p1001998\0\0", "ibm-923_P100-1998"},
82 {"cp1250\0windows1250\0ibm5346p1001998\0\0", "ibm-5346_P100-1998"},
83 {"cp1251\0windows1251\0ibm5347p1001998\0\0", "ibm-5347_P100-1998"},
84 {"cp1252\0windows1252\0ibm5348p1001997\0\0", "ibm-5348_P100-1997"},
85 {"cp1253\0windows1253\0ibm5349p1001998\0\0", "ibm-5349_P100-1998"},
86 {"cp1254\0windows1254\0ibm5350p1001998\0\0", "ibm-5350_P100-1998"},
87 {"cp1255\0windows1255\0ibm9447p1002002\0\0", "ibm-9447_P100-2002"},
88 {"cp1256\0windows1256\0ibm9448x1002005\0\0", "ibm-9448_X100-2005"},
89 {"cp1257\0windows1257\0ibm9449p1002002\0\0", "ibm-9449_P100-2002"},
90 {"cp1258\0windows1258\0ibm5354p1001998\0\0", "ibm-5354_P100-1998"},
91 {"koi8r\0ibm878p1001996\0\0", "ibm-878_P100-1996"},
92 {"koi8u\0ibm1168p1002002\0\0", "ibm-1168_P100-2002"},
93 {"cp437\0ibm437p1001995\0\0", "ibm-437_P100-1995"},
94 {"cp850\0ibm850p1001995\0\0", "ibm-850_P100-1995"},
95 {"cp866\0ibm866p1001995\0\0", "ibm-866_P100-1995"},
96 {"ibm1047\0cp1047\0ibm1047p1001995\0\0", "ibm-1047_P100-1995"},
97 };
98 char* g_source_str;
99 char* g_target_str;
100 char g_mids[BUFFER_SIZE];
101 char g_outs[BUFFER_SIZE];
102 int32_t g_target_num = sizeof(g_mappings) / sizeof(g_mappings[0]);
103 char g_ins[] = {
104 0x00, 0x20, // ' ' (space)
105 0x00, 0x21, // '!'
106 0x00, 0x22, // '"'
107 0x00, 0x23, // '#'
108 0x00, 0x24, // '$'
109 0x00, 0x25, // '%'
110 0x00, 0x26, // '&'
111 0x00, 0x27, // '''
112 0x00, 0x28, // '('
113 0x00, 0x29, // ')'
114 0x00, 0x2A, // '*'
115 0x00, 0x2B, // '+'
116 0x00, 0x2C, // ','
117 0x00, 0x2D, // '-'
118 0x00, 0x2E, // '.'
119 0x00, 0x2F, // '/'
120 0x00, 0x30, // '0'
121 0x00, 0x31, // '1'
122 0x00, 0x32, // '2'
123 0x00, 0x33, // '3'
124 0x00, 0x34, // '4'
125 0x00, 0x35, // '5'
126 0x00, 0x36, // '6'
127 0x00, 0x37, // '7'
128 0x00, 0x38, // '8'
129 0x00, 0x39, // '9'
130 0x00, 0x3A, // ':'
131 0x00, 0x3B, // ';'
132 0x00, 0x3C, // '<'
133 0x00, 0x3D, // '='
134 0x00, 0x3E, // '>'
135 0x00, 0x3F, // '?'
136 0x00, 0x40, // '@'
137 0x00, 0x41, // 'A'
138 0x00, 0x42, // 'B'
139 0x00, 0x43, // 'C'
140 0x00, 0x44, // 'D'
141 0x00, 0x45, // 'E'
142 0x00, 0x46, // 'F'
143 0x00, 0x47, // 'G'
144 0x00, 0x48, // 'H'
145 0x00, 0x49, // 'I'
146 0x00, 0x4A, // 'J'
147 0x00, 0x4B, // 'K'
148 0x00, 0x4C, // 'L'
149 0x00, 0x4D, // 'M'
150 0x00, 0x4E, // 'N'
151 0x00, 0x4F, // 'O'
152 0x00, 0x50, // 'P'
153 0x00, 0x51, // 'Q'
154 0x00, 0x52, // 'R'
155 0x00, 0x53, // 'S'
156 0x00, 0x54, // 'T'
157 0x00, 0x55, // 'U'
158 0x00, 0x56, // 'V'
159 0x00, 0x57, // 'W'
160 0x00, 0x58, // 'X'
161 0x00, 0x59, // 'Y'
162 0x00, 0x5A, // 'Z'
163 0x00, 0x5B, // '['
164 0x00, 0x5C, // '\\'
165 0x00, 0x5D, // ']'
166 0x00, 0x5E, // '^'
167 0x00, 0x5F, // '_'
168 0x00, 0x60, // '`'
169 0x00, 0x61, // 'a'
170 0x00, 0x62, // 'b'
171 0x00, 0x63, // 'c'
172 0x00, 0x64, // 'd'
173 0x00, 0x65, // 'e'
174 0x00, 0x66, // 'f'
175 0x00, 0x67, // 'g'
176 0x00, 0x68, // 'h'
177 0x00, 0x69, // 'i'
178 0x00, 0x6A, // 'j'
179 0x00, 0x6B, // 'k'
180 0x00, 0x6C, // 'l'
181 0x00, 0x6D, // 'm'
182 0x00, 0x6E, // 'n'
183 0x00, 0x6F, // 'o'
184 0x00, 0x70, // 'p'
185 0x00, 0x71, // 'q'
186 0x00, 0x72, // 'r'
187 0x00, 0x73, // 's'
188 0x00, 0x74, // 't'
189 0x00, 0x75, // 'u'
190 0x00, 0x76, // 'v'
191 0x00, 0x77, // 'w'
192 0x00, 0x78, // 'x'
193 0x00, 0x79, // 'y'
194 0x00, 0x7A, // 'z'
195 0x00, 0x7B, // '{'
196 0x00, 0x7C, // '|'
197 0x00, 0x7D, // '}'
198 0x00, 0x7E // '~'
199 };
200 size_t g_ins_len = sizeof(g_ins);
201 char* g_ins_zh = "Big5 编码示例";
202 size_t g_ins_zh_len;
203
iconv_close_with_strerror(iconv_t cd)204 void iconv_close_with_strerror(iconv_t cd)
205 {
206 if (iconv_close(cd)) {
207 t_error("closed iconv failed, error: %s \n", strerror(errno));
208 }
209 }
210
alias_test(void)211 void alias_test(void)
212 {
213 char* s;
214 StatefulCombined *scd = 0;
215 for (s = g_source_str; *s;) {
216 scd = (void *)iconv_open(s, s);
217 if (scd == (iconv_t)-1) {
218 t_error("iconv opened failed, from: %s, to: %s, error: %s \n", s, s, strerror(errno));
219 return;
220 }
221 if (strcmp((void*)scd->to, g_target_str) != 0) {
222 t_error("verify error: [input]%s, [actual_to]%s [expect_to]%s\n", s, scd->to, g_target_str);
223 }
224 if (strcmp((void*)scd->from, g_target_str) != 0) {
225 t_error("verify error: [input]%s, [actual_from]%s [expect_from]%s\n", s, scd->from, g_target_str);
226 }
227 s += strlen(s) + 1;
228 iconv_close_with_strerror(scd);
229 }
230 }
231
iconv_test(char * from,char * to,char ** inptrptr,size_t * input_len_ptr,char ** outptrptr,size_t * output_len_ptr)232 size_t iconv_test(char* from, char* to,
233 char** inptrptr, size_t* input_len_ptr, char** outptrptr, size_t* output_len_ptr)
234 {
235 iconv_t cd = iconv_open((void*)to, (void*)from);
236 if (cd == (iconv_t)-1) {
237 t_error("iconv opened failed, from: %s, to: %s, error: %s \n", from, to, strerror(errno));
238 return (size_t)-1;
239 }
240
241 size_t res = iconv(cd, inptrptr, input_len_ptr, outptrptr, output_len_ptr);
242 if (res) {
243 iconv_close_with_strerror(cd);
244 return res;
245 }
246
247 iconv_close_with_strerror(cd);
248 return res;
249 }
250
iconv_exchange(char * from,char * to,char * ins,size_t ins_len)251 void iconv_exchange(char* from, char* to, char* ins, size_t ins_len)
252 {
253 char* ins_ptr = ins;
254 char* mids_ptr = g_mids;
255 char* outs_ptr = g_outs;
256 size_t ins_bytes = ins_len;
257 size_t mids_bytes = BUFFER_SIZE;
258 size_t outs_bytes = BUFFER_SIZE;
259
260 iconv_test(from, to, &ins_ptr, &ins_bytes, &mids_ptr, &mids_bytes);
261
262 ins_ptr = g_mids;
263 ins_bytes = BUFFER_SIZE - mids_bytes;
264 iconv_test(to, from, &ins_ptr, &ins_bytes, &outs_ptr, &outs_bytes);
265 }
266
charcmp(char * a,char * b)267 static int charcmp(char* a, char* b)
268 {
269 for (; *a && *b; a++, b++) {
270 if (*a != *b) {return 1;}
271 }
272 return *a != *b;
273 }
274
iconv_exchange_with_charcmp(char * from,char * to,char * ins,size_t ins_len)275 void iconv_exchange_with_charcmp(char* from, char* to, char* ins, size_t ins_len)
276 {
277 iconv_exchange(from, to, ins, ins_len);
278 if (charcmp(ins, g_outs) != 0) {
279 t_error("compare error [type]%s, [ins] %s, [outs] %s\n",
280 to, ins, g_outs);
281 }
282 }
283
test_to_ignore_skip(void)284 void test_to_ignore_skip(void)
285 {
286 char* expect = "Big5 示例";
287 iconv_exchange("utf8", "big5//IGNORE", g_ins_zh, g_ins_zh_len);
288 if (strcmp(expect, g_outs) != 0) {
289 t_error("iconv with ignore error: [ins] %s [outs] %s [expect] %s\n",
290 g_ins_zh, g_outs, expect);
291 }
292 }
293
test_to_translit_skip(void)294 void test_to_translit_skip(void)
295 {
296 char* expect = "Big5 ??示例";
297 iconv_exchange("utf8", "big5//TRANSLIT", g_ins_zh, g_ins_zh_len);
298 if (strcmp(expect, g_outs) != 0) {
299 t_error("iconv with translit error: [ins] %s [outs] %s [expect] %s\n",
300 g_ins_zh, g_outs, expect);
301 }
302 }
303
test_errno_ilseq(void)304 void test_errno_ilseq(void)
305 {
306 char* ins_ptr = g_ins_zh;
307 size_t ins_bytes = g_ins_zh_len;
308 char* outs_ptr = g_outs;
309 size_t outs_bytes = BUFFER_SIZE;
310 size_t res = iconv_test("utf8", "big5", &ins_ptr, &ins_bytes, &outs_ptr, &outs_bytes);
311 if (res != (size_t)-1 || errno != EILSEQ) {
312 t_error("Failed: [ins] %s [outs] %s [res] %d [errno] %s\n",
313 g_ins_zh, g_outs, res, strerror(errno));
314 }
315 }
316
test_errno_e2big(void)317 void test_errno_e2big(void)
318 {
319 char* ins_ptr = g_ins_zh;
320 size_t ins_bytes = g_ins_zh_len;
321 char* outs_ptr = g_outs;
322 size_t outs_bytes = 10;
323 size_t res = iconv_test("utf8", "utf16", &ins_ptr, &ins_bytes, &outs_ptr, &outs_bytes);
324 if (res != (size_t)-1 || errno != E2BIG) {
325 t_error("Failed: [ins] %s [outs] %s [res] %d [errno] %s\n",
326 g_ins_zh, g_outs, res, strerror(errno));
327 }
328 }
329
test_empty_type(void)330 void test_empty_type(void)
331 {
332 StatefulCombined *scd = 0;
333 scd = (void *)iconv_open("", "");
334 if (strcmp((void*)scd->to, "UTF-8") != 0 || strcmp((void*)scd->from, "UTF-8") != 0) {
335 t_error("verify error: empty type not default fill utf8");
336 }
337 iconv_close_with_strerror(scd);
338 }
339
test_large_string(void)340 void test_large_string(void)
341 {
342 iconv_t cd = iconv_open("utf8", "utf16");
343 if (cd == (iconv_t)-1) {
344 t_error("iconv open failed, from utf8 to utf16,error: %s \n", strerror(errno));
345 return;
346 }
347 char* inptr = malloc(EXTRA_LARGE_SIZE);
348 if (inptr == NULL) {
349 t_error("malloc failed, errno : %s \n", strerror(errno));
350 return;
351 }
352 memset(inptr, 'A', EXTRA_LARGE_SIZE - 1);
353 size_t input_len_ptr = EXTRA_LARGE_SIZE;
354 char* outptr = malloc(EXTRA_LARGE_SIZE * 4);
355 if (outptr == NULL) {
356 t_error("malloc failed, errno : %s \n", strerror(errno));
357 return;
358 }
359 size_t output_len_ptr = EXTRA_LARGE_SIZE * 4;
360 size_t res = iconv(cd, &inptr, &input_len_ptr, &outptr, &output_len_ptr);
361 if (res == -1) {
362 t_error("iconv failed, error: %s \n", strerror(errno));
363 }
364 iconv_close_with_strerror(cd);
365 }
366
main(void)367 int main(void)
368 {
369 int icu_res = set_iconv_icu_enable();
370 if (icu_res != 0) {
371 t_error("set_iconv_icu_enable failed, error: %d \n", icu_res);
372 return t_status;
373 }
374 icu_res = set_iconv_icu_enable();
375 if (icu_res != 0) {
376 t_error("set_iconv_icu_enable twice failed, error: %d \n", icu_res);
377 return t_status;
378 }
379 g_ins_zh_len = strlen(g_ins_zh);
380
381 for (int i = 0; i < g_target_num; i++) {
382 g_target_str = (void*)g_mappings[i].target;
383 g_source_str = (void*)g_mappings[i].source;
384
385 // test all avail alias with iconv_open
386 alias_test();
387
388 // test iconv without ignore
389 iconv_exchange_with_charcmp("utf16", g_target_str, g_ins, g_ins_len);
390
391 // test iconv with ignore (norm input->not skip)
392 char* target_str_with_ignore = malloc(strlen(g_target_str) + IGNORE_SIZE);
393 strcpy(target_str_with_ignore, g_target_str);
394 strcat(target_str_with_ignore, "//IGNORE");
395 iconv_exchange_with_charcmp("utf16", target_str_with_ignore, g_ins, g_ins_len);
396 iconv_exchange_with_charcmp("utf16//IGNORE", target_str_with_ignore, g_ins, g_ins_len);
397 free(target_str_with_ignore);
398 }
399
400 // test iconv with ignore (special input -> skip)
401 test_to_ignore_skip();
402
403 // test iconv with translit (special input -> translit)
404 test_to_translit_skip();
405
406 // test basic type (iso885916)
407 iconv_exchange_with_charcmp("utf16", "iso885916", g_ins, g_ins_len);
408
409 // test errno
410 test_errno_ilseq();
411 test_errno_e2big();
412
413 // empty type -> fill UTF-8
414 test_empty_type();
415
416 // test extra large string convert
417 test_large_string();
418
419 return t_status;
420 }
421 #endif