kernel32: Add UTF-7 support. (try 2)

Alex Henrie alexhenrie24 at gmail.com
Mon Jul 30 00:38:45 CDT 2012


Fixes bug 27388.

As requested, try 2 puts everything in kernel32, does not use malloc,
and has more tests. The new tests exposed a couple of mistakes which
are now fixed.

---
 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..3047eeb 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 + (<ALPHA>+<BETA>+x) <NOT EQUAL TO> <ALPHA><BETA>"
+       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 a 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, 0x597D, 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, 2);
+    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



More information about the wine-patches mailing list