From: Paul Gofman pgofman@codeweavers.com
--- dlls/msvcr100/msvcr100.spec | 4 +- dlls/msvcr110/msvcr110.spec | 4 +- dlls/msvcr120/msvcr120.spec | 4 +- dlls/msvcr80/msvcr80.spec | 4 +- dlls/msvcr80/tests/msvcr80.c | 133 ++++++++++++++++++++++++++++++++++- dlls/msvcr90/msvcr90.spec | 4 +- dlls/msvcrt/mbcs.c | 64 +++++++++++++++++ dlls/ucrtbase/tests/string.c | 85 ++++++++++++++++++++++ dlls/ucrtbase/ucrtbase.spec | 8 +-- include/msvcrt/mbstring.h | 2 + 10 files changed, 297 insertions(+), 15 deletions(-)
diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index 68e502af597..7e6397051e9 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -1157,8 +1157,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcr110/msvcr110.spec b/dlls/msvcr110/msvcr110.spec index 560002e59ed..010d222d665 100644 --- a/dlls/msvcr110/msvcr110.spec +++ b/dlls/msvcr110/msvcr110.spec @@ -1514,8 +1514,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec index 46715817932..caddf750038 100644 --- a/dlls/msvcr120/msvcr120.spec +++ b/dlls/msvcr120/msvcr120.spec @@ -1525,8 +1525,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index 6cce6ee22ee..b4548945236 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -829,8 +829,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcr80/tests/msvcr80.c b/dlls/msvcr80/tests/msvcr80.c index fa04b024031..82379e1246f 100644 --- a/dlls/msvcr80/tests/msvcr80.c +++ b/dlls/msvcr80/tests/msvcr80.c @@ -39,6 +39,44 @@
#define MSVCRT_FD_BLOCK_SIZE 32
+#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(invalid_parameter_handler); + +static void __cdecl test_invalid_parameter_handler(const wchar_t *expression, + const wchar_t *function, const wchar_t *file, + unsigned line, uintptr_t arg) +{ + CHECK_EXPECT(invalid_parameter_handler); + ok(expression == NULL, "expression is not NULL\n"); + ok(function == NULL, "function is not NULL\n"); + ok(file == NULL, "file is not NULL\n"); + ok(line == 0, "line = %u\n", line); + ok(arg == 0, "arg = %Ix\n", arg); +} + typedef struct { HANDLE handle; @@ -57,6 +95,7 @@ typedef struct
static ioinfo **__pioinfo;
+static _invalid_parameter_handler (__cdecl *p__set_invalid_parameter_handler)(_invalid_parameter_handler); static int (WINAPIV *p__open)(const char *, int, ...); static int (__cdecl *p__close)(int); static intptr_t (__cdecl *p__get_osfhandle)(int); @@ -64,6 +103,8 @@ static int (__cdecl *p_strcmp)(const char *, const char *); static int (__cdecl *p_strncmp)(const char *, const char *, size_t); static int (__cdecl *p_dupenv_s)(char **, size_t *, const char *); static int (__cdecl *p_wdupenv_s)(wchar_t **, size_t *, const wchar_t *); +static errno_t (__cdecl *p__mbsncpy_s)(unsigned char*,size_t,const unsigned char*,size_t); +
#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hcrt,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) @@ -78,6 +119,8 @@ static BOOL init(void) return FALSE; }
+ SET(p__set_invalid_parameter_handler, "_set_invalid_parameter_handler"); + SET(__pioinfo, "__pioinfo"); SET(p__open,"_open"); SET(p__close,"_close"); @@ -87,7 +130,7 @@ static BOOL init(void) SET(p_strncmp, "strncmp"); SET(p_dupenv_s, "_dupenv_s"); SET(p_wdupenv_s, "_wdupenv_s"); - + SET(p__mbsncpy_s, "_mbsncpy_s"); return TRUE; }
@@ -216,13 +259,101 @@ static void test_wdupenv_s(void) ok( !tmp, "_wdupenv_s returned pointer is %p\n", tmp ); }
+static char *buf_to_string(const unsigned char *bin, int len, int nr) +{ + static char buf[2][1024]; + char *w = buf[nr]; + int i; + + for (i = 0; i < len; i++) + { + sprintf(w, "%02x ", (unsigned char)bin[i]); + w += strlen(w); + } + return buf[nr]; +} + +#define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); } +#define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, "Binary buffer mismatch - expected %s, got %s\n", buf_to_string((unsigned char *)value, len, 1), buf_to_string((buf), len, 0)); } + +static void test__mbsncpy_s(void) +{ + unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5\x0"; /* correct string */ + unsigned char buf[16]; + errno_t err; + + errno = 0xdeadbeef; + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, 6, mbstring, 1); + ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, 6, mbstring, 2); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\xb1\0\xcc", 4); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, 2, mbstring, _TRUNCATE); + ok(err == STRUNCATE, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, 2, mbstring, 1); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = p__mbsncpy_s(buf, 2, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == ERANGE, "got %d.\n", err); + expect_bin(buf, "\x0\xb1\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = p__mbsncpy_s(buf, 1, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == ERANGE, "got %d.\n", err); + expect_bin(buf, "\x0\xcc", 2); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = p__mbsncpy_s(buf, 0, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == EINVAL, "got %d.\n", err); + expect_bin(buf, "\xcc", 1); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = p__mbsncpy_s(buf, 0, mbstring, 0); + CHECK_CALLED(invalid_parameter_handler); + ok(err == EINVAL, "got %d.\n", err); + expect_bin(buf, "\xcc", 1); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, -1, mbstring, 0); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\x0\xcc", 2); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, -1, mbstring, 256); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\xb1\xb2\xb3Q\xb4\xb5\x0\xcc", 9); +} + START_TEST(msvcr80) { if(!init()) return;
+ ok(p__set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, + "Invalid parameter handler was already set\n"); + test_ioinfo_flags(); test_strcmp(); test_dupenv_s(); test_wdupenv_s(); + test__mbsncpy_s(); } diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index ca22d7460be..c19f7298235 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -807,8 +807,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c index ce8a3115eeb..3ddbae09078 100644 --- a/dlls/msvcrt/mbcs.c +++ b/dlls/msvcrt/mbcs.c @@ -900,6 +900,70 @@ unsigned char* CDECL _mbsncpy_l(unsigned char* dst, const unsigned char* src, si return ret; }
+#if _MSVCR_VER>=80 +errno_t CDECL _mbsncpy_s_l(unsigned char* dst, size_t maxsize, const unsigned char* src, size_t n, _locale_t locale) +{ + BOOL truncate = (n == _TRUNCATE); + unsigned char *start = dst; + pthreadmbcinfo mbcinfo; + + if(!MSVCRT_CHECK_PMT(dst != NULL)) return EINVAL; + if (!MSVCRT_CHECK_PMT(maxsize != 0)) return EINVAL; + if (!MSVCRT_CHECK_PMT(src != NULL)) + { + *start = 0; + return EINVAL; + } + + if (!n) + { + *start = 0; + return 0; + } + + if (locale) + mbcinfo = locale->mbcinfo; + else + mbcinfo = get_mbcinfo(); + + while (*src && n && maxsize) + { + if (mbcinfo->ismbcodepage && _ismbblead_l(*src, locale)) + { + --maxsize; + if (!*(src + 1)) + { + *dst++ = 0; + break; + } + *dst++ = *src++; + if (!maxsize) break; + } + --maxsize; + --n; + *dst++ = *src++; + } + + if (!maxsize && truncate) + { + *(dst - 1) = 0; + return STRUNCATE; + } + if (!maxsize) + { + *start = 0; + if (!MSVCRT_CHECK_PMT(FALSE)) return ERANGE; + } + *dst = 0; + return 0; +} + +errno_t CDECL _mbsncpy_s(unsigned char* dst, size_t maxsize, const unsigned char* src, size_t n) +{ + return _mbsncpy_s_l(dst, maxsize, src, n, NULL); +} +#endif + /********************************************************************* * _mbsncpy(MSVCRT.@) * REMARKS diff --git a/dlls/ucrtbase/tests/string.c b/dlls/ucrtbase/tests/string.c index 6dcd15fb5b9..5789e7ba619 100644 --- a/dlls/ucrtbase/tests/string.c +++ b/dlls/ucrtbase/tests/string.c @@ -651,6 +651,90 @@ static void test_strcmp(void) ok( ret == 0, "wrong ret %d\n", ret ); }
+static char *buf_to_string(const unsigned char *bin, int len, int nr) +{ + static char buf[2][1024]; + char *w = buf[nr]; + int i; + + for (i = 0; i < len; i++) + { + sprintf(w, "%02x ", (unsigned char)bin[i]); + w += strlen(w); + } + return buf[nr]; +} + +#define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); } +#define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, "Binary buffer mismatch - expected %s, got %s\n", buf_to_string((unsigned char *)value, len, 1), buf_to_string((buf), len, 0)); } + +static void test__mbsncpy_s(void) +{ + unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5\x0"; /* correct string */ + unsigned char buf[16]; + errno_t err; + + errno = 0xdeadbeef; + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, 6, mbstring, 1); + ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, 6, mbstring, 2); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\xb1\0\xcc", 4); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, 2, mbstring, _TRUNCATE); + ok(err == STRUNCATE, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, 2, mbstring, 1); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = _mbsncpy_s(buf, 2, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == ERANGE, "got %d.\n", err); + expect_bin(buf, "\x0\xb1\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = _mbsncpy_s(buf, 1, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == ERANGE, "got %d.\n", err); + expect_bin(buf, "\x0\xcc", 2); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = _mbsncpy_s(buf, 0, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == EINVAL, "got %d.\n", err); + expect_bin(buf, "\xcc", 1); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = _mbsncpy_s(buf, 0, mbstring, 0); + CHECK_CALLED(invalid_parameter_handler); + ok(err == EINVAL, "got %d.\n", err); + expect_bin(buf, "\xcc", 1); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, -1, mbstring, 0); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\x0\xcc", 2); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, -1, mbstring, 256); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\xb1\xb2\xb3Q\xb4\xb5\x0\xcc", 9); +} + START_TEST(string) { ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, @@ -669,4 +753,5 @@ START_TEST(string) test_SpecialCasing(); test__mbbtype_l(); test_strcmp(); + test__mbsncpy_s(); } diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec index 449b734ad34..054fc4055f4 100644 --- a/dlls/ucrtbase/ucrtbase.spec +++ b/dlls/ucrtbase/ucrtbase.spec @@ -673,8 +673,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) @@ -1242,8 +1242,8 @@ @ stub _o__mbsncoll_l @ cdecl _o__mbsncpy(ptr str long) _mbsncpy @ cdecl _o__mbsncpy_l(ptr str long ptr) _mbsncpy_l -@ stub _o__mbsncpy_s -@ stub _o__mbsncpy_s_l +@ cdecl _o__mbsncpy_s(ptr long str long) _mbsncpy_s +@ cdecl _o__mbsncpy_s_l(ptr long str long ptr) _mbsncpy_s_l @ cdecl _o__mbsnextc(str) _mbsnextc @ cdecl _o__mbsnextc_l(str ptr) _mbsnextc_l @ cdecl _o__mbsnicmp(str str long) _mbsnicmp diff --git a/include/msvcrt/mbstring.h b/include/msvcrt/mbstring.h index 28a0e41f10d..f51d8ed6bc3 100644 --- a/include/msvcrt/mbstring.h +++ b/include/msvcrt/mbstring.h @@ -93,6 +93,8 @@ _ACRTIMP size_t __cdecl _mbsnccnt(const unsigned char*,size_t); _ACRTIMP int __cdecl _mbsncmp(const unsigned char*,const unsigned char*,size_t); _ACRTIMP int __cdecl _mbsncoll(const unsigned char*,const unsigned char*,size_t); _ACRTIMP unsigned char* __cdecl _mbsncpy(unsigned char*,const unsigned char*,size_t); +_ACRTIMP errno_t __cdecl _mbsncpy_s(unsigned char*,size_t,const unsigned char*,size_t); +_ACRTIMP errno_t __cdecl _mbsncpy_s_l(unsigned char*,size_t,const unsigned char*,size_t,_locale_t); _ACRTIMP unsigned int __cdecl _mbsnextc(const unsigned char*); _ACRTIMP unsigned int __cdecl _mbsnextc_l(const unsigned char*,_locale_t); _ACRTIMP int __cdecl _mbsnicmp(const unsigned char*,const unsigned char*,size_t);