From a622af49a7cda0c35d6f45ab68922fa93e0331e0 Mon Sep 17 00:00:00 2001 From: Andrew Nguyen Date: Thu, 21 Oct 2010 02:55:43 -0500 Subject: [PATCH] msvcrt: Implement _mbsnbcat_s. --- dlls/msvcr100/msvcr100.spec | 2 +- dlls/msvcr80/msvcr80.spec | 2 +- dlls/msvcr90/msvcr90.spec | 2 +- dlls/msvcrt/mbcs.c | 49 ++++++++++++++ dlls/msvcrt/msvcrt.spec | 4 +- dlls/msvcrt/tests/string.c | 130 ++++++++++++++++++++++++++++++++++++ include/msvcrt/mbstring.h | 1 + 7 files changed, 185 insertions(+), 5 deletions(-) diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index 6573f1c3725..212f30e4793 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -925,7 +925,7 @@ @ stub _mbslwr_s_l @ cdecl _mbsnbcat(str str long) msvcrt._mbsnbcat @ stub _mbsnbcat_l -@ stub _mbsnbcat_s +@ cdecl _mbsnbcat_s(str long ptr long) msvcrt._mbsnbcat_s @ stub _mbsnbcat_s_l @ cdecl _mbsnbcmp(str str long) msvcrt._mbsnbcmp @ stub _mbsnbcmp_l diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index 819ed0ade96..43c0032e098 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -771,7 +771,7 @@ @ stub _mbslwr_s_l @ cdecl _mbsnbcat(str str long) msvcrt._mbsnbcat @ stub _mbsnbcat_l -@ stub _mbsnbcat_s +@ cdecl _mbsnbcat_s(str long ptr long) msvcrt._mbsnbcat_s @ stub _mbsnbcat_s_l @ cdecl _mbsnbcmp(str str long) msvcrt._mbsnbcmp @ stub _mbsnbcmp_l diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index 7a8123d783e..74480afc451 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -759,7 +759,7 @@ @ stub _mbslwr_s_l @ cdecl _mbsnbcat(str str long) msvcrt._mbsnbcat @ stub _mbsnbcat_l -@ stub _mbsnbcat_s +@ cdecl _mbsnbcat_s(str long ptr long) msvcrt._mbsnbcat_s @ stub _mbsnbcat_s_l @ cdecl _mbsnbcmp(str str long) msvcrt._mbsnbcmp @ stub _mbsnbcmp_l diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c index 76d562cdfdd..d92365f3bab 100644 --- a/dlls/msvcrt/mbcs.c +++ b/dlls/msvcrt/mbcs.c @@ -1439,6 +1439,55 @@ unsigned char* CDECL _mbsnbcat(unsigned char* dst, const unsigned char* src, MSV return u_strncat(dst, src, len); /* ASCII CP */ } +int CDECL _mbsnbcat_s(unsigned char *dst, MSVCRT_size_t size, const unsigned char *src, MSVCRT_size_t len) +{ + unsigned char *ptr = dst; + MSVCRT_size_t i; + + if (!dst && !size && !src && !len) + return 0; + + if (!dst || !size || !src) + { + if (dst && size) + *dst = '\0'; + + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; + } + + /* Find the null terminator of the destination buffer. */ + while (size && *ptr) + size--, ptr++; + + if (!size) + { + *dst = '\0'; + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; + } + + /* If necessary, check that the character preceding the null terminator is + * a lead byte and move the pointer back by one for later overwrite. */ + if (ptr != dst && get_locale()->locinfo->mb_cur_max > 1 && MSVCRT_isleadbyte(*(ptr - 1))) + size++, ptr--; + + for (i = 0; *src && i < len; i++) + { + *ptr++ = *src++; + size--; + + if (!size) + { + *dst = '\0'; + *MSVCRT__errno() = MSVCRT_ERANGE; + return MSVCRT_ERANGE; + } + } + + *ptr = '\0'; + return 0; +} /********************************************************************* * _mbsncat(MSVCRT.@) diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index c0f3d355338..1b3739f65c1 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -699,9 +699,9 @@ # stub _mbslwr_l # stub _mbslwr_s # stub _mbslwr_s_l -@ cdecl _mbsnbcat (str str long) +@ cdecl _mbsnbcat(str str long) # stub _mbsnbcat_l -# stub _mbsnbcat_s +@ cdecl _mbsnbcat_s(str long ptr long) # stub _mbsnbcat_s_l @ cdecl _mbsnbcmp(str str long) # stub _mbsnbcmp_l diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 85e4cf36681..9f7370ebb92 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -50,6 +50,7 @@ static void* (__cdecl *pmemcpy)(void *, const void *, size_t n); static int* (__cdecl *pmemcmp)(void *, const void *, size_t n); static int (__cdecl *pstrcpy_s)(char *dst, size_t len, const char *src); static int (__cdecl *pstrcat_s)(char *dst, size_t len, const char *src); +static int (__cdecl *p_mbsnbcat_s)(unsigned char *dst, size_t size, const unsigned char *src, size_t count); static int (__cdecl *p_mbsnbcpy_s)(unsigned char * dst, size_t size, const unsigned char * src, size_t count); static int (__cdecl *p_wcscpy_s)(wchar_t *wcDest, size_t size, const wchar_t *wcSrc); static int (__cdecl *p_wcsncat_s)(wchar_t *dst, size_t elem, const wchar_t *src, size_t count); @@ -1468,6 +1469,133 @@ static void test_wcsncat_s(void) ok(ret == EINVAL, "err = %d\n", ret); } +static void test__mbsnbcat_s(void) +{ + unsigned char dest[16]; + const unsigned char first[] = "dinosaur"; + const unsigned char second[] = "duck"; + int ret; + + if (!p_mbsnbcat_s) + { + win_skip("Skipping _mbsnbcat_s tests\n"); + return; + } + + /* Test invalid arguments. */ + ret = p_mbsnbcat_s(NULL, 0, NULL, 0); + ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret); + + errno = EBADF; + ret = p_mbsnbcat_s(NULL, 10, NULL, 0); + ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + errno = EBADF; + ret = p_mbsnbcat_s(NULL, 0, NULL, 10); + ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + memset(dest, 'X', sizeof(dest)); + errno = EBADF; + ret = p_mbsnbcat_s(dest, 0, NULL, 0); + ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(dest[0] == 'X', "Expected the output buffer to be untouched\n"); + + memset(dest, 'X', sizeof(dest)); + errno = EBADF; + ret = p_mbsnbcat_s(dest, 0, second, 0); + ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(dest[0] == 'X', "Expected the output buffer to be untouched\n"); + + memset(dest, 'X', sizeof(dest)); + errno = EBADF; + ret = p_mbsnbcat_s(dest, sizeof(dest), NULL, 0); + ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(dest[0] == '\0', "Expected the output buffer to be null terminated\n"); + + memset(dest, 'X', sizeof(dest)); + errno = EBADF; + ret = p_mbsnbcat_s(dest, sizeof(dest), NULL, 10); + ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(dest[0] == '\0', "Expected the output buffer to be null terminated\n"); + + memset(dest, 'X', sizeof(dest)); + dest[0] = '\0'; + ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second)); + ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret); + ok(!memcmp(dest, second, sizeof(second)), + "Expected the output buffer string to be \"duck\"\n"); + + /* Test source truncation behavior. */ + memset(dest, 'X', sizeof(dest)); + memcpy(dest, first, sizeof(first)); + ret = p_mbsnbcat_s(dest, sizeof(dest), second, 0); + ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret); + ok(!memcmp(dest, first, sizeof(first)), + "Expected the output buffer string to be \"dinosaur\"\n"); + + memset(dest, 'X', sizeof(dest)); + memcpy(dest, first, sizeof(first)); + ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second)); + ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret); + ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")), + "Expected the output buffer string to be \"dinosaurduck\"\n"); + + memset(dest, 'X', sizeof(dest)); + memcpy(dest, first, sizeof(first)); + ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second) + 1); + ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret); + ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")), + "Expected the output buffer string to be \"dinosaurduck\"\n"); + + memset(dest, 'X', sizeof(dest)); + memcpy(dest, first, sizeof(first)); + ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second) - 1); + ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret); + ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")), + "Expected the output buffer string to be \"dinosaurduck\"\n"); + + memset(dest, 'X', sizeof(dest)); + memcpy(dest, first, sizeof(first)); + ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second) - 2); + ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret); + ok(!memcmp(dest, "dinosaurduc", sizeof("dinosaurduc")), + "Expected the output buffer string to be \"dinosaurduc\"\n"); + + /* Test destination truncation behavior. */ + memset(dest, 'X', sizeof(dest)); + memcpy(dest, first, sizeof(first)); + errno = EBADF; + ret = p_mbsnbcat_s(dest, sizeof(first) - 1, second, sizeof(second)); + ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(!memcmp(dest, "\0inosaur", sizeof("\0inosaur") - 1), + "Expected the output buffer string to be \"\\0inosaur\" without ending null terminator\n"); + + memset(dest, 'X', sizeof(dest)); + memcpy(dest, first, sizeof(first)); + errno = EBADF; + ret = p_mbsnbcat_s(dest, sizeof(first), second, sizeof(second)); + ok(ret == ERANGE, "Expected _mbsnbcat_s to return ERANGE, got %d\n", ret); + ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno); + ok(!memcmp(dest, "\0inosaurd", sizeof("\0inosaurd") - 1), + "Expected the output buffer string to be \"\\0inosaurd\" without ending null terminator\n"); + + memset(dest, 'X', sizeof(dest)); + memcpy(dest, first, sizeof(first)); + errno = EBADF; + ret = p_mbsnbcat_s(dest, sizeof(first) + 1, second, sizeof(second)); + ok(ret == ERANGE, "Expected _mbsnbcat_s to return ERANGE, got %d\n", ret); + ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno); + ok(!memcmp(dest, "\0inosaurdu", sizeof("\0inosaurdu") - 1), + "Expected the output buffer string to be \"\\0inosaurdu\" without ending null terminator\n"); +} + START_TEST(string) { char mem[100]; @@ -1484,6 +1612,7 @@ START_TEST(string) SET(p__mb_cur_max,"__mb_cur_max"); pstrcpy_s = (void *)GetProcAddress( hMsvcrt,"strcpy_s" ); pstrcat_s = (void *)GetProcAddress( hMsvcrt,"strcat_s" ); + p_mbsnbcat_s = (void *)GetProcAddress( hMsvcrt,"_mbsnbcat_s" ); p_mbsnbcpy_s = (void *)GetProcAddress( hMsvcrt,"_mbsnbcpy_s" ); p_wcscpy_s = (void *)GetProcAddress( hMsvcrt,"wcscpy_s" ); p_wcsncat_s = (void *)GetProcAddress( hMsvcrt,"wcsncat_s" ); @@ -1533,4 +1662,5 @@ START_TEST(string) test__itoa_s(); test__strlwr_s(); test_wcsncat_s(); + test__mbsnbcat_s(); } diff --git a/include/msvcrt/mbstring.h b/include/msvcrt/mbstring.h index f3d7edf9bf2..a4d0746bcaf 100644 --- a/include/msvcrt/mbstring.h +++ b/include/msvcrt/mbstring.h @@ -76,6 +76,7 @@ unsigned char* __cdecl _mbsinc(const unsigned char*); size_t __cdecl _mbslen(const unsigned char*); unsigned char* __cdecl _mbslwr(unsigned char*); unsigned char* __cdecl _mbsnbcat(unsigned char*,const unsigned char*,size_t); +errno_t __cdecl _mbsnbcat_s(unsigned char*,size_t,const unsigned char*,size_t); int __cdecl _mbsnbcmp(const unsigned char*,const unsigned char*,size_t); int __cdecl _mbsnbcoll(const unsigned char*,const unsigned char*,size_t); size_t __cdecl _mbsnbcnt(const unsigned char*,size_t);