kernel32: Correct WideCharToMultiByte and MultiByteToWideChar error codes and conditions (try 2)

Alex Henrie alexhenrie24 at gmail.com
Thu May 10 00:43:52 CDT 2012


Refactored the new tests a little, partly in response to feedback on wine-devel.

---
 dlls/kernel32/locale.c       |   38 ++++++++++++++---
 dlls/kernel32/tests/locale.c |   94 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+), 6 deletions(-)

diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index b506f15..b73f9b3 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -1878,7 +1878,7 @@ INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen,
     const union cptable *table;
     int ret;
 
-    if (!src || (!dst && dstlen))
+    if (!src || !srclen || (!dst && dstlen))
     {
         SetLastError( ERROR_INVALID_PARAMETER );
         return 0;
@@ -1889,14 +1889,19 @@ INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen,
     switch(page)
     {
     case CP_SYMBOL:
-        if( flags)
+        if (flags)
         {
-            SetLastError( ERROR_INVALID_PARAMETER );
+            SetLastError( ERROR_INVALID_FLAGS );
             return 0;
         }
         ret = wine_cpsymbol_mbstowcs( src, srclen, dst, dstlen );
         break;
     case CP_UTF7:
+        if (flags)
+        {
+            SetLastError( ERROR_INVALID_FLAGS );
+            return 0;
+        }
         FIXME("UTF-7 not supported\n");
         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
         return 0;
@@ -1969,7 +1974,7 @@ INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen,
     const union cptable *table;
     int ret, used_tmp;
 
-    if (!src || (!dst && dstlen))
+    if (!src || !srclen || (!dst && dstlen))
     {
         SetLastError( ERROR_INVALID_PARAMETER );
         return 0;
@@ -1980,7 +1985,13 @@ INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen,
     switch(page)
     {
     case CP_SYMBOL:
-        if( flags || defchar || used)
+        /* when using CP_SYMBOL, ERROR_INVALID_FLAGS takes precedence */
+        if (flags)
+        {
+            SetLastError( ERROR_INVALID_FLAGS );
+            return 0;
+        }
+        if (defchar || used)
         {
             SetLastError( ERROR_INVALID_PARAMETER );
             return 0;
@@ -1988,6 +1999,17 @@ INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen,
         ret = wine_cpsymbol_wcstombs( src, srclen, dst, dstlen );
         break;
     case CP_UTF7:
+        /* when using CP_UTF7, ERROR_INVALID_PARAMETER takes precedence */
+        if (defchar || used)
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return 0;
+        }
+        if (flags)
+        {
+            SetLastError( ERROR_INVALID_FLAGS );
+            return 0;
+        }
         FIXME("UTF-7 not supported\n");
         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
         return 0;
@@ -2000,7 +2022,11 @@ INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen,
         }
         /* fall through */
     case CP_UTF8:
-        if (used) *used = FALSE;  /* all chars are valid for UTF-8 */
+        if (defchar || used)
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return 0;
+        }
         ret = wine_utf8_wcstombs( flags, src, srclen, dst, dstlen );
         break;
     default:
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index 3216ef9..9cbb124 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -3137,6 +3137,99 @@ static void test_IdnToUnicode(void)
     }
 }
 
