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