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