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