1 /*
2 * PROJECT: ReactOS API tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test for WideCharToMultiByte
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 #define ntv6(x) (LOBYTE(LOWORD(GetVersion())) >= 6 ? (x) : 0)
11
12 static
13 VOID
Utf8Convert_(_In_ PCWSTR WideString,_In_ PCSTR ExpectedUtf8_2003,_In_ PCSTR ExpectedUtf8_Vista,_In_ BOOL IsInvalid,_In_ PCSTR File,_In_ INT Line)14 Utf8Convert_(
15 _In_ PCWSTR WideString,
16 _In_ PCSTR ExpectedUtf8_2003,
17 _In_ PCSTR ExpectedUtf8_Vista,
18 _In_ BOOL IsInvalid,
19 _In_ PCSTR File,
20 _In_ INT Line)
21 {
22 int WideLen;
23 int Utf8Len;
24 char Buffer[32];
25 int Ret;
26 ULONG i;
27 ULONG Error;
28 PCSTR ExpectedUtf8;
29
30 ExpectedUtf8 = ntv6(1) ? ExpectedUtf8_Vista : ExpectedUtf8_2003;
31 WideLen = lstrlenW(WideString);
32 Utf8Len = lstrlenA(ExpectedUtf8);
33
34 /* Get length only */
35 Ret = WideCharToMultiByte(CP_UTF8, 0, WideString, WideLen, NULL, 0, NULL, NULL);
36 ok_(File, Line)(Ret == Utf8Len, "Length check: Ret = %d\n", Ret);
37
38 /* Get length including nul */
39 Ret = WideCharToMultiByte(CP_UTF8, 0, WideString, WideLen + 1, NULL, 0, NULL, NULL);
40 ok_(File, Line)(Ret == Utf8Len + 1, "Length check with null: Ret = %d\n", Ret);
41
42 /* Convert, excluding null */
43 FillMemory(Buffer, sizeof(Buffer), 0x55);
44 Ret = WideCharToMultiByte(CP_UTF8, 0, WideString, WideLen, Buffer, sizeof(Buffer), NULL, NULL);
45 ok_(File, Line)(Ret == Utf8Len, "Convert: Ret = %d\n", Ret);
46 for (i = 0; i < Utf8Len; i++)
47 {
48 ok_(File, Line)(Buffer[i] == ExpectedUtf8[i], "Convert: Buffer[%lu] = 0x%x, expected 0x%x\n", i, (unsigned char)Buffer[i], (unsigned char)ExpectedUtf8[i]);
49 }
50
51 /* Convert, including null */
52 FillMemory(Buffer, sizeof(Buffer), 0x55);
53 Ret = WideCharToMultiByte(CP_UTF8, 0, WideString, WideLen + 1, Buffer, sizeof(Buffer), NULL, NULL);
54 ok_(File, Line)(Ret == Utf8Len + 1, "Convert with null: Ret = %d\n", Ret);
55 for (i = 0; i < Utf8Len + 1; i++)
56 {
57 ok_(File, Line)(Buffer[i] == ExpectedUtf8[i], "Convert with null: Buffer[%lu] = 0x%x, expected 0x%x\n", i, (unsigned char)Buffer[i], (unsigned char)ExpectedUtf8[i]);
58 }
59
60 /* Get length, reject invalid */
61 SetLastError(0xfeedf00d);
62 Ret = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, WideString, WideLen + 1, NULL, 0, NULL, NULL);
63 Error = GetLastError();
64 if (!ntv6(1))
65 {
66 ok_(File, Line)(Ret == 0, "Length check, reject invalid, NT5: Ret = %d\n", Ret);
67 ok_(File, Line)(Error == ERROR_INVALID_FLAGS, "Length check, reject invalid, NT5: Error = %lu\n", Error);
68 }
69 else if (IsInvalid)
70 {
71 ok_(File, Line)(Ret == 0, "Length check, reject invalid: Ret = %d\n", Ret);
72 ok_(File, Line)(Error == ERROR_NO_UNICODE_TRANSLATION, "Length check, reject invalid: Error = %lu\n", Error);
73 }
74 else
75 {
76 ok_(File, Line)(Ret == Utf8Len + 1, "Length check, reject invalid: Ret = %d\n", Ret);
77 }
78
79 /* Convert, reject invalid */
80 FillMemory(Buffer, sizeof(Buffer), 0x55);
81 SetLastError(0xfeedf00d);
82 Ret = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, WideString, WideLen + 1, Buffer, sizeof(Buffer), NULL, NULL);
83 Error = GetLastError();
84 if (!ntv6(1))
85 {
86 ok_(File, Line)(Ret == 0, "Convert, reject invalid, NT5: Ret = %d\n", Ret);
87 ok_(File, Line)(Error == ERROR_INVALID_FLAGS, "Convert, reject invalid, NT5: Error = %lu\n", Error);
88 }
89 else if (IsInvalid)
90 {
91 ok_(File, Line)(Ret == 0, "Convert, reject invalid: Ret = %d\n", Ret);
92 ok_(File, Line)(Error == ERROR_NO_UNICODE_TRANSLATION, "Convert, reject invalid: Error = %lu\n", Error);
93 for (i = 0; i < Utf8Len + 1; i++)
94 {
95 ok_(File, Line)(Buffer[i] == ExpectedUtf8[i], "Convert, reject invalid: Buffer[%lu] = 0x%x, expected 0x%x\n", i, (unsigned char)Buffer[i], (unsigned char)ExpectedUtf8[i]);
96 }
97 }
98 else
99 {
100 ok_(File, Line)(Ret == Utf8Len + 1, "Convert, reject invalid: Ret = %d\n", Ret);
101 for (i = 0; i < Utf8Len + 1; i++)
102 {
103 ok_(File, Line)(Buffer[i] == ExpectedUtf8[i], "Convert, reject invalid: Buffer[%lu] = 0x%x, expected 0x%x\n", i, (unsigned char)Buffer[i], (unsigned char)ExpectedUtf8[i]);
104 }
105 }
106 }
107 #define Utf8Convert(w, e, i) Utf8Convert_(w, e, e, i, __FILE__, __LINE__)
108 #define Utf8Convert_Vista(w, e, i, e2) Utf8Convert_(w, e, e2, i, __FILE__, __LINE__)
109
110 static
111 VOID
TestUtf8(VOID)112 TestUtf8(VOID)
113 {
114 Utf8Convert(L"", "", FALSE);
115
116 /* Various character ranges */
117 Utf8Convert(L"A", "A", FALSE);
118 Utf8Convert(L"\x007f", "\x7f", FALSE);
119 Utf8Convert(L"\x0080", "\xc2\x80", FALSE);
120 Utf8Convert(L"\x00ff", "\xc3\xbf", FALSE);
121 Utf8Convert(L"\x0100", "\xc4\x80", FALSE);
122 Utf8Convert(L"\x07ff", "\xdf\xbf", FALSE);
123 Utf8Convert(L"\x0800", "\xe0\xa0\x80", FALSE);
124 Utf8Convert(L"\xd7ff", "\xed\x9f\xbf", FALSE);
125 Utf8Convert(L"\xe000", "\xee\x80\x80", FALSE);
126 Utf8Convert(L"\xffff", "\xef\xbf\xbf", FALSE);
127
128 /* surrogate pairs */
129 Utf8Convert(L"\xd800\xdc00", "\xf0\x90\x80\x80", FALSE); /* U+10000 */
130 Utf8Convert(L"\xd800\xdfff", "\xf0\x90\x8f\xbf", FALSE); /* U+103ff */
131 Utf8Convert(L"\xd801\xdc00", "\xf0\x90\x90\x80", FALSE); /* U+10400 */
132 Utf8Convert(L"\xdbff\xdfff", "\xf4\x8f\xbf\xbf", FALSE); /* U+10ffff */
133
134 /* standalone lead surrogate becomes 0xfffd on Vista, goes through verbatim on 2003 */
135 Utf8Convert_Vista(L"\xd800", "\xed\xa0\x80", TRUE,
136 "\xef\xbf\xbd");
137 Utf8Convert_Vista(L"\xd800-", "\xed\xa0\x80-", TRUE,
138 "\xef\xbf\xbd-");
139 Utf8Convert_Vista(L"\xdbff", "\xed\xaf\xbf", TRUE,
140 "\xef\xbf\xbd");
141 Utf8Convert_Vista(L"\xdbff-", "\xed\xaf\xbf-", TRUE,
142 "\xef\xbf\xbd-");
143
144 /* standalone trail surrogate becomes 0xfffd */
145 Utf8Convert_Vista(L"\xdc00", "\xed\xb0\x80", TRUE,
146 "\xef\xbf\xbd");
147 Utf8Convert_Vista(L"\xdc00-", "\xed\xb0\x80-", TRUE,
148 "\xef\xbf\xbd-");
149 Utf8Convert_Vista(L"\xdfff", "\xed\xbf\xbf", TRUE,
150 "\xef\xbf\xbd");
151 Utf8Convert_Vista(L"\xdfff-", "\xed\xbf\xbf-", TRUE,
152 "\xef\xbf\xbd-");
153
154 /* Reverse surrogate pair */
155 Utf8Convert_Vista(L"\xdfff\xdbff", "\xed\xbf\xbf\xed\xaf\xbf", TRUE,
156 "\xef\xbf\xbd\xef\xbf\xbd");
157
158 /* Byte order marks */
159 Utf8Convert(L"\xfeff", "\xef\xbb\xbf", FALSE);
160 Utf8Convert(L"\xfffe", "\xef\xbf\xbe", FALSE);
161
162 /* canonically equivalent representations -- no normalization should happen */
163 Utf8Convert(L"\x1e09", "\xe1\xb8\x89", FALSE);
164 Utf8Convert(L"\x0107\x0327", "\xc4\x87\xcc\xa7", FALSE);
165 Utf8Convert(L"\x00e7\x0301", "\xc3\xa7\xcc\x81", FALSE);
166 Utf8Convert(L"\x0063\x0327\x0301", "\x63\xcc\xa7\xcc\x81", FALSE);
167 Utf8Convert(L"\x0063\x0301\x0327", "\x63\xcc\x81\xcc\xa7", FALSE);
168 }
169
START_TEST(WideCharToMultiByte)170 START_TEST(WideCharToMultiByte)
171 {
172 TestUtf8();
173 }
174