FreeRDP
Loading...
Searching...
No Matches
TestUnicodeConversion.c
1
2#include <stdio.h>
3#include <winpr/wtypes.h>
4#include <winpr/crt.h>
5#include <winpr/assert.h>
6#include <winpr/error.h>
7#include <winpr/print.h>
8#include <winpr/windows.h>
9
10#define TESTCASE_BUFFER_SIZE 8192
11
12#ifndef MIN
13#define MIN(x, y) (((x) < (y)) ? (x) : (y))
14#endif
15
16typedef struct
17{
18 const char* utf8;
19 size_t utf8len;
20 const WCHAR* utf16;
21 size_t utf16len;
22} testcase_t;
23
24// TODO: The unit tests do not check for valid code points, so always end the test
25// strings with a simple ASCII symbol for now.
26static const testcase_t unit_testcases[] = {
27 { "foo", 3, (const WCHAR*)"f\x00o\x00o\x00\x00\x00", 3 },
28 { "foo", 4, (const WCHAR*)"f\x00o\x00o\x00\x00\x00", 4 },
29 { "βœŠπŸŽ…Δ™Κ₯κ£Έπ‘—Ša", 19,
30 (const WCHAR*)"\x0a\x27\x3c\xd8\x85\xdf\x19\x01\xa5\x02\xf8\xa8\x05\xd8\xca\xdd\x61\x00\x00"
31 "\x00",
32 9 }
33};
34
35static void create_prefix(char* prefix, size_t prefixlen, size_t buffersize, SSIZE_T rc,
36 SSIZE_T inputlen, const testcase_t* test, const char* fkt, size_t line)
37{
38 (void)_snprintf(prefix, prefixlen,
39 "[%s:%" PRIuz "] '%s' [utf8: %" PRIuz ", utf16: %" PRIuz "] buffersize: %" PRIuz
40 ", rc: %" PRIdz ", inputlen: %" PRIdz ":: ",
41 fkt, line, test->utf8, test->utf8len, test->utf16len, buffersize, rc, inputlen);
42}
43
44static BOOL check_short_buffer(const char* prefix, int rc, size_t buffersize,
45 const testcase_t* test, BOOL utf8)
46{
47 if ((rc > 0) && ((size_t)rc <= buffersize))
48 return TRUE;
49
50 size_t len = test->utf8len;
51 if (!utf8)
52 len = test->utf16len;
53
54 if (buffersize > len)
55 {
56 (void)fprintf(stderr,
57 "%s length does not match buffersize: %" PRId32 " != %" PRIuz
58 ",but is large enough to hold result\n",
59 prefix, rc, buffersize);
60 return FALSE;
61 }
62 const DWORD err = GetLastError();
63 if (err != ERROR_INSUFFICIENT_BUFFER)
64 {
65
66 (void)fprintf(stderr,
67 "%s length does not match buffersize: %" PRId32 " != %" PRIuz
68 ", unexpected GetLastError() 0x08%" PRIx32 "\n",
69 prefix, rc, buffersize, err);
70 return FALSE;
71 }
72 else
73 return TRUE;
74}
75
76#define compare_utf16(what, buffersize, rc, inputlen, test) \
77 compare_utf16_int((what), (buffersize), (rc), (inputlen), (test), __func__, __LINE__)
78static BOOL compare_utf16_int(const WCHAR* what, size_t buffersize, SSIZE_T rc, SSIZE_T inputlen,
79 const testcase_t* test, const char* fkt, size_t line)
80{
81 char prefix[8192] = { 0 };
82 create_prefix(prefix, ARRAYSIZE(prefix), buffersize, rc, inputlen, test, fkt, line);
83
84 WINPR_ASSERT(what || (buffersize == 0));
85 WINPR_ASSERT(test);
86
87 const size_t welen = _wcsnlen(test->utf16, test->utf16len);
88 if (buffersize > welen)
89 {
90 if ((rc < 0) || ((size_t)rc != welen))
91 {
92 (void)fprintf(stderr,
93 "%s length does not match expectation: %" PRIdz " != %" PRIuz "\n",
94 prefix, rc, welen);
95 return FALSE;
96 }
97 }
98 else
99 {
100 if (!check_short_buffer(prefix, WINPR_ASSERTING_INT_CAST(SSIZE_T, rc), buffersize, test,
101 FALSE))
102 return FALSE;
103 }
104
105 if ((rc > 0) && (buffersize > (size_t)rc))
106 {
107 const size_t wlen = _wcsnlen(what, buffersize);
108 if ((rc < 0) || (wlen > (size_t)rc))
109 {
110 (void)fprintf(stderr, "%s length does not match wcslen: %" PRIdz " < %" PRIuz "\n",
111 prefix, rc, wlen);
112 return FALSE;
113 }
114 }
115
116 if (rc >= 0)
117 {
118 if (memcmp(test->utf16, what, rc * sizeof(WCHAR)) != 0)
119 {
120 (void)fprintf(stderr, "%s contents does not match expectations: TODO '%s' != '%s'\n",
121 prefix, test->utf8, test->utf8);
122 return FALSE;
123 }
124 }
125
126 printf("%s success\n", prefix);
127
128 return TRUE;
129}
130
131#define compare_utf8(what, buffersize, rc, inputlen, test) \
132 compare_utf8_int((what), (buffersize), (rc), (inputlen), (test), __func__, __LINE__)
133static BOOL compare_utf8_int(const char* what, size_t buffersize, SSIZE_T rc, SSIZE_T inputlen,
134 const testcase_t* test, const char* fkt, size_t line)
135{
136 char prefix[8192] = { 0 };
137 create_prefix(prefix, ARRAYSIZE(prefix), buffersize, rc, inputlen, test, fkt, line);
138
139 WINPR_ASSERT(what || (buffersize == 0));
140 WINPR_ASSERT(test);
141
142 const size_t slen = strnlen(test->utf8, test->utf8len);
143 if (buffersize > slen)
144 {
145 if ((rc < 0) || ((size_t)rc != slen))
146 {
147 (void)fprintf(stderr,
148 "%s length does not match expectation: %" PRIdz " != %" PRIuz "\n",
149 prefix, rc, slen);
150 return FALSE;
151 }
152 }
153 else
154 {
155 if (!check_short_buffer(prefix, WINPR_ASSERTING_INT_CAST(SSIZE_T, rc), buffersize, test,
156 TRUE))
157 return FALSE;
158 }
159
160 if ((rc > 0) && (buffersize > (size_t)rc))
161 {
162 const size_t wlen = strnlen(what, buffersize);
163 if (wlen != (size_t)rc)
164 {
165 (void)fprintf(stderr, "%s length does not match strnlen: %" PRIdz " != %" PRIuz "\n",
166 prefix, rc, wlen);
167 return FALSE;
168 }
169 }
170
171 if (rc >= 0)
172 {
173 if (memcmp(test->utf8, what, rc) != 0)
174 {
175 (void)fprintf(stderr, "%s contents does not match expectations: '%s' != '%s'\n", prefix,
176 what, test->utf8);
177 return FALSE;
178 }
179 }
180
181 printf("%s success\n", prefix);
182
183 return TRUE;
184}
185
186static BOOL test_convert_to_utf16(const testcase_t* test)
187{
188 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf16len, test->utf16len + 1,
189 test->utf16len - 1 };
190 const size_t max = test->utf16len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
191
192 const SSIZE_T rc2 = ConvertUtf8ToWChar(test->utf8, NULL, 0);
193 const size_t wlen = _wcsnlen(test->utf16, test->utf16len);
194 if ((rc2 < 0) || ((size_t)rc2 != wlen))
195 {
196 char prefix[8192] = { 0 };
197 create_prefix(prefix, ARRAYSIZE(prefix), 0, rc2, -1, test, __func__, __LINE__);
198 (void)fprintf(stderr,
199 "%s ConvertUtf8ToWChar(%s, NULL, 0) expected %" PRIuz ", got %" PRIdz "\n",
200 prefix, test->utf8, wlen, rc2);
201 return FALSE;
202 }
203 for (size_t x = 0; x < max; x++)
204 {
205 WCHAR buffer[TESTCASE_BUFFER_SIZE] = { 0 };
206 const SSIZE_T rc = ConvertUtf8ToWChar(test->utf8, buffer, len[x]);
207 if (!compare_utf16(buffer, len[x], rc, -1, test))
208 return FALSE;
209 }
210
211 return TRUE;
212}
213
214static BOOL test_convert_to_utf16_n(const testcase_t* test)
215{
216 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf16len, test->utf16len + 1,
217 test->utf16len - 1 };
218 const size_t max = test->utf16len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
219
220 const SSIZE_T rc2 = ConvertUtf8NToWChar(test->utf8, test->utf8len, NULL, 0);
221 const size_t wlen = _wcsnlen(test->utf16, test->utf16len);
222 if ((rc2 < 0) || ((size_t)rc2 != wlen))
223 {
224 char prefix[8192] = { 0 };
225 create_prefix(prefix, ARRAYSIZE(prefix), 0, rc2,
226 WINPR_ASSERTING_INT_CAST(SSIZE_T, test->utf8len), test, __func__, __LINE__);
227 (void)fprintf(stderr,
228 "%s ConvertUtf8NToWChar(%s, %" PRIuz ", NULL, 0) expected %" PRIuz
229 ", got %" PRIdz "\n",
230 prefix, test->utf8, test->utf8len, wlen, rc2);
231 return FALSE;
232 }
233
234 for (size_t x = 0; x < max; x++)
235 {
236 const size_t ilen[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
237 test->utf8len - 1 };
238 const size_t imax = test->utf8len > 0 ? ARRAYSIZE(ilen) : ARRAYSIZE(ilen) - 1;
239
240 for (size_t y = 0; y < imax; y++)
241 {
242 WCHAR buffer[TESTCASE_BUFFER_SIZE] = { 0 };
243 SSIZE_T rc = ConvertUtf8NToWChar(test->utf8, ilen[x], buffer, len[x]);
244 if (!compare_utf16(buffer, len[x], rc, ilen[x], test))
245 return FALSE;
246 }
247 }
248 return TRUE;
249}
250
251static BOOL test_convert_to_utf8(const testcase_t* test)
252{
253 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
254 test->utf8len - 1 };
255 const size_t max = test->utf8len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
256
257 const SSIZE_T rc2 = ConvertWCharToUtf8(test->utf16, NULL, 0);
258 const size_t wlen = strnlen(test->utf8, test->utf8len);
259 if ((rc2 < 0) || ((size_t)rc2 != wlen))
260 {
261 char prefix[8192] = { 0 };
262 create_prefix(prefix, ARRAYSIZE(prefix), 0, rc2, -1, test, __func__, __LINE__);
263 (void)fprintf(stderr,
264 "%s ConvertWCharToUtf8(%s, NULL, 0) expected %" PRIuz ", got %" PRIdz "\n",
265 prefix, test->utf8, wlen, rc2);
266 return FALSE;
267 }
268
269 for (size_t x = 0; x < max; x++)
270 {
271 char buffer[TESTCASE_BUFFER_SIZE] = { 0 };
272 SSIZE_T rc = ConvertWCharToUtf8(test->utf16, buffer, len[x]);
273 if (!compare_utf8(buffer, len[x], rc, -1, test))
274 return FALSE;
275 }
276
277 return TRUE;
278}
279
280static BOOL test_convert_to_utf8_n(const testcase_t* test)
281{
282 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
283 test->utf8len - 1 };
284 const size_t max = test->utf8len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
285
286 const SSIZE_T rc2 = ConvertWCharNToUtf8(test->utf16, test->utf16len, NULL, 0);
287 const size_t wlen = strnlen(test->utf8, test->utf8len);
288 if ((rc2 < 0) || ((size_t)rc2 != wlen))
289 {
290 char prefix[8192] = { 0 };
291 create_prefix(prefix, ARRAYSIZE(prefix), 0, rc2,
292 WINPR_ASSERTING_INT_CAST(SSIZE_T, test->utf16len), test, __func__, __LINE__);
293 (void)fprintf(stderr,
294 "%s ConvertWCharNToUtf8(%s, %" PRIuz ", NULL, 0) expected %" PRIuz
295 ", got %" PRIdz "\n",
296 prefix, test->utf8, test->utf16len, wlen, rc2);
297 return FALSE;
298 }
299
300 for (size_t x = 0; x < max; x++)
301 {
302 const size_t ilen[] = { TESTCASE_BUFFER_SIZE, test->utf16len, test->utf16len + 1,
303 test->utf16len - 1 };
304 const size_t imax = test->utf16len > 0 ? ARRAYSIZE(ilen) : ARRAYSIZE(ilen) - 1;
305
306 for (size_t y = 0; y < imax; y++)
307 {
308 char buffer[TESTCASE_BUFFER_SIZE] = { 0 };
309 SSIZE_T rc = ConvertWCharNToUtf8(test->utf16, ilen[x], buffer, len[x]);
310 if (!compare_utf8(buffer, len[x], rc, ilen[x], test))
311 return FALSE;
312 }
313 }
314
315 return TRUE;
316}
317
318static BOOL test_conversion(const testcase_t* testcases, size_t count)
319{
320 WINPR_ASSERT(testcases || (count == 0));
321 for (size_t x = 0; x < count; x++)
322 {
323 const testcase_t* test = &testcases[x];
324
325 printf("Running test case %" PRIuz " [%s]\n", x, test->utf8);
326 if (!test_convert_to_utf16(test))
327 return FALSE;
328 if (!test_convert_to_utf16_n(test))
329 return FALSE;
330 if (!test_convert_to_utf8(test))
331 return FALSE;
332 if (!test_convert_to_utf8_n(test))
333 return FALSE;
334 }
335 return TRUE;
336}
337
338#if defined(WITH_WINPR_DEPRECATED)
339
340#define compare_win_utf16(what, buffersize, rc, inputlen, test) \
341 compare_win_utf16_int((what), (buffersize), (rc), (inputlen), (test), __func__, __LINE__)
342static BOOL compare_win_utf16_int(const WCHAR* what, size_t buffersize, int rc, int inputlen,
343 const testcase_t* test, const char* fkt, size_t line)
344{
345 char prefix[8192] = { 0 };
346 create_prefix(prefix, ARRAYSIZE(prefix), buffersize, rc, inputlen, test, fkt, line);
347
348 WINPR_ASSERT(what || (buffersize == 0));
349 WINPR_ASSERT(test);
350
351 BOOL isNullTerminated = TRUE;
352 if (inputlen > 0)
353 isNullTerminated = strnlen(test->utf8, inputlen) < inputlen;
354 size_t welen = _wcsnlen(test->utf16, buffersize);
355 if (isNullTerminated)
356 welen++;
357
358 if (buffersize >= welen)
359 {
360 if ((inputlen >= 0) && (rc > buffersize))
361 {
362 (void)fprintf(stderr, "%s length does not match expectation: %d > %" PRIuz "\n", prefix,
363 rc, buffersize);
364 return FALSE;
365 }
366 else if ((inputlen < 0) && (rc != welen))
367 {
368 (void)fprintf(stderr, "%s length does not match expectation: %d != %" PRIuz "\n",
369 prefix, rc, welen);
370 return FALSE;
371 }
372 }
373 else
374 {
375 if (!check_short_buffer(prefix, rc, buffersize, test, FALSE))
376 return FALSE;
377 }
378
379 if ((rc > 0) && (buffersize > rc))
380 {
381 size_t wlen = _wcsnlen(what, buffersize);
382 if (isNullTerminated)
383 wlen++;
384 if ((inputlen >= 0) && (buffersize < rc))
385 {
386 (void)fprintf(stderr, "%s length does not match wcslen: %d > %" PRIuz "\n", prefix, rc,
387 buffersize);
388 return FALSE;
389 }
390 else if ((inputlen < 0) && (welen > rc))
391 {
392 (void)fprintf(stderr, "%s length does not match wcslen: %d < %" PRIuz "\n", prefix, rc,
393 wlen);
394 return FALSE;
395 }
396 }
397
398 const size_t cmp_size = MIN(rc, test->utf16len) * sizeof(WCHAR);
399 if (memcmp(test->utf16, what, cmp_size) != 0)
400 {
401 (void)fprintf(stderr, "%s contents does not match expectations: TODO '%s' != '%s'\n",
402 prefix, test->utf8, test->utf8);
403 return FALSE;
404 }
405
406 printf("%s success\n", prefix);
407
408 return TRUE;
409}
410
411#define compare_win_utf8(what, buffersize, rc, inputlen, test) \
412 compare_win_utf8_int((what), (buffersize), (rc), (inputlen), (test), __func__, __LINE__)
413static BOOL compare_win_utf8_int(const char* what, size_t buffersize, SSIZE_T rc, SSIZE_T inputlen,
414 const testcase_t* test, const char* fkt, size_t line)
415{
416 char prefix[8192] = { 0 };
417 create_prefix(prefix, ARRAYSIZE(prefix), buffersize, rc, inputlen, test, fkt, line);
418
419 WINPR_ASSERT(what || (buffersize == 0));
420 WINPR_ASSERT(test);
421
422 BOOL isNullTerminated = TRUE;
423 if (inputlen > 0)
424 isNullTerminated = _wcsnlen(test->utf16, inputlen) < inputlen;
425
426 size_t slen = strnlen(test->utf8, test->utf8len);
427 if (isNullTerminated)
428 slen++;
429
430 if (buffersize > slen)
431 {
432 if ((inputlen >= 0) && (rc > buffersize))
433 {
434 (void)fprintf(stderr, "%s length does not match expectation: %" PRIdz " > %" PRIuz "\n",
435 prefix, rc, buffersize);
436 return FALSE;
437 }
438 else if ((inputlen < 0) && (rc != slen))
439 {
440 (void)fprintf(stderr,
441 "%s length does not match expectation: %" PRIdz " != %" PRIuz "\n",
442 prefix, rc, slen);
443 return FALSE;
444 }
445 }
446 else
447 {
448 if (!check_short_buffer(prefix, rc, buffersize, test, TRUE))
449 return FALSE;
450 }
451
452 if ((rc > 0) && (buffersize > rc))
453 {
454 size_t wlen = strnlen(what, buffersize);
455 if (isNullTerminated)
456 wlen++;
457
458 if (wlen > rc)
459 {
460 (void)fprintf(stderr, "%s length does not match wcslen: %" PRIdz " < %" PRIuz "\n",
461 prefix, rc, wlen);
462 return FALSE;
463 }
464 }
465
466 const size_t cmp_size = MIN(test->utf8len, rc);
467 if (memcmp(test->utf8, what, cmp_size) != 0)
468 {
469 (void)fprintf(stderr, "%s contents does not match expectations: '%s' != '%s'\n", prefix,
470 what, test->utf8);
471 return FALSE;
472 }
473 printf("%s success\n", prefix);
474
475 return TRUE;
476}
477#endif
478
479#if defined(WITH_WINPR_DEPRECATED)
480static BOOL test_win_convert_to_utf16(const testcase_t* test)
481{
482 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf16len, test->utf16len + 1,
483 test->utf16len - 1 };
484 const size_t max = test->utf16len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
485
486 const int rc2 = MultiByteToWideChar(CP_UTF8, 0, test->utf8, -1, NULL, 0);
487 const size_t wlen = _wcsnlen(test->utf16, test->utf16len);
488 if (rc2 != wlen + 1)
489 {
490 char prefix[8192] = { 0 };
491 create_prefix(prefix, ARRAYSIZE(prefix), 0, rc2, -1, test, __func__, __LINE__);
492 (void)fprintf(stderr,
493 "%s MultiByteToWideChar(CP_UTF8, 0, %s, [-1], NULL, 0) expected %" PRIuz
494 ", got %d\n",
495 prefix, test->utf8, wlen + 1, rc2);
496 return FALSE;
497 }
498 for (size_t x = 0; x < max; x++)
499 {
500 WCHAR buffer[TESTCASE_BUFFER_SIZE] = { 0 };
501 const int rc = MultiByteToWideChar(CP_UTF8, 0, test->utf8, -1, buffer, len[x]);
502 if (!compare_win_utf16(buffer, len[x], rc, -1, test))
503 return FALSE;
504 }
505
506 return TRUE;
507}
508
509static BOOL test_win_convert_to_utf16_n(const testcase_t* test)
510{
511 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf16len, test->utf16len + 1,
512 test->utf16len - 1 };
513 const size_t max = test->utf16len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
514
515 BOOL isNullTerminated = strnlen(test->utf8, test->utf8len) < test->utf8len;
516 const int rc2 = MultiByteToWideChar(CP_UTF8, 0, test->utf8, test->utf8len, NULL, 0);
517 size_t wlen = _wcsnlen(test->utf16, test->utf16len);
518 if (isNullTerminated)
519 wlen++;
520
521 if (rc2 != wlen)
522 {
523 char prefix[8192] = { 0 };
524 create_prefix(prefix, ARRAYSIZE(prefix), 0, rc2, test->utf8len, test, __func__, __LINE__);
525 (void)fprintf(stderr,
526 "%s MultiByteToWideChar(CP_UTF8, 0, %s, %" PRIuz ", NULL, 0) expected %" PRIuz
527 ", got %d\n",
528 prefix, test->utf8, test->utf8len, wlen, rc2);
529 return FALSE;
530 }
531
532 for (size_t x = 0; x < max; x++)
533 {
534 const size_t ilen[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
535 test->utf8len - 1 };
536 const size_t imax = test->utf8len > 0 ? ARRAYSIZE(ilen) : ARRAYSIZE(ilen) - 1;
537
538 for (size_t y = 0; y < imax; y++)
539 {
540 char mbuffer[TESTCASE_BUFFER_SIZE] = { 0 };
541 WCHAR buffer[TESTCASE_BUFFER_SIZE] = { 0 };
542 strncpy(mbuffer, test->utf8, test->utf8len);
543 const int rc = MultiByteToWideChar(CP_UTF8, 0, mbuffer, ilen[x], buffer, len[x]);
544 if (!compare_win_utf16(buffer, len[x], rc, ilen[x], test))
545 return FALSE;
546 }
547 }
548 return TRUE;
549}
550#endif
551
552#if defined(WITH_WINPR_DEPRECATED)
553static BOOL test_win_convert_to_utf8(const testcase_t* test)
554{
555 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
556 test->utf8len - 1 };
557 const size_t max = test->utf8len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
558
559 const int rc2 = WideCharToMultiByte(CP_UTF8, 0, test->utf16, -1, NULL, 0, NULL, NULL);
560 const size_t wlen = strnlen(test->utf8, test->utf8len) + 1;
561 if (rc2 != wlen)
562 {
563 char prefix[8192] = { 0 };
564 create_prefix(prefix, ARRAYSIZE(prefix), 0, rc2, -1, test, __func__, __LINE__);
565 (void)fprintf(
566 stderr,
567 "%s WideCharToMultiByte(CP_UTF8, 0, %s, -1, NULL, 0, NULL, NULL) expected %" PRIuz
568 ", got %d\n",
569 prefix, test->utf8, wlen, rc2);
570 return FALSE;
571 }
572
573 for (size_t x = 0; x < max; x++)
574 {
575 char buffer[TESTCASE_BUFFER_SIZE] = { 0 };
576 int rc = WideCharToMultiByte(CP_UTF8, 0, test->utf16, -1, buffer, len[x], NULL, NULL);
577 if (!compare_win_utf8(buffer, len[x], rc, -1, test))
578 return FALSE;
579 }
580
581 return TRUE;
582}
583
584static BOOL test_win_convert_to_utf8_n(const testcase_t* test)
585{
586 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
587 test->utf8len - 1 };
588 const size_t max = test->utf8len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
589
590 const BOOL isNullTerminated = _wcsnlen(test->utf16, test->utf16len) < test->utf16len;
591 const int rc2 =
592 WideCharToMultiByte(CP_UTF8, 0, test->utf16, test->utf16len, NULL, 0, NULL, NULL);
593 size_t wlen = strnlen(test->utf8, test->utf8len);
594 if (isNullTerminated)
595 wlen++;
596
597 if (rc2 != wlen)
598 {
599 char prefix[8192] = { 0 };
600 create_prefix(prefix, ARRAYSIZE(prefix), 0, rc2, test->utf16len, test, __func__, __LINE__);
601 (void)fprintf(stderr,
602 "%s WideCharToMultiByte(CP_UTF8, 0, %s, %" PRIuz
603 ", NULL, 0, NULL, NULL) expected %" PRIuz ", got %d\n",
604 prefix, test->utf8, test->utf16len, wlen, rc2);
605 return FALSE;
606 }
607
608 for (size_t x = 0; x < max; x++)
609 {
610 const size_t ilen[] = { TESTCASE_BUFFER_SIZE, test->utf16len, test->utf16len + 1,
611 test->utf16len - 1 };
612 const size_t imax = test->utf16len > 0 ? ARRAYSIZE(ilen) : ARRAYSIZE(ilen) - 1;
613
614 for (size_t y = 0; y < imax; y++)
615 {
616 WCHAR wbuffer[TESTCASE_BUFFER_SIZE] = { 0 };
617 char buffer[TESTCASE_BUFFER_SIZE] = { 0 };
618 memcpy(wbuffer, test->utf16, test->utf16len * sizeof(WCHAR));
619 const int rc =
620 WideCharToMultiByte(CP_UTF8, 0, wbuffer, ilen[x], buffer, len[x], NULL, NULL);
621 if (!compare_win_utf8(buffer, len[x], rc, ilen[x], test))
622 return FALSE;
623 }
624 }
625
626 return TRUE;
627}
628
629static BOOL test_win_conversion(const testcase_t* testcases, size_t count)
630{
631 WINPR_ASSERT(testcases || (count == 0));
632 for (size_t x = 0; x < count; x++)
633 {
634 const testcase_t* test = &testcases[x];
635
636 printf("Running test case %" PRIuz " [%s]\n", x, test->utf8);
637 if (!test_win_convert_to_utf16(test))
638 return FALSE;
639 if (!test_win_convert_to_utf16_n(test))
640 return FALSE;
641 if (!test_win_convert_to_utf8(test))
642 return FALSE;
643 if (!test_win_convert_to_utf8_n(test))
644 return FALSE;
645 }
646 return TRUE;
647}
648#endif
649
650#if defined(WITH_WINPR_DEPRECATED)
651/* Letters */
652
653static BYTE c_cedilla_UTF8[] = "\xC3\xA7\x00";
654static BYTE c_cedilla_UTF16[] = "\xE7\x00\x00\x00";
655static int c_cedilla_cchWideChar = 2;
656static int c_cedilla_cbMultiByte = 3;
657
658/* English */
659
660static BYTE en_Hello_UTF8[] = "Hello\0";
661static BYTE en_Hello_UTF16[] = "\x48\x00\x65\x00\x6C\x00\x6C\x00\x6F\x00\x00\x00";
662static int en_Hello_cchWideChar = 6;
663static int en_Hello_cbMultiByte = 6;
664
665static BYTE en_HowAreYou_UTF8[] = "How are you?\0";
666static BYTE en_HowAreYou_UTF16[] =
667 "\x48\x00\x6F\x00\x77\x00\x20\x00\x61\x00\x72\x00\x65\x00\x20\x00"
668 "\x79\x00\x6F\x00\x75\x00\x3F\x00\x00\x00";
669static int en_HowAreYou_cchWideChar = 13;
670static int en_HowAreYou_cbMultiByte = 13;
671
672/* French */
673
674static BYTE fr_Hello_UTF8[] = "Allo\0";
675static BYTE fr_Hello_UTF16[] = "\x41\x00\x6C\x00\x6C\x00\x6F\x00\x00\x00";
676static int fr_Hello_cchWideChar = 5;
677static int fr_Hello_cbMultiByte = 5;
678
679static BYTE fr_HowAreYou_UTF8[] =
680 "\x43\x6F\x6D\x6D\x65\x6E\x74\x20\xC3\xA7\x61\x20\x76\x61\x3F\x00";
681static BYTE fr_HowAreYou_UTF16[] =
682 "\x43\x00\x6F\x00\x6D\x00\x6D\x00\x65\x00\x6E\x00\x74\x00\x20\x00"
683 "\xE7\x00\x61\x00\x20\x00\x76\x00\x61\x00\x3F\x00\x00\x00";
684static int fr_HowAreYou_cchWideChar = 15;
685static int fr_HowAreYou_cbMultiByte = 16;
686
687/* Russian */
688
689static BYTE ru_Hello_UTF8[] = "\xD0\x97\xD0\xB4\xD0\xBE\xD1\x80\xD0\xBE\xD0\xB2\xD0\xBE\x00";
690static BYTE ru_Hello_UTF16[] = "\x17\x04\x34\x04\x3E\x04\x40\x04\x3E\x04\x32\x04\x3E\x04\x00\x00";
691static int ru_Hello_cchWideChar = 8;
692static int ru_Hello_cbMultiByte = 15;
693
694static BYTE ru_HowAreYou_UTF8[] =
695 "\xD0\x9A\xD0\xB0\xD0\xBA\x20\xD0\xB4\xD0\xB5\xD0\xBB\xD0\xB0\x3F\x00";
696static BYTE ru_HowAreYou_UTF16[] =
697 "\x1A\x04\x30\x04\x3A\x04\x20\x00\x34\x04\x35\x04\x3B\x04\x30\x04"
698 "\x3F\x00\x00\x00";
699static int ru_HowAreYou_cchWideChar = 10;
700static int ru_HowAreYou_cbMultiByte = 17;
701
702/* Arabic */
703
704static BYTE ar_Hello_UTF8[] = "\xD8\xA7\xD9\x84\xD8\xB3\xD9\x84\xD8\xA7\xD9\x85\x20\xD8\xB9\xD9"
705 "\x84\xD9\x8A\xD9\x83\xD9\x85\x00";
706static BYTE ar_Hello_UTF16[] = "\x27\x06\x44\x06\x33\x06\x44\x06\x27\x06\x45\x06\x20\x00\x39\x06"
707 "\x44\x06\x4A\x06\x43\x06\x45\x06\x00\x00";
708static int ar_Hello_cchWideChar = 13;
709static int ar_Hello_cbMultiByte = 24;
710
711static BYTE ar_HowAreYou_UTF8[] = "\xD9\x83\xD9\x8A\xD9\x81\x20\xD8\xAD\xD8\xA7\xD9\x84\xD9\x83\xD8"
712 "\x9F\x00";
713static BYTE ar_HowAreYou_UTF16[] =
714 "\x43\x06\x4A\x06\x41\x06\x20\x00\x2D\x06\x27\x06\x44\x06\x43\x06"
715 "\x1F\x06\x00\x00";
716static int ar_HowAreYou_cchWideChar = 10;
717static int ar_HowAreYou_cbMultiByte = 18;
718
719/* Chinese */
720
721static BYTE ch_Hello_UTF8[] = "\xE4\xBD\xA0\xE5\xA5\xBD\x00";
722static BYTE ch_Hello_UTF16[] = "\x60\x4F\x7D\x59\x00\x00";
723static int ch_Hello_cchWideChar = 3;
724static int ch_Hello_cbMultiByte = 7;
725
726static BYTE ch_HowAreYou_UTF8[] = "\xE4\xBD\xA0\xE5\xA5\xBD\xE5\x90\x97\x00";
727static BYTE ch_HowAreYou_UTF16[] = "\x60\x4F\x7D\x59\x17\x54\x00\x00";
728static int ch_HowAreYou_cchWideChar = 4;
729static int ch_HowAreYou_cbMultiByte = 10;
730
731/* Uppercasing */
732
733static BYTE ru_Administrator_lower[] = "\xd0\x90\xd0\xb4\xd0\xbc\xd0\xb8\xd0\xbd\xd0\xb8\xd1\x81"
734 "\xd1\x82\xd1\x80\xd0\xb0\xd1\x82\xd0\xbe\xd1\x80\x00";
735
736static BYTE ru_Administrator_upper[] = "\xd0\x90\xd0\x94\xd0\x9c\xd0\x98\xd0\x9d\xd0\x98\xd0\xa1"
737 "\xd0\xa2\xd0\xa0\xd0\x90\xd0\xa2\xd0\x9e\xd0\xa0\x00";
738
739static void string_hexdump(const BYTE* data, size_t length)
740{
741 size_t offset = 0;
742
743 char* str = winpr_BinToHexString(data, length, TRUE);
744 if (!str)
745 return;
746
747 while (offset < length)
748 {
749 const size_t diff = (length - offset) * 3;
750 WINPR_ASSERT(diff <= INT_MAX);
751 printf("%04" PRIxz " %.*s\n", offset, (int)diff, &str[offset]);
752 offset += 16;
753 }
754
755 free(str);
756}
757
758static int convert_utf8_to_utf16(BYTE* lpMultiByteStr, BYTE* expected_lpWideCharStr,
759 int expected_cchWideChar)
760{
761 int rc = -1;
762 int length = 0;
763 size_t cbMultiByte = 0;
764 int cchWideChar = 0;
765 LPWSTR lpWideCharStr = NULL;
766
767 cbMultiByte = strlen((char*)lpMultiByteStr);
768 cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)lpMultiByteStr, -1, NULL, 0);
769
770 printf("MultiByteToWideChar Input UTF8 String:\n");
771 string_hexdump(lpMultiByteStr, cbMultiByte + 1);
772
773 printf("MultiByteToWideChar required cchWideChar: %d\n", cchWideChar);
774
775 if (cchWideChar != expected_cchWideChar)
776 {
777 printf("MultiByteToWideChar unexpected cchWideChar: actual: %d expected: %d\n", cchWideChar,
778 expected_cchWideChar);
779 goto fail;
780 }
781
782 lpWideCharStr = (LPWSTR)calloc((size_t)cchWideChar, sizeof(WCHAR));
783 if (!lpWideCharStr)
784 {
785 printf("MultiByteToWideChar: unable to allocate memory for test\n");
786 goto fail;
787 }
788 lpWideCharStr[cchWideChar - 1] =
789 0xFFFF; /* should be overwritten if null terminator is inserted properly */
790 length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)lpMultiByteStr, cbMultiByte + 1, lpWideCharStr,
791 cchWideChar);
792
793 printf("MultiByteToWideChar converted length (WCHAR): %d\n", length);
794
795 if (!length)
796 {
797 DWORD error = GetLastError();
798 printf("MultiByteToWideChar error: 0x%08" PRIX32 "\n", error);
799 goto fail;
800 }
801
802 if (length != expected_cchWideChar)
803 {
804 printf("MultiByteToWideChar unexpected converted length (WCHAR): actual: %d expected: %d\n",
805 length, expected_cchWideChar);
806 goto fail;
807 }
808
809 if (_wcscmp(lpWideCharStr, (WCHAR*)expected_lpWideCharStr) != 0)
810 {
811 printf("MultiByteToWideChar unexpected string:\n");
812
813 printf("UTF8 String:\n");
814 string_hexdump(lpMultiByteStr, cbMultiByte + 1);
815
816 printf("UTF16 String (actual):\n");
817 string_hexdump((BYTE*)lpWideCharStr, length * sizeof(WCHAR));
818
819 printf("UTF16 String (expected):\n");
820 string_hexdump(expected_lpWideCharStr, expected_cchWideChar * sizeof(WCHAR));
821
822 goto fail;
823 }
824
825 printf("MultiByteToWideChar Output UTF16 String:\n");
826 string_hexdump((BYTE*)lpWideCharStr, length * sizeof(WCHAR));
827 printf("\n");
828
829 rc = length;
830fail:
831 free(lpWideCharStr);
832
833 return rc;
834}
835#endif
836
837#if defined(WITH_WINPR_DEPRECATED)
838static int convert_utf16_to_utf8(BYTE* lpWideCharStr, BYTE* expected_lpMultiByteStr,
839 int expected_cbMultiByte)
840{
841 int rc = -1;
842 int length = 0;
843 int cchWideChar = 0;
844 int cbMultiByte = 0;
845 LPSTR lpMultiByteStr = NULL;
846
847 cchWideChar = _wcslen((WCHAR*)lpWideCharStr);
848 cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)lpWideCharStr, -1, NULL, 0, NULL, NULL);
849
850 printf("WideCharToMultiByte Input UTF16 String:\n");
851 string_hexdump(lpWideCharStr, (cchWideChar + 1) * sizeof(WCHAR));
852
853 printf("WideCharToMultiByte required cbMultiByte: %d\n", cbMultiByte);
854
855 if (cbMultiByte != expected_cbMultiByte)
856 {
857 printf("WideCharToMultiByte unexpected cbMultiByte: actual: %d expected: %d\n", cbMultiByte,
858 expected_cbMultiByte);
859 goto fail;
860 }
861
862 lpMultiByteStr = (LPSTR)malloc(cbMultiByte);
863 if (!lpMultiByteStr)
864 {
865 printf("WideCharToMultiByte: unable to allocate memory for test\n");
866 goto fail;
867 }
868 lpMultiByteStr[cbMultiByte - 1] =
869 (CHAR)0xFF; /* should be overwritten if null terminator is inserted properly */
870 length = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)lpWideCharStr, cchWideChar + 1,
871 lpMultiByteStr, cbMultiByte, NULL, NULL);
872
873 printf("WideCharToMultiByte converted length (BYTE): %d\n", length);
874
875 if (!length)
876 {
877 DWORD error = GetLastError();
878 printf("WideCharToMultiByte error: 0x%08" PRIX32 "\n", error);
879 goto fail;
880 }
881
882 if (length != expected_cbMultiByte)
883 {
884 printf("WideCharToMultiByte unexpected converted length (BYTE): actual: %d expected: %d\n",
885 length, expected_cbMultiByte);
886 goto fail;
887 }
888
889 if (strcmp(lpMultiByteStr, (char*)expected_lpMultiByteStr) != 0)
890 {
891 printf("WideCharToMultiByte unexpected string:\n");
892
893 printf("UTF16 String:\n");
894 string_hexdump(lpWideCharStr, (cchWideChar + 1) * sizeof(WCHAR));
895
896 printf("UTF8 String (actual):\n");
897 string_hexdump((BYTE*)lpMultiByteStr, cbMultiByte);
898
899 printf("UTF8 String (expected):\n");
900 string_hexdump(expected_lpMultiByteStr, expected_cbMultiByte);
901
902 goto fail;
903 }
904
905 printf("WideCharToMultiByte Output UTF8 String:\n");
906 string_hexdump((BYTE*)lpMultiByteStr, cbMultiByte);
907 printf("\n");
908
909 rc = length;
910fail:
911 free(lpMultiByteStr);
912
913 return rc;
914}
915#endif
916
917#if defined(WITH_WINPR_DEPRECATED)
918static BOOL test_unicode_uppercasing(BYTE* lower, BYTE* upper)
919{
920 WCHAR* lowerW = NULL;
921 int lowerLength = 0;
922 WCHAR* upperW = NULL;
923 int upperLength = 0;
924
925 lowerLength = ConvertToUnicode(CP_UTF8, 0, (LPSTR)lower, -1, &lowerW, 0);
926 upperLength = ConvertToUnicode(CP_UTF8, 0, (LPSTR)upper, -1, &upperW, 0);
927
928 CharUpperBuffW(lowerW, lowerLength);
929
930 if (_wcscmp(lowerW, upperW) != 0)
931 {
932 printf("Lowercase String:\n");
933 string_hexdump((BYTE*)lowerW, lowerLength * 2);
934
935 printf("Uppercase String:\n");
936 string_hexdump((BYTE*)upperW, upperLength * 2);
937
938 return FALSE;
939 }
940
941 free(lowerW);
942 free(upperW);
943
944 printf("success\n\n");
945 return TRUE;
946}
947#endif
948
949#if defined(WITH_WINPR_DEPRECATED)
950static BOOL test_ConvertFromUnicode_wrapper(void)
951{
952 const BYTE src1[] =
953 "\x52\x00\x49\x00\x43\x00\x48\x00\x20\x00\x54\x00\x45\x00\x58\x00\x54\x00\x20\x00\x46\x00"
954 "\x4f\x00\x52\x00\x4d\x00\x41\x00\x54\x00\x40\x00\x40\x00\x40\x00";
955 const BYTE src2[] = "\x52\x00\x49\x00\x43\x00\x48\x00\x20\x00\x54\x00\x45\x00\x58\x00\x54\x00"
956 "\x20\x00\x46\x00\x4f\x00\x52\x00\x4d\x00\x41\x00\x54\x00\x00\x00";
957 /* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 */
958 const CHAR cmp0[] = { 'R', 'I', 'C', 'H', ' ', 'T', 'E', 'X', 'T',
959 ' ', 'F', 'O', 'R', 'M', 'A', 'T', 0 };
960 CHAR* dst = NULL;
961 int i = 0;
962
963 /* Test unterminated unicode string:
964 * ConvertFromUnicode must always null-terminate, even if the src string isn't
965 */
966
967 printf("Input UTF16 String:\n");
968 string_hexdump((const BYTE*)src1, 19 * sizeof(WCHAR));
969
970 i = ConvertFromUnicode(CP_UTF8, 0, (const WCHAR*)src1, 16, &dst, 0, NULL, NULL);
971 if (i != 16)
972 {
973 (void)fprintf(stderr,
974 "ConvertFromUnicode failure A1: unexpectedly returned %d instead of 16\n", i);
975 goto fail;
976 }
977 if (dst == NULL)
978 {
979 (void)fprintf(stderr, "ConvertFromUnicode failure A2: destination is NULL\n");
980 goto fail;
981 }
982 if ((i = strlen(dst)) != 16)
983 {
984 (void)fprintf(stderr, "ConvertFromUnicode failure A3: dst length is %d instead of 16\n", i);
985 goto fail;
986 }
987 if (strcmp(dst, cmp0))
988 {
989 (void)fprintf(stderr, "ConvertFromUnicode failure A4: data mismatch\n");
990 goto fail;
991 }
992 printf("Output UTF8 String:\n");
993 string_hexdump((BYTE*)dst, i + 1);
994
995 free(dst);
996 dst = NULL;
997
998 /* Test null-terminated string */
999
1000 printf("Input UTF16 String:\n");
1001 string_hexdump((const BYTE*)src2, (_wcslen((const WCHAR*)src2) + 1) * sizeof(WCHAR));
1002
1003 i = ConvertFromUnicode(CP_UTF8, 0, (const WCHAR*)src2, -1, &dst, 0, NULL, NULL);
1004 if (i != 17)
1005 {
1006 (void)fprintf(stderr,
1007 "ConvertFromUnicode failure B1: unexpectedly returned %d instead of 17\n", i);
1008 goto fail;
1009 }
1010 if (dst == NULL)
1011 {
1012 (void)fprintf(stderr, "ConvertFromUnicode failure B2: destination is NULL\n");
1013 goto fail;
1014 }
1015 if ((i = strlen(dst)) != 16)
1016 {
1017 (void)fprintf(stderr, "ConvertFromUnicode failure B3: dst length is %d instead of 16\n", i);
1018 goto fail;
1019 }
1020 if (strcmp(dst, cmp0))
1021 {
1022 (void)fprintf(stderr, "ConvertFromUnicode failure B: data mismatch\n");
1023 goto fail;
1024 }
1025 printf("Output UTF8 String:\n");
1026 string_hexdump((BYTE*)dst, i + 1);
1027
1028 free(dst);
1029 dst = NULL;
1030
1031 printf("success\n\n");
1032
1033 return TRUE;
1034
1035fail:
1036 free(dst);
1037 return FALSE;
1038}
1039
1040static BOOL test_ConvertToUnicode_wrapper(void)
1041{
1042 /* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 */
1043 const CHAR src1[] = { 'R', 'I', 'C', 'H', ' ', 'T', 'E', 'X', 'T', ' ',
1044 'F', 'O', 'R', 'M', 'A', 'T', '@', '@', '@' };
1045 const CHAR src2[] = { 'R', 'I', 'C', 'H', ' ', 'T', 'E', 'X', 'T',
1046 ' ', 'F', 'O', 'R', 'M', 'A', 'T', 0 };
1047 const BYTE cmp0[] = "\x52\x00\x49\x00\x43\x00\x48\x00\x20\x00\x54\x00\x45\x00\x58\x00\x54\x00"
1048 "\x20\x00\x46\x00\x4f\x00\x52\x00\x4d\x00\x41\x00\x54\x00\x00\x00";
1049 WCHAR* dst = NULL;
1050 int ii = 0;
1051 size_t i = 0;
1052
1053 /* Test static string buffers of differing sizes */
1054 {
1055 char name[] = "someteststring";
1056 const BYTE cmp[] = { 's', 0, 'o', 0, 'm', 0, 'e', 0, 't', 0, 'e', 0, 's', 0, 't', 0,
1057 's', 0, 't', 0, 'r', 0, 'i', 0, 'n', 0, 'g', 0, 0, 0 };
1058 WCHAR xname[128] = { 0 };
1059 LPWSTR aname = NULL;
1060 LPWSTR wname = &xname[0];
1061 const size_t len = strnlen(name, ARRAYSIZE(name) - 1);
1062 ii = ConvertToUnicode(CP_UTF8, 0, name, len, &wname, ARRAYSIZE(xname));
1063 if (ii != (SSIZE_T)len)
1064 goto fail;
1065
1066 if (memcmp(wname, cmp, sizeof(cmp)) != 0)
1067 goto fail;
1068
1069 ii = ConvertToUnicode(CP_UTF8, 0, name, len, &aname, 0);
1070 if (ii != (SSIZE_T)len)
1071 goto fail;
1072 ii = memcmp(aname, cmp, sizeof(cmp));
1073 free(aname);
1074 if (ii != 0)
1075 goto fail;
1076 }
1077
1078 /* Test unterminated unicode string:
1079 * ConvertToUnicode must always null-terminate, even if the src string isn't
1080 */
1081
1082 printf("Input UTF8 String:\n");
1083 string_hexdump((const BYTE*)src1, 19);
1084
1085 ii = ConvertToUnicode(CP_UTF8, 0, src1, 16, &dst, 0);
1086 if (ii != 16)
1087 {
1088 (void)fprintf(stderr,
1089 "ConvertToUnicode failure A1: unexpectedly returned %d instead of 16\n", ii);
1090 goto fail;
1091 }
1092 i = (size_t)ii;
1093 if (dst == NULL)
1094 {
1095 (void)fprintf(stderr, "ConvertToUnicode failure A2: destination is NULL\n");
1096 goto fail;
1097 }
1098 if ((i = _wcslen(dst)) != 16)
1099 {
1100 (void)fprintf(stderr,
1101 "ConvertToUnicode failure A3: dst length is %" PRIuz " instead of 16\n", i);
1102 goto fail;
1103 }
1104 if (_wcscmp(dst, (const WCHAR*)cmp0))
1105 {
1106 (void)fprintf(stderr, "ConvertToUnicode failure A4: data mismatch\n");
1107 goto fail;
1108 }
1109 printf("Output UTF16 String:\n");
1110 string_hexdump((const BYTE*)dst, (i + 1) * sizeof(WCHAR));
1111
1112 free(dst);
1113 dst = NULL;
1114
1115 /* Test null-terminated string */
1116
1117 printf("Input UTF8 String:\n");
1118 string_hexdump((const BYTE*)src2, strlen(src2) + 1);
1119
1120 i = ConvertToUnicode(CP_UTF8, 0, src2, -1, &dst, 0);
1121 if (i != 17)
1122 {
1123 (void)fprintf(
1124 stderr, "ConvertToUnicode failure B1: unexpectedly returned %" PRIuz " instead of 17\n",
1125 i);
1126 goto fail;
1127 }
1128 if (dst == NULL)
1129 {
1130 (void)fprintf(stderr, "ConvertToUnicode failure B2: destination is NULL\n");
1131 goto fail;
1132 }
1133 if ((i = _wcslen(dst)) != 16)
1134 {
1135 (void)fprintf(stderr,
1136 "ConvertToUnicode failure B3: dst length is %" PRIuz " instead of 16\n", i);
1137 goto fail;
1138 }
1139 if (_wcscmp(dst, (const WCHAR*)cmp0))
1140 {
1141 (void)fprintf(stderr, "ConvertToUnicode failure B: data mismatch\n");
1142 goto fail;
1143 }
1144 printf("Output UTF16 String:\n");
1145 string_hexdump((BYTE*)dst, (i + 1) * 2);
1146
1147 free(dst);
1148 dst = NULL;
1149
1150 printf("success\n\n");
1151
1152 return TRUE;
1153
1154fail:
1155 free(dst);
1156 return FALSE;
1157}
1158#endif
1159
1160int TestUnicodeConversion(int argc, char* argv[])
1161{
1162 WINPR_UNUSED(argc);
1163 WINPR_UNUSED(argv);
1164
1165 if (!test_conversion(unit_testcases, ARRAYSIZE(unit_testcases)))
1166 return -1;
1167
1168#if defined(WITH_WINPR_DEPRECATED)
1169 if (!test_win_conversion(unit_testcases, ARRAYSIZE(unit_testcases)))
1170 return -1;
1171
1172 /* Letters */
1173
1174 printf("Letters\n");
1175
1176 if (convert_utf8_to_utf16(c_cedilla_UTF8, c_cedilla_UTF16, c_cedilla_cchWideChar) < 1)
1177 return -1;
1178
1179 if (convert_utf16_to_utf8(c_cedilla_UTF16, c_cedilla_UTF8, c_cedilla_cbMultiByte) < 1)
1180 return -1;
1181
1182 /* English */
1183
1184 printf("English\n");
1185
1186 if (convert_utf8_to_utf16(en_Hello_UTF8, en_Hello_UTF16, en_Hello_cchWideChar) < 1)
1187 return -1;
1188 if (convert_utf8_to_utf16(en_HowAreYou_UTF8, en_HowAreYou_UTF16, en_HowAreYou_cchWideChar) < 1)
1189 return -1;
1190
1191 if (convert_utf16_to_utf8(en_Hello_UTF16, en_Hello_UTF8, en_Hello_cbMultiByte) < 1)
1192 return -1;
1193 if (convert_utf16_to_utf8(en_HowAreYou_UTF16, en_HowAreYou_UTF8, en_HowAreYou_cbMultiByte) < 1)
1194 return -1;
1195
1196 /* French */
1197
1198 printf("French\n");
1199
1200 if (convert_utf8_to_utf16(fr_Hello_UTF8, fr_Hello_UTF16, fr_Hello_cchWideChar) < 1)
1201 return -1;
1202 if (convert_utf8_to_utf16(fr_HowAreYou_UTF8, fr_HowAreYou_UTF16, fr_HowAreYou_cchWideChar) < 1)
1203 return -1;
1204
1205 if (convert_utf16_to_utf8(fr_Hello_UTF16, fr_Hello_UTF8, fr_Hello_cbMultiByte) < 1)
1206 return -1;
1207 if (convert_utf16_to_utf8(fr_HowAreYou_UTF16, fr_HowAreYou_UTF8, fr_HowAreYou_cbMultiByte) < 1)
1208 return -1;
1209
1210 /* Russian */
1211
1212 printf("Russian\n");
1213
1214 if (convert_utf8_to_utf16(ru_Hello_UTF8, ru_Hello_UTF16, ru_Hello_cchWideChar) < 1)
1215 return -1;
1216 if (convert_utf8_to_utf16(ru_HowAreYou_UTF8, ru_HowAreYou_UTF16, ru_HowAreYou_cchWideChar) < 1)
1217 return -1;
1218
1219 if (convert_utf16_to_utf8(ru_Hello_UTF16, ru_Hello_UTF8, ru_Hello_cbMultiByte) < 1)
1220 return -1;
1221 if (convert_utf16_to_utf8(ru_HowAreYou_UTF16, ru_HowAreYou_UTF8, ru_HowAreYou_cbMultiByte) < 1)
1222 return -1;
1223
1224 /* Arabic */
1225
1226 printf("Arabic\n");
1227
1228 if (convert_utf8_to_utf16(ar_Hello_UTF8, ar_Hello_UTF16, ar_Hello_cchWideChar) < 1)
1229 return -1;
1230 if (convert_utf8_to_utf16(ar_HowAreYou_UTF8, ar_HowAreYou_UTF16, ar_HowAreYou_cchWideChar) < 1)
1231 return -1;
1232
1233 if (convert_utf16_to_utf8(ar_Hello_UTF16, ar_Hello_UTF8, ar_Hello_cbMultiByte) < 1)
1234 return -1;
1235 if (convert_utf16_to_utf8(ar_HowAreYou_UTF16, ar_HowAreYou_UTF8, ar_HowAreYou_cbMultiByte) < 1)
1236 return -1;
1237
1238 /* Chinese */
1239
1240 printf("Chinese\n");
1241
1242 if (convert_utf8_to_utf16(ch_Hello_UTF8, ch_Hello_UTF16, ch_Hello_cchWideChar) < 1)
1243 return -1;
1244 if (convert_utf8_to_utf16(ch_HowAreYou_UTF8, ch_HowAreYou_UTF16, ch_HowAreYou_cchWideChar) < 1)
1245 return -1;
1246
1247 if (convert_utf16_to_utf8(ch_Hello_UTF16, ch_Hello_UTF8, ch_Hello_cbMultiByte) < 1)
1248 return -1;
1249 if (convert_utf16_to_utf8(ch_HowAreYou_UTF16, ch_HowAreYou_UTF8, ch_HowAreYou_cbMultiByte) < 1)
1250 return -1;
1251
1252#endif
1253
1254 /* Uppercasing */
1255#if defined(WITH_WINPR_DEPRECATED)
1256 printf("Uppercasing\n");
1257
1258 if (!test_unicode_uppercasing(ru_Administrator_lower, ru_Administrator_upper))
1259 return -1;
1260#endif
1261
1262 /* ConvertFromUnicode */
1263#if defined(WITH_WINPR_DEPRECATED)
1264 printf("ConvertFromUnicode\n");
1265
1266 if (!test_ConvertFromUnicode_wrapper())
1267 return -1;
1268
1269 /* ConvertToUnicode */
1270
1271 printf("ConvertToUnicode\n");
1272
1273 if (!test_ConvertToUnicode_wrapper())
1274 return -1;
1275#endif
1276 /*
1277
1278 printf("----------------------------------------------------------\n\n");
1279
1280 if (0)
1281 {
1282 BYTE src[] = { 'R',0,'I',0,'C',0,'H',0,' ',0, 'T',0,'E',0,'X',0,'T',0,'
1283 ',0,'F',0,'O',0,'R',0,'M',0,'A',0,'T',0,'@',0,'@',0 };
1284 //BYTE src[] = { 'R',0,'I',0,'C',0,'H',0,' ',0, 0,0, 'T',0,'E',0,'X',0,'T',0,'
1285 ',0,'F',0,'O',0,'R',0,'M',0,'A',0,'T',0,'@',0,'@',0 };
1286 //BYTE src[] = { 0,0,'R',0,'I',0,'C',0,'H',0,' ',0, 'T',0,'E',0,'X',0,'T',0,'
1287 ',0,'F',0,'O',0,'R',0,'M',0,'A',0,'T',0,'@',0,'@',0 }; char* dst = NULL; int num; num =
1288 ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) src, 16, &dst, 0, NULL, NULL);
1289 printf("ConvertFromUnicode returned %d dst=[%s]\n", num, dst);
1290 string_hexdump((BYTE*)dst, num+1);
1291 }
1292 if (1)
1293 {
1294 char src[] = "RICH TEXT FORMAT@@@@@@";
1295 WCHAR *dst = NULL;
1296 int num;
1297 num = ConvertToUnicode(CP_UTF8, 0, src, 16, &dst, 0);
1298 printf("ConvertToUnicode returned %d dst=%p\n", num, (void*) dst);
1299 string_hexdump((BYTE*)dst, num * 2 + 2);
1300
1301 }
1302 */
1303
1304 return 0;
1305}