msvcrt: test and fix _mbccpy, _mbsncpy and _mbsnbcpy

Mikolaj Zalewski mikolajz at google.com
Wed Aug 22 12:48:51 CDT 2007


-------------- next part --------------
From 6ac5c622a25f71d9c16ebe317991b3969707360e Mon Sep 17 00:00:00 2001
From: Mikolaj Zalewski <mikolaj at zalewski.pl>
Date: Wed, 22 Aug 2007 10:47:01 -0700
Subject: [PATCH] msvcrt: test and fix _mbccpy, _mbsncpy and _mbsnbcpy
---
 dlls/msvcrt/mbcs.c         |   56 +++++++++++++++++++++++++++----------------
 dlls/msvcrt/tests/string.c |   57 ++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 90 insertions(+), 23 deletions(-)

diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c
index 38c249b..0452089 100644
--- a/dlls/msvcrt/mbcs.c
+++ b/dlls/msvcrt/mbcs.c
@@ -31,6 +31,8 @@ #include "msvcrt/mbctype.h"
 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
 
 unsigned char MSVCRT_mbctype[257];
+static int g_mbcp_is_multibyte = 0;
+
 int MSVCRT___mb_cur_max = 1;
 extern int MSVCRT___lc_collate_cp;
 
@@ -207,6 +209,8 @@ int CDECL _setmbcp(int cp)
   {
     /* trail bytes not available through kernel32 but stored in a structure in msvcrt */
     struct cp_extra_info_t *cpextra = g_cpextrainfo;
+    
+    g_mbcp_is_multibyte = 1;
     while (TRUE)
     {
       if (cpextra->cp == 0 || cpextra->cp == newcp)
@@ -226,6 +230,8 @@ int CDECL _setmbcp(int cp)
       cpextra++;
     }
   }
+  else
+    g_mbcp_is_multibyte = 0;
 
   /* we can't use GetStringTypeA directly because we don't have a locale - only a code page
    */
