reactos/sdk/lib/crt/mbstring/_setmbcp.c

222 lines
6 KiB
C

/*
* msvcrt.dll mbcs functions
*
* Copyright 1999 Alexandre Julliard
* Copyright 2000 Jon Griffths
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* FIXME
* Not currently binary compatible with win32. MSVCRT_mbctype must be
* populated correctly and the ismb* functions should reference it.
*/
#include <precomp.h>
#include <mbctype.h>
/* It seems that the data about valid trail bytes is not available from kernel32
* so we have to store is here. The format is the same as for lead bytes in CPINFO */
struct cp_extra_info_t
{
int cp;
BYTE TrailBytes[MAX_LEADBYTES];
};
static struct cp_extra_info_t g_cpextrainfo[] =
{
{932, {0x40, 0x7e, 0x80, 0xfc, 0, 0}},
{936, {0x40, 0xfe, 0, 0}},
{949, {0x41, 0xfe, 0, 0}},
{950, {0x40, 0x7e, 0xa1, 0xfe, 0, 0}},
{1361, {0x31, 0x7e, 0x81, 0xfe, 0, 0}},
{20932, {1, 255, 0, 0}}, /* seems to give different results on different systems */
{0, {1, 255, 0, 0}} /* match all with FIXME */
};
/*********************************************************************
* INTERNAL: _setmbcp_l
*/
int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo)
{
const char format[] = ".%d";
int newcp;
CPINFO cpi;
BYTE *bytes;
WORD chartypes[256];
char bufA[256];
WCHAR bufW[256];
int charcount;
int ret;
int i;
if(!mbcinfo)
mbcinfo = get_mbcinfo();
switch (cp)
{
case _MB_CP_ANSI:
newcp = GetACP();
break;
case _MB_CP_OEM:
newcp = GetOEMCP();
break;
case _MB_CP_LOCALE:
newcp = get_locinfo()->lc_codepage;
if(newcp)
break;
/* fall through (C locale) */
case _MB_CP_SBCS:
newcp = 20127; /* ASCII */
break;
default:
newcp = cp;
break;
}
if(lcid == -1) {
sprintf(bufA, format, newcp);
mbcinfo->mblcid = MSVCRT_locale_to_LCID(bufA, NULL);
} else {
mbcinfo->mblcid = lcid;
}
if(mbcinfo->mblcid == -1)
{
WARN("Can't assign LCID to codepage (%d)\n", mbcinfo->mblcid);
mbcinfo->mblcid = 0;
}
if (!GetCPInfo(newcp, &cpi))
{
WARN("Codepage %d not found\n", newcp);
*_errno() = EINVAL;
return -1;
}
/* setup the _mbctype */
memset(mbcinfo->mbctype, 0, sizeof(unsigned char[257]));
memset(mbcinfo->mbcasemap, 0, sizeof(unsigned char[256]));
bytes = cpi.LeadByte;
while (bytes[0] || bytes[1])
{
for (i = bytes[0]; i <= bytes[1]; i++)
mbcinfo->mbctype[i + 1] |= _M1;
bytes += 2;
}
if (cpi.MaxCharSize > 1)
{
/* trail bytes not available through kernel32 but stored in a structure in msvcrt */
struct cp_extra_info_t *cpextra = g_cpextrainfo;
mbcinfo->ismbcodepage = 1;
while (TRUE)
{
if (cpextra->cp == 0 || cpextra->cp == newcp)
{
if (cpextra->cp == 0)
FIXME("trail bytes data not available for DBCS codepage %d - assuming all bytes\n", newcp);
bytes = cpextra->TrailBytes;
while (bytes[0] || bytes[1])
{
for (i = bytes[0]; i <= bytes[1]; i++)
mbcinfo->mbctype[i + 1] |= _M2;
bytes += 2;
}
break;
}
cpextra++;
}
}
else
mbcinfo->ismbcodepage = 0;
/* we can't use GetStringTypeA directly because we don't have a locale - only a code page
*/
charcount = 0;
for (i = 0; i < 256; i++)
if (!(mbcinfo->mbctype[i + 1] & _M1))
bufA[charcount++] = i;
ret = MultiByteToWideChar(newcp, 0, bufA, charcount, bufW, charcount);
if (ret != charcount)
ERR("MultiByteToWideChar of chars failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
GetStringTypeW(CT_CTYPE1, bufW, charcount, chartypes);
charcount = 0;
for (i = 0; i < 256; i++)
if (!(mbcinfo->mbctype[i + 1] & _M1))
{
if (chartypes[charcount] & C1_UPPER)
{
mbcinfo->mbctype[i + 1] |= _SBUP;
bufW[charcount] = tolowerW(bufW[charcount]);
}
else if (chartypes[charcount] & C1_LOWER)
{
mbcinfo->mbctype[i + 1] |= _SBLOW;
bufW[charcount] = toupperW(bufW[charcount]);
}
charcount++;
}
ret = WideCharToMultiByte(newcp, 0, bufW, charcount, bufA, charcount, NULL, NULL);
if (ret != charcount)
ERR("WideCharToMultiByte failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
charcount = 0;
for (i = 0; i < 256; i++)
{
if(!(mbcinfo->mbctype[i + 1] & _M1))
{
if(mbcinfo->mbctype[i] & (C1_UPPER|C1_LOWER))
mbcinfo->mbcasemap[i] = bufA[charcount];
charcount++;
}
}
if (newcp == 932) /* CP932 only - set _MP and _MS */
{
/* On Windows it's possible to calculate the _MP and _MS from CT_CTYPE1
* and CT_CTYPE3. But as of Wine 0.9.43 we return wrong values what makes
* it hard. As this is set only for codepage 932 we hardcode it what gives
* also faster execution.
*/
for (i = 161; i <= 165; i++)
mbcinfo->mbctype[i + 1] |= _MP;
for (i = 166; i <= 223; i++)
mbcinfo->mbctype[i + 1] |= _MS;
}
mbcinfo->mbcodepage = newcp;
if(global_locale && mbcinfo == MSVCRT_locale->mbcinfo)
memcpy(_mbctype, MSVCRT_locale->mbcinfo->mbctype, sizeof(_mbctype));
return 0;
}
/*********************************************************************
* _setmbcp (MSVCRT.@)
*/
int CDECL _setmbcp(int cp)
{
return _setmbcp_l(cp, -1, NULL);
}