From a529ef4875d958cb598ba2ca7b935cfe2ffc0cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Thu, 15 Nov 2007 16:32:33 +0100 Subject: [PATCH] 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(+) diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c index cc619e5968a..14a962ace60 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); @@ -442,6 +443,71 @@ unsigned char* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, MSVC return ret; } +/********************************************************************* + * _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 diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 567f19339a4..568dcc20c96 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 9e966050fc9..c6dcd3429be 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(); }