From: Alex Henrie Subject: kernel32: Add UTF-7 support. (try 3) Message-Id: <20120730210853.0ff93b3257b9f2db505d77f6@gmail.com> Date: Mon, 30 Jul 2012 21:08:53 -0600 Fixes bug 27388. Try 3 fixes example #8 in the accompanying tests, which was not testing what it was supposed to be testing. Only the test changed, not kernel32. --- dlls/kernel32/locale.c | 524 +++++++++++++++++++++++++++++++++++++++- dlls/kernel32/tests/codepage.c | 126 ++++++++++ 2 files changed, 642 insertions(+), 8 deletions(-) diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c index 90603f2..32f2ee6 100644 --- a/dlls/kernel32/locale.c +++ b/dlls/kernel32/locale.c @@ -1869,6 +1869,252 @@ BOOL WINAPI EnumSystemCodePagesW( CODEPAGE_ENUMPROCW lpfnCodePageEnum, DWORD fla /*********************************************************************** + * write_to_w_string + * + * Helper for utf7_mbstowcs + * + * RETURNS + * 0 on success, -1 on error + */ +static int write_to_w_string(WCHAR* dst, int dstlen, int* index, WCHAR character) +{ + if (*index >= dstlen) + { + return -1; + } + + dst[*index] = character; + (*index)++; + return 0; +} + +/*********************************************************************** + * utf7_mbstowcs + * + * UTF-7 to UTF-16 string conversion, helper for MultiByteToWideChar + * + * RETURNS + * On success, the number of characters written + * On dst buffer overflow, -1 + * On invalid input char, -2 + */ +static int utf7_mbstowcs(const char* src, int srclen, WCHAR* dst, int dstlen) +{ + static const WCHAR base64_decoding_table[] = { + /* \0 */ -1, + /* \x01 */ -1, + /* \x02 */ -1, + /* \x03 */ -1, + /* \x04 */ -1, + /* \x05 */ -1, + /* \x06 */ -1, + /* \a */ -1, + /* \b */ -1, + /* \t */ -1, + /* \n */ -1, + /* \v */ -1, + /* \f */ -1, + /* \r */ -1, + /* \x0E */ -1, + /* \x0F */ -1, + /* \x10 */ -1, + /* \x11 */ -1, + /* \x12 */ -1, + /* \x13 */ -1, + /* \x14 */ -1, + /* \x15 */ -1, + /* \x16 */ -1, + /* \x17 */ -1, + /* \x18 */ -1, + /* \x19 */ -1, + /* \x1A */ -1, + /* \e */ -1, + /* \x1C */ -1, + /* \x1D */ -1, + /* \x1E */ -1, + /* \x1F */ -1, + /* */ -1, + /* ! */ -1, + /* " */ -1, + /* # */ -1, + /* $ */ -1, + /* % */ -1, + /* & */ -1, + /* ' */ -1, + /* ( */ -1, + /* ) */ -1, + /* * */ -1, + /* + */ 62, + /* , */ -1, + /* - */ -1, + /* . */ -1, + /* / */ 63, + /* 0 */ 52, + /* 1 */ 53, + /* 2 */ 54, + /* 3 */ 55, + /* 4 */ 56, + /* 5 */ 57, + /* 6 */ 58, + /* 7 */ 59, + /* 8 */ 60, + /* 9 */ 61, + /* : */ -1, + /* ; */ -1, + /* < */ -1, + /* = */ -1, + /* > */ -1, + /* ? */ -1, + /* @ */ -1, + /* A */ 0, + /* B */ 1, + /* C */ 2, + /* D */ 3, + /* E */ 4, + /* F */ 5, + /* G */ 6, + /* H */ 7, + /* I */ 8, + /* J */ 9, + /* K */ 10, + /* L */ 11, + /* M */ 12, + /* N */ 13, + /* O */ 14, + /* P */ 15, + /* Q */ 16, + /* R */ 17, + /* S */ 18, + /* T */ 19, + /* U */ 20, + /* V */ 21, + /* W */ 22, + /* X */ 23, + /* Y */ 24, + /* Z */ 25, + /* [ */ -1, + /* \ */ -1, + /* ] */ -1, + /* ^ */ -1, + /* _ */ -1, + /* ` */ -1, + /* a */ 26, + /* b */ 27, + /* c */ 28, + /* d */ 29, + /* e */ 30, + /* f */ 31, + /* g */ 32, + /* h */ 33, + /* i */ 34, + /* j */ 35, + /* k */ 36, + /* l */ 37, + /* m */ 38, + /* n */ 39, + /* o */ 40, + /* p */ 41, + /* q */ 42, + /* r */ 43, + /* s */ 44, + /* t */ 45, + /* u */ 46, + /* v */ 47, + /* w */ 48, + /* x */ 49, + /* y */ 50, + /* z */ 51 + }; + + BOOL dry_run = !dst || !dstlen; + int source_index = 0; + int dest_index = 0; + + do + { + if (src[source_index] == 0 && srclen == -1) + { + if (dry_run) dest_index++; else if (write_to_w_string(dst, dstlen, &dest_index, 0)) return -1; + /* when srclen=-1, terminate at the first null character found */ + break; + } + else if (src[source_index] == '+') + { + WCHAR byte_pair = 0; + short offset = 0; + + source_index++; /* skip the + sign */ + + if (src[source_index] == '-') + { + /* just a plus sign escaped as +- */ + if (dry_run) dest_index++; else if (write_to_w_string(dst, dstlen, &dest_index, '+')) return -1; + source_index++; + continue; + } + + for (;;) + { + WCHAR sextet = src[source_index]; + if (sextet == '-') + { + /* skip over the - and signal end of base64 decoding */ + source_index++; + sextet = -1; + } + else if (sextet <= 'z') + { + sextet = base64_decoding_table[sextet]; + } + else + { + sextet = -1; + } + + if (sextet == (WCHAR)-1) + { + /* -1 means that the next character of src is not part of a base64 sequence */ + /* in other words, all sextets in this base64 sequence have been processed */ + /* the current, unfinished byte pair is discarded */ + break; + } + + if (offset > 0) + { + byte_pair |= (sextet << 10) >> offset; + } + else + { + byte_pair |= sextet << (10 - offset); + } + offset += 6; + if (offset > 15) + { + /* this byte pair is done */ + if (dry_run) dest_index++; else if (write_to_w_string(dst, dstlen, &dest_index, byte_pair)) return -1; + byte_pair = 0; + /* back up the offset to begin writing to the next byte pair, + including writing any part of the current sextet that didn't fit in the last byte pair */ + offset -= 22; + } + else + { + /* this sextet is done */ + source_index++; + } + } + } + else + { + if (dry_run) dest_index++; else if (write_to_w_string(dst, dstlen, &dest_index, src[source_index])) return -1; + source_index++; + } + } while (srclen == -1 || source_index < srclen); + + return dest_index; +} + +/*********************************************************************** * MultiByteToWideChar (KERNEL32.@) * * Convert a multibyte character string into a Unicode string. @@ -1878,7 +2124,7 @@ BOOL WINAPI EnumSystemCodePagesW( CODEPAGE_ENUMPROCW lpfnCodePageEnum, DWORD fla * flags [I] Character mapping flags * src [I] Source string buffer * srclen [I] Length of src (in bytes), or -1 if src is NUL terminated - * dst [O] Destination buffer + * dst [O] Destination buffer, or NULL to compute the required length * dstlen [I] Length of dst (in WCHARs), or 0 to compute the required length * * RETURNS @@ -1921,9 +2167,8 @@ INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen, SetLastError( ERROR_INVALID_FLAGS ); return 0; } - FIXME("UTF-7 not supported\n"); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return 0; + ret = utf7_mbstowcs( src, srclen, dst, dstlen ); + break; case CP_UNIXCP: if (unix_cptable) { @@ -1963,6 +2208,270 @@ INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen, /*********************************************************************** + * can_directly_encode + * + * Helper for utf7_wcstombs + */ +static BOOL utf7_can_directly_encode(WCHAR codepoint) +{ + static const BOOL directly_encodable_ascii[] = { + /* \0 */ TRUE, /* special case */ + /* \x01 */ FALSE, + /* \x02 */ FALSE, + /* \x03 */ FALSE, + /* \x04 */ FALSE, + /* \x05 */ FALSE, + /* \x06 */ FALSE, + /* \a */ FALSE, + /* \b */ FALSE, + /* \t */ TRUE, + /* \n */ TRUE, + /* \v */ FALSE, + /* \f */ FALSE, + /* \r */ TRUE, + /* \x0E */ FALSE, + /* \x0F */ FALSE, + /* \x10 */ FALSE, + /* \x11 */ FALSE, + /* \x12 */ FALSE, + /* \x13 */ FALSE, + /* \x14 */ FALSE, + /* \x15 */ FALSE, + /* \x16 */ FALSE, + /* \x17 */ FALSE, + /* \x18 */ FALSE, + /* \x19 */ FALSE, + /* \x1A */ FALSE, + /* \e */ FALSE, + /* \x1C */ FALSE, + /* \x1D */ FALSE, + /* \x1E */ FALSE, + /* \x1F */ FALSE, + /* */ TRUE, + /* ! */ FALSE, + /* " */ FALSE, + /* # */ FALSE, + /* $ */ FALSE, + /* % */ FALSE, + /* & */ FALSE, + /* ' */ TRUE, + /* ( */ TRUE, + /* ) */ TRUE, + /* * */ FALSE, + /* + */ TRUE, /* special case */ + /* , */ TRUE, + /* - */ TRUE, + /* . */ TRUE, + /* / */ TRUE, + /* 0 */ TRUE, + /* 1 */ TRUE, + /* 2 */ TRUE, + /* 3 */ TRUE, + /* 4 */ TRUE, + /* 5 */ TRUE, + /* 6 */ TRUE, + /* 7 */ TRUE, + /* 8 */ TRUE, + /* 9 */ TRUE, + /* : */ TRUE, + /* ; */ FALSE, + /* < */ FALSE, + /* = */ FALSE, + /* > */ FALSE, + /* ? */ TRUE, + /* @ */ FALSE, + /* A */ TRUE, + /* B */ TRUE, + /* C */ TRUE, + /* D */ TRUE, + /* E */ TRUE, + /* F */ TRUE, + /* G */ TRUE, + /* H */ TRUE, + /* I */ TRUE, + /* J */ TRUE, + /* K */ TRUE, + /* L */ TRUE, + /* M */ TRUE, + /* N */ TRUE, + /* O */ TRUE, + /* P */ TRUE, + /* Q */ TRUE, + /* R */ TRUE, + /* S */ TRUE, + /* T */ TRUE, + /* U */ TRUE, + /* V */ TRUE, + /* W */ TRUE, + /* X */ TRUE, + /* Y */ TRUE, + /* Z */ TRUE, + /* [ */ FALSE, + /* \ */ FALSE, + /* ] */ FALSE, + /* ^ */ FALSE, + /* _ */ FALSE, + /* ` */ FALSE, + /* a */ TRUE, + /* b */ TRUE, + /* c */ TRUE, + /* d */ TRUE, + /* e */ TRUE, + /* f */ TRUE, + /* g */ TRUE, + /* h */ TRUE, + /* i */ TRUE, + /* j */ TRUE, + /* k */ TRUE, + /* l */ TRUE, + /* m */ TRUE, + /* n */ TRUE, + /* o */ TRUE, + /* p */ TRUE, + /* q */ TRUE, + /* r */ TRUE, + /* s */ TRUE, + /* t */ TRUE, + /* u */ TRUE, + /* v */ TRUE, + /* w */ TRUE, + /* x */ TRUE, + /* y */ TRUE, + /* z */ TRUE, + /* { */ FALSE, + /* | */ FALSE, + /* } */ FALSE, + /* ~ */ FALSE + }; + + if (codepoint <= '~') + { + return directly_encodable_ascii[codepoint]; + } + else + { + return FALSE; + } +} + +/*********************************************************************** + * write_to_c_string + * + * Helper for utf7_wcstombs + * + * RETURNS + * 0 on success, -1 on error + */ +static int write_to_c_string(char* dst, int dstlen, int* index, char character) +{ + if (*index >= dstlen) + { + return -1; + } + + dst[*index] = character; + (*index)++; + return 0; +} + +/*********************************************************************** + * utf7_wcstombs + * + * UTF-16 to UTF-7 string conversion, helper for WideCharToMultiByte + * + * RETURNS + * On success, the number of characters written + * On dst buffer overflow, -1 + * On invalid input char, -2 + */ +static int utf7_wcstombs(const WCHAR* src, int srclen, char* dst, int dstlen) +{ + static const char base64_encoding_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + BOOL dry_run = !dst || !dstlen; + int source_index = 0; + int dest_index = 0; + + do + { + if (src[source_index] == 0 && srclen == -1) + { + /* when srclen=-1, terminate at the first null character found */ + if (dry_run) dest_index++; else if (write_to_c_string(dst, dstlen, &dest_index, 0)) return -1; + break; + } + else if (src[source_index] == '+') + { + if (dry_run) + { + dest_index += 2; + } + else + { + if (write_to_c_string(dst, dstlen, &dest_index, '+')) return -1; + if (write_to_c_string(dst, dstlen, &dest_index, '-')) return -1; + } + source_index++; + } + else if (utf7_can_directly_encode(src[source_index])) + { + if (dry_run) dest_index++; else if (write_to_c_string(dst, dstlen, &dest_index, src[source_index])) return -1; + source_index++; + } + else + { + unsigned int offset; + WCHAR char1; + WCHAR char2; + + offset = 16; + char2 = src[source_index]; + source_index++; + + if (dry_run) dest_index++; else if (write_to_c_string(dst, dstlen, &dest_index, '+')) return -1; + + for (;;) + { + unsigned int chars_back_to_back; + + if (offset > 15) + { + if (char2 == 0) + { + /* signal to end; the next character of src is directly encodable */ + break; + } + char1 = char2; + if (utf7_can_directly_encode(src[source_index])) + { + /* do not include the next character of src in the base64 sequence */ + /* pad the bits of the last character to be encoded with zeroes if needed */ + char2 = 0; + } + else + { + /* claim the next character for inclusion in the base64 sequence */ + char2 = src[source_index]; + source_index++; + } + offset -= 16; + } + + chars_back_to_back = ((unsigned int)char1 << 16) | (unsigned int)char2; + if (dry_run) dest_index++; else if (write_to_c_string(dst, dstlen, &dest_index, base64_encoding_table[(chars_back_to_back << offset) >> 26])) return -1; + offset += 6; + } + + /* Windows always explicitly terminates the base64 sequence even though RFC 2152 (page 3, rule 2) does not require this */ + if (dry_run) dest_index++; else if (write_to_c_string(dst, dstlen, &dest_index, '-')) return -1; + } + } + while (srclen == -1 || source_index < srclen); + + return dest_index; +} + +/*********************************************************************** * WideCharToMultiByte (KERNEL32.@) * * Convert a Unicode character string into a multibyte string. @@ -1972,7 +2481,7 @@ INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen, * flags [I] Mapping Flags (MB_ constants from "winnls.h"). * src [I] Source string buffer * srclen [I] Length of src (in WCHARs), or -1 if src is NUL terminated - * dst [O] Destination buffer + * dst [O] Destination buffer, or NULL to compute the required length * dstlen [I] Length of dst (in bytes), or 0 to compute the required length * defchar [I] Default character to use for conversion if no exact * conversion can be made @@ -2029,9 +2538,8 @@ INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen, SetLastError( ERROR_INVALID_FLAGS ); return 0; } - FIXME("UTF-7 not supported\n"); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return 0; + ret = utf7_wcstombs( src, srclen, dst, dstlen ); + break; case CP_UNIXCP: if (unix_cptable) { diff --git a/dlls/kernel32/tests/codepage.c b/dlls/kernel32/tests/codepage.c index c980348..248913d 100644 --- a/dlls/kernel32/tests/codepage.c +++ b/dlls/kernel32/tests/codepage.c @@ -412,6 +412,130 @@ static void test_string_conversion(LPBOOL bUsedDefaultChar) ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); } +static void test_utf7_string_conversion(void) +{ + /* tests which ASCII characters are base64-encoded and which are not */ + WCHAR example_0_utf16[] = {'\t',' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.', + '/','0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?', + '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','`','a', + 'b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r', + 's','t','u','v','w','x','y','z','{','|','}','~',0}; + int example_0_utf16_len = sizeof(example_0_utf16) / sizeof(WCHAR); + char example_0_utf7[] = "\t +ACEAIgAjACQAJQAm-'()+ACo-+-,-./0123456789:+ADsAPAA9AD4-?+AEA-ABCDEFGHIJKLMNOPQRSTUVWXYZ+AFsAXABdAF4AXwBg-abcdefghijklmnopqrstuvwxyz+AHsAfAB9AH4-"; + int example_0_utf7_len = sizeof(example_0_utf7); + + /* this string is the Unicode for "5 + (++x) " + it tests: + - a + before a non-base64 character + - a + between two non-directly-encodable characters + - a + before a base64 character */ + WCHAR example_1_utf16[] = {'5',' ','+',' ','(',0x0391,'+',0x0392,'+','x',')',' ',0x2260,' ',0x0391,0x0392,0}; + int example_1_utf16_len = sizeof(example_1_utf16) / sizeof(WCHAR); + char example_1_utf7[] = "5 +- (+A5E-+-+A5I-+-x) +ImA- +A5EDkg-"; + int example_1_utf7_len = sizeof(example_1_utf7); + + /* tests a null char before the end of the buffer */ + WCHAR example_2_utf16[] = {'a',0,'b',0}; + int example_2_utf16_len = sizeof(example_2_utf16) / sizeof(WCHAR); + char example_2_utf7[] = "a\0b"; + int example_2_utf7_len = sizeof(example_2_utf7); + + /* tests some invalid UTF-7 */ + /* (number of bits in base64 sequence is not a multiple of 16 and the last bit is a 1) */ + char example_3_utf7[] = "+T2B-hello"; + WCHAR example_3_utf16[] = {0x4F60,'h','e','l','l','o',0}; + int example_3_utf16_len = sizeof(example_3_utf16) / sizeof(WCHAR); + + /* tests some more invalid UTF-7 */ + /* (number of bits in base64 sequence is a multiple of 8 but not a multiple of 16) */ + char example_4_utf7[] = "+T2BZ-hello"; + WCHAR example_4_utf16[] = {0x4F60,'h','e','l','l','o',0}; + int example_4_utf16_len = sizeof(example_3_utf16) / sizeof(WCHAR); + + /* tests a buffer that is too small */ + WCHAR example_5_utf16[] = {'h','e','l','l','o',0}; + char example_5_utf7[] = "he"; + + /* tests another buffer that is too small */ + char example_6_utf7[] = "hello"; + WCHAR example_6_utf16[] = {'h','e',0}; + + /* tests a buffer that runs out in the middle of encoding a UTF-7 sequence */ + WCHAR example_7_utf16[] = {0x4F60,0x597D,0}; + char example_7_utf7[] = "+T"; + + /* tests a buffer that runs out in the middle of decoding a UTF-7 sequence */ + char example_8_utf7[] = "+T2BZfQ-"; + WCHAR example_8_utf16[] = {0x4F60, 0}; + + char c_buffer[256] = {0}; + WCHAR w_buffer[256] = {0}; + int len; + + + len = WideCharToMultiByte(CP_UTF7, 0, example_0_utf16, -1, c_buffer, 256, NULL, NULL); + ok(len == example_0_utf7_len && strcmp(c_buffer, example_0_utf7) == 0, "len=%i dst=\"%s\"\n", len, c_buffer); + + len = MultiByteToWideChar(CP_UTF7, 0, example_0_utf7, -1, w_buffer, 256); + ok(len == example_0_utf16_len && winetest_strcmpW(w_buffer, example_0_utf16) == 0, "len=%i dst=%s\n", len, wine_dbgstr_w(w_buffer)); + + /* 4 more tests to just compute the required length */ + len = WideCharToMultiByte(CP_UTF7, 0, example_0_utf16, -1, NULL, 0, NULL, NULL); + ok(len == example_0_utf7_len, "len=%i\n", len); + + len = WideCharToMultiByte(CP_UTF7, 0, example_0_utf16, -1, c_buffer, 0, NULL, NULL); + ok(len == example_0_utf7_len, "len=%i\n", len); + + len = MultiByteToWideChar(CP_UTF7, 0, example_0_utf7, -1, NULL, 0); + ok(len == example_0_utf16_len, "len=%i\n", len); + + len = MultiByteToWideChar(CP_UTF7, 0, example_0_utf7, -1, w_buffer, 0); + ok(len == example_0_utf16_len, "len=%i\n", len); + + + len = WideCharToMultiByte(CP_UTF7, 0, example_1_utf16, -1, c_buffer, 256, NULL, NULL); + ok(len == example_1_utf7_len && strcmp(c_buffer, example_1_utf7) == 0, "len=%i dst=\"%s\"\n", len, c_buffer); + + len = MultiByteToWideChar(CP_UTF7, 0, example_1_utf7, -1, w_buffer, 256); + ok(len == example_1_utf16_len && winetest_strcmpW(w_buffer, example_1_utf16) == 0, "len=%i dst=%s\n", len, wine_dbgstr_w(w_buffer)); + + + len = WideCharToMultiByte(CP_UTF7, 0, example_2_utf16, example_2_utf16_len, c_buffer, 256, NULL, NULL); + ok(len == example_2_utf7_len && strcmp(c_buffer, example_2_utf7) == 0, "len=%i dst=\"%s\"\n", len, c_buffer); + + len = MultiByteToWideChar(CP_UTF7, 0, example_2_utf7, example_2_utf7_len, w_buffer, 256); + ok(len == example_2_utf16_len && winetest_strcmpW(w_buffer, example_2_utf16) == 0, "len=%i dst=%s\n", len, wine_dbgstr_w(w_buffer)); + + + len = MultiByteToWideChar(CP_UTF7, 0, example_3_utf7, -1, w_buffer, 256); + ok(len == example_3_utf16_len && winetest_strcmpW(w_buffer, example_3_utf16) == 0, "len=%i dst=%s\n", len, wine_dbgstr_w(w_buffer)); + + + len = MultiByteToWideChar(CP_UTF7, 0, example_4_utf7, -1, w_buffer, 256); + ok(len == example_4_utf16_len && winetest_strcmpW(w_buffer, example_4_utf16) == 0, "len=%i dst=%s\n", len, wine_dbgstr_w(w_buffer)); + + + memset(c_buffer, 0, sizeof(c_buffer)); + len = WideCharToMultiByte(CP_UTF7, 0, example_5_utf16, -1, c_buffer, 2, NULL, NULL); + ok(len == 0 && strcmp(c_buffer, example_5_utf7) == 0, "len=%i dst=\"%s\"\n", len, c_buffer); + + + memset(w_buffer, 0, sizeof(w_buffer)); + len = MultiByteToWideChar(CP_UTF7, 0, example_6_utf7, -1, w_buffer, 2); + ok(len == 0 && winetest_strcmpW(w_buffer, example_6_utf16) == 0, "len=%i dst=%s\n", len, wine_dbgstr_w(w_buffer)); + + + memset(c_buffer, 0, sizeof(c_buffer)); + len = WideCharToMultiByte(CP_UTF7, 0, example_7_utf16, -1, c_buffer, 2, NULL, NULL); + ok(len == 0 && strcmp(c_buffer, example_7_utf7) == 0, "len=%i dst=\"%s\"\n", len, c_buffer); + + + memset(w_buffer, 0, sizeof(w_buffer)); + len = MultiByteToWideChar(CP_UTF7, 0, example_8_utf7, -1, w_buffer, 1); + ok(len == 0 && winetest_strcmpW(w_buffer, example_8_utf16) == 0, "len=%i dst=%s\n", len, wine_dbgstr_w(w_buffer)); +} + static void test_undefined_byte_char(void) { static const struct tag_testset { @@ -477,5 +601,7 @@ START_TEST(codepage) test_string_conversion(NULL); test_string_conversion(&bUsedDefaultChar); + test_utf7_string_conversion(); + test_undefined_byte_char(); } -- 1.7.9.5