@@ -385,26 +391,39 @@ MSVCRT_size_t CDECL _mbslen(const unsign
 void CDECL _mbccpy(unsigned char* dest, const unsigned char* src)
 {
   *dest = *src;
-  if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src))
+  if(_ismbblead(*src))
     *++dest = *++src; /* MB char */
 }
 
 /*********************************************************************
  *		_mbsncpy(MSVCRT.@)
+ * REMARKS
+ *  The parameter n is the number or characters to copy, not the size of
+ *  the buffer. Use _mbsnbcpy for a function analogical to strncpy
  */
 unsigned char* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
 {
   unsigned char* ret = dst;
   if(!n)
     return dst;
-  if(MSVCRT___mb_cur_max > 1)
+  if (g_mbcp_is_multibyte)
   {
     while (*src && n)
     {
       n--;
-      *dst++ = *src;
-      if (MSVCRT_isleadbyte(*src++))
-          *dst++ = *src++;
+      if (_ismbblead(*src))
+      {
+        if (!*(src+1)) 
+        {
+            *dst++ = 0;
+            *dst++ = 0;
+            break;
+        }
+
+        *dst++ = *src++;
+      }
+
+      *dst++ = *src++;
     }
   }
   else
@@ -421,32 +440,27 @@ unsigned char* CDECL _mbsncpy(unsigned c
 
 /*********************************************************************
  *              _mbsnbcpy(MSVCRT.@)
+ * REMARKS
+ *  Like strncpy this function doesn't enforce the string to be
+ *  NUL-terminated
  */
 unsigned char* CDECL _mbsnbcpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
 {
   unsigned char* ret = dst;
   if(!n)
     return dst;
-  if(MSVCRT___mb_cur_max > 1)
+  if(g_mbcp_is_multibyte)
   {
-    while (*src && (n > 1))
-    {
-      n--;
-      *dst++ = *src;
-      if (MSVCRT_isleadbyte(*src++))
-      {
-        *dst++ = *src++;
-        n--;
-      }
-    }
-    if (*src && n && !MSVCRT_isleadbyte(*src))
+    int is_lead = 0;
+    while (*src && n)
     {
-      /* If the last character is a multi-byte character then
-       * we cannot copy it since we have only one byte left
-       */
-      *dst++ = *src;
+      is_lead = (!is_lead && _ismbblead(*src));
       n--;
+      *dst++ = *src++;
     }
+
+    if (is_lead) /* if string ends with a lead, remove it */
+	*(dst - 1) = 0;
   }
   else
   {
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c
index 4f82652..d400823 100644
--- a/dlls/msvcrt/tests/string.c
+++ b/dlls/msvcrt/tests/string.c
@@ -23,9 +23,26 @@ #include "winbase.h"
 #include <string.h>
 #include <mbstring.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <mbctype.h>
+#include <locale.h>
+
+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* (*pmemcpy)(void *, const void *, size_t n);
 static int* (*pmemcmp)(void *, const void *, size_t n);
@@ -33,6 +50,8 @@ static int* (*pmemcmp)(void *, const voi
 #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)
 
+HMODULE hMsvcrt;
+
 static void test_swab( void ) {
     char original[]  = "BADCFEHGJILKNMPORQTSVUXWZY@#";
     char expected1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ@#";
@@ -167,7 +186,8 @@ static void test_mbcp(void)
     int curr_mbcp = _getmbcp();
     unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2 \xb3\xb4 \xb5"; /* incorrect string */
     unsigned char *mbstring2 = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5"; /* correct string */
-    unsigned char *mbsonlylead = (unsigned char *)"\xb0";
+    unsigned char *mbsonlylead = (unsigned char *)"\xb0\0\xb1\xb2";
+    unsigned char buf[16];
 
     /* some two single-byte code pages*/
     test_codepage(1252);
@@ -201,6 +221,40 @@ static void test_mbcp(void)
     expect_eq(_mbslen(mbsonlylead), 0, int, "%d");          /* lead + NUL not counted as character */
     expect_eq(_mbslen(mbstring), 4, int, "%d");             /* lead + invalid trail counted */
 
+    /* _mbccpy/_mbsncpy */
+    memset(buf, 0xff, sizeof(buf));
+    _mbccpy(buf, mbstring);
+    expect_bin(buf, "\xb0\xb1\xff", 3);
+
+    memset(buf, 0xff, sizeof(buf));
+    _mbsncpy(buf, mbstring, 1);
+    expect_bin(buf, "\xb0\xb1\xff", 3);
+    memset(buf, 0xff, sizeof(buf));
+    _mbsncpy(buf, mbstring, 2);
+    expect_bin(buf, "\xb0\xb1\xb2 \xff", 5);
+    memset(buf, 0xff, sizeof(buf));
+    _mbsncpy(buf, mbstring, 3);
+    expect_bin(buf, "\xb0\xb1\xb2 \xb3\xb4\xff", 7);
+    memset(buf, 0xff, sizeof(buf));
+    _mbsncpy(buf, mbstring, 4);
+    expect_bin(buf, "\xb0\xb1\xb2 \xb3\xb4 \xff", 8);
+    memset(buf, 0xff, sizeof(buf));
+    _mbsncpy(buf, mbstring, 5);
+    expect_bin(buf, "\xb0\xb1\xb2 \xb3\xb4 \0\0\xff", 10);
+    memset(buf, 0xff, sizeof(buf));
+    _mbsncpy(buf, mbsonlylead, 6);
+    expect_bin(buf, "\0\0\0\0\0\0\0\xff", 8);
+
+    memset(buf, 0xff, sizeof(buf));
+    _mbsnbcpy(buf, mbstring2, 2);
+    expect_bin(buf, "\xb0\xb1\xff", 3);
+    _mbsnbcpy(buf, mbstring2, 3);
+    expect_bin(buf, "\xb0\xb1\0\xff", 4);
+    _mbsnbcpy(buf, mbstring2, 4);
+    expect_bin(buf, "\xb0\xb1\xb2\xb3\xff", 5);
+    memset(buf, 0xff, sizeof(buf));
+    _mbsnbcpy(buf, mbsonlylead, 5);
+    expect_bin(buf, "\0\0\0\0\0\xff", 6);
 
     /* functions that depend on locale codepage, not mbcp.
      * we hope the current locale to be SBCS because setlocale(LC_ALL, ".1252") seems not to work yet
@@ -263,7 +317,6 @@ START_TEST(string)
     void *mem;
     static const char xilstring[]="c:/xilinx";
     int nLen;
-    HMODULE hMsvcrt;
 
     hMsvcrt = GetModuleHandleA("msvcrt.dll");
     if (!hMsvcrt)
-- 
1.4.1


More information about the wine-patches mailing list