msvcrt: Test and fix _mbccpy, _mbsncpy and _mbsnbcpy.
This commit is contained in:
parent
5b62c8461c
commit
c5268a20ab
|
@ -31,6 +31,8 @@
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||||
|
|
||||||
unsigned char MSVCRT_mbctype[257];
|
unsigned char MSVCRT_mbctype[257];
|
||||||
|
static int g_mbcp_is_multibyte = 0;
|
||||||
|
|
||||||
int MSVCRT___mb_cur_max = 1;
|
int MSVCRT___mb_cur_max = 1;
|
||||||
extern int MSVCRT___lc_collate_cp;
|
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 */
|
/* trail bytes not available through kernel32 but stored in a structure in msvcrt */
|
||||||
struct cp_extra_info_t *cpextra = g_cpextrainfo;
|
struct cp_extra_info_t *cpextra = g_cpextrainfo;
|
||||||
|
|
||||||
|
g_mbcp_is_multibyte = 1;
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
if (cpextra->cp == 0 || cpextra->cp == newcp)
|
if (cpextra->cp == 0 || cpextra->cp == newcp)
|
||||||
|
@ -226,6 +230,8 @@ int CDECL _setmbcp(int cp)
|
||||||
cpextra++;
|
cpextra++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
g_mbcp_is_multibyte = 0;
|
||||||
|
|
||||||
/* we can't use GetStringTypeA directly because we don't have a locale - only a code page
|
/* 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 unsigned char* str)
|
||||||
void CDECL _mbccpy(unsigned char* dest, const unsigned char* src)
|
void CDECL _mbccpy(unsigned char* dest, const unsigned char* src)
|
||||||
{
|
{
|
||||||
*dest = *src;
|
*dest = *src;
|
||||||
if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src))
|
if(_ismbblead(*src))
|
||||||
*++dest = *++src; /* MB char */
|
*++dest = *++src; /* MB char */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* _mbsncpy(MSVCRT.@)
|
* _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* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
|
||||||
{
|
{
|
||||||
unsigned char* ret = dst;
|
unsigned char* ret = dst;
|
||||||
if(!n)
|
if(!n)
|
||||||
return dst;
|
return dst;
|
||||||
if(MSVCRT___mb_cur_max > 1)
|
if (g_mbcp_is_multibyte)
|
||||||
{
|
{
|
||||||
while (*src && n)
|
while (*src && n)
|
||||||
{
|
{
|
||||||
n--;
|
n--;
|
||||||
*dst++ = *src;
|
if (_ismbblead(*src))
|
||||||
if (MSVCRT_isleadbyte(*src++))
|
{
|
||||||
*dst++ = *src++;
|
if (!*(src+1))
|
||||||
|
{
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst++ = *src++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst++ = *src++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -421,32 +440,27 @@ unsigned char* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, MSVC
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* _mbsnbcpy(MSVCRT.@)
|
* _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* CDECL _mbsnbcpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
|
||||||
{
|
{
|
||||||
unsigned char* ret = dst;
|
unsigned char* ret = dst;
|
||||||
if(!n)
|
if(!n)
|
||||||
return dst;
|
return dst;
|
||||||
if(MSVCRT___mb_cur_max > 1)
|
if(g_mbcp_is_multibyte)
|
||||||
{
|
{
|
||||||
while (*src && (n > 1))
|
int is_lead = 0;
|
||||||
|
while (*src && n)
|
||||||
{
|
{
|
||||||
|
is_lead = (!is_lead && _ismbblead(*src));
|
||||||
n--;
|
n--;
|
||||||
*dst++ = *src;
|
*dst++ = *src++;
|
||||||
if (MSVCRT_isleadbyte(*src++))
|
|
||||||
{
|
|
||||||
*dst++ = *src++;
|
|
||||||
n--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (*src && n && !MSVCRT_isleadbyte(*src))
|
|
||||||
{
|
|
||||||
/* If the last character is a multi-byte character then
|
|
||||||
* we cannot copy it since we have only one byte left
|
|
||||||
*/
|
|
||||||
*dst++ = *src;
|
|
||||||
n--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_lead) /* if string ends with a lead, remove it */
|
||||||
|
*(dst - 1) = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,9 +23,26 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <mbstring.h>
|
#include <mbstring.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <mbctype.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_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 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);
|
||||||
|
@ -33,6 +50,8 @@ static int* (*pmemcmp)(void *, const void *, size_t n);
|
||||||
#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)
|
||||||
|
|
||||||
|
HMODULE hMsvcrt;
|
||||||
|
|
||||||
static void test_swab( void ) {
|
static void test_swab( void ) {
|
||||||
char original[] = "BADCFEHGJILKNMPORQTSVUXWZY@#";
|
char original[] = "BADCFEHGJILKNMPORQTSVUXWZY@#";
|
||||||
char expected1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ@#";
|
char expected1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ@#";
|
||||||
|
@ -167,7 +186,8 @@ static void test_mbcp(void)
|
||||||
int curr_mbcp = _getmbcp();
|
int curr_mbcp = _getmbcp();
|
||||||
unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2 \xb3\xb4 \xb5"; /* incorrect string */
|
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 *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*/
|
/* some two single-byte code pages*/
|
||||||
test_codepage(1252);
|
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(mbsonlylead), 0, int, "%d"); /* lead + NUL not counted as character */
|
||||||
expect_eq(_mbslen(mbstring), 4, int, "%d"); /* lead + invalid trail counted */
|
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.
|
/* 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
|
* 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;
|
void *mem;
|
||||||
static const char xilstring[]="c:/xilinx";
|
static const char xilstring[]="c:/xilinx";
|
||||||
int nLen;
|
int nLen;
|
||||||
HMODULE hMsvcrt;
|
|
||||||
|
|
||||||
hMsvcrt = GetModuleHandleA("msvcrt.dll");
|
hMsvcrt = GetModuleHandleA("msvcrt.dll");
|
||||||
if (!hMsvcrt)
|
if (!hMsvcrt)
|
||||||
|
|
Loading…
Reference in New Issue