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 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 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 170 START_TEST(WideCharToMultiByte) 171 { 172 TestUtf8(); 173 } 174