windows-nt/Source/XPSP1/NT/base/win32/winnls/mbcs.c
2020-09-26 16:20:57 +08:00

3989 lines
142 KiB
C

/*++
Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
Module Name:
mbcs.c
Abstract:
This file contains functions that convert multibyte character strings
to wide character strings, convert wide character strings to multibyte
character strings, convert a multibyte character string from one code
page to a multibyte character string of another code page, and get the
DBCS leadbyte ranges for a given code page.
APIs found in this file:
IsValidCodePage
GetACP
GetOEMCP
GetCPInfo
GetCPInfoExW
IsDBCSLeadByte
IsDBCSLeadByteEx
MultiByteToWideChar
WideCharToMultiByte
Revision History:
05-31-91 JulieB Created.
--*/
//
// Include Files.
//
#include "nls.h"
//
// Forward Declarations.
//
int
GetWCCompSB(
PMB_TABLE pMBTbl,
LPBYTE pMBStr,
LPWSTR pWCStr,
LPWSTR pEndWCStr);
int
GetWCCompMB(
PCP_HASH pHashN,
PMB_TABLE pMBTbl,
LPBYTE pMBStr,
LPBYTE pEndMBStr,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
int *pmbIncr);
int
GetWCCompSBErr(
PCP_HASH pHashN,
PMB_TABLE pMBTbl,
LPBYTE pMBStr,
LPWSTR pWCStr,
LPWSTR pEndWCStr);
int
GetWCCompMBErr(
PCP_HASH pHashN,
PMB_TABLE pMBTbl,
LPBYTE pMBStr,
LPBYTE pEndMBStr,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
int *pmbIncr);
int
GetMBNoDefault(
PCP_HASH pHashN,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
LPBYTE pMBStr,
int cbMultiByte,
DWORD dwFlags);
int
GetMBDefault(
PCP_HASH pHashN,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
LPBYTE pMBStr,
int cbMultiByte,
WORD wDefault,
LPBOOL pUsedDef,
DWORD dwFlags);
int
GetMBDefaultComp(
PCP_HASH pHashN,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
LPBYTE pMBStr,
int cbMultiByte,
WORD wDefault,
LPBOOL pUsedDef,
DWORD dwFlags);
int
GetMBCompSB(
PCP_HASH pHashN,
DWORD dwFlags,
LPWSTR pWCStr,
LPBYTE pMBStr,
int mbCount,
WORD wDefault,
LPBOOL pUsedDef);
int
GetMBCompMB(
PCP_HASH pHashN,
DWORD dwFlags,
LPWSTR pWCStr,
LPBYTE pMBStr,
int mbCount,
WORD wDefault,
LPBOOL pUsedDef,
BOOL *fError,
BOOL fOnlyOne);
UINT
GetMacCodePage(void);
//-------------------------------------------------------------------------//
// INTERNAL MACROS //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// CHECK_DBCS_LEAD_BYTE
//
// Returns the offset to the DBCS table for the given leadbyte character.
// If the given character is not a leadbyte, then it returns zero (table
// value).
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define CHECK_DBCS_LEAD_BYTE(pDBCSOff, Ch) \
(pDBCSOff ? ((WORD)(pDBCSOff[Ch])) : ((WORD)0))
////////////////////////////////////////////////////////////////////////////
//
// CHECK_ERROR_WC_SINGLE
//
// Checks to see if the default character was used due to an invalid
// character. Sets last error and returns 0 characters written if an
// invalid character was used.
//
// NOTE: This macro may return if an error is encountered.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define CHECK_ERROR_WC_SINGLE( pHashN, \
wch, \
Ch ) \
{ \
if ( ( (wch == pHashN->pCPInfo->wUniDefaultChar) && \
(Ch != pHashN->pCPInfo->wTransUniDefaultChar) ) || \
( (wch >= PRIVATE_USE_BEGIN) && (wch <= PRIVATE_USE_END) ) ) \
{ \
SetLastError(ERROR_NO_UNICODE_TRANSLATION); \
return (0); \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// CHECK_ERROR_WC_MULTI
//
// Checks to see if the default character was used due to an invalid
// character. Sets last error and returns 0 characters written if an
// invalid character was used.
//
// NOTE: This macro may return if an error is encountered.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define CHECK_ERROR_WC_MULTI( pHashN, \
wch, \
lead, \
trail ) \
{ \
if ((wch == pHashN->pCPInfo->wUniDefaultChar) && \
(MAKEWORD(trail, lead) != pHashN->pCPInfo->wTransUniDefaultChar)) \
{ \
SetLastError(ERROR_NO_UNICODE_TRANSLATION); \
return (0); \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// CHECK_ERROR_WC_MULTI_SPECIAL
//
// Checks to see if the default character was used due to an invalid
// character. Sets it to 0xffff if invalid.
//
// DEFINED AS A MACRO.
//
// 08-21-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define CHECK_ERROR_WC_MULTI_SPECIAL( pHashN, \
pWCStr, \
lead, \
trail ) \
{ \
if ((*pWCStr == pHashN->pCPInfo->wUniDefaultChar) && \
(MAKEWORD(trail, lead) != pHashN->pCPInfo->wTransUniDefaultChar)) \
{ \
*pWCStr = 0xffff; \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_WC_SINGLE
//
// Fills in pWCStr with the wide character(s) for the corresponding single
// byte character from the appropriate translation table.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_WC_SINGLE( pMBTbl, \
pMBStr, \
pWCStr ) \
{ \
*pWCStr = pMBTbl[*pMBStr]; \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_WC_SINGLE_SPECIAL
//
// Fills in pWCStr with the wide character(s) for the corresponding single
// byte character from the appropriate translation table. Also checks for
// invalid characters - if invalid, it fills in 0xffff instead.
//
// DEFINED AS A MACRO.
//
// 08-21-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_WC_SINGLE_SPECIAL( pHashN, \
pMBTbl, \
pMBStr, \
pWCStr ) \
{ \
*pWCStr = pMBTbl[*pMBStr]; \
\
if ( ( (*pWCStr == pHashN->pCPInfo->wUniDefaultChar) && \
(*pMBStr != pHashN->pCPInfo->wTransUniDefaultChar) ) || \
( (*pWCStr >= PRIVATE_USE_BEGIN) && \
(*pWCStr <= PRIVATE_USE_END) ) ) \
{ \
*pWCStr = 0xffff; \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_WC_MULTI
//
// Fills in pWCStr with the wide character(s) for the corresponding multibyte
// character from the appropriate translation table. The number of bytes
// used from the pMBStr buffer (single byte or double byte) is stored in
// the mbIncr parameter.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_WC_MULTI( pHashN, \
pMBTbl, \
pMBStr, \
pEndMBStr, \
pWCStr, \
pEndWCStr, \
mbIncr ) \
{ \
WORD Offset; /* offset to DBCS table for range */ \
\
\
if (Offset = CHECK_DBCS_LEAD_BYTE(pHashN->pDBCSOffsets, *pMBStr)) \
{ \
/* \
* DBCS Lead Byte. Make sure there is a trail byte with the \
* lead byte. \
*/ \
if (pMBStr + 1 == pEndMBStr) \
{ \
/* \
* There is no trail byte with the lead byte. The lead byte \
* is the LAST character in the string. Translate to NULL. \
*/ \
*pWCStr = (WCHAR)0; \
mbIncr = 1; \
} \
else if (*(pMBStr + 1) == 0) \
{ \
/* \
* There is no trail byte with the lead byte. The lead byte \
* is followed by a NULL. Translate to NULL. \
* \
* Increment by 2 so that the null is not counted twice. \
*/ \
*pWCStr = (WCHAR)0; \
mbIncr = 2; \
} \
else \
{ \
/* \
* Fill in the wide character translation from the double \
* byte character table. \
*/ \
*pWCStr = (pHashN->pDBCSOffsets + Offset)[*(pMBStr + 1)]; \
mbIncr = 2; \
} \
} \
else \
{ \
/* \
* Not DBCS Lead Byte. Fill in the wide character translation \
* from the single byte character table. \
*/ \
*pWCStr = pMBTbl[*pMBStr]; \
mbIncr = 1; \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_WC_MULTI_ERR
//
// Fills in pWCStr with the wide character(s) for the corresponding multibyte
// character from the appropriate translation table. The number of bytes
// used from the pMBStr buffer (single byte or double byte) is stored in
// the mbIncr parameter.
//
// Once the character has been translated, it checks to be sure the
// character was valid. If not, it sets last error and return 0 characters
// written.
//
// NOTE: This macro may return if an error is encountered.
//
// DEFINED AS A MACRO.
//
// 09-01-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_WC_MULTI_ERR( pHashN, \
pMBTbl, \
pMBStr, \
pEndMBStr, \
pWCStr, \
pEndWCStr, \
mbIncr ) \
{ \
WORD Offset; /* offset to DBCS table for range */ \
\
\
if (Offset = CHECK_DBCS_LEAD_BYTE(pHashN->pDBCSOffsets, *pMBStr)) \
{ \
/* \
* DBCS Lead Byte. Make sure there is a trail byte with the \
* lead byte. \
*/ \
if ((pMBStr + 1 == pEndMBStr) || (*(pMBStr + 1) == 0)) \
{ \
/* \
* There is no trail byte with the lead byte. Return error. \
*/ \
SetLastError(ERROR_NO_UNICODE_TRANSLATION); \
return (0); \
} \
\
/* \
* Fill in the wide character translation from the double \
* byte character table. \
*/ \
*pWCStr = (pHashN->pDBCSOffsets + Offset)[*(pMBStr + 1)]; \
mbIncr = 2; \
\
/* \
* Make sure an invalid character was not translated to \
* the default char. Return an error if invalid. \
*/ \
CHECK_ERROR_WC_MULTI( pHashN, \
*pWCStr, \
*pMBStr, \
*(pMBStr + 1) ); \
} \
else \
{ \
/* \
* Not DBCS Lead Byte. Fill in the wide character translation \
* from the single byte character table. \
*/ \
*pWCStr = pMBTbl[*pMBStr]; \
mbIncr = 1; \
\
/* \
* Make sure an invalid character was not translated to \
* the default char. Return an error if invalid. \
*/ \
CHECK_ERROR_WC_SINGLE( pHashN, \
*pWCStr, \
*pMBStr ); \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_WC_MULTI_ERR_SPECIAL
//
// Fills in pWCStr with the wide character(s) for the corresponding multibyte
// character from the appropriate translation table. The number of bytes
// used from the pMBStr buffer (single byte or double byte) is stored in
// the mbIncr parameter.
//
// Once the character has been translated, it checks to be sure the
// character was valid. If not, it fills in 0xffff.
//
// DEFINED AS A MACRO.
//
// 08-21-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_WC_MULTI_ERR_SPECIAL( pHashN, \
pMBTbl, \
pMBStr, \
pEndMBStr, \
pWCStr, \
pEndWCStr, \
mbIncr ) \
{ \
WORD Offset; /* offset to DBCS table for range */ \
\
\
if (Offset = CHECK_DBCS_LEAD_BYTE(pHashN->pDBCSOffsets, *pMBStr)) \
{ \
/* \
* DBCS Lead Byte. Make sure there is a trail byte with the \
* lead byte. \
*/ \
if ((pMBStr + 1 == pEndMBStr) || (*(pMBStr + 1) == 0)) \
{ \
/* \
* There is no trail byte with the lead byte. The lead byte \
* is the LAST character in the string. Translate to 0xffff. \
*/ \
*pWCStr = (WCHAR)0xffff; \
mbIncr = 1; \
} \
else \
{ \
/* \
* Fill in the wide character translation from the double \
* byte character table. \
*/ \
*pWCStr = (pHashN->pDBCSOffsets + Offset)[*(pMBStr + 1)]; \
mbIncr = 2; \
\
/* \
* Make sure an invalid character was not translated to \
* the default char. Translate to 0xffff if invalid. \
*/ \
CHECK_ERROR_WC_MULTI_SPECIAL( pHashN, \
pWCStr, \
*pMBStr, \
*(pMBStr + 1) ); \
} \
} \
else \
{ \
/* \
* Not DBCS Lead Byte. Fill in the wide character translation \
* from the single byte character table. \
* Make sure an invalid character was not translated to \
* the default char. Return an error if invalid. \
*/ \
GET_WC_SINGLE_SPECIAL( pHashN, \
pMBTbl, \
pMBStr, \
pWCStr ); \
mbIncr = 1; \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// COPY_MB_CHAR
//
// Copies a multibyte character to the given string buffer. If the
// high byte of the multibyte word is zero, then it is a single byte
// character and the number of characters written (returned) is 1.
// Otherwise, it is a double byte character and the number of characters
// written (returned) is 2.
//
// NumByte will be 0 if the buffer is too small for the translation.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define COPY_MB_CHAR( mbChar, \
pMBStr, \
NumByte, \
fOnlyOne ) \
{ \
if (HIBYTE(mbChar)) \
{ \
/* \
* Make sure there is enough room in the buffer for both bytes. \
*/ \
if (fOnlyOne) \
{ \
NumByte = 0; \
} \
else \
{ \
/* \
* High Byte is NOT zero, so it's a DOUBLE byte char. \
* Return 2 characters written. \
*/ \
*pMBStr = HIBYTE(mbChar); \
*(pMBStr + 1) = LOBYTE(mbChar); \
NumByte = 2; \
} \
} \
else \
{ \
/* \
* High Byte IS zero, so it's a SINGLE byte char. \
* Return 1 character written. \
*/ \
*pMBStr = LOBYTE(mbChar); \
NumByte = 1; \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_SB
//
// Fills in pMBStr with the single byte character for the corresponding
// wide character from the appropriate translation table.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_SB( pWC, \
wChar, \
pMBStr ) \
{ \
*pMBStr = ((BYTE *)(pWC))[wChar]; \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_MB
//
// Fills in pMBStr with the multi byte character for the corresponding
// wide character from the appropriate translation table.
//
// mbCount will be 0 if the buffer is too small for the translation.
//
// Broken Down Version:
// --------------------
// mbChar = ((WORD *)(pHashN->pWC))[wChar];
// COPY_MB_CHAR(mbChar, pMBStr, mbCount);
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_MB( pWC, \
wChar, \
pMBStr, \
mbCount, \
fOnlyOne ) \
{ \
COPY_MB_CHAR( ((WORD *)(pWC))[wChar], \
pMBStr, \
mbCount, \
fOnlyOne ); \
}
////////////////////////////////////////////////////////////////////////////
//
// ELIMINATE_BEST_FIT_SB
//
// Checks to see if a single byte Best Fit character was used. If so,
// it replaces it with a single byte default character.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define ELIMINATE_BEST_FIT_SB( pHashN, \
wChar, \
pMBStr ) \
{ \
if ((pHashN->pMBTbl)[*pMBStr] != wChar) \
{ \
*pMBStr = LOBYTE(pHashN->pCPInfo->wDefaultChar); \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// ELIMINATE_BEST_FIT_MB
//
// Checks to see if a multi byte Best Fit character was used. If so,
// it replaces it with a multi byte default character.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define ELIMINATE_BEST_FIT_MB( pHashN, \
wChar, \
pMBStr, \
mbCount, \
fOnlyOne ) \
{ \
WORD Offset; \
WORD wDefault; \
\
if (((mbCount == 1) && ((pHashN->pMBTbl)[*pMBStr] != wChar)) || \
((mbCount == 2) && \
(Offset = CHECK_DBCS_LEAD_BYTE(pHashN->pDBCSOffsets, *pMBStr)) && \
(((pHashN->pDBCSOffsets + Offset)[*(pMBStr + 1)]) != wChar))) \
{ \
wDefault = pHashN->pCPInfo->wDefaultChar; \
if (HIBYTE(wDefault)) \
{ \
if (fOnlyOne) \
{ \
mbCount = 0; \
} \
else \
{ \
*pMBStr = HIBYTE(wDefault); \
*(pMBStr + 1) = LOBYTE(wDefault); \
mbCount = 2; \
} \
} \
else \
{ \
*pMBStr = LOBYTE(wDefault); \
mbCount = 1; \
} \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_DEFAULT_WORD
//
// Takes a pointer to a character string (either one or two characters),
// and converts it to a WORD value. If the character is not DBCS, then it
// zero extends the high byte.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_DEFAULT_WORD(pOff, pDefault) \
(CHECK_DBCS_LEAD_BYTE(pOff, *pDefault) \
? MAKEWORD(*(pDefault + 1), *pDefault) \
: MAKEWORD(*pDefault, 0))
////////////////////////////////////////////////////////////////////////////
//
// DEFAULT_CHAR_CHECK_SB
//
// Checks to see if the default character is used. If it is, it sets
// pUsedDef to TRUE (if non-null). If the user specified a default, then
// the user's default character is used.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define DEFAULT_CHAR_CHECK_SB( pHashN, \
wch, \
pMBStr, \
wDefChar, \
pUsedDef ) \
{ \
WORD wSysDefChar = pHashN->pCPInfo->wDefaultChar; \
\
\
/* \
* Check for default character being used. \
*/ \
if ((*pMBStr == (BYTE)wSysDefChar) && \
(wch != pHashN->pCPInfo->wTransDefaultChar)) \
{ \
/* \
* Default was used. Set the pUsedDef parameter to TRUE. \
*/ \
*pUsedDef = TRUE; \
\
/* \
* If the user specified a different default character than \
* the system default, use that character instead. \
*/ \
if (wSysDefChar != wDefChar) \
{ \
*pMBStr = LOBYTE(wDefChar); \
} \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// DEFAULT_CHAR_CHECK_MB
//
// Checks to see if the default character is used. If it is, it sets
// pUsedDef to TRUE (if non-null). If the user specified a default, then
// the user's default character is used. The number of bytes written to
// the buffer is returned.
//
// NumByte will be -1 if the buffer is too small for the translation.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define DEFAULT_CHAR_CHECK_MB( pHashN, \
wch, \
pMBStr, \
wDefChar, \
pUsedDef, \
NumByte, \
fOnlyOne ) \
{ \
WORD wSysDefChar = pHashN->pCPInfo->wDefaultChar; \
\
\
/* \
* Set NumByte to zero for return (zero bytes written). \
*/ \
NumByte = 0; \
\
/* \
* Check for default character being used. \
*/ \
if ((*pMBStr == (BYTE)wSysDefChar) && \
(wch != pHashN->pCPInfo->wTransDefaultChar)) \
{ \
/* \
* Default was used. Set the pUsedDef parameter to TRUE. \
*/ \
*pUsedDef = TRUE; \
\
/* \
* If the user specified a different default character than \
* the system default, use that character instead. \
*/ \
if (wSysDefChar != wDefChar) \
{ \
COPY_MB_CHAR( wDefChar, \
pMBStr, \
NumByte, \
fOnlyOne ); \
if (NumByte == 0) \
{ \
NumByte = -1; \
} \
} \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_WC_TRANSLATION_SB
//
// Gets the 1:1 translation of a given wide character. It fills in the
// string pointer with the single byte character.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_WC_TRANSLATION_SB( pHashN, \
wch, \
pMBStr, \
wDefault, \
pUsedDef, \
dwFlags ) \
{ \
GET_SB( pHashN->pWC, \
wch, \
pMBStr ); \
if (dwFlags & WC_NO_BEST_FIT_CHARS) \
{ \
ELIMINATE_BEST_FIT_SB( pHashN, \
wch, \
pMBStr ); \
} \
DEFAULT_CHAR_CHECK_SB( pHashN, \
wch, \
pMBStr, \
wDefault, \
pUsedDef ); \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_WC_TRANSLATION_MB
//
// Gets the 1:1 translation of a given wide character. It fills in the
// appropriate number of characters for the multibyte character and then
// returns the number of characters written to the multibyte string.
//
// mbCnt will be 0 if the buffer is too small for the translation.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_WC_TRANSLATION_MB( pHashN, \
wch, \
pMBStr, \
wDefault, \
pUsedDef, \
mbCnt, \
fOnlyOne, \
dwFlags ) \
{ \
int mbCnt2; /* number of characters written */ \
\
\
GET_MB( pHashN->pWC, \
wch, \
pMBStr, \
mbCnt, \
fOnlyOne ); \
if (dwFlags & WC_NO_BEST_FIT_CHARS) \
{ \
ELIMINATE_BEST_FIT_MB( pHashN, \
wch, \
pMBStr, \
mbCnt, \
fOnlyOne ); \
} \
if (mbCnt) \
{ \
DEFAULT_CHAR_CHECK_MB( pHashN, \
wch, \
pMBStr, \
wDefault, \
pUsedDef, \
mbCnt2, \
fOnlyOne ); \
if (mbCnt2 == -1) \
{ \
mbCnt = 0; \
} \
else if (mbCnt2) \
{ \
mbCnt = mbCnt2; \
} \
} \
}
////////////////////////////////////////////////////////////////////////////
//
// GET_CP_HASH_NODE
//
// Sets the code page value (if a special value is passed in) and the
// hash node pointer. If the code page value is invalid, the pointer
// to the hash node will be set to NULL.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_CP_HASH_NODE( CodePage, \
pHashN ) \
{ \
PLOC_HASH pHashLoc; \
\
\
/* \
* Check for the ACP, OEMCP, or MACCP. Fill in the appropriate \
* value for the code page if one of these values is given. \
* Otherwise, just get the hash node for the given code page. \
*/ \
if (CodePage == gAnsiCodePage) \
{ \
pHashN = gpACPHashN; \
} \
else if (CodePage == gOemCodePage) \
{ \
pHashN = gpOEMCPHashN; \
} \
else if (CodePage == CP_ACP) \
{ \
CodePage = gAnsiCodePage; \
pHashN = gpACPHashN; \
} \
else if (CodePage == CP_OEMCP) \
{ \
CodePage = gOemCodePage; \
pHashN = gpOEMCPHashN; \
} \
else if (CodePage == CP_SYMBOL) \
{ \
pHashN = NULL; \
} \
else if (CodePage == CP_MACCP) \
{ \
CodePage = GetMacCodePage(); \
pHashN = gpMACCPHashN; \
} \
else if (CodePage == CP_THREAD_ACP) \
{ \
VALIDATE_LOCALE(NtCurrentTeb()->CurrentLocale, pHashLoc, FALSE); \
if (pHashLoc != NULL) \
{ \
CodePage = pHashLoc->pLocaleFixed->DefaultACP; \
} \
if (CodePage == CP_ACP) \
{ \
CodePage = gAnsiCodePage; \
pHashN = gpACPHashN; \
} \
else if (CodePage == CP_OEMCP) \
{ \
CodePage = gOemCodePage; \
pHashN = gpOEMCPHashN; \
} \
else if (CodePage == CP_MACCP) \
{ \
CodePage = GetMacCodePage(); \
pHashN = gpMACCPHashN; \
} \
else \
{ \
pHashN = GetCPHashNode(CodePage); \
} \
} \
else \
{ \
pHashN = GetCPHashNode(CodePage); \
} \
}
//-------------------------------------------------------------------------//
// API ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// IsValidCodePage
//
// Checks that the given code page is a valid one. It does so by querying
// the registry. If the code page is found, then TRUE is returned.
// Otherwise, FALSE is returned.
//
// 05-31-1991 JulieB Created.
// 05-31-2002 ShawnSte Make it not force the loading of the code page
////////////////////////////////////////////////////////////////////////////
BOOL WINAPI IsValidCodePage(
UINT CodePage)
{
//
// Do not allow special code page values to be valid here.
// (CP_ACP, CP_OEMCP, CP_MACCP, CP_THREAD_ACP, CP_SYMBOL are invalid)
//
//
// Do the quick check for the code page value equal to either
// the Ansi code page value or the OEM code page value.
//
if ((CodePage == gAnsiCodePage) || (CodePage == gOemCodePage) ||
(CodePage == CP_UTF7) || (CodePage == CP_UTF8))
{
//
// Return success.
//
return (TRUE);
}
//
// Check for other code page values.
//
// If a node already exists, then we're OK
if (IsCPHashNodeLoaded(CodePage) == TRUE)
{
//
// Return success.
//
return (TRUE);
}
//
// Hash node doesn't exist. Have to look in the registry.
// True if this works, false if it doesn't
//
return GetCPFileNameFromRegistry(CodePage, NULL, 0);
}
////////////////////////////////////////////////////////////////////////////
//
// GetACP
//
// Returns the ANSI code page for the system. If the registry value is
// not readable, then the chosen default ACP is used (NLS_DEFAULT_ACP).
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
UINT WINAPI GetACP()
{
//
// Return the ACP stored in the cache.
//
return (gAnsiCodePage);
}
////////////////////////////////////////////////////////////////////////////
//
// SetCPGlobal
//
// Sets the code page global, used by Setup to force the code page into
// the correct value during GUI mode.
//
// 02-15-99 JimSchm Created.
////////////////////////////////////////////////////////////////////////////
UINT
WINAPI
SetCPGlobal (
IN UINT NewAcp
)
{
UINT oldVal;
oldVal = gAnsiCodePage;
//
// Sets the ACP global. This is a private exported routine, not an API.
//
gAnsiCodePage = NewAcp;
return oldVal;
}
////////////////////////////////////////////////////////////////////////////
//
// GetOEMCP
//
// Returns the OEM code page for the system. If the registry value is
// not readable, then the chosen default ACP is used (NLS_DEFAULT_OEMCP).
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
UINT WINAPI GetOEMCP()
{
//
// Return the OEMCP stored in the cache.
//
return (gOemCodePage);
}
////////////////////////////////////////////////////////////////////////////
//
// GetCPInfo
//
// Returns information about a given code page.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL WINAPI GetCPInfo(
UINT CodePage,
LPCPINFO lpCPInfo)
{
PCP_HASH pHashN; // ptr to CP hash node
PCP_TABLE pInfo; // ptr to CP information in file
WORD wDefChar; // default character
BYTE *pLeadBytes; // ptr to lead byte ranges
UINT Ctr; // loop counter
//
// See if it's a special code page value for UTF translations.
//
if (CodePage >= NLS_CP_ALGORITHM_RANGE)
{
return (UTFCPInfo(CodePage, lpCPInfo, FALSE));
}
//
// Get the code page value and the appropriate hash node.
//
GET_CP_HASH_NODE(CodePage, pHashN);
//
// Invalid Parameter Check:
// - validate code page - get hash node containing translation tables
// - lpCPInfo is NULL
//
if ( (pHashN == NULL) ||
((pHashN->pCPInfo == NULL) && (pHashN->pfnCPProc == NULL)) ||
(lpCPInfo == NULL) )
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// See if the given code page is in the DLL range.
//
if (pHashN->pfnCPProc)
{
//
// Call the DLL to get the code page information.
//
return ( (*(pHashN->pfnCPProc))( CodePage,
NLS_CP_CPINFO,
NULL,
0,
NULL,
0,
lpCPInfo ) );
}
//
// Fill in the CPINFO structure with the appropriate information.
//
pInfo = pHashN->pCPInfo;
//
// Get the max char size.
//
lpCPInfo->MaxCharSize = (UINT)((WORD)pInfo->MaxCharSize);
//
// Get the default character.
//
wDefChar = pInfo->wDefaultChar;
if (HIBYTE(wDefChar))
{
(lpCPInfo->DefaultChar)[0] = HIBYTE(wDefChar);
(lpCPInfo->DefaultChar)[1] = LOBYTE(wDefChar);
}
else
{
(lpCPInfo->DefaultChar)[0] = LOBYTE(wDefChar);
(lpCPInfo->DefaultChar)[1] = (BYTE)0;
}
//
// Get the leadbytes.
//
pLeadBytes = pInfo->LeadByte;
for (Ctr = 0; Ctr < MAX_LEADBYTES; Ctr++)
{
(lpCPInfo->LeadByte)[Ctr] = pLeadBytes[Ctr];
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// GetCPInfoExW
//
// Returns information about a given code page.
//
// 11-15-96 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL WINAPI GetCPInfoExW(
UINT CodePage,
DWORD dwFlags,
LPCPINFOEXW lpCPInfoEx)
{
PCP_HASH pHashN; // ptr to CP hash node
PCP_TABLE pInfo; // ptr to CP information in file
WORD wDefChar; // default character
BYTE *pLeadBytes; // ptr to lead byte ranges
UINT Ctr; // loop counter
//
// See if it's a special code page value for UTF translations.
//
if (CodePage >= NLS_CP_ALGORITHM_RANGE)
{
if (UTFCPInfo(CodePage, (LPCPINFO)lpCPInfoEx, TRUE))
{
if (GetStringTableEntry( CodePage,
0,
lpCPInfoEx->CodePageName,
MAX_PATH,
RC_CODE_PAGE_NAME ) != 0)
{
return (TRUE);
}
}
return (FALSE);
}
//
// Get the code page value and the appropriate hash node.
//
GET_CP_HASH_NODE(CodePage, pHashN);
//
// Invalid Parameter Check:
// - validate code page - get hash node containing translation tables
// - lpCPInfoEx is NULL
//
if ( (pHashN == NULL) ||
((pHashN->pCPInfo == NULL) && (pHashN->pfnCPProc == NULL)) ||
(lpCPInfoEx == NULL) )
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Invalid Flags Check:
// - flags not 0
//
if (dwFlags != 0)
{
SetLastError(ERROR_INVALID_FLAGS);
return (FALSE);
}
//
// See if the given code page is in the DLL range.
//
if (pHashN->pfnCPProc)
{
//
// Call the DLL to get the code page information.
//
if (((*(pHashN->pfnCPProc))( CodePage,
NLS_CP_CPINFOEX,
NULL,
0,
NULL,
0,
(LPCPINFO)lpCPInfoEx )) == TRUE)
{
return (TRUE);
}
else
{
//
// See if the CPINFO will succeed. If so, then add the
// default CPINFOEX info to the structure.
//
if (((*(pHashN->pfnCPProc))( CodePage,
NLS_CP_CPINFO,
NULL,
0,
NULL,
0,
(LPCPINFO)lpCPInfoEx )) == TRUE)
{
//
// Fill in the Ex version info.
//
lpCPInfoEx->UnicodeDefaultChar = L'?';
lpCPInfoEx->CodePage = CodePage;
GetStringTableEntry( CodePage,
0,
lpCPInfoEx->CodePageName,
MAX_PATH,
RC_CODE_PAGE_NAME );
SetLastError(NO_ERROR);
return (TRUE);
}
return (FALSE);
}
}
//
// Fill in the CPINFO structure with the appropriate information.
//
pInfo = pHashN->pCPInfo;
//
// Get the max char size.
//
lpCPInfoEx->MaxCharSize = (UINT)((WORD)pInfo->MaxCharSize);
//
// Get the default character.
//
wDefChar = pInfo->wDefaultChar;
if (HIBYTE(wDefChar))
{
(lpCPInfoEx->DefaultChar)[0] = HIBYTE(wDefChar);
(lpCPInfoEx->DefaultChar)[1] = LOBYTE(wDefChar);
}
else
{
(lpCPInfoEx->DefaultChar)[0] = LOBYTE(wDefChar);
(lpCPInfoEx->DefaultChar)[1] = (BYTE)0;
}
//
// Get the leadbytes.
//
pLeadBytes = pInfo->LeadByte;
for (Ctr = 0; Ctr < MAX_LEADBYTES; Ctr++)
{
(lpCPInfoEx->LeadByte)[Ctr] = pLeadBytes[Ctr];
}
//
// Get the Unicode default character.
//
lpCPInfoEx->UnicodeDefaultChar = pInfo->wUniDefaultChar;
//
// Get the code page id.
//
lpCPInfoEx->CodePage = CodePage;
//
// Get the code page name.
//
if (GetStringTableEntry( CodePage,
0,
lpCPInfoEx->CodePageName,
MAX_PATH,
RC_CODE_PAGE_NAME ) == 0)
{
return (FALSE);
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// IsDBCSLeadByte
//
// Checks to see if a given character is a DBCS lead byte in the ACP.
// Returns TRUE if it is, FALSE if it is not.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL WINAPI IsDBCSLeadByte(
BYTE TestChar)
{
//
// Get the hash node for the ACP.
//
if (gpACPHashN == NULL)
{
SetLastError(ERROR_FILE_NOT_FOUND);
return (FALSE);
}
//
// See if the given character is a DBCS lead byte.
//
if (CHECK_DBCS_LEAD_BYTE(gpACPHashN->pDBCSOffsets, TestChar))
{
//
// Return success - IS a DBCS lead byte.
//
return (TRUE);
}
//
// Return failure - is NOT a DBCS lead byte.
//
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// IsDBCSLeadByteEx
//
// Checks to see if a given character is a DBCS lead byte in the given
// code page. Returns TRUE if it is, FALSE if it is not.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL WINAPI IsDBCSLeadByteEx(
UINT CodePage,
BYTE TestChar)
{
PCP_HASH pHashN; // ptr to CP hash node
//
// See if it's a special code page value for UTF translations.
//
if (CodePage >= NLS_CP_ALGORITHM_RANGE)
{
//
// Return that it's not a DBCS leadbyte.
//
return (FALSE);
}
//
// Get the code page value and the appropriate hash node.
//
GET_CP_HASH_NODE(CodePage, pHashN);
//
// Invalid Parameter Check:
// - validate code page
//
if (pHashN == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// See if the given character is a DBCS lead byte.
//
if (CHECK_DBCS_LEAD_BYTE(pHashN->pDBCSOffsets, TestChar))
{
//
// Return success - IS a DBCS lead byte.
//
return (TRUE);
}
//
// Return failure - is NOT a DBCS lead byte.
//
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// MultiByteToWideChar
//
// Maps a multibyte character string to its wide character string
// counterpart.
//
// 05-31-91 JulieB Created.
// 09-01-93 JulieB Add support for MB_ERR_INVALID_CHARS flag.
////////////////////////////////////////////////////////////////////////////
int WINAPI MultiByteToWideChar(
UINT CodePage,
DWORD dwFlags,
LPCSTR lpMultiByteStr,
int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar)
{
PCP_HASH pHashN; // ptr to CP hash node
register LPBYTE pMBStr; // ptr to search through MB string
register LPWSTR pWCStr; // ptr to search through WC string
LPBYTE pEndMBStr; // ptr to end of MB search string
LPWSTR pEndWCStr; // ptr to end of WC string buffer
int wcIncr; // amount to increment pWCStr
int mbIncr; // amount to increment pMBStr
int wcCount = 0; // count of wide chars written
int CompSet; // if MB_COMPOSITE flag is set
PMB_TABLE pMBTbl; // ptr to correct MB table (MB or GLYPH)
int ctr; // loop counter
//
// See if it's a special code page value for UTF translations.
//
if (CodePage >= NLS_CP_ALGORITHM_RANGE)
{
return (UTFToUnicode( CodePage,
dwFlags,
lpMultiByteStr,
cbMultiByte,
lpWideCharStr,
cchWideChar ));
}
//
// Get the code page value and the appropriate hash node.
//
GET_CP_HASH_NODE(CodePage, pHashN);
//
// Invalid Parameter Check:
// - length of MB string is 0
// - wide char buffer size is negative
// - MB string is NULL
// - length of WC string is NOT zero AND
// (WC string is NULL OR src and dest pointers equal)
//
if ( (cbMultiByte == 0) || (cchWideChar < 0) ||
(lpMultiByteStr == NULL) ||
((cchWideChar != 0) &&
((lpWideCharStr == NULL) ||
(lpMultiByteStr == (LPSTR)lpWideCharStr))) )
{
SetLastError(ERROR_INVALID_PARAMETER);
return (0);
}
//
// If cbMultiByte is -1, then the string is null terminated and we
// need to get the length of the string. Add one to the length to
// include the null termination. (This will always be at least 1.)
//
if (cbMultiByte <= -1)
{
cbMultiByte = strlen(lpMultiByteStr) + 1;
}
//
// Check for valid code page.
//
if (pHashN == NULL)
{
//
// Special case the CP_SYMBOL code page.
//
if ((CodePage == CP_SYMBOL) && (dwFlags == 0))
{
//
// If the caller just wants the size of the buffer needed
// to do this translation, return the size of the MB string.
//
if (cchWideChar == 0)
{
return (cbMultiByte);
}
//
// Make sure the buffer is large enough.
//
if (cchWideChar < cbMultiByte)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
//
// Translate SB char xx to Unicode f0xx.
// 0x00->0x1f map to 0x0000->0x001f
// 0x20->0xff map to 0xf020->0xf0ff
//
for (ctr = 0; ctr < cbMultiByte; ctr++)
{
lpWideCharStr[ctr] = ((BYTE)(lpMultiByteStr[ctr]) < 0x20)
? (WCHAR)lpMultiByteStr[ctr]
: MAKEWORD(lpMultiByteStr[ctr], 0xf0);
}
return (cbMultiByte);
}
else
{
SetLastError(((CodePage == CP_SYMBOL) && (dwFlags != 0))
? ERROR_INVALID_FLAGS
: ERROR_INVALID_PARAMETER);
return (0);
}
}
//
// See if the given code page is in the DLL range.
//
if (pHashN->pfnCPProc)
{
//
// Invalid Flags Check:
// - flags not 0
//
if (dwFlags != 0)
{
SetLastError(ERROR_INVALID_FLAGS);
return (0);
}
//
// Call the DLL to do the translation.
//
return ( (*(pHashN->pfnCPProc))( CodePage,
NLS_CP_MBTOWC,
(LPSTR)lpMultiByteStr,
cbMultiByte,
(LPWSTR)lpWideCharStr,
cchWideChar,
NULL ) );
}
//
// Invalid Flags Check:
// - flags other than valid ones
// - composite and precomposed both set
//
if ( (dwFlags & MB_INVALID_FLAG) ||
((dwFlags & MB_PRECOMPOSED) && (dwFlags & MB_COMPOSITE)) )
{
SetLastError(ERROR_INVALID_FLAGS);
return (0);
}
//
// Initialize multibyte character loop pointers.
//
pMBStr = (LPBYTE)lpMultiByteStr;
pEndMBStr = pMBStr + cbMultiByte;
CompSet = dwFlags & MB_COMPOSITE;
//
// Get the correct MB table (MB or GLYPH).
//
if ((dwFlags & MB_USEGLYPHCHARS) && (pHashN->pGlyphTbl != NULL))
{
pMBTbl = pHashN->pGlyphTbl;
}
else
{
pMBTbl = pHashN->pMBTbl;
}
//
// If cchWideChar is 0, then we can't use lpWideCharStr. In this
// case, we simply want to count the number of characters that would
// be written to the buffer.
//
if (cchWideChar == 0)
{
WCHAR pTempStr[MAX_COMPOSITE]; // tmp buffer - max for composite
//
// For each multibyte char, translate it to its corresponding
// wide char and increment the wide character count.
//
pEndWCStr = pTempStr + MAX_COMPOSITE;
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
if (CompSet)
{
//
// Composite flag is set.
//
if (dwFlags & MB_ERR_INVALID_CHARS)
{
//
// Error check flag is set.
//
while (pMBStr < pEndMBStr)
{
if (!(wcIncr = GetWCCompSBErr( pHashN,
pMBTbl,
pMBStr,
pTempStr,
pEndWCStr )))
{
return (0);
}
pMBStr++;
wcCount += wcIncr;
}
}
else
{
//
// Error check flag is NOT set.
//
while (pMBStr < pEndMBStr)
{
wcCount += GetWCCompSB( pMBTbl,
pMBStr,
pTempStr,
pEndWCStr );
pMBStr++;
}
}
}
else
{
//
// Composite flag is NOT set.
//
if (dwFlags & MB_ERR_INVALID_CHARS)
{
//
// Error check flag is set.
//
wcCount = (int)(pEndMBStr - pMBStr);
while (pMBStr < pEndMBStr)
{
GET_WC_SINGLE( pMBTbl,
pMBStr,
pTempStr );
CHECK_ERROR_WC_SINGLE( pHashN,
*pTempStr,
*pMBStr );
pMBStr++;
}
}
else
{
//
// Error check flag is NOT set.
//
// Just return the size of the MB string, since
// it's a 1:1 translation.
//
wcCount = (int)(pEndMBStr - pMBStr);
}
}
}
else
{
//
// Multi Byte Character Code Page.
//
if (CompSet)
{
//
// Composite flag is set.
//
if (dwFlags & MB_ERR_INVALID_CHARS)
{
//
// Error check flag is set.
//
while (pMBStr < pEndMBStr)
{
if (!(wcIncr = GetWCCompMBErr( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pTempStr,
pEndWCStr,
&mbIncr )))
{
return (0);
}
pMBStr += mbIncr;
wcCount += wcIncr;
}
}
else
{
//
// Error check flag is NOT set.
//
while (pMBStr < pEndMBStr)
{
wcCount += GetWCCompMB( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pTempStr,
pEndWCStr,
&mbIncr );
pMBStr += mbIncr;
}
}
}
else
{
//
// Composite flag is NOT set.
//
if (dwFlags & MB_ERR_INVALID_CHARS)
{
//
// Error check flag is set.
//
while (pMBStr < pEndMBStr)
{
GET_WC_MULTI_ERR( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pTempStr,
pEndWCStr,
mbIncr );
pMBStr += mbIncr;
wcCount++;
}
}
else
{
//
// Error check flag is NOT set.
//
while (pMBStr < pEndMBStr)
{
GET_WC_MULTI( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pTempStr,
pEndWCStr,
mbIncr );
pMBStr += mbIncr;
wcCount++;
}
}
}
}
}
else
{
//
// Initialize wide character loop pointers.
//
pWCStr = lpWideCharStr;
pEndWCStr = pWCStr + cchWideChar;
//
// For each multibyte char, translate it to its corresponding
// wide char, store it in lpWideCharStr, and increment the wide
// character count.
//
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
if (CompSet)
{
//
// Composite flag is set.
//
if (dwFlags & MB_ERR_INVALID_CHARS)
{
//
// Error check flag is set.
//
while ((pMBStr < pEndMBStr) && (pWCStr < pEndWCStr))
{
if (!(wcIncr = GetWCCompSBErr( pHashN,
pMBTbl,
pMBStr,
pWCStr,
pEndWCStr )))
{
return (0);
}
pMBStr++;
pWCStr += wcIncr;
}
wcCount = (int)(pWCStr - lpWideCharStr);
}
else
{
//
// Error check flag is NOT set.
//
while ((pMBStr < pEndMBStr) && (pWCStr < pEndWCStr))
{
pWCStr += GetWCCompSB( pMBTbl,
pMBStr,
pWCStr,
pEndWCStr );
pMBStr++;
}
wcCount = (int)(pWCStr - lpWideCharStr);
}
}
else
{
//
// Composite flag is NOT set.
//
if (dwFlags & MB_ERR_INVALID_CHARS)
{
//
// Error check flag is set.
//
wcCount = (int)(pEndMBStr - pMBStr);
if ((pEndWCStr - pWCStr) < wcCount)
{
wcCount = (int)(pEndWCStr - pWCStr);
}
for (ctr = wcCount; ctr > 0; ctr--)
{
GET_WC_SINGLE( pMBTbl,
pMBStr,
pWCStr );
CHECK_ERROR_WC_SINGLE( pHashN,
*pWCStr,
*pMBStr );
pMBStr++;
pWCStr++;
}
}
else
{
//
// Error check flag is NOT set.
//
wcCount = (int)(pEndMBStr - pMBStr);
if ((pEndWCStr - pWCStr) < wcCount)
{
wcCount = (int)(pEndWCStr - pWCStr);
}
for (ctr = wcCount; ctr > 0; ctr--)
{
GET_WC_SINGLE( pMBTbl,
pMBStr,
pWCStr );
pMBStr++;
pWCStr++;
}
}
}
}
else
{
//
// Multi Byte Character Code Page.
//
if (CompSet)
{
//
// Composite flag is set.
//
if (dwFlags & MB_ERR_INVALID_CHARS)
{
//
// Error check flag is set.
//
while ((pMBStr < pEndMBStr) && (pWCStr < pEndWCStr))
{
if (!(wcIncr = GetWCCompMBErr( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pWCStr,
pEndWCStr,
&mbIncr )))
{
return (0);
}
pMBStr += mbIncr;
pWCStr += wcIncr;
}
wcCount = (int)(pWCStr - lpWideCharStr);
}
else
{
//
// Error check flag is NOT set.
//
while ((pMBStr < pEndMBStr) && (pWCStr < pEndWCStr))
{
pWCStr += GetWCCompMB( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pWCStr,
pEndWCStr,
&mbIncr );
pMBStr += mbIncr;
}
wcCount = (int)(pWCStr - lpWideCharStr);
}
}
else
{
//
// Composite flag is NOT set.
//
if (dwFlags & MB_ERR_INVALID_CHARS)
{
//
// Error check flag is set.
//
while ((pMBStr < pEndMBStr) && (pWCStr < pEndWCStr))
{
GET_WC_MULTI_ERR( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pWCStr,
pEndWCStr,
mbIncr );
pMBStr += mbIncr;
pWCStr++;
}
wcCount = (int)(pWCStr - lpWideCharStr);
}
else
{
//
// Error check flag is NOT set.
//
while ((pMBStr < pEndMBStr) && (pWCStr < pEndWCStr))
{
GET_WC_MULTI( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pWCStr,
pEndWCStr,
mbIncr );
pMBStr += mbIncr;
pWCStr++;
}
wcCount = (int)(pWCStr - lpWideCharStr);
}
}
}
//
// Make sure wide character buffer was large enough.
//
if (pMBStr < pEndMBStr)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
}
//
// Return the number of characters written (or that would have
// been written) to the buffer.
//
return (wcCount);
}
////////////////////////////////////////////////////////////////////////////
//
// WideCharToMultiByte
//
// Maps a wide character string to its multibyte character string
// counterpart.
//
// NOTE: Most significant bit of dwFlags parameter is used by this routine
// to indicate that the caller only wants the count of the number of
// characters written, not the string (ie. do not back up in buffer).
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int WINAPI WideCharToMultiByte(
UINT CodePage,
DWORD dwFlags,
LPCWSTR lpWideCharStr,
int cchWideChar,
LPSTR lpMultiByteStr,
int cbMultiByte,
LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
PCP_HASH pHashN; // ptr to CP hash node
LPWSTR pWCStr; // ptr to search through WC string
LPWSTR pEndWCStr; // ptr to end of WC string buffer
WORD wDefault = 0; // default character as a word
int IfNoDefault; // if default check is to be made
int IfCompositeChk; // if check for composite
BOOL TmpUsed; // temp storage for default used
int ctr; // loop counter
//
// See if it's a special code page value for UTF translations.
//
if (CodePage >= NLS_CP_ALGORITHM_RANGE)
{
return (UnicodeToUTF( CodePage,
dwFlags,
lpWideCharStr,
cchWideChar,
lpMultiByteStr,
cbMultiByte,
lpDefaultChar,
lpUsedDefaultChar ));
}
//
// Get the code page value and the appropriate hash node.
//
GET_CP_HASH_NODE(CodePage, pHashN);
//
// Invalid Parameter Check:
// - length of WC string is 0
// - multibyte buffer size is negative
// - WC string is NULL
// - length of WC string is NOT zero AND
// (MB string is NULL OR src and dest pointers equal)
//
if ( (cchWideChar == 0) || (cbMultiByte < 0) ||
(lpWideCharStr == NULL) ||
((cbMultiByte != 0) &&
((lpMultiByteStr == NULL) ||
(lpWideCharStr == (LPWSTR)lpMultiByteStr))) )
{
SetLastError(ERROR_INVALID_PARAMETER);
return (0);
}
//
// If cchWideChar is -1, then the string is null terminated and we
// need to get the length of the string. Add one to the length to
// include the null termination. (This will always be at least 1.)
//
if (cchWideChar <= -1)
{
cchWideChar = NlsStrLenW(lpWideCharStr) + 1;
}
//
// Check for valid code page.
//
if (pHashN == NULL)
{
//
// Special case the CP_SYMBOL code page.
//
if ((CodePage == CP_SYMBOL) && (dwFlags == 0) &&
(lpDefaultChar == NULL) && (lpUsedDefaultChar == NULL))
{
//
// If the caller just wants the size of the buffer needed
// to do this translation, return the size of the MB string.
//
if (cbMultiByte == 0)
{
return (cchWideChar);
}
//
// Make sure the buffer is large enough.
//
if (cbMultiByte < cchWideChar)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
//
// Translate Unicode char f0xx to SB xx.
// 0x0000->0x001f map to 0x00->0x1f
// 0xf020->0xf0ff map to 0x20->0xff
//
for (ctr = 0; ctr < cchWideChar; ctr++)
{
if ((lpWideCharStr[ctr] >= 0x0020) &&
((lpWideCharStr[ctr] < 0xf020) ||
(lpWideCharStr[ctr] > 0xf0ff)))
{
SetLastError(ERROR_NO_UNICODE_TRANSLATION); \
return (0);
}
lpMultiByteStr[ctr] = (BYTE)lpWideCharStr[ctr];
}
return (cchWideChar);
}
else
{
SetLastError(((CodePage == CP_SYMBOL) && (dwFlags != 0))
? ERROR_INVALID_FLAGS
: ERROR_INVALID_PARAMETER);
return (0);
}
}
//
// See if the given code page is in the DLL range.
//
if (pHashN->pfnCPProc)
{
//
// Invalid Parameter Check:
// - lpDefaultChar not NULL
// - lpUsedDefaultChar not NULL
//
if ((lpDefaultChar != NULL) || (lpUsedDefaultChar != NULL))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (0);
}
//
// Invalid Flags Check:
// - flags not 0
//
if (dwFlags != 0)
{
SetLastError(ERROR_INVALID_FLAGS);
return (0);
}
//
// Call the DLL to do the translation.
//
return ( (*(pHashN->pfnCPProc))( CodePage,
NLS_CP_WCTOMB,
(LPSTR)lpMultiByteStr,
cbMultiByte,
(LPWSTR)lpWideCharStr,
cchWideChar,
NULL ) );
}
//
// Invalid Flags Check:
// - compositechk flag is not set AND any of comp flags are set
// - flags other than valid ones
//
if ( ((!(IfCompositeChk = (dwFlags & WC_COMPOSITECHECK))) &&
(dwFlags & WC_COMPCHK_FLAGS)) ||
(dwFlags & WC_INVALID_FLAG) )
{
SetLastError(ERROR_INVALID_FLAGS);
return (0);
}
//
// Initialize wide character loop pointers.
//
pWCStr = (LPWSTR)lpWideCharStr;
pEndWCStr = pWCStr + cchWideChar;
//
// Set the IfNoDefault parameter to TRUE if both lpDefaultChar and
// lpUsedDefaultChar are NULL.
//
IfNoDefault = ((lpDefaultChar == NULL) && (lpUsedDefaultChar == NULL));
//
// If the composite check flag is NOT set AND both of the default
// parameters (lpDefaultChar and lpUsedDefaultChar) are null, then
// do the quick translation.
//
if (IfNoDefault && !IfCompositeChk)
{
//
// Translate WC string to MB string, ignoring default chars.
//
return (GetMBNoDefault( pHashN,
pWCStr,
pEndWCStr,
(LPBYTE)lpMultiByteStr,
cbMultiByte,
dwFlags ));
}
//
// Set the system default character.
//
wDefault = pHashN->pCPInfo->wDefaultChar;
//
// See if the default check is needed.
//
if (!IfNoDefault)
{
//
// If lpDefaultChar is NULL, then use the system default.
// Form a word out of the default character. Single byte
// characters are zero extended, DBCS characters are as is.
//
if (lpDefaultChar != NULL)
{
wDefault = GET_DEFAULT_WORD( pHashN->pDBCSOffsets,
(LPBYTE)lpDefaultChar );
}
//
// If lpUsedDefaultChar is NULL, then it won't be used later
// on if a default character is detected. Otherwise, we need
// to initialize it.
//
if (lpUsedDefaultChar == NULL)
{
lpUsedDefaultChar = &TmpUsed;
}
*lpUsedDefaultChar = FALSE;
//
// Check for "composite check" flag.
//
if (!IfCompositeChk)
{
//
// Translate WC string to MB string, checking for the use of the
// default character.
//
return (GetMBDefault( pHashN,
pWCStr,
pEndWCStr,
(LPBYTE)lpMultiByteStr,
cbMultiByte,
wDefault,
lpUsedDefaultChar,
dwFlags ));
}
else
{
//
// Translate WC string to MB string, checking for the use of the
// default character.
//
return (GetMBDefaultComp( pHashN,
pWCStr,
pEndWCStr,
(LPBYTE)lpMultiByteStr,
cbMultiByte,
wDefault,
lpUsedDefaultChar,
dwFlags ));
}
}
else
{
//
// The only case left here is that the Composite check
// flag IS set and the default check flag is NOT set.
//
// Translate WC string to MB string, checking for the use of the
// default character.
//
return (GetMBDefaultComp( pHashN,
pWCStr,
pEndWCStr,
(LPBYTE)lpMultiByteStr,
cbMultiByte,
wDefault,
&TmpUsed,
dwFlags ));
}
}
//-------------------------------------------------------------------------//
// INTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// GetWCCompSB
//
// Fills in pWCStr with the wide character(s) for the corresponding single
// byte character from the appropriate translation table and returns the
// number of wide characters written. This routine should only be called
// when the precomposed forms need to be translated to composite.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetWCCompSB(
PMB_TABLE pMBTbl,
LPBYTE pMBStr,
LPWSTR pWCStr,
LPWSTR pEndWCStr)
{
//
// Get the single byte to wide character translation.
//
GET_WC_SINGLE(pMBTbl, pMBStr, pWCStr);
//
// Fill in the composite form of the character (if one exists)
// and return the number of wide characters written.
//
return (InsertCompositeForm(pWCStr, pEndWCStr));
}
////////////////////////////////////////////////////////////////////////////
//
// GetWCCompMB
//
// Fills in pWCStr with the wide character(s) for the corresponding multibyte
// character from the appropriate translation table and returns the number
// of wide characters written. The number of bytes used from the pMBStr
// buffer (single byte or double byte) is returned in the mbIncr parameter.
// This routine should only be called when the precomposed forms need to be
// translated to composite.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetWCCompMB(
PCP_HASH pHashN,
PMB_TABLE pMBTbl,
LPBYTE pMBStr,
LPBYTE pEndMBStr,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
int *pmbIncr)
{
//
// Get the multibyte to wide char translation.
//
GET_WC_MULTI( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pWCStr,
pEndWCStr,
*pmbIncr );
//
// Fill in the composite form of the character (if one exists)
// and return the number of wide characters written.
//
return (InsertCompositeForm(pWCStr, pEndWCStr));
}
////////////////////////////////////////////////////////////////////////////
//
// GetWCCompSBErr
//
// Fills in pWCStr with the wide character(s) for the corresponding single
// byte character from the appropriate translation table and returns the
// number of wide characters written. This routine should only be called
// when the precomposed forms need to be translated to composite.
//
// Checks to be sure an invalid character is not translated to the default
// character. If so, it sets last error and returns 0 characters written.
//
// 09-01-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetWCCompSBErr(
PCP_HASH pHashN,
PMB_TABLE pMBTbl,
LPBYTE pMBStr,
LPWSTR pWCStr,
LPWSTR pEndWCStr)
{
//
// Get the single byte to wide character translation.
//
GET_WC_SINGLE(pMBTbl, pMBStr, pWCStr);
//
// Make sure an invalid character was not translated to the
// default char. If it was, set last error and return 0
// characters written.
//
CHECK_ERROR_WC_SINGLE(pHashN, *pWCStr, *pMBStr);
//
// Fill in the composite form of the character (if one exists)
// and return the number of wide characters written.
//
return (InsertCompositeForm(pWCStr, pEndWCStr));
}
////////////////////////////////////////////////////////////////////////////
//
// GetWCCompMBErr
//
// Fills in pWCStr with the wide character(s) for the corresponding multibyte
// character from the appropriate translation table and returns the number
// of wide characters written. The number of bytes used from the pMBStr
// buffer (single byte or double byte) is returned in the mbIncr parameter.
// This routine should only be called when the precomposed forms need to be
// translated to composite.
//
// Checks to be sure an invalid character is not translated to the default
// character. If so, it sets last error and returns 0 characters written.
//
// 09-01-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetWCCompMBErr(
PCP_HASH pHashN,
PMB_TABLE pMBTbl,
LPBYTE pMBStr,
LPBYTE pEndMBStr,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
int *pmbIncr)
{
//
// Get the multibyte to wide char translation.
//
// Make sure an invalid character was not translated to the
// default char. If it was, set last error and return 0
// characters written.
//
GET_WC_MULTI_ERR( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pWCStr,
pEndWCStr,
*pmbIncr );
//
// Fill in the composite form of the character (if one exists)
// and return the number of wide characters written.
//
return (InsertCompositeForm(pWCStr, pEndWCStr));
}
////////////////////////////////////////////////////////////////////////////
//
// GetMBNoDefault
//
// Translates the wide character string to a multibyte string and returns
// the number of bytes written.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetMBNoDefault(
PCP_HASH pHashN,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
LPBYTE pMBStr,
int cbMultiByte,
DWORD dwFlags)
{
int mbIncr; // amount to increment pMBStr
int mbCount = 0; // count of multibyte chars written
LPBYTE pEndMBStr; // ptr to end of MB string buffer
PWC_TABLE pWC = pHashN->pWC; // ptr to WC table
int ctr; // loop counter
//
// If cbMultiByte is 0, then we can't use pMBStr. In this
// case, we simply want to count the number of characters that
// would be written to the buffer.
//
if (cbMultiByte == 0)
{
BYTE pTempStr[2]; // tmp buffer - 2 bytes for DBCS
//
// For each wide char, translate it to its corresponding multibyte
// char and increment the multibyte character count.
//
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
// Just return the count of characters - it will be the
// same number of characters as the source string.
//
mbCount = (int)(pEndWCStr - pWCStr);
}
else
{
//
// Multi Byte Character Code Page.
//
if (dwFlags & WC_NO_BEST_FIT_CHARS)
{
while (pWCStr < pEndWCStr)
{
GET_MB( pWC,
*pWCStr,
pTempStr,
mbIncr,
FALSE );
ELIMINATE_BEST_FIT_MB( pHashN,
*pWCStr,
pTempStr,
mbIncr,
FALSE );
pWCStr++;
mbCount += mbIncr;
}
}
else
{
while (pWCStr < pEndWCStr)
{
GET_MB( pWC,
*pWCStr,
pTempStr,
mbIncr,
FALSE );
pWCStr++;
mbCount += mbIncr;
}
}
}
}
else
{
//
// Initialize multibyte loop pointers.
//
pEndMBStr = pMBStr + cbMultiByte;
//
// For each wide char, translate it to its corresponding
// multibyte char, store it in pMBStr, and increment the
// multibyte character count.
//
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
mbCount = (int)(pEndWCStr - pWCStr);
if ((pEndMBStr - pMBStr) < mbCount)
{
mbCount = (int)(pEndMBStr - pMBStr);
}
if (dwFlags & WC_NO_BEST_FIT_CHARS)
{
for (ctr = mbCount; ctr > 0; ctr--)
{
GET_SB( pWC,
*pWCStr,
pMBStr );
ELIMINATE_BEST_FIT_SB( pHashN,
*pWCStr,
pMBStr );
pWCStr++;
pMBStr++;
}
}
else
{
for (ctr = mbCount; ctr > 0; ctr--)
{
GET_SB( pWC,
*pWCStr,
pMBStr );
pWCStr++;
pMBStr++;
}
}
}
else
{
//
// Multi Byte Character Code Page.
//
if (dwFlags & WC_NO_BEST_FIT_CHARS)
{
while ((pWCStr < pEndWCStr) && (pMBStr < pEndMBStr))
{
GET_MB( pWC,
*pWCStr,
pMBStr,
mbIncr,
((pMBStr + 1) < pEndMBStr) ? FALSE : TRUE );
ELIMINATE_BEST_FIT_MB( pHashN,
*pWCStr,
pMBStr,
mbIncr,
((pMBStr + 1) < pEndMBStr) ? FALSE : TRUE );
if (mbIncr == 0)
{
//
// Not enough space in buffer.
//
break;
}
pWCStr++;
mbCount += mbIncr;
pMBStr += mbIncr;
}
}
else
{
while ((pWCStr < pEndWCStr) && (pMBStr < pEndMBStr))
{
GET_MB( pWC,
*pWCStr,
pMBStr,
mbIncr,
((pMBStr + 1) < pEndMBStr) ? FALSE : TRUE );
if (mbIncr == 0)
{
//
// Not enough space in buffer.
//
break;
}
pWCStr++;
mbCount += mbIncr;
pMBStr += mbIncr;
}
}
}
//
// Make sure multibyte character buffer was large enough.
//
if (pWCStr < pEndWCStr)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
}
//
// Return the number of characters written (or that would have
// been written) to the buffer.
//
return (mbCount);
}
////////////////////////////////////////////////////////////////////////////
//
// GetMBDefault
//
// Translates the wide character string to a multibyte string and returns
// the number of bytes written. This also checks for the use of the default
// character, so the translation is slower.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetMBDefault(
PCP_HASH pHashN,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
LPBYTE pMBStr,
int cbMultiByte,
WORD wDefault,
LPBOOL pUsedDef,
DWORD dwFlags)
{
int mbIncr; // amount to increment pMBStr
int mbIncr2; // amount to increment pMBStr
int mbCount = 0; // count of multibyte chars written
LPBYTE pEndMBStr; // ptr to end of MB string buffer
PWC_TABLE pWC = pHashN->pWC; // ptr to WC table
int ctr; // loop counter
//
// If cbMultiByte is 0, then we can't use pMBStr. In this
// case, we simply want to count the number of characters that
// would be written to the buffer.
//
if (cbMultiByte == 0)
{
BYTE pTempStr[2]; // tmp buffer - 2 bytes for DBCS
//
// For each wide char, translate it to its corresponding multibyte
// char and increment the multibyte character count.
//
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
mbCount = (int)(pEndWCStr - pWCStr);
if (dwFlags & WC_NO_BEST_FIT_CHARS)
{
while (pWCStr < pEndWCStr)
{
GET_SB( pWC,
*pWCStr,
pTempStr );
ELIMINATE_BEST_FIT_SB( pHashN,
*pWCStr,
pTempStr );
DEFAULT_CHAR_CHECK_SB( pHashN,
*pWCStr,
pTempStr,
wDefault,
pUsedDef );
pWCStr++;
}
}
else
{
while (pWCStr < pEndWCStr)
{
GET_SB( pWC,
*pWCStr,
pTempStr );
DEFAULT_CHAR_CHECK_SB( pHashN,
*pWCStr,
pTempStr,
wDefault,
pUsedDef );
pWCStr++;
}
}
}
else
{
//
// Multi Byte Character Code Page.
//
if (dwFlags & WC_NO_BEST_FIT_CHARS)
{
while (pWCStr < pEndWCStr)
{
GET_MB( pWC,
*pWCStr,
pTempStr,
mbIncr,
FALSE );
ELIMINATE_BEST_FIT_MB( pHashN,
*pWCStr,
pTempStr,
mbIncr,
FALSE );
DEFAULT_CHAR_CHECK_MB( pHashN,
*pWCStr,
pTempStr,
wDefault,
pUsedDef,
mbIncr2,
FALSE );
mbCount += (mbIncr2) ? (mbIncr2) : (mbIncr);
pWCStr++;
}
}
else
{
while (pWCStr < pEndWCStr)
{
GET_MB( pWC,
*pWCStr,
pTempStr,
mbIncr,
FALSE );
DEFAULT_CHAR_CHECK_MB( pHashN,
*pWCStr,
pTempStr,
wDefault,
pUsedDef,
mbIncr2,
FALSE );
mbCount += (mbIncr2) ? (mbIncr2) : (mbIncr);
pWCStr++;
}
}
}
}
else
{
//
// Initialize multibyte loop pointers.
//
pEndMBStr = pMBStr + cbMultiByte;
//
// For each wide char, translate it to its corresponding
// multibyte char, store it in pMBStr, and increment the
// multibyte character count.
//
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
mbCount = (int)(pEndWCStr - pWCStr);
if ((pEndMBStr - pMBStr) < mbCount)
{
mbCount = (int)(pEndMBStr - pMBStr);
}
if (dwFlags & WC_NO_BEST_FIT_CHARS)
{
for (ctr = mbCount; ctr > 0; ctr--)
{
GET_SB( pWC,
*pWCStr,
pMBStr );
ELIMINATE_BEST_FIT_SB( pHashN,
*pWCStr,
pMBStr );
DEFAULT_CHAR_CHECK_SB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef );
pWCStr++;
pMBStr++;
}
}
else
{
for (ctr = mbCount; ctr > 0; ctr--)
{
GET_SB( pWC,
*pWCStr,
pMBStr );
DEFAULT_CHAR_CHECK_SB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef );
pWCStr++;
pMBStr++;
}
}
}
else
{
//
// Multi Byte Character Code Page.
//
if (dwFlags & WC_NO_BEST_FIT_CHARS)
{
while ((pWCStr < pEndWCStr) && (pMBStr < pEndMBStr))
{
GET_MB( pWC,
*pWCStr,
pMBStr,
mbIncr,
((pMBStr + 1) < pEndMBStr) ? FALSE : TRUE );
ELIMINATE_BEST_FIT_MB( pHashN,
*pWCStr,
pMBStr,
mbIncr,
((pMBStr + 1) < pEndMBStr) ? FALSE : TRUE );
DEFAULT_CHAR_CHECK_MB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef,
mbIncr2,
((pMBStr + 1) < pEndMBStr) ? FALSE : TRUE );
if ((mbIncr == 0) || (mbIncr2 == -1))
{
//
// Not enough room in buffer.
//
break;
}
mbCount += (mbIncr2) ? (mbIncr2) : (mbIncr);
pWCStr++;
pMBStr += mbIncr;
}
}
else
{
while ((pWCStr < pEndWCStr) && (pMBStr < pEndMBStr))
{
GET_MB( pWC,
*pWCStr,
pMBStr,
mbIncr,
((pMBStr + 1) < pEndMBStr) ? FALSE : TRUE );
DEFAULT_CHAR_CHECK_MB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef,
mbIncr2,
((pMBStr + 1) < pEndMBStr) ? FALSE : TRUE );
if ((mbIncr == 0) || (mbIncr2 == -1))
{
//
// Not enough room in buffer.
//
break;
}
mbCount += (mbIncr2) ? (mbIncr2) : (mbIncr);
pWCStr++;
pMBStr += mbIncr;
}
}
}
//
// Make sure multibyte character buffer was large enough.
//
if (pWCStr < pEndWCStr)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
}
//
// Return the number of characters written (or that would have
// been written) to the buffer.
//
return (mbCount);
}
////////////////////////////////////////////////////////////////////////////
//
// GetMBDefaultComp
//
// Translates the wide character string to a multibyte string and returns
// the number of bytes written. This also checks for the use of the default
// character and tries to convert composite forms to precomposed forms, so
// the translation is a lot slower.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetMBDefaultComp(
PCP_HASH pHashN,
LPWSTR pWCStr,
LPWSTR pEndWCStr,
LPBYTE pMBStr,
int cbMultiByte,
WORD wDefault,
LPBOOL pUsedDef,
DWORD dwFlags)
{
int mbIncr; // amount to increment pMBStr
int mbCount = 0; // count of multibyte chars written
LPBYTE pEndMBStr; // ptr to end of MB string buffer
BOOL fError; // if error during MB conversion
//
// If cbMultiByte is 0, then we can't use pMBStr. In this
// case, we simply want to count the number of characters that
// would be written to the buffer.
//
if (cbMultiByte == 0)
{
BYTE pTempStr[2]; // tmp buffer - 2 bytes for DBCS
//
// Set most significant bit of flags to indicate to the
// GetMBComp routine that it's using a temporary storage
// area, so don't back up in the buffer.
//
SET_MSB(dwFlags);
//
// For each wide char, translate it to its corresponding multibyte
// char and increment the multibyte character count.
//
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
while (pWCStr < pEndWCStr)
{
//
// Get the translation.
//
mbCount += GetMBCompSB( pHashN,
dwFlags,
pWCStr,
pTempStr,
mbCount,
wDefault,
pUsedDef );
pWCStr++;
}
}
else
{
//
// Multi Byte Character Code Page.
//
while (pWCStr < pEndWCStr)
{
//
// Get the translation.
//
mbCount += GetMBCompMB( pHashN,
dwFlags,
pWCStr,
pTempStr,
mbCount,
wDefault,
pUsedDef,
&fError,
FALSE );
pWCStr++;
}
}
}
else
{
//
// Initialize multibyte loop pointers.
//
pEndMBStr = pMBStr + cbMultiByte;
//
// For each wide char, translate it to its corresponding
// multibyte char, store it in pMBStr, and increment the
// multibyte character count.
//
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
while ((pWCStr < pEndWCStr) && (pMBStr < pEndMBStr))
{
//
// Get the translation.
//
mbIncr = GetMBCompSB( pHashN,
dwFlags,
pWCStr,
pMBStr,
mbCount,
wDefault,
pUsedDef );
pWCStr++;
mbCount += mbIncr;
pMBStr += mbIncr;
}
}
else
{
//
// Multi Byte Character Code Page.
//
while ((pWCStr < pEndWCStr) && (pMBStr < pEndMBStr))
{
//
// Get the translation.
//
mbIncr = GetMBCompMB( pHashN,
dwFlags,
pWCStr,
pMBStr,
mbCount,
wDefault,
pUsedDef,
&fError,
((pMBStr + 1) < pEndMBStr) ? FALSE : TRUE );
if (fError)
{
//
// Not enough room in the buffer.
//
break;
}
pWCStr++;
mbCount += mbIncr;
pMBStr += mbIncr;
}
}
//
// Make sure multibyte character buffer was large enough.
//
if (pWCStr < pEndWCStr)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
}
//
// Return the number of characters written (or that would have
// been written) to the buffer.
//
return (mbCount);
}
////////////////////////////////////////////////////////////////////////////
//
// GetMBCompSB
//
// Fills in pMBStr with the byte character(s) for the corresponding wide
// character from the appropriate translation table and returns the number
// of byte characters written to pMBStr. This routine is only called if
// the defaultcheck and compositecheck flags were both set.
//
// NOTE: Most significant bit of dwFlags parameter is used by this routine
// to indicate that the caller only wants the count of the number of
// characters written, not the string (ie. do not back up in buffer).
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetMBCompSB(
PCP_HASH pHashN,
DWORD dwFlags,
LPWSTR pWCStr,
LPBYTE pMBStr,
int mbCount,
WORD wDefault,
LPBOOL pUsedDef)
{
WCHAR PreComp; // precomposed wide character
if ((pTblPtrs->pDefaultSortkey == NULL) ||
(!IS_NONSPACE_ONLY(pTblPtrs->pDefaultSortkey, *pWCStr)))
{
//
// Get the 1:1 translation from wide char to single byte.
//
GET_WC_TRANSLATION_SB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef,
dwFlags );
return (1);
}
else
{
if (mbCount < 1)
{
//
// Need to handle the nonspace character by itself, since
// it is the first character in the string.
//
if (dwFlags & WC_DISCARDNS)
{
//
// Discard the non-spacing char, so just return with
// zero chars written.
//
return (0);
}
else if (dwFlags & WC_DEFAULTCHAR)
{
//
// Need to replace the nonspace character with the default
// character and return the number of characters written
// to the multibyte string.
//
*pUsedDef = TRUE;
*pMBStr = LOBYTE(wDefault);
return (1);
}
else // WC_SEPCHARS - default
{
//
// Get the 1:1 translation from wide char to multibyte
// of the non-spacing char and return the number of
// characters written to the multibyte string.
//
GET_WC_TRANSLATION_SB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef,
dwFlags );
return (1);
}
}
else if (PreComp = GetPreComposedChar(*pWCStr, *(pWCStr - 1)))
{
//
// Back up in the single byte string and write the
// precomposed char.
//
if (!IS_MSB(dwFlags))
{
pMBStr--;
}
GET_WC_TRANSLATION_SB( pHashN,
PreComp,
pMBStr,
wDefault,
pUsedDef,
dwFlags );
return (0);
}
else
{
if (dwFlags & WC_DISCARDNS)
{
//
// Discard the non-spacing char, so just return with
// zero chars written.
//
return (0);
}
else if (dwFlags & WC_DEFAULTCHAR)
{
//
// Need to replace the base character with the default
// character. Since we've already written the base
// translation char in the single byte string, we need to
// back up in the single byte string and write the default
// char.
//
if (!IS_MSB(dwFlags))
{
pMBStr--;
}
*pUsedDef = TRUE;
*pMBStr = LOBYTE(wDefault);
return (0);
}
else // WC_SEPCHARS - default
{
//
// Get the 1:1 translation from wide char to multibyte
// of the non-spacing char and return the number of
// characters written to the multibyte string.
//
GET_WC_TRANSLATION_SB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef,
dwFlags );
return (1);
}
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// GetMBCompMB
//
// Fills in pMBStr with the byte character(s) for the corresponding wide
// character from the appropriate translation table and returns the number
// of byte characters written to pMBStr. This routine is only called if
// the defaultcheck and compositecheck flags were both set.
//
// If the buffer was too small, the fError flag will be set to TRUE.
//
// NOTE: Most significant bit of dwFlags parameter is used by this routine
// to indicate that the caller only wants the count of the number of
// characters written, not the string (ie. do not back up in buffer).
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetMBCompMB(
PCP_HASH pHashN,
DWORD dwFlags,
LPWSTR pWCStr,
LPBYTE pMBStr,
int mbCount,
WORD wDefault,
LPBOOL pUsedDef,
BOOL *fError,
BOOL fOnlyOne)
{
WCHAR PreComp; // precomposed wide character
BYTE pTmpSp[2]; // temp space - 2 bytes for DBCS
int nCnt; // number of characters written
*fError = FALSE;
if ((pTblPtrs->pDefaultSortkey == NULL) ||
(!IS_NONSPACE_ONLY(pTblPtrs->pDefaultSortkey, *pWCStr)))
{
//
// Get the 1:1 translation from wide char to multibyte.
// This also handles DBCS and returns the number of characters
// written to the multibyte string.
//
GET_WC_TRANSLATION_MB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef,
nCnt,
fOnlyOne,
dwFlags );
if (nCnt == 0)
{
*fError = TRUE;
}
return (nCnt);
}
else
{
if (mbCount < 1)
{
//
// Need to handle the nonspace character by itself, since
// it is the first character in the string.
//
if (dwFlags & WC_DISCARDNS)
{
//
// Discard the non-spacing char, so just return with
// zero chars written.
//
return (0);
}
else if (dwFlags & WC_DEFAULTCHAR)
{
//
// Need to replace the nonspace character with the default
// character and return the number of characters written
// to the multibyte string.
//
*pUsedDef = TRUE;
COPY_MB_CHAR( wDefault,
pMBStr,
nCnt,
fOnlyOne );
if (nCnt == 0)
{
*fError = TRUE;
}
return (nCnt);
}
else // WC_SEPCHARS - default
{
//
// Get the 1:1 translation from wide char to multibyte
// of the non-spacing char and return the number of
// characters written to the multibyte string.
//
GET_WC_TRANSLATION_MB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef,
nCnt,
fOnlyOne,
dwFlags );
if (nCnt == 0)
{
*fError = TRUE;
}
return (nCnt);
}
}
else if (PreComp = GetPreComposedChar(*pWCStr, *(pWCStr - 1)))
{
//
// Get the 1:1 translation from wide char to multibyte
// of the precomposed char, back up in the multibyte string,
// write the precomposed char, and return the DIFFERENCE of
// the number of characters written to the the multibyte
// string.
//
GET_WC_TRANSLATION_MB( pHashN,
*(pWCStr - 1),
pTmpSp,
wDefault,
pUsedDef,
nCnt,
fOnlyOne,
dwFlags );
if (nCnt == 0)
{
*fError = TRUE;
return (nCnt);
}
if (!IS_MSB(dwFlags))
{
pMBStr -= nCnt;
}
GET_WC_TRANSLATION_MB( pHashN,
PreComp,
pMBStr,
wDefault,
pUsedDef,
mbCount,
fOnlyOne,
dwFlags );
if (mbCount == 0)
{
*fError = TRUE;
}
return (mbCount - nCnt);
}
else
{
if (dwFlags & WC_DISCARDNS)
{
//
// Discard the non-spacing char, so just return with
// zero chars written.
//
return (0);
}
else if (dwFlags & WC_DEFAULTCHAR)
{
//
// Need to replace the base character with the default
// character. Since we've already written the base
// translation char in the multibyte string, we need to
// back up in the multibyte string and return the
// DIFFERENCE of the number of characters written
// (could be negative).
//
//
// If the previous character written is the default
// character, then the base character for this nonspace
// character has already been replaced. Simply throw
// this character away and return zero chars written.
//
if (!IS_MSB(dwFlags))
{
//
// Not using a temporary buffer, so find out if the
// previous character translated was the default char.
//
if ((MAKEWORD(*(pMBStr - 1), 0) == wDefault) ||
((mbCount > 1) &&
(MAKEWORD(*(pMBStr - 1), *(pMBStr - 2)) == wDefault)))
{
return (0);
}
}
else
{
//
// Using a temporary buffer. The temp buffer is 2 bytes
// in length and contains the previous character written.
//
if ((MAKEWORD(*pMBStr, 0) == wDefault) ||
((mbCount > 1) &&
(MAKEWORD(*pMBStr, *(pMBStr + 1)) == wDefault)))
{
return (0);
}
}
//
// Get the 1:1 translation from wide char to multibyte
// of the base char, back up in the multibyte string,
// write the default char, and return the DIFFERENCE of
// the number of characters written to the the multibyte
// string.
//
GET_WC_TRANSLATION_MB( pHashN,
*(pWCStr - 1),
pTmpSp,
wDefault,
pUsedDef,
nCnt,
fOnlyOne,
dwFlags );
if (nCnt == 0)
{
*fError = TRUE;
return (nCnt);
}
if (!IS_MSB(dwFlags))
{
pMBStr -= nCnt;
}
*pUsedDef = TRUE;
COPY_MB_CHAR( wDefault,
pMBStr,
mbCount,
fOnlyOne );
if (mbCount == 0)
{
*fError = TRUE;
}
return (mbCount - nCnt);
}
else // WC_SEPCHARS - default
{
//
// Get the 1:1 translation from wide char to multibyte
// of the non-spacing char and return the number of
// characters written to the multibyte string.
//
GET_WC_TRANSLATION_MB( pHashN,
*pWCStr,
pMBStr,
wDefault,
pUsedDef,
nCnt,
fOnlyOne,
dwFlags );
if (nCnt == 0)
{
*fError = TRUE;
}
return (nCnt);
}
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// GetMacCodePage
//
// Returns the system default Mac code page.
//
// 09-22-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
UINT GetMacCodePage()
{
PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query information
BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
UNICODE_STRING ObUnicodeStr; // unicode string
UINT CodePage; // code page value
PCP_HASH pHashN; // ptr to hash node
//
// See if the Mac code page globals have been initialized yet.
// If they have, return the mac code page value.
//
if (gMacCodePage != 0)
{
return (gMacCodePage);
}
//
// Make sure code page key is open.
//
OPEN_CODEPAGE_KEY(NLS_DEFAULT_MACCP);
//
// Query the registry for the Mac CP value.
//
CodePage = 0;
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
if ((QueryRegValue( hCodePageKey,
NLS_VALUE_MACCP,
&pKeyValueFull,
MAX_KEY_VALUE_FULLINFO,
NULL )) == NO_ERROR)
{
//
// Convert the value to an integer.
//
RtlInitUnicodeString(&ObUnicodeStr, GET_VALUE_DATA_PTR(pKeyValueFull));
if (RtlUnicodeStringToInteger(&ObUnicodeStr, 10, (PULONG)&CodePage))
{
CodePage = 0;
}
}
//
// Make sure the CodePage value was set.
//
if (CodePage == 0)
{
//
// Registry value is corrupt, so use default Mac code page.
//
CodePage = NLS_DEFAULT_MACCP;
}
//
// Get the hash node for the Mac code page.
//
pHashN = GetCPHashNode(CodePage);
//
// Make sure the Mac hash node is valid.
//
if (pHashN == NULL)
{
//
// Invalid hash node, which means either the registry is
// corrupt, or setup failed to install a file. Use the
// Ansi code page values.
//
CodePage = gAnsiCodePage;
pHashN = gpACPHashN;
}
//
// Set the final MAC CP values.
//
RtlEnterCriticalSection(&gcsTblPtrs);
if (gMacCodePage == 0)
{
gpMACCPHashN = pHashN;
gMacCodePage = CodePage;
}
RtlLeaveCriticalSection(&gcsTblPtrs);
//
// Return the Mac code page value.
//
return (gMacCodePage);
}
////////////////////////////////////////////////////////////////////////////
//
// SpecialMBToWC
//
// Maps a multibyte character string to its wide character string
// counterpart.
//
// 08-21-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int SpecialMBToWC(
PCP_HASH pHashN,
DWORD dwFlags,
LPCSTR lpMultiByteStr,
int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar)
{
register LPBYTE pMBStr; // ptr to search through MB string
register LPWSTR pWCStr; // ptr to search through WC string
LPBYTE pEndMBStr; // ptr to end of MB search string
LPWSTR pEndWCStr; // ptr to end of WC string buffer
int mbIncr; // amount to increment pMBStr
int wcCount = 0; // count of wide chars written
PMB_TABLE pMBTbl; // ptr to MB table
int ctr; // loop counter
//
// Initialize multibyte character loop pointers.
//
pMBStr = (LPBYTE)lpMultiByteStr;
pEndMBStr = pMBStr + cbMultiByte;
//
// Get the MB table.
//
pMBTbl = pHashN->pMBTbl;
//
// If cchWideChar is 0, then we can't use lpWideCharStr. In this
// case, we simply want to count the number of characters that would
// be written to the buffer.
//
if (cchWideChar == 0)
{
//
// For each multibyte char, translate it to its corresponding
// wide char and increment the wide character count.
//
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
wcCount = (int)(pEndMBStr - pMBStr);
}
else
{
//
// Multi Byte Character Code Page.
//
WCHAR pTempStr[MAX_COMPOSITE]; // tmp buffer
pEndWCStr = pTempStr + MAX_COMPOSITE;
while (pMBStr < pEndMBStr)
{
GET_WC_MULTI( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pTempStr,
pEndWCStr,
mbIncr );
pMBStr += mbIncr;
wcCount++;
}
}
}
else
{
//
// Initialize wide character loop pointers.
//
pWCStr = lpWideCharStr;
pEndWCStr = pWCStr + cchWideChar;
//
// For each multibyte char, translate it to its corresponding
// wide char, store it in lpWideCharStr, and increment the wide
// character count.
//
if (IS_SBCS_CP(pHashN))
{
//
// Single Byte Character Code Page.
//
wcCount = (int)(pEndMBStr - pMBStr);
if ((pEndWCStr - pWCStr) < wcCount)
{
wcCount = (int)(pEndWCStr - pWCStr);
}
if (dwFlags & MB_INVALID_CHAR_CHECK)
{
//
// Error check flag is set.
//
for (ctr = wcCount; ctr > 0; ctr--)
{
GET_WC_SINGLE_SPECIAL( pHashN,
pMBTbl,
pMBStr,
pWCStr );
pMBStr++;
pWCStr++;
}
}
else
{
//
// Error check flag is NOT set.
//
for (ctr = wcCount; ctr > 0; ctr--)
{
GET_WC_SINGLE( pMBTbl,
pMBStr,
pWCStr );
pMBStr++;
pWCStr++;
}
}
}
else
{
//
// Multi Byte Character Code Page.
//
if (dwFlags & MB_INVALID_CHAR_CHECK)
{
//
// Error check flag is set.
//
while ((pMBStr < pEndMBStr) && (pWCStr < pEndWCStr))
{
GET_WC_MULTI_ERR_SPECIAL( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pWCStr,
pEndWCStr,
mbIncr );
pMBStr += mbIncr;
pWCStr++;
}
wcCount = (int)(pWCStr - lpWideCharStr);
}
else
{
//
// Error check flag is NOT set.
//
while ((pMBStr < pEndMBStr) && (pWCStr < pEndWCStr))
{
GET_WC_MULTI( pHashN,
pMBTbl,
pMBStr,
pEndMBStr,
pWCStr,
pEndWCStr,
mbIncr );
pMBStr += mbIncr;
pWCStr++;
}
wcCount = (int)(pWCStr - lpWideCharStr);
}
}
//
// Make sure wide character buffer was large enough.
//
if (pMBStr < pEndMBStr)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
}
//
// Return the number of characters written (or that would have
// been written) to the buffer.
//
return (wcCount);
}