|
|
/*++
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"
#include "nlssafe.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) { WCHAR wszFileName[MAX_SMALL_BUF_LEN]; // file name (Actually l2 chars is max: c_nlsXXXXX.nls\0
WCHAR wszFilePath[MAX_PATH_LEN]; // ptr to full path
//
// 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
//
if (FALSE == GetCPFileNameFromRegistry(CodePage, wszFileName, MAX_SMALL_BUF_LEN)) { return FALSE; }
// Guess we need a full path
if((0 == GetSystemDirectoryW(wszFilePath, MAX_PATH_LEN)) || FAILED(StringCchCatW(wszFilePath, MAX_PATH_LEN, L"\\")) || FAILED(StringCchCatW(wszFilePath, MAX_PATH_LEN, wszFileName))) { // Best we can do.
return FALSE; }
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(wszFilePath)) { return FALSE; } return TRUE; }
////////////////////////////////////////////////////////////////////////////
//
// 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) { if (CodePage != CP_UTF8 && CodePage != CP_UTF7) { // NOTE: This condition has to be updated if we have more codepages in
// the NLS_CP_ALGORITHM_RANGE.
SetLastError(ERROR_INVALID_PARAMETER); } //
// 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); }
|