3 #include <winpr/wtypes.h>
5 #include <winpr/assert.h>
6 #include <winpr/error.h>
7 #include <winpr/print.h>
8 #include <winpr/windows.h>
10 #define TESTCASE_BUFFER_SIZE 8192
13 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
26 static 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"
35 static 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)
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);
44 static BOOL check_short_buffer(
const char* prefix,
int rc,
size_t buffersize,
45 const testcase_t* test, BOOL utf8)
47 if ((rc > 0) && ((
size_t)rc <= buffersize))
50 size_t len = test->utf8len;
57 "%s length does not match buffersize: %" PRId32
" != %" PRIuz
58 ",but is large enough to hold result\n",
59 prefix, rc, buffersize);
62 const DWORD err = GetLastError();
63 if (err != ERROR_INSUFFICIENT_BUFFER)
67 "%s length does not match buffersize: %" PRId32
" != %" PRIuz
68 ", unexpected GetLastError() 0x08%" PRIx32
"\n",
69 prefix, rc, buffersize, err);
76 #define compare_utf16(what, buffersize, rc, inputlen, test) \
77 compare_utf16_int((what), (buffersize), (rc), (inputlen), (test), __func__, __LINE__)
78 static 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)
81 char prefix[8192] = { 0 };
82 create_prefix(prefix, ARRAYSIZE(prefix), buffersize, rc, inputlen, test, fkt, line);
84 WINPR_ASSERT(what || (buffersize == 0));
87 const size_t welen = _wcsnlen(test->utf16, test->utf16len);
88 if (buffersize > welen)
90 if ((rc < 0) || ((
size_t)rc != welen))
93 "%s length does not match expectation: %" PRIdz
" != %" PRIuz
"\n",
100 if (!check_short_buffer(prefix, WINPR_ASSERTING_INT_CAST(SSIZE_T, rc), buffersize, test,
105 if ((rc > 0) && (buffersize > (size_t)rc))
107 const size_t wlen = _wcsnlen(what, buffersize);
108 if ((rc < 0) || (wlen > (
size_t)rc))
110 (void)fprintf(stderr,
"%s length does not match wcslen: %" PRIdz
" < %" PRIuz
"\n",
118 if (memcmp(test->utf16, what, rc *
sizeof(WCHAR)) != 0)
120 (void)fprintf(stderr,
"%s contents does not match expectations: TODO '%s' != '%s'\n",
121 prefix, test->utf8, test->utf8);
126 printf(
"%s success\n", prefix);
131 #define compare_utf8(what, buffersize, rc, inputlen, test) \
132 compare_utf8_int((what), (buffersize), (rc), (inputlen), (test), __func__, __LINE__)
133 static 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)
136 char prefix[8192] = { 0 };
137 create_prefix(prefix, ARRAYSIZE(prefix), buffersize, rc, inputlen, test, fkt, line);
139 WINPR_ASSERT(what || (buffersize == 0));
142 const size_t slen = strnlen(test->utf8, test->utf8len);
143 if (buffersize > slen)
145 if ((rc < 0) || ((
size_t)rc != slen))
147 (void)fprintf(stderr,
148 "%s length does not match expectation: %" PRIdz
" != %" PRIuz
"\n",
155 if (!check_short_buffer(prefix, WINPR_ASSERTING_INT_CAST(SSIZE_T, rc), buffersize, test,
160 if ((rc > 0) && (buffersize > (size_t)rc))
162 const size_t wlen = strnlen(what, buffersize);
163 if (wlen != (
size_t)rc)
165 (void)fprintf(stderr,
"%s length does not match strnlen: %" PRIdz
" != %" PRIuz
"\n",
173 if (memcmp(test->utf8, what, rc) != 0)
175 (void)fprintf(stderr,
"%s contents does not match expectations: '%s' != '%s'\n", prefix,
181 printf(
"%s success\n", prefix);
186 static BOOL test_convert_to_utf16(
const testcase_t* test)
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;
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))
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);
203 for (
size_t x = 0; x < max; x++)
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))
214 static BOOL test_convert_to_utf16_n(
const testcase_t* test)
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;
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))
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);
234 for (
size_t x = 0; x < max; x++)
236 const size_t ilen[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
238 const size_t imax = test->utf8len > 0 ? ARRAYSIZE(ilen) : ARRAYSIZE(ilen) - 1;
240 for (
size_t y = 0; y < imax; y++)
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))
251 static BOOL test_convert_to_utf8(
const testcase_t* test)
253 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
255 const size_t max = test->utf8len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
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))
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);
269 for (
size_t x = 0; x < max; x++)
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))
280 static BOOL test_convert_to_utf8_n(
const testcase_t* test)
282 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
284 const size_t max = test->utf8len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
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))
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);
300 for (
size_t x = 0; x < max; x++)
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;
306 for (
size_t y = 0; y < imax; y++)
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))
318 static BOOL test_conversion(
const testcase_t* testcases,
size_t count)
320 WINPR_ASSERT(testcases || (count == 0));
321 for (
size_t x = 0; x < count; x++)
323 const testcase_t* test = &testcases[x];
325 printf(
"Running test case %" PRIuz
" [%s]\n", x, test->utf8);
326 if (!test_convert_to_utf16(test))
328 if (!test_convert_to_utf16_n(test))
330 if (!test_convert_to_utf8(test))
332 if (!test_convert_to_utf8_n(test))
338 #if defined(WITH_WINPR_DEPRECATED)
340 #define compare_win_utf16(what, buffersize, rc, inputlen, test) \
341 compare_win_utf16_int((what), (buffersize), (rc), (inputlen), (test), __func__, __LINE__)
342 static 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)
345 char prefix[8192] = { 0 };
346 create_prefix(prefix, ARRAYSIZE(prefix), buffersize, rc, inputlen, test, fkt, line);
348 WINPR_ASSERT(what || (buffersize == 0));
351 BOOL isNullTerminated = TRUE;
353 isNullTerminated = strnlen(test->utf8, inputlen) < inputlen;
354 size_t welen = _wcsnlen(test->utf16, buffersize);
355 if (isNullTerminated)
358 if (buffersize >= welen)
360 if ((inputlen >= 0) && (rc > buffersize))
362 (void)fprintf(stderr,
"%s length does not match expectation: %d > %" PRIuz
"\n", prefix,
366 else if ((inputlen < 0) && (rc != welen))
368 (void)fprintf(stderr,
"%s length does not match expectation: %d != %" PRIuz
"\n",
375 if (!check_short_buffer(prefix, rc, buffersize, test, FALSE))
379 if ((rc > 0) && (buffersize > rc))
381 size_t wlen = _wcsnlen(what, buffersize);
382 if (isNullTerminated)
384 if ((inputlen >= 0) && (buffersize < rc))
386 (void)fprintf(stderr,
"%s length does not match wcslen: %d > %" PRIuz
"\n", prefix, rc,
390 else if ((inputlen < 0) && (welen > rc))
392 (void)fprintf(stderr,
"%s length does not match wcslen: %d < %" PRIuz
"\n", prefix, rc,
398 const size_t cmp_size = MIN(rc, test->utf16len) *
sizeof(WCHAR);
399 if (memcmp(test->utf16, what, cmp_size) != 0)
401 (void)fprintf(stderr,
"%s contents does not match expectations: TODO '%s' != '%s'\n",
402 prefix, test->utf8, test->utf8);
406 printf(
"%s success\n", prefix);
411 #define compare_win_utf8(what, buffersize, rc, inputlen, test) \
412 compare_win_utf8_int((what), (buffersize), (rc), (inputlen), (test), __func__, __LINE__)
413 static 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)
416 char prefix[8192] = { 0 };
417 create_prefix(prefix, ARRAYSIZE(prefix), buffersize, rc, inputlen, test, fkt, line);
419 WINPR_ASSERT(what || (buffersize == 0));
422 BOOL isNullTerminated = TRUE;
424 isNullTerminated = _wcsnlen(test->utf16, inputlen) < inputlen;
426 size_t slen = strnlen(test->utf8, test->utf8len);
427 if (isNullTerminated)
430 if (buffersize > slen)
432 if ((inputlen >= 0) && (rc > buffersize))
434 (void)fprintf(stderr,
"%s length does not match expectation: %" PRIdz
" > %" PRIuz
"\n",
435 prefix, rc, buffersize);
438 else if ((inputlen < 0) && (rc != slen))
440 (void)fprintf(stderr,
441 "%s length does not match expectation: %" PRIdz
" != %" PRIuz
"\n",
448 if (!check_short_buffer(prefix, rc, buffersize, test, TRUE))
452 if ((rc > 0) && (buffersize > rc))
454 size_t wlen = strnlen(what, buffersize);
455 if (isNullTerminated)
460 (void)fprintf(stderr,
"%s length does not match wcslen: %" PRIdz
" < %" PRIuz
"\n",
466 const size_t cmp_size = MIN(test->utf8len, rc);
467 if (memcmp(test->utf8, what, cmp_size) != 0)
469 (void)fprintf(stderr,
"%s contents does not match expectations: '%s' != '%s'\n", prefix,
473 printf(
"%s success\n", prefix);
479 #if defined(WITH_WINPR_DEPRECATED)
480 static BOOL test_win_convert_to_utf16(
const testcase_t* test)
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;
486 const int rc2 = MultiByteToWideChar(CP_UTF8, 0, test->utf8, -1, NULL, 0);
487 const size_t wlen = _wcsnlen(test->utf16, test->utf16len);
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
495 prefix, test->utf8, wlen + 1, rc2);
498 for (
size_t x = 0; x < max; x++)
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))
509 static BOOL test_win_convert_to_utf16_n(
const testcase_t* test)
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;
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)
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
528 prefix, test->utf8, test->utf8len, wlen, rc2);
532 for (
size_t x = 0; x < max; x++)
534 const size_t ilen[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
536 const size_t imax = test->utf8len > 0 ? ARRAYSIZE(ilen) : ARRAYSIZE(ilen) - 1;
538 for (
size_t y = 0; y < imax; y++)
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))
552 #if defined(WITH_WINPR_DEPRECATED)
553 static BOOL test_win_convert_to_utf8(
const testcase_t* test)
555 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
557 const size_t max = test->utf8len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
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;
563 char prefix[8192] = { 0 };
564 create_prefix(prefix, ARRAYSIZE(prefix), 0, rc2, -1, test, __func__, __LINE__);
567 "%s WideCharToMultiByte(CP_UTF8, 0, %s, -1, NULL, 0, NULL, NULL) expected %" PRIuz
569 prefix, test->utf8, wlen, rc2);
573 for (
size_t x = 0; x < max; x++)
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))
584 static BOOL test_win_convert_to_utf8_n(
const testcase_t* test)
586 const size_t len[] = { TESTCASE_BUFFER_SIZE, test->utf8len, test->utf8len + 1,
588 const size_t max = test->utf8len > 0 ? ARRAYSIZE(len) : ARRAYSIZE(len) - 1;
590 const BOOL isNullTerminated = _wcsnlen(test->utf16, test->utf16len) < test->utf16len;
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)
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);
608 for (
size_t x = 0; x < max; x++)
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;
614 for (
size_t y = 0; y < imax; y++)
616 WCHAR wbuffer[TESTCASE_BUFFER_SIZE] = { 0 };
617 char buffer[TESTCASE_BUFFER_SIZE] = { 0 };
618 memcpy(wbuffer, test->utf16, test->utf16len *
sizeof(WCHAR));
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))
629 static BOOL test_win_conversion(
const testcase_t* testcases,
size_t count)
631 WINPR_ASSERT(testcases || (count == 0));
632 for (
size_t x = 0; x < count; x++)
634 const testcase_t* test = &testcases[x];
636 printf(
"Running test case %" PRIuz
" [%s]\n", x, test->utf8);
637 if (!test_win_convert_to_utf16(test))
639 if (!test_win_convert_to_utf16_n(test))
641 if (!test_win_convert_to_utf8(test))
643 if (!test_win_convert_to_utf8_n(test))
650 #if defined(WITH_WINPR_DEPRECATED)
653 static BYTE c_cedilla_UTF8[] =
"\xC3\xA7\x00";
654 static BYTE c_cedilla_UTF16[] =
"\xE7\x00\x00\x00";
655 static int c_cedilla_cchWideChar = 2;
656 static int c_cedilla_cbMultiByte = 3;
660 static BYTE en_Hello_UTF8[] =
"Hello\0";
661 static BYTE en_Hello_UTF16[] =
"\x48\x00\x65\x00\x6C\x00\x6C\x00\x6F\x00\x00\x00";
662 static int en_Hello_cchWideChar = 6;
663 static int en_Hello_cbMultiByte = 6;
665 static BYTE en_HowAreYou_UTF8[] =
"How are you?\0";
666 static 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";
669 static int en_HowAreYou_cchWideChar = 13;
670 static int en_HowAreYou_cbMultiByte = 13;
674 static BYTE fr_Hello_UTF8[] =
"Allo\0";
675 static BYTE fr_Hello_UTF16[] =
"\x41\x00\x6C\x00\x6C\x00\x6F\x00\x00\x00";
676 static int fr_Hello_cchWideChar = 5;
677 static int fr_Hello_cbMultiByte = 5;
679 static BYTE fr_HowAreYou_UTF8[] =
680 "\x43\x6F\x6D\x6D\x65\x6E\x74\x20\xC3\xA7\x61\x20\x76\x61\x3F\x00";
681 static 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";
684 static int fr_HowAreYou_cchWideChar = 15;
685 static int fr_HowAreYou_cbMultiByte = 16;
689 static BYTE ru_Hello_UTF8[] =
"\xD0\x97\xD0\xB4\xD0\xBE\xD1\x80\xD0\xBE\xD0\xB2\xD0\xBE\x00";
690 static BYTE ru_Hello_UTF16[] =
"\x17\x04\x34\x04\x3E\x04\x40\x04\x3E\x04\x32\x04\x3E\x04\x00\x00";
691 static int ru_Hello_cchWideChar = 8;
692 static int ru_Hello_cbMultiByte = 15;
694 static BYTE ru_HowAreYou_UTF8[] =
695 "\xD0\x9A\xD0\xB0\xD0\xBA\x20\xD0\xB4\xD0\xB5\xD0\xBB\xD0\xB0\x3F\x00";
696 static BYTE ru_HowAreYou_UTF16[] =
697 "\x1A\x04\x30\x04\x3A\x04\x20\x00\x34\x04\x35\x04\x3B\x04\x30\x04"
699 static int ru_HowAreYou_cchWideChar = 10;
700 static int ru_HowAreYou_cbMultiByte = 17;
704 static 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";
706 static 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";
708 static int ar_Hello_cchWideChar = 13;
709 static int ar_Hello_cbMultiByte = 24;
711 static BYTE ar_HowAreYou_UTF8[] =
"\xD9\x83\xD9\x8A\xD9\x81\x20\xD8\xAD\xD8\xA7\xD9\x84\xD9\x83\xD8"
713 static BYTE ar_HowAreYou_UTF16[] =
714 "\x43\x06\x4A\x06\x41\x06\x20\x00\x2D\x06\x27\x06\x44\x06\x43\x06"
716 static int ar_HowAreYou_cchWideChar = 10;
717 static int ar_HowAreYou_cbMultiByte = 18;
721 static BYTE ch_Hello_UTF8[] =
"\xE4\xBD\xA0\xE5\xA5\xBD\x00";
722 static BYTE ch_Hello_UTF16[] =
"\x60\x4F\x7D\x59\x00\x00";
723 static int ch_Hello_cchWideChar = 3;
724 static int ch_Hello_cbMultiByte = 7;
726 static BYTE ch_HowAreYou_UTF8[] =
"\xE4\xBD\xA0\xE5\xA5\xBD\xE5\x90\x97\x00";
727 static BYTE ch_HowAreYou_UTF16[] =
"\x60\x4F\x7D\x59\x17\x54\x00\x00";
728 static int ch_HowAreYou_cchWideChar = 4;
729 static int ch_HowAreYou_cbMultiByte = 10;
733 static 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";
736 static 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";
739 static void string_hexdump(
const BYTE* data,
size_t length)
743 char* str = winpr_BinToHexString(data, length, TRUE);
747 while (offset < length)
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]);
758 static int convert_utf8_to_utf16(BYTE* lpMultiByteStr, BYTE* expected_lpWideCharStr,
759 int expected_cchWideChar)
763 size_t cbMultiByte = 0;
765 LPWSTR lpWideCharStr = NULL;
767 cbMultiByte = strlen((
char*)lpMultiByteStr);
768 cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)lpMultiByteStr, -1, NULL, 0);
770 printf(
"MultiByteToWideChar Input UTF8 String:\n");
771 string_hexdump(lpMultiByteStr, cbMultiByte + 1);
773 printf(
"MultiByteToWideChar required cchWideChar: %d\n", cchWideChar);
775 if (cchWideChar != expected_cchWideChar)
777 printf(
"MultiByteToWideChar unexpected cchWideChar: actual: %d expected: %d\n", cchWideChar,
778 expected_cchWideChar);
782 lpWideCharStr = (LPWSTR)calloc((
size_t)cchWideChar,
sizeof(WCHAR));
785 printf(
"MultiByteToWideChar: unable to allocate memory for test\n");
788 lpWideCharStr[cchWideChar - 1] =
790 length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)lpMultiByteStr, cbMultiByte + 1, lpWideCharStr,
793 printf(
"MultiByteToWideChar converted length (WCHAR): %d\n", length);
797 DWORD error = GetLastError();
798 printf(
"MultiByteToWideChar error: 0x%08" PRIX32
"\n", error);
802 if (length != expected_cchWideChar)
804 printf(
"MultiByteToWideChar unexpected converted length (WCHAR): actual: %d expected: %d\n",
805 length, expected_cchWideChar);
809 if (_wcscmp(lpWideCharStr, (WCHAR*)expected_lpWideCharStr) != 0)
811 printf(
"MultiByteToWideChar unexpected string:\n");
813 printf(
"UTF8 String:\n");
814 string_hexdump(lpMultiByteStr, cbMultiByte + 1);
816 printf(
"UTF16 String (actual):\n");
817 string_hexdump((BYTE*)lpWideCharStr, length *
sizeof(WCHAR));
819 printf(
"UTF16 String (expected):\n");
820 string_hexdump(expected_lpWideCharStr, expected_cchWideChar *
sizeof(WCHAR));
825 printf(
"MultiByteToWideChar Output UTF16 String:\n");
826 string_hexdump((BYTE*)lpWideCharStr, length *
sizeof(WCHAR));
837 #if defined(WITH_WINPR_DEPRECATED)
838 static int convert_utf16_to_utf8(BYTE* lpWideCharStr, BYTE* expected_lpMultiByteStr,
839 int expected_cbMultiByte)
845 LPSTR lpMultiByteStr = NULL;
847 cchWideChar = _wcslen((WCHAR*)lpWideCharStr);
848 cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)lpWideCharStr, -1, NULL, 0, NULL, NULL);
850 printf(
"WideCharToMultiByte Input UTF16 String:\n");
851 string_hexdump(lpWideCharStr, (cchWideChar + 1) *
sizeof(WCHAR));
853 printf(
"WideCharToMultiByte required cbMultiByte: %d\n", cbMultiByte);
855 if (cbMultiByte != expected_cbMultiByte)
857 printf(
"WideCharToMultiByte unexpected cbMultiByte: actual: %d expected: %d\n", cbMultiByte,
858 expected_cbMultiByte);
862 lpMultiByteStr = (LPSTR)malloc(cbMultiByte);
865 printf(
"WideCharToMultiByte: unable to allocate memory for test\n");
868 lpMultiByteStr[cbMultiByte - 1] =
870 length = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)lpWideCharStr, cchWideChar + 1,
871 lpMultiByteStr, cbMultiByte, NULL, NULL);
873 printf(
"WideCharToMultiByte converted length (BYTE): %d\n", length);
877 DWORD error = GetLastError();
878 printf(
"WideCharToMultiByte error: 0x%08" PRIX32
"\n", error);
882 if (length != expected_cbMultiByte)
884 printf(
"WideCharToMultiByte unexpected converted length (BYTE): actual: %d expected: %d\n",
885 length, expected_cbMultiByte);
889 if (strcmp(lpMultiByteStr, (
char*)expected_lpMultiByteStr) != 0)
891 printf(
"WideCharToMultiByte unexpected string:\n");
893 printf(
"UTF16 String:\n");
894 string_hexdump(lpWideCharStr, (cchWideChar + 1) *
sizeof(WCHAR));
896 printf(
"UTF8 String (actual):\n");
897 string_hexdump((BYTE*)lpMultiByteStr, cbMultiByte);
899 printf(
"UTF8 String (expected):\n");
900 string_hexdump(expected_lpMultiByteStr, expected_cbMultiByte);
905 printf(
"WideCharToMultiByte Output UTF8 String:\n");
906 string_hexdump((BYTE*)lpMultiByteStr, cbMultiByte);
911 free(lpMultiByteStr);
917 #if defined(WITH_WINPR_DEPRECATED)
918 static BOOL test_unicode_uppercasing(BYTE* lower, BYTE* upper)
920 WCHAR* lowerW = NULL;
922 WCHAR* upperW = NULL;
925 lowerLength = ConvertToUnicode(CP_UTF8, 0, (LPSTR)lower, -1, &lowerW, 0);
926 upperLength = ConvertToUnicode(CP_UTF8, 0, (LPSTR)upper, -1, &upperW, 0);
928 CharUpperBuffW(lowerW, lowerLength);
930 if (_wcscmp(lowerW, upperW) != 0)
932 printf(
"Lowercase String:\n");
933 string_hexdump((BYTE*)lowerW, lowerLength * 2);
935 printf(
"Uppercase String:\n");
936 string_hexdump((BYTE*)upperW, upperLength * 2);
944 printf(
"success\n\n");
949 #if defined(WITH_WINPR_DEPRECATED)
950 static BOOL test_ConvertFromUnicode_wrapper(
void)
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";
958 const CHAR cmp0[] = {
'R',
'I',
'C',
'H',
' ',
'T',
'E',
'X',
'T',
959 ' ',
'F',
'O',
'R',
'M',
'A',
'T', 0 };
967 printf(
"Input UTF16 String:\n");
968 string_hexdump((
const BYTE*)src1, 19 *
sizeof(WCHAR));
970 i = ConvertFromUnicode(CP_UTF8, 0, (
const WCHAR*)src1, 16, &dst, 0, NULL, NULL);
973 (void)fprintf(stderr,
974 "ConvertFromUnicode failure A1: unexpectedly returned %d instead of 16\n", i);
979 (void)fprintf(stderr,
"ConvertFromUnicode failure A2: destination is NULL\n");
982 if ((i = strlen(dst)) != 16)
984 (void)fprintf(stderr,
"ConvertFromUnicode failure A3: dst length is %d instead of 16\n", i);
987 if (strcmp(dst, cmp0))
989 (void)fprintf(stderr,
"ConvertFromUnicode failure A4: data mismatch\n");
992 printf(
"Output UTF8 String:\n");
993 string_hexdump((BYTE*)dst, i + 1);
1000 printf(
"Input UTF16 String:\n");
1001 string_hexdump((
const BYTE*)src2, (_wcslen((
const WCHAR*)src2) + 1) *
sizeof(WCHAR));
1003 i = ConvertFromUnicode(CP_UTF8, 0, (
const WCHAR*)src2, -1, &dst, 0, NULL, NULL);
1006 (void)fprintf(stderr,
1007 "ConvertFromUnicode failure B1: unexpectedly returned %d instead of 17\n", i);
1012 (void)fprintf(stderr,
"ConvertFromUnicode failure B2: destination is NULL\n");
1015 if ((i = strlen(dst)) != 16)
1017 (void)fprintf(stderr,
"ConvertFromUnicode failure B3: dst length is %d instead of 16\n", i);
1020 if (strcmp(dst, cmp0))
1022 (void)fprintf(stderr,
"ConvertFromUnicode failure B: data mismatch\n");
1025 printf(
"Output UTF8 String:\n");
1026 string_hexdump((BYTE*)dst, i + 1);
1031 printf(
"success\n\n");
1040 static BOOL test_ConvertToUnicode_wrapper(
void)
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";
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)
1066 if (memcmp(wname, cmp,
sizeof(cmp)) != 0)
1069 ii = ConvertToUnicode(CP_UTF8, 0, name, len, &aname, 0);
1070 if (ii != (SSIZE_T)len)
1072 ii = memcmp(aname, cmp,
sizeof(cmp));
1082 printf(
"Input UTF8 String:\n");
1083 string_hexdump((
const BYTE*)src1, 19);
1085 ii = ConvertToUnicode(CP_UTF8, 0, src1, 16, &dst, 0);
1088 (void)fprintf(stderr,
1089 "ConvertToUnicode failure A1: unexpectedly returned %d instead of 16\n", ii);
1095 (void)fprintf(stderr,
"ConvertToUnicode failure A2: destination is NULL\n");
1098 if ((i = _wcslen(dst)) != 16)
1100 (void)fprintf(stderr,
1101 "ConvertToUnicode failure A3: dst length is %" PRIuz
" instead of 16\n", i);
1104 if (_wcscmp(dst, (
const WCHAR*)cmp0))
1106 (void)fprintf(stderr,
"ConvertToUnicode failure A4: data mismatch\n");
1109 printf(
"Output UTF16 String:\n");
1110 string_hexdump((
const BYTE*)dst, (i + 1) *
sizeof(WCHAR));
1117 printf(
"Input UTF8 String:\n");
1118 string_hexdump((
const BYTE*)src2, strlen(src2) + 1);
1120 i = ConvertToUnicode(CP_UTF8, 0, src2, -1, &dst, 0);
1124 stderr,
"ConvertToUnicode failure B1: unexpectedly returned %" PRIuz
" instead of 17\n",
1130 (void)fprintf(stderr,
"ConvertToUnicode failure B2: destination is NULL\n");
1133 if ((i = _wcslen(dst)) != 16)
1135 (void)fprintf(stderr,
1136 "ConvertToUnicode failure B3: dst length is %" PRIuz
" instead of 16\n", i);
1139 if (_wcscmp(dst, (
const WCHAR*)cmp0))
1141 (void)fprintf(stderr,
"ConvertToUnicode failure B: data mismatch\n");
1144 printf(
"Output UTF16 String:\n");
1145 string_hexdump((BYTE*)dst, (i + 1) * 2);
1150 printf(
"success\n\n");
1160 int TestUnicodeConversion(
int argc,
char* argv[])
1165 if (!test_conversion(unit_testcases, ARRAYSIZE(unit_testcases)))
1168 #if defined(WITH_WINPR_DEPRECATED)
1169 if (!test_win_conversion(unit_testcases, ARRAYSIZE(unit_testcases)))
1174 printf(
"Letters\n");
1176 if (convert_utf8_to_utf16(c_cedilla_UTF8, c_cedilla_UTF16, c_cedilla_cchWideChar) < 1)
1179 if (convert_utf16_to_utf8(c_cedilla_UTF16, c_cedilla_UTF8, c_cedilla_cbMultiByte) < 1)
1184 printf(
"English\n");
1186 if (convert_utf8_to_utf16(en_Hello_UTF8, en_Hello_UTF16, en_Hello_cchWideChar) < 1)
1188 if (convert_utf8_to_utf16(en_HowAreYou_UTF8, en_HowAreYou_UTF16, en_HowAreYou_cchWideChar) < 1)
1191 if (convert_utf16_to_utf8(en_Hello_UTF16, en_Hello_UTF8, en_Hello_cbMultiByte) < 1)
1193 if (convert_utf16_to_utf8(en_HowAreYou_UTF16, en_HowAreYou_UTF8, en_HowAreYou_cbMultiByte) < 1)
1200 if (convert_utf8_to_utf16(fr_Hello_UTF8, fr_Hello_UTF16, fr_Hello_cchWideChar) < 1)
1202 if (convert_utf8_to_utf16(fr_HowAreYou_UTF8, fr_HowAreYou_UTF16, fr_HowAreYou_cchWideChar) < 1)
1205 if (convert_utf16_to_utf8(fr_Hello_UTF16, fr_Hello_UTF8, fr_Hello_cbMultiByte) < 1)
1207 if (convert_utf16_to_utf8(fr_HowAreYou_UTF16, fr_HowAreYou_UTF8, fr_HowAreYou_cbMultiByte) < 1)
1212 printf(
"Russian\n");
1214 if (convert_utf8_to_utf16(ru_Hello_UTF8, ru_Hello_UTF16, ru_Hello_cchWideChar) < 1)
1216 if (convert_utf8_to_utf16(ru_HowAreYou_UTF8, ru_HowAreYou_UTF16, ru_HowAreYou_cchWideChar) < 1)
1219 if (convert_utf16_to_utf8(ru_Hello_UTF16, ru_Hello_UTF8, ru_Hello_cbMultiByte) < 1)
1221 if (convert_utf16_to_utf8(ru_HowAreYou_UTF16, ru_HowAreYou_UTF8, ru_HowAreYou_cbMultiByte) < 1)
1228 if (convert_utf8_to_utf16(ar_Hello_UTF8, ar_Hello_UTF16, ar_Hello_cchWideChar) < 1)
1230 if (convert_utf8_to_utf16(ar_HowAreYou_UTF8, ar_HowAreYou_UTF16, ar_HowAreYou_cchWideChar) < 1)
1233 if (convert_utf16_to_utf8(ar_Hello_UTF16, ar_Hello_UTF8, ar_Hello_cbMultiByte) < 1)
1235 if (convert_utf16_to_utf8(ar_HowAreYou_UTF16, ar_HowAreYou_UTF8, ar_HowAreYou_cbMultiByte) < 1)
1240 printf(
"Chinese\n");
1242 if (convert_utf8_to_utf16(ch_Hello_UTF8, ch_Hello_UTF16, ch_Hello_cchWideChar) < 1)
1244 if (convert_utf8_to_utf16(ch_HowAreYou_UTF8, ch_HowAreYou_UTF16, ch_HowAreYou_cchWideChar) < 1)
1247 if (convert_utf16_to_utf8(ch_Hello_UTF16, ch_Hello_UTF8, ch_Hello_cbMultiByte) < 1)
1249 if (convert_utf16_to_utf8(ch_HowAreYou_UTF16, ch_HowAreYou_UTF8, ch_HowAreYou_cbMultiByte) < 1)
1255 #if defined(WITH_WINPR_DEPRECATED)
1256 printf(
"Uppercasing\n");
1258 if (!test_unicode_uppercasing(ru_Administrator_lower, ru_Administrator_upper))
1263 #if defined(WITH_WINPR_DEPRECATED)
1264 printf(
"ConvertFromUnicode\n");
1266 if (!test_ConvertFromUnicode_wrapper())
1271 printf(
"ConvertToUnicode\n");
1273 if (!test_ConvertToUnicode_wrapper())