FreeRDP
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 
16 typedef 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.
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"
31  "\x00",
32  9 }
33 };
34 
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)
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 
44 static 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__)
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)
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__)
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)
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 
186 static 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 
214 static 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 
251 static 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 
280 static 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 
318 static 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__)
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)
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__)
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)
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)
480 static 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 
509 static 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)
553 static 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 
584 static 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 
629 static 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 
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;
657 
658 /* English */
659 
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;
664 
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;
671 
672 /* French */
673 
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;
678 
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;
686 
687 /* Russian */
688 
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;
693 
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"
698  "\x3F\x00\x00\x00";
699 static int ru_HowAreYou_cchWideChar = 10;
700 static int ru_HowAreYou_cbMultiByte = 17;
701 
702 /* Arabic */
703 
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;
710 
711 static BYTE ar_HowAreYou_UTF8[] = "\xD9\x83\xD9\x8A\xD9\x81\x20\xD8\xAD\xD8\xA7\xD9\x84\xD9\x83\xD8"
712  "\x9F\x00";
713 static 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";
716 static int ar_HowAreYou_cchWideChar = 10;
717 static int ar_HowAreYou_cbMultiByte = 18;
718 
719 /* Chinese */
720 
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;
725 
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;
730 
731 /* Uppercasing */
732 
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";
735 
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";
738 
739 static 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 
758 static 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;
830 fail:
831  free(lpWideCharStr);
832 
833  return rc;
834 }
835 #endif
836 
837 #if defined(WITH_WINPR_DEPRECATED)
838 static 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;
910 fail:
911  free(lpMultiByteStr);
912 
913  return rc;
914 }
915 #endif
916 
917 #if defined(WITH_WINPR_DEPRECATED)
918 static 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)
950 static 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 
1035 fail:
1036  free(dst);
1037  return FALSE;
1038 }
1039 
1040 static 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 
1154 fail:
1155  free(dst);
1156  return FALSE;
1157 }
1158 #endif
1159 
1160 int 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 }