Stefan Dösinger : msvcrt: Implement _mbsnbcpy_s.

Alexandre Julliard julliard at winehq.org
Fri Nov 16 08:31:24 CST 2007


Module: wine
Branch: master
Commit: a529ef4875d958cb598ba2ca7b935cfe2ffc0cc8
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=a529ef4875d958cb598ba2ca7b935cfe2ffc0cc8

Author: Stefan Dösinger <stefan at codeweavers.com>
Date:   Thu Nov 15 16:32:33 2007 +0100

msvcrt: Implement _mbsnbcpy_s.

---

 dlls/msvcrt/mbcs.c         |   66 ++++++++++++++++++++++++++++++++++++++++++++
 dlls/msvcrt/msvcrt.spec    |    1 +
 dlls/msvcrt/tests/string.c |   50 +++++++++++++++++++++++++++++++++
 3 files changed, 117 insertions(+), 0 deletions(-)

diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c
index cc619e5..14a962a 100644
--- a/dlls/msvcrt/mbcs.c
+++ b/dlls/msvcrt/mbcs.c
@@ -27,6 +27,7 @@
 #include "wine/unicode.h"
 #include "wine/debug.h"
 #include "msvcrt/mbctype.h"
+#include "msvcrt/errno.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
 
@@ -443,6 +444,71 @@ unsigned char* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, MSVC
 }
 
 /*********************************************************************
+ *              _mbsnbcpy_s(MSVCRT.@)
+ * REMARKS
+ * Unlike _mbsnbcpy this function does not pad the rest of the dest
+ * string with 0
+ */
+int CDECL _mbsnbcpy_s(unsigned char* dst, MSVCRT_size_t size, const unsigned char* src, MSVCRT_size_t n)
+{
+    MSVCRT_size_t pos = 0;
+
+    if(!dst || size == 0)
+        return EINVAL;
+    if(!src)
+    {
+        dst[0] = '\0';
+        return EINVAL;
+    }
+    if(!n)
+        return 0;
+
+    if(g_mbcp_is_multibyte)
+    {
+        int is_lead = 0;
+        while (*src && n)
+        {
+            if(pos == size)
+            {
+                dst[0] = '\0';
+                return ERANGE;
+            }
+            is_lead = (!is_lead && _ismbblead(*src));
+            n--;
+            dst[pos++] = *src++;
+        }
+
+        if (is_lead) /* if string ends with a lead, remove it */
+            dst[pos - 1] = 0;
+    }
+    else
+    {
+        while (n)
+        {
+            n--;
+            if(pos == size)
+            {
+                dst[0] = '\0';
+                return ERANGE;
+            }
+
+            if(!(*src)) break;
+            dst[pos++] = *src++;
+        }
+    }
+
+    if(pos < size)
+        dst[pos] = '\0';
+    else
+    {
+        dst[0] = '\0';
+        return ERANGE;
+    }
+
+    return 0;
+}
+
+/*********************************************************************
  *              _mbsnbcpy(MSVCRT.@)
  * REMARKS
  *  Like strncpy this function doesn't enforce the string to be
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec
index 567f193..568dcc2 100644
--- a/dlls/msvcrt/msvcrt.spec
+++ b/dlls/msvcrt/msvcrt.spec
@@ -375,6 +375,7 @@
 @ cdecl _mbsnbcnt(ptr long)
 @ stub _mbsnbcoll #(str str long)
 @ cdecl _mbsnbcpy(ptr str long)
+@ cdecl _mbsnbcpy_s(ptr long str long)
 @ cdecl _mbsnbicmp(str str long)
 @ stub _mbsnbicoll #(str str long)
 @ cdecl _mbsnbset(str long long)
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c
index 9e96605..c6dcd34 100644
--- a/dlls/msvcrt/tests/string.c
+++ b/dlls/msvcrt/tests/string.c
@@ -49,6 +49,7 @@ static void* (*pmemcpy)(void *, const void *, size_t n);
 static int* (*pmemcmp)(void *, const void *, size_t n);
 static int (*pstrcpy_s)(char *dst, size_t len, const char *src);
 static int (*pstrcat_s)(char *dst, size_t len, const char *src);
+static int (*p_mbsnbcpy_s)(unsigned char * dst, size_t size, const unsigned char * src, size_t count);
 
 #define SETNOFAIL(x,y) x = (void*)GetProcAddress(hMsvcrt,y)
 #define SET(x,y) SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y)
@@ -514,6 +515,53 @@ static void test_strcat_s(void)
     ok(ret == EINVAL, "strcat_s: Writing to a NULL string returned %d, expected EINVAL\n", ret);
 }
 
+static void test__mbsnbcpy_s(void)
+{
+    unsigned char dest[8];
+    const unsigned char big[] = "atoolongstringforthislittledestination";
+    const unsigned char small[] = "small";
+    int ret;
+
+    if(!p_mbsnbcpy_s)
+    {
+        skip("_mbsnbcpy_s not found\n");
+        return;
+    }
+
+    memset(dest, 'X', sizeof(dest));
+    ret = p_mbsnbcpy_s(dest, sizeof(dest), small, sizeof(small));
+    ok(ret == 0, "_mbsnbcpy_s: Copying a string into a big enough destination returned %d, expected 0\n", ret);
+    ok(dest[0] == 's' && dest[1] == 'm' && dest[2] == 'a' && dest[3] == 'l' &&
+       dest[4] == 'l' && dest[5] == '\0'&& dest[6] == 'X' && dest[7] == 'X',
+       "Unexpected return data from _mbsnbcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+       dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
+
+    /* WTF? */
+    memset(dest, 'X', sizeof(dest));
+    ret = p_mbsnbcpy_s(dest, sizeof(dest) - 2, big, sizeof(small));
+    ok(ret == ERANGE, "_mbsnbcpy_s: Copying a too long string returned %d, expected ERANGE\n", ret);
+    ok(dest[0] == '\0'&& dest[1] == 't' && dest[2] == 'o' && dest[3] == 'o' &&
+       dest[4] == 'l' && dest[5] == 'o' && dest[6] == 'X' && dest[7] == 'X',
+       "Unexpected return data from _mbsnbcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+       dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
+
+    memset(dest, 'X', sizeof(dest));
+    ret = p_mbsnbcpy_s(dest, sizeof(dest) - 2, big, 4);
+    ok(ret == 0, "_mbsnbcpy_s: Copying a too long string with a count cap returned %d, expected 0\n", ret);
+    ok(dest[0] == 'a' && dest[1] == 't' && dest[2] == 'o' && dest[3] == 'o' &&
+       dest[4] == '\0'&& dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X',
+       "Unexpected return data from _mbsnbcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+       dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
+
+    memset(dest, 'X', sizeof(dest));
+    ret = p_mbsnbcpy_s(dest, sizeof(dest) - 2, small, sizeof(small) + 10);
+    ok(ret == 0, "_mbsnbcpy_s: Copying more data than the source string len returned %d, expected 0\n", ret);
+    ok(dest[0] == 's' && dest[1] == 'm' && dest[2] == 'a' && dest[3] == 'l' &&
+       dest[4] == 'l' && dest[5] == '\0'&& dest[6] == 'X' && dest[7] == 'X',
+       "Unexpected return data from _mbsnbcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+       dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
+}
+
 START_TEST(string)
 {
     char mem[100];
@@ -528,6 +576,7 @@ START_TEST(string)
     SET(pmemcmp,"memcmp");
     SET(pstrcpy_s,"strcpy_s");
     SET(pstrcat_s,"strcat_s");
+    SET(p_mbsnbcpy_s,"_mbsnbcpy_s");
 
     /* MSVCRT memcpy behaves like memmove for overlapping moves,
        MFC42 CString::Insert seems to rely on that behaviour */
@@ -549,4 +598,5 @@ START_TEST(string)
     test_strdup();
     test_strcpy_s();
     test_strcat_s();
+    test__mbsnbcpy_s();
 }




More information about the wine-cvs mailing list