+static void test_WideCharToMultiByte_error(UINT page, DWORD flags, LPCWSTR src,
+                                           INT srclen, LPSTR dst, INT dstlen,
+                                           LPCSTR defchar, BOOL* used,
+                                           const char* test_description,
+                                           DWORD expected_error)
+{
+    SetLastError(ERROR_SUCCESS);
+    WideCharToMultiByte(page, flags, src, srclen, dst, dstlen, defchar, used);
+    ok(GetLastError() == expected_error,
+       "codepage %i, %s, expected error %i got error %i\n", page,
+       test_description, expected_error, GetLastError());
+}
+
+static void test_MultiByteToWideChar_error(UINT page, DWORD flags, LPCSTR src,
+                                           INT srclen, LPWSTR dst, INT dstlen,
+                                           const char* test_description,
+                                           DWORD expected_error)
+{
+    SetLastError(ERROR_SUCCESS);
+    MultiByteToWideChar(page, flags, src, srclen, dst, dstlen);
+    ok(GetLastError() == expected_error,
+       "codepage %i, %s, expected error %i got error %i\n", page,
+       test_description, expected_error, GetLastError());
+}
+
+static void test_WideCharToMultiByte_MultiByteToWideChar(void)
+{
+    char c_string[] = "Hello World";
+    WCHAR w_string[] = {'H','e','l','l','o',' ','W','o','r','l','d',0};
+    BOOL used;
+    
+    /* srclen=0 => ERROR_INVALID_PARAMETER */
+    test_WideCharToMultiByte_error(CP_ACP, 0, w_string, 0, c_string,
+                                   sizeof(c_string), NULL, NULL,
+                                   "srclen=0", ERROR_INVALID_PARAMETER);
+    test_MultiByteToWideChar_error(CP_ACP, 0, c_string, 0, w_string,
+                                   sizeof(w_string)/sizeof(WCHAR),
+                                   "srclen=0", ERROR_INVALID_PARAMETER);
+    
+    /* dst=NULL but dstlen not 0 => ERROR_INVALID_PARAMETER */
+    test_WideCharToMultiByte_error(CP_ACP, 0, w_string,
+                                   sizeof(w_string)/sizeof(WCHAR), NULL,
+                                   sizeof(c_string), NULL, NULL,
+                                   "dst=NULL but dstlen not 0",
+                                   ERROR_INVALID_PARAMETER);
+    test_MultiByteToWideChar_error(CP_ACP, 0, c_string, sizeof(c_string),
+                                   NULL, sizeof(w_string)/sizeof(WCHAR),
+                                   "dst=NULL but dstlen not 0",
+                                   ERROR_INVALID_PARAMETER);
+
+    /* CP_UTF7, CP_UTF8, or CP_SYMBOL and defchar not NULL
+       => ERROR_INVALID_PARAMETER */
+    /* CP_SYMBOL's behavior here is undocumented */
+    test_WideCharToMultiByte_error(CP_UTF7, 0, w_string,
+                                   sizeof(w_string)/sizeof(WCHAR), c_string,
+                                   sizeof(c_string), c_string, NULL,
+                                   "defchar not NULL", ERROR_INVALID_PARAMETER);
+    test_WideCharToMultiByte_error(CP_UTF8, 0, w_string,
+                                   sizeof(w_string)/sizeof(WCHAR), c_string,
+                                   sizeof(c_string), c_string, NULL,
+                                   "defchar not NULL", ERROR_INVALID_PARAMETER);
+    test_WideCharToMultiByte_error(CP_SYMBOL, 0, w_string,
+                                   sizeof(w_string)/sizeof(WCHAR), c_string,
+                                   sizeof(c_string), c_string, NULL,
+                                   "defchar not NULL", ERROR_INVALID_PARAMETER);
+    
+    /* CP_UTF7, CP_UTF8, or CP_SYMBOL and used not NULL
+       => ERROR_INVALID_PARAMETER */
+    /* CP_SYMBOL's behavior here is undocumented */
+    test_WideCharToMultiByte_error(CP_UTF7, 0, w_string,
+                                   sizeof(w_string)/sizeof(WCHAR), c_string,
+                                   sizeof(c_string), NULL, &used,
+                                   "used not NULL", ERROR_INVALID_PARAMETER);
+    test_WideCharToMultiByte_error(CP_UTF8, 0, w_string,
+                                   sizeof(w_string)/sizeof(WCHAR), c_string,
+                                   sizeof(c_string), NULL, &used,
+                                   "used not NULL", ERROR_INVALID_PARAMETER);
+    test_WideCharToMultiByte_error(CP_SYMBOL, 0, w_string,
+                                   sizeof(w_string)/sizeof(WCHAR), c_string,
+                                   sizeof(c_string), NULL, &used,
+                                   "used not NULL", ERROR_INVALID_PARAMETER);
+    
+    /* CP_UTF7, flags not 0 and used not NULL => ERROR_INVALID_PARAMETER */
+    /* (tests precedence of ERROR_INVALID_PARAMETER over ERROR_INVALID_FLAGS) */
+    /* The same test with CP_SYMBOL instead of CP_UTF7 gives
+       ERROR_INVALID_FLAGS instead except on Windows NT4 */
+    test_WideCharToMultiByte_error(CP_UTF7, 1, w_string,
+                                   sizeof(w_string)/sizeof(WCHAR), c_string,
+                                   sizeof(c_string), NULL, &used,
+                                   "flags not 0 and used not NULL",
+                                   ERROR_INVALID_PARAMETER);
+}
+
 START_TEST(locale)
 {
   InitFunctionPointers();
@@ -3169,4 +3262,5 @@ START_TEST(locale)
   test_IdnToUnicode();
   /* this requires collation table patch to make it MS compatible */
   if (0) test_sorting();
+  test_WideCharToMultiByte_MultiByteToWideChar();
 }
-- 
1.7.5.4



More information about the wine-patches mailing list