Commit a529ef48 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

msvcrt: Implement _mbsnbcpy_s.

parent 9582f5c7
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "wine/unicode.h" #include "wine/unicode.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "msvcrt/mbctype.h" #include "msvcrt/mbctype.h"
#include "msvcrt/errno.h"
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
...@@ -443,6 +444,71 @@ unsigned char* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, MSVC ...@@ -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.@) * _mbsnbcpy(MSVCRT.@)
* REMARKS * REMARKS
* Like strncpy this function doesn't enforce the string to be * Like strncpy this function doesn't enforce the string to be
......
...@@ -375,6 +375,7 @@ ...@@ -375,6 +375,7 @@
@ cdecl _mbsnbcnt(ptr long) @ cdecl _mbsnbcnt(ptr long)
@ stub _mbsnbcoll #(str str long) @ stub _mbsnbcoll #(str str long)
@ cdecl _mbsnbcpy(ptr str long) @ cdecl _mbsnbcpy(ptr str long)
@ cdecl _mbsnbcpy_s(ptr long str long)
@ cdecl _mbsnbicmp(str str long) @ cdecl _mbsnbicmp(str str long)
@ stub _mbsnbicoll #(str str long) @ stub _mbsnbicoll #(str str long)
@ cdecl _mbsnbset(str long long) @ cdecl _mbsnbset(str long long)
......
...@@ -49,6 +49,7 @@ static void* (*pmemcpy)(void *, const void *, size_t n); ...@@ -49,6 +49,7 @@ static void* (*pmemcpy)(void *, const void *, size_t n);
static int* (*pmemcmp)(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 (*pstrcpy_s)(char *dst, size_t len, const char *src);
static int (*pstrcat_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 SETNOFAIL(x,y) x = (void*)GetProcAddress(hMsvcrt,y)
#define SET(x,y) SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", 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) ...@@ -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); 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) START_TEST(string)
{ {
char mem[100]; char mem[100];
...@@ -528,6 +576,7 @@ START_TEST(string) ...@@ -528,6 +576,7 @@ START_TEST(string)
SET(pmemcmp,"memcmp"); SET(pmemcmp,"memcmp");
SET(pstrcpy_s,"strcpy_s"); SET(pstrcpy_s,"strcpy_s");
SET(pstrcat_s,"strcat_s"); SET(pstrcat_s,"strcat_s");
SET(p_mbsnbcpy_s,"_mbsnbcpy_s");
/* MSVCRT memcpy behaves like memmove for overlapping moves, /* MSVCRT memcpy behaves like memmove for overlapping moves,
MFC42 CString::Insert seems to rely on that behaviour */ MFC42 CString::Insert seems to rely on that behaviour */
...@@ -549,4 +598,5 @@ START_TEST(string) ...@@ -549,4 +598,5 @@ START_TEST(string)
test_strdup(); test_strdup();
test_strcpy_s(); test_strcpy_s();
test_strcat_s(); test_strcat_s();
test__mbsnbcpy_s();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment