|
|
/*
* @doc INTERNAL * * @module w32sys.cpp - thin layer over Win32 services * * History: <nl> * 1/22/97 joseogl Created * * Copyright (c) 1995-1998 Microsoft Corporation. All rights reserved. */
// This prevents the "W32->" prefix from being prepended to our identifiers.
#define W32SYS_CPP
#include "_common.h"
#include "_host.h"
#include "_font.h"
#include "_edit.h"
#include <malloc.h>
// Include the appropriate implementation.
#if defined(PEGASUS)
#include "w32wince.cpp"
#else
#include "w32win32.cpp"
#endif
ASSERTDATA
/*
* @struct CPGCHAR | * Locally used variable that contains code-page and char-set info */ typedef struct _cpgcharset { INT nCodePage; // @field Code page
BYTE bCharSet; // @field Character set
DWORD dwFontSig; // @field Font signature bits
} CPGCHAR;
static const CPGCHAR rgCpgCharSet[NCHARSETS] = { {1252, ANSI_CHARSET, fLATIN1>>8}, // fLATIN1 has 3 bits
{0, DEFAULT_CHARSET, 0x00000000}, // Not reliably implemented...
{CP_SYMBOL,SYMBOL_CHARSET, 0x00004000}, // No trans, except WORD -> BYTE
{437, PC437_CHARSET, 0x00000000}, // United States IBM
{850, OEM_CHARSET, 0x00000400}, // IBM Multilingual
{1250, EASTEUROPE_CHARSET, 0x00000002}, // Eastern Europe
{1255, HEBREW_CHARSET, 0x00000020}, // Hebrew
{1256, ARABIC_CHARSET, 0x00000040}, // Arabic
{932, SHIFTJIS_CHARSET, 0x00020000}, // Japanese
{1251, RUSSIAN_CHARSET, 0x00000004}, // Russian
{936, GB2312_CHARSET, 0x00040000}, // PRC
{949, HANGEUL_CHARSET, 0x00080000}, // Hangul
{1361, JOHAB_CHARSET, 0x00000000}, // JOHAB
{950, CHINESEBIG5_CHARSET, 0x00100000}, // Chinese
{1253, GREEK_CHARSET, 0x00000008}, // Greek
{1254, TURKISH_CHARSET, 0x00000010}, // Turkish
{1257, BALTIC_CHARSET, 0x00000080}, // Estonia, Lithuania, Latvia
{1258, VIETNAMESE_CHARSET, 0x00000100}, // Vietnamese
{874, THAI_CHARSET, 0x00010000}, // Thai
{CP_DEVANAGARI,DEVANAGARI_CHARSET,0x00200000}, // Devanagari
{CP_TAMIL, TAMIL_CHARSET, 0x00400000}, // Tamil
{CP_GEORGIAN, GEORGIAN_CHARSET, 0x00800000}, // Georgian
{CP_ARMENIAN, ARMENIAN_CHARSET, 0x00000200}, // Armenian
{10000, MAC_CHARSET, 0x00000000} // Most popular Mac (English, etc.)
};
#define cCpgCharSet ARRAY_SIZE(rgCpgCharSet)
#define LANG_TAIWAN MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
const WORD CodePageTable[] = { /* CodePage PLID primary language
------------------------------------- */ 0, // 00 - undefined
1256, // 01 - Arabic
1251, // 02 - Bulgarian
1252, // 03 - Catalan
950, // 04 - Taiwan (Hong Kong, PRC, and Singapore are 936)
1250, // 05 - Czech
1252, // 06 - Danish
1252, // 07 - German
1253, // 08 - Greek
1252, // 09 - English
1252, // 0a - Spanish
1252, // 0b - Finnish
1252, // 0c - French
1255, // 0d - Hebrew
1250, // 0e - Hungarian
1252, // 0f - Icelandic
1252, // 10 - Italian
932, // 11 - Japan
949, // 12 - Korea
1252, // 13 - Dutch
1252, // 14 - Norwegian
1250, // 15 - Polish
1252, // 16 - Portuguese
0, // 17 - Rhaeto-Romanic
1250, // 18 - Romanian
1251, // 19 - Russian
1250, // 1a - Croatian
1250, // 1b - Slovak
1250, // 1c - Albanian
1252, // 1d - Swedish
874, // 1e - Thai
1254, // 1f - Turkish
1256, // 20 - Urdu
1252, // 21 - Indonesian
1251, // 22 - Ukranian
1251, // 23 - Byelorussian
1250, // 24 - Slovenian
1257, // 25 - Estonia
1257, // 26 - Latvian
1257, // 27 - Lithuanian
0, // 28 - Tajik - Tajikistan (undefined)
1256, // 29 - Farsi
1258, // 2a - Vietnanese
CP_ARMENIAN,// 2b - Armenian (Unicode only)
1254, // 2c - Azeri (Latin, can be Cyrillic...)
1252, // 2d - Basque
0, // 2e - Sorbian
1251, // 2f - FYRO Macedonian
1252, // 30 - Sutu
1252, // 31 - Tsonga
1252, // 32 - Tswana
1252, // 33 - Venda
1252, // 34 - Xhosa
1252, // 35 - Zulu
1252, // 36 - Africaans
CP_GEORGIAN,// 37 - Georgian (Unicode only)
1252, // 38 - Faerose
CP_DEVANAGARI,// 39 - Hindi (Indic)
1252, // 3a - Maltese
1252, // 3b - Sami
1252, // 3c - Gaelic
1255, // 3d - Yiddish
1252, // 3e - Malaysian
1251, // 3f - Kazakh
1252, // 40 - Kirghiz
1252, // 41 - Swahili
1252, // 42 - Turkmen
1254, // 43 - Uzbek (Latin, can be Cyrillic...)
1251 // 44 - Tatar
// 45 - Bengali (Indic)
// 46 - Punjabi(Gurmukhi) (Indic)
// 47 - Gujarati (Indic)
// 48 - Oriya (Indic)
// 49 - Tamil (Indic)
// 4a - Telugu (Indic)
// 4b - Kannada (Indic)
// 4c - Malayalam (Indic)
// 4d - Assamese (Indic)
// 4e - Marathi (Indic)
// 4f - Sanskrit (Indic)
// 50* Mongolian - Mongolia
// 51* Tibetan - Tibet
// 52* Welsh - Wales
// 53* Khmer - Cambodia
// 54* Lao - Lao
// 55* Burmese - Mayanmar
// 56* Gallego - Portugal
// 57 - Konkani (Indic)
// 58* Manipuri (Indic)
// 59* Sindhi (Indic)
// 5a
// 5b
// 5c
// 5d
// 5e
// 5f
// 60* Kashmiri
// 61* Nepali - Nepal
// 62* Frisian - Netherlands
// 63* Pashto - Afghanistan
};
#define nCodePageTable ARRAY_SIZE(CodePageTable)
#define lidAzeriCyrillic 0x82C
#define lidSerbianCyrillic 0xC1A
#define lidUzbekCyrillic 0x843
// Our interface pointer
CW32System *W32;
CW32System::CW32System( ) { if(GetVersion(&_dwPlatformId, &_dwMajorVersion, &_dwMinorVersion)) { _fHaveAIMM = FALSE; _fHaveIMMEShare = FALSE; _fHaveIMMProcs = FALSE; _pIMEShare = NULL; _icr3DDarkShadow = COLOR_WINDOWFRAME; if(_dwMajorVersion >= VERS4) _icr3DDarkShadow = COLOR_3DDKSHADOW; }
_syslcid = GetSystemDefaultLCID(); _ACP = ::GetACP();
// BUG FIX #6089
// we need this for backward compatibility of mouse wheel
_MSMouseRoller = RegisterWindowMessageA(MSH_MOUSEWHEEL);
// Register private messages for MSIME98
_MSIMEMouseMsg = RegisterWindowMessageA("MSIMEMouseOperation"); _MSIMEDocFeedMsg = RegisterWindowMessageA("MSIMEDocumentFeed"); _MSIMEQueryPositionMsg = RegisterWindowMessageA("MSIMEQueryPosition"); _MSIMEServiceMsg = RegisterWindowMessageA("MSIMEService");
// get MSIME Reconvert private messages unless we are running in NT5
if (_dwPlatformId == VER_PLATFORM_WIN32_WINDOWS || (_dwPlatformId == VER_PLATFORM_WIN32_NT && _dwMajorVersion <= 4)) { _MSIMEReconvertMsg = RegisterWindowMessageA("MSIMEReconvert"); _MSIMEReconvertRequestMsg = RegisterWindowMessageA("MSIMEReconvertRequest");
} else { _MSIMEReconvertMsg = 0; // private message for reconversion
_MSIMEReconvertRequestMsg = 0; // private message for reconversion request
} }
CW32System::~CW32System() { FreeIME(); FreeOle(); if (_hdcScreen) DeleteDC(_hdcScreen); }
/////////////////////////////// Memory and CRT utility functions /////////////////////////////////
extern "C" {
#ifdef NOCRTOBJS
// Havinf these functions defined here helps eliminate the dependency on the CRT
// Some function definitions copied from CRT sources.
// Typically, it is better to get the objs for these objects from the CRT
// without dragging in the whole thing.
/***
*int memcmp(buf1, buf2, count) - compare memory for lexical order * *Purpose: * Compares count bytes of memory starting at buf1 and buf2 * and find if equal or which one is first in lexical order. * *Entry: * void *buf1, *buf2 - pointers to memory sections to compare * size_t count - length of sections to compare * *Exit: * returns < 0 if buf1 < buf2 * returns 0 if buf1 == buf2 * returns > 0 if buf1 > buf2 * *Exceptions: * *******************************************************************************/
int __cdecl memcmp ( const void * buf1, const void * buf2, size_t count ) { if (!count) return(0);
while ( --count && *(char *)buf1 == *(char *)buf2 ) { buf1 = (char *)buf1 + 1; buf2 = (char *)buf2 + 1; }
return( *((unsigned char *)buf1) - *((unsigned char *)buf2) ); }
/***
*char *memset(dst, val, count) - sets "count" bytes at "dst" to "val" * *Purpose: * Sets the first "count" bytes of the memory starting * at "dst" to the character value "val". * *Entry: * void *dst - pointer to memory to fill with val * int val - value to put in dst bytes * size_t count - number of bytes of dst to fill * *Exit: * returns dst, with filled bytes * *Exceptions: * *******************************************************************************/
void * __cdecl memset ( void *dst, int val, size_t count ) { void *start = dst;
while (count--) { *(char *)dst = (char)val; dst = (char *)dst + 1; }
return(start); }
/***
*memcpy - Copy source buffer to destination buffer * *Purpose: * memcpy() copies a source memory buffer to a destination memory buffer. * This routine does NOT recognize overlapping buffers, and thus can lead * to propogation. * * For cases where propogation must be avoided, memmove() must be used. * *Entry: * void *dst = pointer to destination buffer * const void *src = pointer to source buffer * size_t count = number of bytes to copy * *Exit: * Returns a pointer to the destination buffer * *Exceptions: *******************************************************************************/
void * __cdecl memcpy ( void * dst, const void * src, size_t count ) { void * ret = dst;
/*
* copy from lower addresses to higher addresses */ while (count--) { *(char *)dst = *(char *)src; dst = (char *)dst + 1; src = (char *)src + 1; }
return(ret); }
void * __cdecl memmove(void *dst, const void *src, size_t count) { void * ret = dst;
if (dst <= src || (char *)dst >= ((char *)src + count)) { /*
* Non-Overlapping Buffers * copy from lower addresses to higher addresses */ while (count--) { *(char *)dst = *(char *)src; dst = (char *)dst + 1; src = (char *)src + 1; } } else { /*
* Overlapping Buffers * copy from higher addresses to lower addresses */ dst = (char *)dst + count - 1; src = (char *)src + count - 1;
while (count--) { *(char *)dst = *(char *)src; dst = (char *)dst - 1; src = (char *)src - 1; } }
return(ret); }
/***
*strlen - return the length of a null-terminated string * *Purpose: * Finds the length in bytes of the given string, not including * the final null character. * *Entry: * const char * str - string whose length is to be computed * *Exit: * length of the string "str", exclusive of the final null byte * *Exceptions: * *******************************************************************************/
size_t __cdecl strlen ( const char * str ) { const char *eos = str;
while( *eos++ ) ;
return( (int)(eos - str - 1) ); }
#endif
#ifdef DEBUG
// These functions are only used for RTF logging
/***
*strcmp - compare two strings, returning less than, equal to, or greater than * *Purpose: * STRCMP compares two strings and returns an integer * to indicate whether the first is less than the second, the two are * equal, or whether the first is greater than the second. * * Comparison is done byte by byte on an UNSIGNED basis, which is to * say that Null (0) is less than any other character (1-255). * *Entry: * const char * src - string for left-hand side of comparison * const char * dst - string for right-hand side of comparison * *Exit: * returns -1 if src < dst * returns 0 if src == dst * returns +1 if src > dst * *Exceptions: * *******************************************************************************/
int __cdecl strcmp ( const char * src, const char * dst ) { int ret = 0 ;
while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) ++src, ++dst;
if ( ret < 0 ) ret = -1 ; else if ( ret > 0 ) ret = 1 ;
return( ret ); }
/***
*char *strcat(dst, src) - concatenate (append) one string to another * *Purpose: * Concatenates src onto the end of dest. Assumes enough * space in dest. * *Entry: * char *dst - string to which "src" is to be appended * const char *src - string to be appended to the end of "dst" * *Exit: * The address of "dst" * *Exceptions: * *******************************************************************************/
char * __cdecl strcat ( char * dst, const char * src ) { char * cp = dst;
while( *cp ) cp++; /* find end of dst */
while( *cp++ = *src++ ) ; /* Copy src to end of dst */
return( dst ); /* return dst */
}
#endif
// This function in the runtime traps virtial base calls
int __cdecl _purecall() { MessageBox(NULL,TEXT("Fatal Error : Vrtual base call in RichEdit"),NULL, MB_OK); PostQuitMessage (0); return 0; }
// To avoid brionging in floating point lib
extern int _fltused = 1;
} // end of extern "C" block
size_t CW32System::wcslen(const wchar_t *wcs) { const wchar_t *eos = wcs;
while( *eos++ ) ;
return( (size_t)(eos - wcs - 1) ); }
wchar_t * CW32System::wcscpy(wchar_t * dst, const wchar_t * src) { wchar_t * cp = dst;
while( *cp++ = *src++ ) ; /* Copy src over dst */
return( dst ); }
int CW32System::wcscmp(const wchar_t * src, const wchar_t * dst) { int ret = 0;
while( ! (ret = (int)(*src - *dst)) && *dst) ++src, ++dst;
if ( ret < 0 ) ret = -1 ; else if ( ret > 0 ) ret = 1 ;
return( ret ); }
int CW32System::wcsicmp(const wchar_t * src, const wchar_t * dst) { int ret = 0; wchar_t s,d; do { s = ((*src <= L'Z') && (*dst >= L'A')) ? *src - L'A' + L'a' : *src; d = ((*dst <= L'Z') && (*dst >= L'A')) ? *dst - L'A' + L'a' : *dst; src++; dst++; } while (!(ret = (int)(s - d)) && d);
if ( ret < 0 ) ret = -1 ; else if ( ret > 0 ) ret = 1 ;
return( ret ); }
wchar_t * CW32System::wcsncpy (wchar_t * dest, const wchar_t * source, size_t count) { wchar_t *start = dest; while (count && (*dest++ = *source++)) /* copy string */ count--; if (count) /* pad out with zeroes */ while (--count) *dest++ = L'\0'; return(start); }
int CW32System::wcsnicmp (const wchar_t * first, const wchar_t * last, size_t count) { wchar_t f,l; int result = 0; if ( count ) { do { f = ((*first <= L'Z') && (*first >= L'A')) ? *first - L'A' + L'a' : *first; l = ((*last <= L'Z') && (*last >= L'A')) ? *last - L'A' + L'a' : *last; first++; last++; } while ( (--count) && f && (f == l) ); result = (int)(f - l); } return result; }
unsigned long CW32System::strtoul(const char *nptr) { const char *p; char c; unsigned long number; unsigned digval; unsigned long maxval; p = nptr; /* p is our scanning pointer */ number = 0; /* start with zero */ c = *p++; /* read char */ while ( c == ' ' || c == '\t' ) c = *p++; /* skip whitespace */ if (c == '-') { return 0; } /* if our number exceeds this, we will overflow on multiply */ maxval = ULONG_MAX / 10; for (;;) { /* exit in middle of loop */ /* convert c to value */ digval = (unsigned char) c; if ( digval >= '0' && digval <= '9' ) digval = c - '0'; else return number; /* we now need to compute number = number * base + digval,
but we need to know if overflow occured. This requires a tricky pre-check. */ if (number < maxval || (number == maxval && (unsigned long)digval <= ULONG_MAX % 10)) { /* we won't overflow, go ahead and multiply */ number = number * 10 + digval; } else return 0; c = *p++; /* read next digit */ } }
// CW32System static members
BOOL CW32System::_fLRMorRLM; BOOL CW32System::_fHaveIMMProcs; BOOL CW32System::_fHaveIMMEShare; BOOL CW32System::_fHaveAIMM; UINT CW32System::_fRegisteredXBox; DWORD CW32System::_dwPlatformId; LCID CW32System::_syslcid; DWORD CW32System::_dwMajorVersion; DWORD CW32System::_dwMinorVersion; INT CW32System::_icr3DDarkShadow; UINT CW32System::_MSIMEMouseMsg; UINT CW32System::_MSIMEReconvertMsg; UINT CW32System::_MSIMEReconvertRequestMsg; UINT CW32System::_MSIMEDocFeedMsg; UINT CW32System::_MSIMEQueryPositionMsg; UINT CW32System::_MSIMEServiceMsg; UINT CW32System::_MSMouseRoller; HDC CW32System::_hdcScreen; CIMEShare* CW32System::_pIMEShare;
// CW32System static system parameter members
BOOL CW32System::_fSysParamsOk; BOOL CW32System::_fUsePalette; INT CW32System::_xWidthSys; INT CW32System::_yHeightSys; INT CW32System::_ySysFontLeading; LONG CW32System::_xPerInchScreenDC; LONG CW32System::_yPerInchScreenDC; INT CW32System::_cxBorder; INT CW32System::_cyBorder; INT CW32System::_cxVScroll; INT CW32System::_cyHScroll; LONG CW32System::_dxSelBar; INT CW32System::_cxDoubleClk; INT CW32System::_cyDoubleClk; INT CW32System::_DCT; WORD CW32System::_nScrollInset; WORD CW32System::_nScrollDelay; WORD CW32System::_nScrollInterval; WORD CW32System::_nScrollHAmount; WORD CW32System::_nScrollVAmount; WORD CW32System::_nDragDelay; WORD CW32System::_nDragMinDist; WORD CW32System::_wDeadKey; WORD CW32System::_wKeyboardFlags; WORD CW32System::_wNumKeyPad; WORD CW32System::_fFEFontInfo; BYTE CW32System::_bDigitSubstMode; BYTE CW32System::_bSysCharSet; HCURSOR CW32System::_hcurSizeNS; HCURSOR CW32System::_hcurSizeWE; HCURSOR CW32System::_hcurSizeNWSE; HCURSOR CW32System::_hcurSizeNESW; LONG CW32System::_cLineScroll; HFONT CW32System::_hSystemFont; HKL CW32System::_hklCurrent; HKL CW32System::_hkl[NCHARSETS]; INT CW32System::_sysiniflags; UINT CW32System::_ACP;
DWORD CW32System::_cRefs;
/*
* CW32System::MbcsFromUnicode(pstr, cch, pwstr, cwch, codepage, flags) * * @mfunc * Converts a string to MBCS from Unicode. If cwch equals -1, the string * is assumed to be NULL terminated. -1 is supplied as a default argument. * * @rdesc * If [pstr] is NULL or [cch] is 0, 0 is returned. Otherwise, the number * of characters converted, including the terminating NULL, is returned * (note that converting the empty string will return 1). If the * conversion fails, 0 is returned. * * @devnote * Modifies pstr */ int CW32System::MbcsFromUnicode( LPSTR pstr, //@parm Buffer for MBCS string
int cch, //@parm Size of MBCS buffer, incl space for NULL terminator
LPCWSTR pwstr, //@parm Unicode string to convert
int cwch, //@parm # chars in Unicode string, incl NULL terminator
UINT codepage, //@parm Code page to use (CP_ACP is default)
UN_FLAGS flags) //@parm Indicates if WCH_EMBEDDING should be handled specially
{ TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CW32System::MbcsFromUnicode");
LONG i; LPWSTR pwstrtemp; CTempWcharBuf twcb;
Assert(cch >= 0 && pwstr && (cwch == -1 || cwch > 0));
if(!pstr || !cch) return 0;
// If we have to convert WCH_EMBEDDINGs, scan through and turn
// them into spaces. This is necessary for richedit1.0 compatibity,
// as WideCharToMultiByte will turn WCH_EMBEDDING into a '?'
if(flags == UN_CONVERT_WCH_EMBEDDING) { if(cwch == -1) cwch = wcslen(pwstr) + 1;
pwstrtemp = twcb.GetBuf(cwch); if(pwstrtemp) { for(i = 0; i < cwch; i++) { pwstrtemp[i] = pwstr[i];
if(pwstr[i] == WCH_EMBEDDING) pwstrtemp[i] = L' '; } pwstr = pwstrtemp; } } return WCTMB(codepage, 0, pwstr, cwch, pstr, cch, NULL, NULL, NULL); }
/*
* CW32System::UnicodeFromMbcs(pwstr, cwch, pstr, cch, uiCodePage) * * @mfunc * Converts a string to Unicode from MBCS. If cch equals -1, the string * is assumed to be NULL terminated. -1 is supplied as a default * argument. * * @rdesc * If [pwstr] is NULL or [cwch] is 0, 0 is returned. Otherwise, * the number of characters converted, including the terminating * NULL, is returned (note that converting the empty string will * return 1). If the conversion fails, 0 is returned. * * @devnote * Modifies: [pwstr] */ int CW32System::UnicodeFromMbcs( LPWSTR pwstr, //@parm Buffer for Unicode string
int cwch, //@parm Size of Unicode buffer, incl space for NULL terminator
LPCSTR pstr, //@parm MBCS string to convert
int cch, //@parm # chars in MBCS string, incl NULL terminator
UINT uiCodePage) //@parm Code page to use (CP_ACP is default)
{ TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CW32System::UnicodeFromMbcs");
Assert(pstr && cwch >= 0 && (cch == -1 || cch >= 0));
if(!pwstr || !cwch) return 0;
if(cch >= 3 && IsUTF8BOM((BYTE *)pstr)) { uiCodePage = CP_UTF8; // UTF-8 BOM file
cch -= 3; // Eat the BOM
pstr += 3; } return MBTWC(uiCodePage, 0, pstr, cch, pwstr, cwch, NULL); }
/*
* CW32System::TextHGlobalAtoW (hglobalA) * * @func * translates a unicode string contained in an hglobal and * wraps the ansi version in another hglobal * * @devnote * does *not* free the incoming hglobal */ HGLOBAL CW32System::TextHGlobalAtoW(HGLOBAL hglobalA) { TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CW32System::TextHGlobalAtoW");
if(!hglobalA) return NULL;
HGLOBAL hnew; LPSTR pstr = (LPSTR)GlobalLock(hglobalA); DWORD dwSize = GlobalSize(hglobalA); LONG cbSize = (dwSize + 1) * sizeof(WCHAR); hnew = GlobalAlloc(GMEM_FIXED, cbSize); if(hnew) { LPWSTR pwstr = (LPWSTR)GlobalLock(hnew); UnicodeFromMbcs(pwstr, dwSize + 1, pstr); GlobalUnlock(hnew); } GlobalUnlock(hglobalA); return hnew; }
/*
* CW32System::TextHGlobalWtoA(hglobalW) * * @func * converts a unicode text hglobal into a newly allocated * allocated hglobal with ANSI data * * @devnote * does *NOT* free the incoming hglobal */ HGLOBAL CW32System::TextHGlobalWtoA( HGLOBAL hglobalW ) { TRACEBEGIN(TRCSUBSYSUTIL, TRCSCOPEINTERN, "CW32System::TextHGlobalWtoA");
if(!hglobalW) return NULL;
HGLOBAL hnew = NULL; LPWSTR pwstr = (LPWSTR)GlobalLock(hglobalW); DWORD dwSize = GlobalSize(hglobalW); LONG cbSize = (dwSize * 2) * sizeof(CHAR); hnew = GlobalAlloc(GMEM_FIXED, cbSize);
if( hnew ) { LPSTR pstr = (LPSTR)GlobalLock(hnew); MbcsFromUnicode(pstr, cbSize, pwstr ); GlobalUnlock(hnew); } GlobalUnlock(hglobalW); return hnew; }
/*
* CW32System::ConvertLanguageIDtoCodePage (lid) * * @mfunc Maps a language ID to a Code Page * * @rdesc returns Code Page * * @devnote: * This routine takes advantage of the fact that except for Chinese, * the code page is determined uniquely by the primary language ID, * which is given by the low-order 10 bits of the lcid. * * The WORD CodePageTable could be replaced by a BYTE with the addition * of a couple of if's and the BYTE table replaced by a nibble table * with the addition of a shift and a mask. Since the table is only * 96 bytes long, it seems that the simplicity of using actual code page * values is worth the extra bytes. */ UINT CW32System::ConvertLanguageIDtoCodePage( WORD lid) //@parm Language ID to map to code page
{ UINT j = PRIMARYLANGID(lid); // j = primary language (PLID)
if(j >= LANG_CROATIAN) // PLID = 0x1a
{ if (lid == lidSerbianCyrillic || // Special case for LID = 0xc1a
lid == lidAzeriCyrillic || lid == lidUzbekCyrillic) { return 1251; // Use Cyrillic code page
}
if(j >= nCodePageTable) // Most languages above table
{ // take 1252
if (j == 0x57 || j == 0x61 || IN_RANGE(0x4e, j, 0x4f)) return CP_DEVANAGARI;
if (j == 0x49) return CP_TAMIL;
return 1252; } }
j = CodePageTable[j]; // Translate PLID to code page
if(j != 950 || lid == LANG_TAIWAN) // All but China (except for Taiwan)
return j;
return 936; // Hong Kong SAR, Singapore, and PRC
}
/*
* CW32System::GetLocaleLCID () * * @mfunc Maps an LCID for thread to a Code Page * * @rdesc returns Code Page */ LCID CW32System::GetLocaleLCID() { return GetThreadLocale(); }
/*
* CW32System::GetLocaleCodePage () * * @mfunc Maps an LCID for thread to a Code Page * * @rdesc returns Code Page */ UINT CW32System::GetLocaleCodePage() { #ifdef DEBUG
UINT cpg = W32->DebugDefaultCpg(); if (cpg) return cpg; #endif
return W32->ConvertLanguageIDtoCodePage(GetThreadLocale()); }
/*
* CW32System::GetKeyboardLCID () * * @mfunc Gets LCID for keyboard active on current thread * * @rdesc returns Code Page */ LCID CW32System::GetKeyboardLCID(DWORD dwMakeAPICall) { return (WORD)GetKeyboardLayout(dwMakeAPICall); }
/*
* CW32System::GetKeyboardCodePage () * * @mfunc Gets Code Page for keyboard active on current thread * * @rdesc returns Code Page */ UINT CW32System::GetKeyboardCodePage(DWORD dwMakeAPICall) { return W32->ConvertLanguageIDtoCodePage((WORD)GetKeyboardLayout(dwMakeAPICall)); }
/*
* CW32System::InitKeyboardFlags () * * @mfunc * Initializes keyboard flags. Used when control gains focus. Note that * Win95 doesn't support VK_RSHIFT, so if either shift key is pressed * when focus is regained, it'll be assumed to be the left shift. */ void CW32System::InitKeyboardFlags() { _wKeyboardFlags = 0; if(GetKeyState(VK_SHIFT) < 0) SetKeyboardFlag(GetKeyState(VK_RSHIFT) < 0 ? RSHIFT : LSHIFT); }
/*
* CW32System::GetKeyboardFlag (dwKeyMask, wKey) * * @mfunc * Return whether wKey is depressed. Check with OS for agreement. * If OS says it isn't depressed, reset our internal flags. In * any event, return TRUE/FALSE in agreement with the system (bad * client may have eaten keystrokes, thereby destabilizing our * internal keyboard state. * * @rdesc * TRUE iff wKey is depressed */ BOOL CW32System::GetKeyboardFlag ( WORD dwKeyMask, //@parm _wKeyboardFlags mask like ALT, CTRL, or SHIFT
WORD wKey) //@parm VK_xxx like VK_MENU, VK_CONTROL, or VK_SHIFT
{ BOOL fFlag = (GetKeyboardFlags() & dwKeyMask) != 0;
if(fFlag ^ ((GetKeyState(wKey) & 0x8000) != 0)) { // System doesn't agree with our internal state
// (bad client ate a WM_KEYDOWN)
if(fFlag) { ResetKeyboardFlag(dwKeyMask); return FALSE; } // Don't set an internal _wKeyboardFlag since we check for it
// anyhow and client might not send WM_KEYUP either
return TRUE; } return fFlag; }
/*
* CW32System::IsAlef(ch) * * @func * Used to determine if base character is a Arabic-type Alef. * * @rdesc * TRUE iff the base character is an Arabic-type Alef. * * @comm * AlefWithMaddaAbove, AlefWithHamzaAbove, AlefWithHamzaBelow, * and Alef are valid matches. */ BOOL CW32System::IsAlef( TCHAR ch) { return IN_RANGE(0x622, ch, 0x627) && ch != 0x624 && ch != 0x626; }
/*
* CW32System::IsBiDiLcid(lcid) * * @func * Return TRUE if lcid corresponds to an RTL language * * @rdesc * TRUE if lcid corresponds to an RTL language */ BOOL CW32System::IsBiDiLcid( LCID lcid) { return PRIMARYLANGID(lcid) == LANG_ARABIC || PRIMARYLANGID(lcid) == LANG_HEBREW || PRIMARYLANGID(lcid) == LANG_URDU || PRIMARYLANGID(lcid) == LANG_FARSI; }
/*
* CW32System::IsIndicLcid(lcid) * * @func * Return TRUE if lcid corresponds to an Indic language * * @rdesc * TRUE if lcid corresponds to an Indic language */ BOOL CW32System::IsIndicLcid( LCID lcid) { WORD wLangId = PRIMARYLANGID(lcid); return wLangId == LANG_HINDI || wLangId == LANG_KONKANI || wLangId == LANG_NEPALI || IN_RANGE(LANG_BENGALI, wLangId, LANG_SANSKRIT); }
/*
* CW32System::IsIndicKbdInstalled() * * @func * Return TRUE if any Indic kbd installed */ bool CW32System::IsIndicKbdInstalled() { for (int i = INDIC_FIRSTINDEX; i <= INDIC_LASTINDEX; i++) if (_hkl[i] != 0) return true; return false; }
/*
* CW32System::IsComplexScriptLcid(lcid) * * @func * Return TRUE if lcid corresponds to any complex script locales * */ BOOL CW32System::IsComplexScriptLcid( LCID lcid) { return IsBiDiLcid(lcid) || PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_THAI || PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_VIETNAMESE || IsIndicLcid(lcid); }
/*
* CW32System::IsBiDiDiacritic(ch) * * @func Used to determine if character is a Arabic or Hebrew diacritic. * * @rdesc TRUE iff character is a diacritic */ BOOL CW32System::IsBiDiDiacritic( TCHAR ch) { return IN_RANGE(0x64B, ch, 0x670) && (ch <= 0x652 || ch == 0x670) || // Arabic
IN_RANGE(0x591, ch, 0x5C4) && (ch != 0x5A2 && ch != 0x5BA && // Hebrew
ch != 0x5BE && ch != 0x5C0 && ch != 0x5C3); }
/*
* CW32System::IsVietCdmSequenceValid(ch1, ch2) * * @mfunc * Check if ch2 can follow ch1 in case ch2 is a combining diacritic mark (CDM). * Main use is for Vietnamese users (Chau Vu provides the logic below). * * @rdesc * TRUE if ch2 can follow ch1 */ BOOL CW32System::IsVietCdmSequenceValid( WCHAR ch1, WCHAR ch2) { if (!IN_RANGE(0x300, ch2, 0x323) || // Fast out
!IN_RANGE(0x300, ch2, 0x301) && ch2 != 0x303 && ch2 != 0x309 && ch2 != 0x323) { return TRUE; // Not Vietnamese tone mark
} // � � �
static const BYTE vowels[] = {0xF4, 0xEA, 0xE2, 'y', 'u', 'o', 'i', 'e', 'a'};
for(int i = ARRAY_SIZE(vowels); i--; ) if((ch1 | 0x20) == vowels[i]) // Vietnamese tone mark follows
return TRUE; // vowel
return IN_RANGE(0x102, ch1, 0x103) || // A-breve, a-breve
IN_RANGE(0x1A0, ch1, 0x1A1) || // O-horn, o-horn
IN_RANGE(0x1AF, ch1, 0x1B0); // U-horn, u-horn
}
/*
* CW32System::IsFELCID(lcid) * * @mfunc * Returns TRUE iff lcid is for a East Asian country/region. * * @rdesc * TRUE iff lcid is for a East Asian country/region. */ bool CW32System::IsFELCID( LCID lcid) { switch(PRIMARYLANGID(LANGIDFROMLCID(lcid))) { case LANG_CHINESE: case LANG_JAPANESE: case LANG_KOREAN: return true; } return false; }
/*
* CW32System::IsFECharSet(bCharSet) * * @mfunc * Returns TRUE iff charset may be for a East Asian country/region. * * @rdesc * TRUE iff charset may be for a East Asian country/region. * */ BOOL CW32System::IsFECharSet( BYTE bCharSet) { switch(bCharSet) { case CHINESEBIG5_CHARSET: case SHIFTJIS_CHARSET: case HANGEUL_CHARSET: case JOHAB_CHARSET: case GB2312_CHARSET: return TRUE; }
return FALSE; }
/*
* CW32System::Is8BitCodePage(CodePage) * * @mfunc * Returns TRUE iff the codepage is 8-bit */ BOOL CW32System::Is8BitCodePage( unsigned CodePage) { if(!CodePage) CodePage = GetACP();
return IN_RANGE(1250, CodePage, 1258) || CodePage == 874; }
/*
* CW32System::IsFECodePageFont(dwFontCodePageSig) * * @mfunc * Returns TRUE iff the font codepage signature reveals only East Asian support */ BOOL CW32System::IsFECodePageFont( DWORD dwFontCodePageSig) { DWORD dwFE = 0x001e0000; // Shift-JIS + PRC + Hangeul + Taiwan
DWORD dwOthers = 0x000101fc; // The rest of the world except for Latin-1 and Latin-2
return (dwFontCodePageSig & dwFE) && !(dwFontCodePageSig & dwOthers); }
/*
* CW32System::IsRTLChar(ch) * * @mfunc * Returns TRUE iff ch Arabic or Hebrew * * @rdesc * TRUE iff ch is Arabic or Hebrew */ BOOL IsRTLChar( TCHAR ch) { // Remark: what about Arabic Presentation Forms?
// (0xFB50 - 0xFDFF, 0xFE70 - 0xFEFF)
return IN_RANGE(0x590, ch, 0x6FF) || ch == RTLMARK; }
/*
* CW32System::IsRTLCharSet(bCharSet) * * @mfunc * Returns TRUE iff charset is Arabic or Hebrew * * @rdesc * TRUE iff charset may be for Arabic or Hebrew */ BOOL CW32System::IsRTLCharSet( BYTE bCharSet) { return IN_RANGE(HEBREW_CHARSET, bCharSet, ARABIC_CHARSET); }
/*
* CW32System::IsZWG(ch, bCharSet) * * @mfunc * Determines whether a single-byte character is a zero-width glyph * or not. Requires a charset. * * @rdesc * TRUE if the character is a zero-width glyph, FALSE otherwise. */ BOOL CW32System::IsZWG( char ch, BYTE bCharSet) { if(IN_RANGE(0x9D, ch, 0x9E)) return bCharSet == ARABIC_CHARSET;
if(IN_RANGE(0xFD, ch, 0xFE)) return IN_RANGE(HEBREW_CHARSET, bCharSet, ARABIC_CHARSET);
return FALSE; }
typedef struct { WCHAR codepoint; WORD CharFlags; BYTE runlength; } Data_125X;
/*
* CW32System::GetCharFlags125x(ch) * * @mfunc * Returns char flags for ch as defined in rgCpgCharSet for 125x * codepages. Bit 0: 1252, bit 1: 1250, bit 2: 1251, else bit x: * 125x (for 1253 - 1258). * * @rdesc * 125x char flags for ch */ DWORD CW32System::GetCharFlags125x( WCHAR ch) //@parm Char to examine
{ static const WORD rgCpgMask[] = { 0x1FF, // 0xA0
0x131, // 0xA1
0x1F1, // 0xA2
0x1F9, // 0xA3
0x1DF, // 0xA4
0x179, // 0xA5
0x1FF, // 0xA6
0x1FF, // 0xA7
0x1FB, // 0xA8
0x1FF, // 0xA9
0x111, // 0xAA
0x1FF, // 0xAB
0x1FF, // 0xAC
0x1FF, // 0xAD
0x1FF, // 0xAE
0x1F1, // 0xAF
0x1FF, // 0xB0
0x1FF, // 0xB1
0x1F9, // 0xB2
0x1F9, // 0xB3
0x1F3, // 0xB4
0x1FF, // 0xB5
0x1FF, // 0xB6
0x1FF, // 0xB7
0x1F3, // 0xB8
0x1F1, // 0xB9
0x111, // 0xBA
0x1FF, // 0xBB
0x1F1, // 0xBC
0x1F9, // 0xBD
0x1F1, // 0xBE
0x131, // 0xBF
0x111, // 0xC0
0x113, // 0xC1
0x113, // 0xC2
0x011, // 0xC3
0x193, // 0xC4
0x191, // 0xC5
0x191, // 0xC6
0x113, // 0xC7
0x111, // 0xC8
0x193, // 0xC9
0x111, // 0xCA
0x113, // 0xCB
0x011, // 0xCC
0x113, // 0xCD
0x113, // 0xCE
0x111, // 0xCF
0x001, // 0xD0
0x111, // 0xD1
0x011, // 0xD2
0x193, // 0xD3
0x113, // 0xD4
0x091, // 0xD5
0x193, // 0xD6
0x1F3, // 0xD7
0x191, // 0xD8
0x111, // 0xD9
0x113, // 0xDA
0x111, // 0xDB
0x193, // 0xDC
0x003, // 0xDD
0x001, // 0xDE
0x193, // 0xDF
0x151, // 0xE0
0x113, // 0xE1
0x153, // 0xE2
0x011, // 0xE3
0x193, // 0xE4
0x191, // 0xE5
0x191, // 0xE6
0x153, // 0xE7
0x151, // 0xE8
0x1D3, // 0xE9
0x151, // 0xEA
0x153, // 0xEB
0x011, // 0xEC
0x113, // 0xED
0x153, // 0xEE
0x151, // 0xEF
0x001, // 0xF0
0x111, // 0xF1
0x011, // 0xF2
0x193, // 0xF3
0x153, // 0xF4
0x091, // 0xF5
0x193, // 0xF6
0x1F3, // 0xF7
0x191, // 0xF8
0x151, // 0xF9
0x113, // 0xFA
0x151, // 0xFB
0x1D3, // 0xFC
0x003, // 0xFD
0x001, // 0xFE
0x111 // 0xFF
}; static const Data_125X Table_125X[] = { { 0x100, 0x080, 2}, { 0x102, 0x102, 2}, { 0x104, 0x082, 4}, { 0x10c, 0x082, 2}, { 0x10e, 0x002, 2}, { 0x110, 0x102, 2}, { 0x112, 0x080, 2}, { 0x116, 0x080, 2}, { 0x118, 0x082, 2}, { 0x11a, 0x002, 2}, { 0x11e, 0x010, 2}, { 0x122, 0x080, 2}, { 0x12a, 0x080, 2}, { 0x12e, 0x080, 2}, { 0x130, 0x010, 2}, { 0x136, 0x080, 2}, { 0x139, 0x002, 2}, { 0x13b, 0x080, 2}, { 0x13d, 0x002, 2}, { 0x141, 0x082, 4}, { 0x145, 0x080, 2}, { 0x147, 0x002, 2}, { 0x14c, 0x080, 2}, { 0x150, 0x002, 2}, { 0x152, 0x151, 2}, { 0x154, 0x002, 2}, { 0x156, 0x080, 2}, { 0x158, 0x002, 2}, { 0x15a, 0x082, 2}, { 0x15e, 0x012, 2}, { 0x160, 0x093, 2}, { 0x162, 0x002, 4}, { 0x16a, 0x080, 2}, { 0x16e, 0x002, 4}, { 0x172, 0x080, 2}, { 0x178, 0x111, 1}, { 0x179, 0x082, 4}, { 0x17d, 0x083, 2}, { 0x192, 0x179, 1}, { 0x1A0, 0x100, 2}, { 0x1AF, 0x100, 2}, { 0x2c6, 0x171, 1}, { 0x2c7, 0x082, 1}, { 0x2d8, 0x002, 1}, { 0x2d9, 0x082, 1}, { 0x2db, 0x082, 1}, { 0x2dc, 0x131, 1}, { 0x2dd, 0x002, 1}, { 0x300, 0x100, 2}, { 0x303, 0x100, 1}, { 0x309, 0x100, 1}, { 0x323, 0x100, 1}, { 0x384, 0x008, 3}, { 0x388, 0x008, 3}, { 0x38c, 0x008, 1}, { 0x38e, 0x008, 20}, { 0x3a3, 0x008, 44}, { 0x401, 0x004, 12}, { 0x40e, 0x004, 66}, { 0x451, 0x004, 12}, { 0x45e, 0x004, 2}, { 0x490, 0x004, 2}, { 0x5b0, 0x020, 20}, { 0x5d0, 0x020, 27}, { 0x5F0, 0x020, 5}, { 0x60c, 0x040, 1}, { 0x61b, 0x040, 1}, { 0x61f, 0x040, 1}, { 0x621, 0x040, 26}, { 0x640, 0x040, 19}, { 0x679, 0x040, 1}, { 0x67e, 0x040, 1}, { 0x686, 0x040, 1}, { 0x688, 0x040, 1}, { 0x691, 0x040, 1}, { 0x698, 0x040, 1}, { 0x6a9, 0x040, 1}, { 0x6af, 0x040, 1}, { 0x6ba, 0x040, 1}, { 0x6be, 0x040, 1}, { 0x6c1, 0x040, 1}, { 0x6d2, 0x040, 1}, {0x200c, 0x040, 2}, {0x200e, 0x060, 2}, {0x2013, 0x1ff, 2}, {0x2015, 0x008, 1}, {0x2018, 0x1ff, 3}, {0x201c, 0x1ff, 3}, {0x2020, 0x1ff, 3}, {0x2026, 0x1ff, 1}, {0x2030, 0x1ff, 1}, {0x2039, 0x1ff, 2}, {0x20AA, 0x020, 1}, {0x20AB, 0x100, 1}, {0x20AC, 0x1ff, 1}, {0x2116, 0x004, 1}, {0x2122, 0x1ff, 1} };
// Easy check for ASCII
if(ch <= 0x7f) return 0x1ff00;
// Easy check for missing codes
if(ch > 0x2122) return 0;
if(IN_RANGE(0xA0, ch, 0xFF)) return rgCpgMask[ch - 0xA0] << 8;
// Perform binary search to find entry in table
int low = 0; int high = ARRAY_SIZE(Table_125X) - 1; int middle; int midval; int runlength; while(low <= high) { middle = (high + low) / 2; midval = Table_125X[middle].codepoint; if(midval > ch) high = middle - 1; else low = middle + 1; runlength = Table_125X[middle].runlength; if(ch >= midval && ch <= midval + runlength - 1) return Table_125X[middle].CharFlags << 8; } return 0; }
/*
* CW32System::IsUTF8BOM(pstr) * * @mfunc * Return TRUE if pstr points at a UTF-8 BOM * * @rdesc * TRUE iff pstr points at a UTF-8 BOM */ BOOL CW32System::IsUTF8BOM( BYTE *pstr) { BYTE *pstrUtf8BOM = szUTF8BOM;
for(LONG i = 3; i--; ) if(*pstr++ != *pstrUtf8BOM++) return FALSE; return TRUE; }
/*
* CW32System::GetTrailBytesCount(ach, cpg) * * @mfunc * Returns number of trail bytes iff the byte ach is a lead byte for the code page cpg. * * @rdesc * count of trail bytes if ach is lead byte for cpg * * @comm * This is needed to support CP_UTF8 as well as DBC. * This function potentially doesn't support as many code pages as the * Win32 IsDBCSLeadByte() function (and it might not be as up-to-date). * An AssertSz() is included to compare the results when the code page * is supported by the system. * * Reference: \\sparrow\sysnls\cptable\win95. See code-page txt files * in subdirectories windows\txt and others\txt. */ int CW32System::GetTrailBytesCount(BYTE ach, UINT cpg) {
if(ach < 0x81) // Smallest known lead
return 0; // byte = 0x81:
// early out
BOOL bDBLeadByte = FALSE; // Variable to check
// result with system
// ifdef DEBUG
if (cpg == CP_UTF8) { int cTrailBytes = 0; // Number of trail bytes for CP_UTF8(0 - 3)
if (ach >= 0x0F0) // Handle 4-byte form for 16 UTF-16 planes
cTrailBytes = 3; // above the BMP) expect:
// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
else if (ach >= 0x0E0) // Need at least 3 bytes of form
cTrailBytes = 2; // 1110bbbb 10bbbbbb 10bbbbbb
else if (ach >= 0x0C0) // Need at least 2 bytes of form
cTrailBytes = 1; // 110bbbbb 10bbbbbb
return cTrailBytes; } else if(cpg > 950) { if(cpg < 1361) // E.g., the 125x's are
return 0; // SBCSs: early out
else if(cpg == 1361) // Korean Johab
bDBLeadByte = IN_RANGE(0x84, ach, 0xd3) || // 0x84 <= ach <= 0xd3
IN_RANGE(0xd8, ach, 0xde) || // 0xd8 <= ach <= 0xde
IN_RANGE(0xe0, ach, 0xf9); // 0xe0 <= ach <= 0xf9
else if(cpg == 10001) // Mac Japanese
goto JIS;
else if(cpg == 10002) // Mac Trad Chinese (Big5)
bDBLeadByte = ach <= 0xfe;
else if(cpg == 10003) // Mac Korean
bDBLeadByte = IN_RANGE(0xa1, ach, 0xac) || // 0xa1 <= ach <= 0xac
IN_RANGE(0xb0, ach, 0xc8) || // 0xb0 <= ach <= 0xc8
IN_RANGE(0xca, ach, 0xfd); // 0xca <= ach <= 0xfd
else if(cpg == 10008) // Mac Simplified Chinese
bDBLeadByte = IN_RANGE(0xa1, ach, 0xa9) || // 0xa1 <= ach <= 0xa9
IN_RANGE(0xb0, ach, 0xf7); // 0xb0 <= ach <= 0xf7
} else if (cpg >= 932) // cpg <= 950
{ if(cpg == 950 || cpg == 949 || cpg == 936) // Chinese (Taiwan, HK),
bDBLeadByte = ach <= 0xfe; // Korean Ext Wansung,
// PRC GBK: 0x81 - 0xfe
else if(cpg == 932) // Japanese
JIS: bDBLeadByte = ach <= 0x9f || IN_RANGE(0xe0, ach, 0xfc); }
#ifdef DEBUG
TCHAR ch; static BYTE asz[2] = {0xe0, 0xe0}; // All code pages above
// if cpg == 0, fRet will FALSE but IsDBCSLeadByteEx may succeed.
if ( cpg && cpg != CP_SYMBOL && cpg != CP_UTF8) { // If system supports cpg, then fRet should agree with system result
AssertSz(MultiByteToWideChar(cpg, 0, (char *)asz, 2, &ch, 1) <= 0 || bDBLeadByte == IsDBCSLeadByteEx(cpg, ach), "bDBLeadByte differs from IsDBCSLeadByteEx()"); } #endif
return bDBLeadByte ? 1 : 0; }
/*
* CW32System::GetGdiCharSet(bCharSet) * * @func * Map CHARFORMAT charset to GDI charset (charset used in CreateFont) */ BYTE CW32System::GetGdiCharSet(BYTE bCharSet) { return IsPrivateCharSet(bCharSet) ? DEFAULT_CHARSET : bCharSet; }
/*
* CW32System::GetCharSet(nCP, pScriptIndex) * * @func * Get character set for code page <p nCP>. Also returns script index * in *pScriptIndex * * @rdesc * CharSet for code page <p nCP> */ BYTE CW32System::GetCharSet( INT nCP, //@parm Code page or index
int *pScriptIndex) //@parm Out parm to receive index
{ TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "GetCharSet");
if(nCP < NCHARSETS) // nCP is already an index
{ nCP = max(nCP, 0); if(pScriptIndex) *pScriptIndex = nCP; return rgCpgCharSet[nCP].bCharSet; }
const CPGCHAR * pcpgchar = rgCpgCharSet;
for (int i = 0; i < cCpgCharSet; i++, ++pcpgchar) { if(pcpgchar->nCodePage == nCP) break; } if(i == cCpgCharSet) i = -1;
if (pScriptIndex) *pScriptIndex = i;
return i >= 0 ? pcpgchar->bCharSet : 0; }
/*
* CW32System::MatchFECharSet(dwCharInfo, dwFontSig) * * @func * Get a FE character set for a FE char * * @rdesc * CharSet */ BYTE CW32System::MatchFECharSet( DWORD dwCharInfo, //@parm Char Info
DWORD dwFontSig) //@parm Font Signature
{ TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::MatchFECharSet");
// Convert Font Signature to our internal char info
dwFontSig = (dwFontSig << 8) & ~0x00ffff;
// Get rid of lower word
dwCharInfo &= ~0x00ffff;
if (dwCharInfo & dwFontSig & (fKANA | fCHINESE | fHANGUL | fBIG5)) // Perfect match
goto Exit;
if (!(dwFontSig & (fKANA | fCHINESE | fHANGUL | fBIG5))) // Not a FE font
goto Exit;
if (dwCharInfo & (fCHINESE | fBIG5)) { if (dwFontSig & fBIG5) return CHINESEBIG5_CHARSET; if (dwFontSig & fHANGUL) return HANGEUL_CHARSET; if (dwFontSig & fKANA) return SHIFTJIS_CHARSET; }
Exit: return GetCharSet(W32->ScriptIndexFromFontSig(dwCharInfo >> 8), NULL); }
/*
* CW32System::GetCodePage(bCharSet) * * @func * Get code page for character set <p bCharSet> * * @rdesc * Code page for character set <p bCharSet> */ INT CW32System::GetCodePage( BYTE bCharSet) //@parm CharSet
{ TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "GetCodePage");
const CPGCHAR *pcpgchar = rgCpgCharSet;
for (int i = 0; i < cCpgCharSet ; i++, ++pcpgchar) { if (pcpgchar->bCharSet == bCharSet) return pcpgchar->nCodePage; } return 0; }
/*
* CW32System::GetFontSig(wCharSet) * * @func * Get font signature bits for character set <p wCharSet>. If * wCharSet > 256, treat as a codepage * * @rdesc * Font signature mask for character set (or codepage) <p bCharSet> */ DWORD CW32System::GetFontSig( WORD wCharSet) { TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::GetFontSig");
const CPGCHAR * pcpgchar = rgCpgCharSet; BOOL fCodePage = wCharSet > 255;
for (int i = 0; i < cCpgCharSet; i++) { if(wCharSet == (WORD)(fCodePage ? pcpgchar->nCodePage : pcpgchar->bCharSet)) return pcpgchar->dwFontSig; ++pcpgchar; } return 0; }
/*
* CW32System::GetFirstAvailCharSet(DWORD dwFontSig) * * @func * Get first available charset from font signature bits */ BYTE CW32System::GetFirstAvailCharSet( DWORD dwFontSig) { const CPGCHAR * pcpgchar = rgCpgCharSet;
for (int i = 0; i < cCpgCharSet; i++) { if(pcpgchar->dwFontSig & dwFontSig) return pcpgchar->bCharSet; ++pcpgchar; } return ANSI_CHARSET; }
/*
* CW32System::GetFontSigFromScript(iScript) * * @func * Get font signature bits for script <p iScript> * * @rdesc * Font signature mask for script <p iScript> */ DWORD CW32System::GetFontSigFromScript( int iScript) { return rgCpgCharSet[iScript].dwFontSig; }
/*
* CW32System::ScriptIndexFromFontSig(dwFontSig) * * @func * Get script index from font signature * * @rdesc * Script index from font signature <p dwFontSig> * * @devnote * Linear search */ LONG CW32System::ScriptIndexFromFontSig( DWORD dwFontSig) { TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::ScriptIndexFromFontSig");
const CPGCHAR *pcpgchar = rgCpgCharSet;
for (int i = 0; i < cCpgCharSet; i++, ++pcpgchar) { if(pcpgchar->dwFontSig == dwFontSig) return i; } return -1; // Not found
}
/*
* CW32System::ScriptIndexFromCharSet(bCharSet) * * @func * Get script index from bCharSet * * @rdesc * Script index character set <p bCharSet> * * @devnote * Linear search */ LONG CW32System::ScriptIndexFromCharSet( BYTE bCharSet) { TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::ScriptIndexFromCharSet");
const CPGCHAR *pcpgchar = rgCpgCharSet;
for (int i = 0; i < cCpgCharSet; i++, ++pcpgchar) { if(pcpgchar->bCharSet == bCharSet) return i; } return -1; // Not found
}
/*
* CW32System::IsCharSetValid(bCharSet) * * @func * Return TRUE iff <p bCharSet> is a valid character set index * * @rdesc * TRUE iff <p bCharSet> is a valid character set index */ BOOL CW32System::IsCharSetValid( BYTE bCharSet) //@parm CharSet
{ TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::IsCharSetValid");
return ScriptIndexFromCharSet(bCharSet) >= 0; }
/*
* CW32System::GetScreenDC(void) * * @mfunc * Returns you a default screen DC which richedit caches for its lifetime. * * Note, you need to serialize access to DCs, so make sure its used in the * renderer and measurer or otherwise protected by a CLock. * * @rdesc * Screen HDC if succeeded. */ HDC CW32System::GetScreenDC() { if (!_hdcScreen) _hdcScreen = CreateIC(L"DISPLAY", NULL, NULL, NULL);;
//Verify DC validity
Assert(GetDeviceCaps(_hdcScreen, LOGPIXELSX));
return _hdcScreen; }
/*
* CW32System::GetTextMetrics(hdc, &lf, &tm) * * @mfunc * CreateFontIndirect(lf), select into hdc, and get TEXTMETRICS * * @rdesc * TRUE if succeeded and selected facename is same as lf.lfFaceName */ BOOL CW32System::GetTextMetrics( HDC hdc, LOGFONT & lf, TEXTMETRIC &tm) { HFONT hfont = CreateFontIndirect(&lf); if(!hfont) return FALSE;
HFONT hfontOld = SelectFont(hdc, hfont); WCHAR szFaceName[LF_FACESIZE + 1];
BOOL fRet = GetTextFace(hdc, LF_FACESIZE, szFaceName) && !wcsicmp(lf.lfFaceName, szFaceName) && W32->GetTextMetrics(hdc, &tm);
SelectFont(hdc, hfontOld); DeleteObject(hfont); return fRet; }
/*
* CW32System::ValidateStreamWparam(wparam) * * @mfunc * Examine lparam to see if hiword is a valid codepage. If not set it * to 0 and turn off SF_USECODEPAGE flag * * @rdesc * Validated lparam */ WPARAM CW32System::ValidateStreamWparam( WPARAM wparam) //@parm EM_STREAMIN/OUT wparam
{ TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::ValidateStreamWparam");
if ((wparam & SF_USECODEPAGE) && !IsValidCodePage(HIWORD(wparam)) && HIWORD(wparam) != CP_UTF8) { // Invalid codepage, so reset codepage parameters
wparam &= 0xFFFF & ~SF_USECODEPAGE; } return wparam; }
/*
* CW32System::MECharClass(ch) * * @func * return ME character type for purposes of CharSet stamping. Values * are: * * 0: Arabic (specific RTL) * 1: Hebrew (specific RTL) * 2: RTL (generic RTL, e.g., RTL mark) * 3: LTR * 4: EOP or start/end of text * 5: ASCII digit * 6: punctuation and neutrals * * @rdesc * ME character class */ CC CW32System::MECharClass( TCHAR ch) { AssertSz(CC_NEUTRAL > CC_ASCIIDIGIT && CC_ASCIIDIGIT > CC_EOP && CC_EOP > CC_LTR && CC_LTR > CC_RTL && CC_RTL > CC_ARABIC, "CW32System::MECharClass: invalid CC values");
// Work down Unicode values from large to small. Use nested if
// statements to reduce the number executed.
// Remark: what about Arabic Presentation Forms?
// (0xFB50 - 0xFDFF, 0xFE70 - 0xFEFF)
if(ch >= 0x700) { if(IN_RANGE(ENQUAD, ch, RTLMARK)) { // ENQUAD thru RTLMARK
if(ch == RTLMARK) // Maybe add more Unicode general
return CC_RTL; // punctuation?
if(IN_RANGE(ZWNJ, ch, ZWJ)) // ZWNJ & ZWJ are handled as Arabic,
return CC_ARABIC; // even though they actually shouldn't
// affect layout.
if(ch < ZWNJ) return CC_NEUTRAL; // Various blanks are neutral
} return CC_LTR; }
if(ch >= 0x40) { if(ch >= 0x590) return (ch >= 0x600) ? CC_ARABIC : CC_HEBREW;
if(IN_RANGE(0x7B, (ch | 0x20), 0x7F) || ch == 0x60 || ch == 0x40) return CC_NEUTRAL; // [\]^_{|}~`@
return CC_LTR; }
if(ch >= 0x20) { if(IN_RANGE(0x30, ch, 0x39)) return CC_ASCIIDIGIT;
return CC_NEUTRAL; }
Assert(ch < 0x20); if((1 << ch) & 0x00003201) /* IsASCIIEOP(ch) || ch == TAB || !ch */ return CC_EOP; return CC_LTR; }
/*
* CW32System::ScriptIndexFromChar (ch) * * @mfunc * Returns index into CharSet/CodePage table rgCpgCharSet corresponding * to the Unicode character ch provided such an assignment is * reasonably unambiguous, that is, the currently assigned Unicode * characters in various ranges have Windows code-page equivalents. * Ambiguous or impossible assignments return UNKNOWN_INDEX, which * means that the character can only be represented by Unicode in this * simple model. Note that the UNKNOWN_INDEX, HAN_INDEX, and FE_INDEX * are negative values, i.e., they imply further processing to figure * out what (if any) charset index to use. Other indices may also * require run processing, such as the blank in BiDi text. We need * to mark our right-to-left runs with an Arabic or Hebrew char set, * while we mark left-to-right runs with a left-to-right char set. * * If the index has the FE_FLAG bit set, then the character is some kind * of FE "DBCS" character, like a Han, Kana, or Hangul character. * FE_INDEX, HAN_INDEX, HANGUL_INDEX, and SHIFTJIS_INDEX all have this * flag set. * * @rdesc * Script index in low word, and possible some extra flags, like * FE_FLAG in high word */ LONG CW32System::ScriptIndexFromChar( TCHAR ch) //@parm Unicode character to examine
{ if(ch < 256) return ANSI_INDEX;
if(ch < 0x700) { if(ch >= 0x600) return ARABIC_INDEX;
if(ch > 0x590) return HEBREW_INDEX;
if(ch < 0x500) { if(ch >= 0x400) return RUSSIAN_INDEX;
if(ch >= 0x370) return GREEK_INDEX; } } else if(ch < 0x2500) { if(IN_RANGE(0xE00, ch, 0xE7F)) // Thai
return THAI_INDEX; } else if(ch < 0xAC00) { if(ch >= 0x3400) // CJK Ideographs
return HAN_INDEX;
if(ch >= 0x3100) return FE_INDEX;
if(ch > 0x3040) // Katakana and Hiragana
return SHIFTJIS_INDEX;
if(ch >= 0x3000) return FE_INDEX; } else if(ch < 0xD800) return HANGUL_INDEX;
else if(ch > 0xFF00) { if(ch < 0xFF65) // Fullwidth ASCII and halfwidth
return HAN_INDEX; // CJK punctuation
if(ch < 0xFFA0) // Halfwidth Katakana
return SHIFTJIS_INDEX;
if(ch < 0xFFE0) // Halfwidth Jamo
return HANGUL_INDEX;
if(ch < 0xFFEF) // Fullwidth punctuation and currency
return HAN_INDEX; // signs; halfwidth forms, arrows
} // and shapes
return UNKNOWN_INDEX; }
/*
* CW32System::MBTWC (CodePage, dwFlags, pstrMB, cchMB, pstrWC, cchWC, pfNoCodePage) * * @mfunc * Convert MultiByte (MB) string pstrMB of length cchMB to WideChar (WC) * string pstrWC of length cchWC according to the flags dwFlags and code * page CodePage. If CodePage = SYMBOL_CODEPAGE * (usually for SYMBOL_CHARSET strings), * convert each byte in pstrMB to a wide char with a zero high byte * and a low byte equal to the MultiByte string byte, i.e., no * translation other than a zero extend into the high byte. Else call * the Win32 MultiByteToWideChar() function. * * @rdesc * Count of characters converted */ int CW32System::MBTWC( INT CodePage, //@parm Code page to use for conversion
DWORD dwFlags, //@parm Flags to guide conversion
LPCSTR pstrMB, //@parm MultiByte string to convert to WideChar
int cchMB, //@parm Count of chars (bytes) in pstrMB or -1
LPWSTR pstrWC, //@parm WideChar string to receive converted chars
int cchWC, //@parm Max count for pstrWC or 0 to get cch needed
LPBOOL pfNoCodePage) //@parm Out parm to receive whether code page is on system
{ BOOL fNoCodePage = FALSE; // Default code page is on OS
int cch = -1;
if(CodePage == CP_UTF8) { DWORD ch,ch1;
for(cch = 0; cchMB--; ) { ch = ch1 = *(BYTE *)pstrMB++; Assert(ch < 256); if(ch > 127 && cchMB && IN_RANGE(0x80, *(BYTE *)pstrMB, 0xBF)) { // Need at least 2 bytes of form 110bbbbb 10bbbbbb
ch1 = ((ch1 & 0x1F) << 6) + (*pstrMB++ & 0x3F); cchMB--; if(ch >= 0xE0 && cchMB && IN_RANGE(0x80, *(BYTE *)pstrMB, 0xBF)) { // Need at least 3 bytes of form 1110bbbb 10bbbbbb 10bbbbbb
ch1 = (ch1 << 6) + (*pstrMB++ & 0x3F); cchMB--; if (ch >= 0xF0 && cchMB && IN_RANGE(0x80, *(BYTE *)pstrMB, 0xBF)) { // Handle 4-byte form for 16 UTF-16 planes above the
// BMP) expect: 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
ch1 = ((ch1 & 0x7FFF) << 6) + (*(BYTE *)pstrMB++ & 0x3F) - 0x10000; // Subtract offset for BMP
if(ch1 <= 0xFFFFF) // Fits in 20 bits
{ cch++; // Two 16-bit surrogate codes
if(cch < cchWC) *pstrWC++ = UTF16_LEAD + (ch1 >> 10); ch1 = (ch1 & 0x3FF) + UTF16_TRAIL; cchMB--; } else ch1 = '?'; } } } cch++; if(cch < cchWC) *pstrWC++ = ch1; if(!ch) break; } } else if(CodePage != CP_SYMBOL) // Not SYMBOL_CHARSET
{ fNoCodePage = TRUE; // Default codepage isn't on OS
if(CodePage >= 0) // Might be..
{ cch = MultiByteToWideChar( CodePage, dwFlags, pstrMB, cchMB, pstrWC, cchWC); if(cch > 0) fNoCodePage = FALSE; // Codepage is on OS
} } if(pfNoCodePage) *pfNoCodePage = fNoCodePage;
if(cch <= 0) { // SYMBOL_CHARSET or conversion failed: bytes -> words with
// high bytes of 0. Return count for full conversion
if(cchWC <= 0) return cchMB >= 0 ? cchMB : (strlen(pstrMB) + 1);
int cchMBMax = cchMB;
if(cchMB < 0) // If negative, use NULL termination
cchMBMax = tomForward; // of pstrMB
cchMBMax = min(cchMBMax, cchWC);
for(cch = 0; (cchMB < 0 ? *pstrMB : 1) && cch < cchMBMax; cch++) { *pstrWC++ = (unsigned char)*pstrMB++; } // NULL-terminate the WC string if the MB string was NULL-terminated,
// and if there is room in the WC buffer.
if(cchMB < 0 && cch < cchWC) { *pstrWC = 0; cch++; } } return cch; }
/*
* CW32System::WCTMB (CodePage, dwFlags, pstrWC, cchWC, pstrMB, cchMB, * pchDefault, pfUsedDef, pfNoCodePage, fTestCodePage) * * @mfunc * Convert WideChar (WC) string pstrWC of length cchWC to MultiByte (MB) * string pstrMB of length cchMB according to the flags dwFlags and code * page CodePage. If CodePage = SYMBOL_CODEPAGE * (usually for SYMBOL_CHARSET strings), * convert each character in pstrWC to a byte, discarding the high byte. * Else call the Win32 WideCharToMultiByte() function. * * @rdesc * Count of bytes stored in target string pstrMB */ int CW32System::WCTMB( INT CodePage, //@parm Code page to use for conversion
DWORD dwFlags, //@parm Flags to guide conversion
LPCWSTR pstrWC, //@parm WideChar string to convert
int cchWC, //@parm Count for pstrWC or -1 to use NULL termination
LPSTR pstrMB, //@parm MultiByte string to receive converted chars
int cchMB, //@parm Count of chars (bytes) in pstrMB or 0
LPCSTR pchDefault, //@parm Default char to use if conversion fails
LPBOOL pfUsedDef, //@parm Out parm to receive whether default char used
LPBOOL pfNoCodePage, //@parm Out parm to receive whether code page is on system
BOOL fTestCodePage)//@parm Test CodePage could handle the pstrWC
{ int cch = -1; // No chars converted yet
BOOL fNoCodePage = FALSE; // Default code page is on OS
if(pfUsedDef) // Default that all chars can be
*pfUsedDef = FALSE; // converted
#ifndef WC_NO_BEST_FIT_CHARS
#define WC_NO_BEST_FIT_CHARS 0x400
#endif
if (_dwPlatformId == VER_PLATFORM_WIN32_NT && _dwMajorVersion > 4 && !dwFlags) { dwFlags = WC_NO_BEST_FIT_CHARS; }
if(CodePage == CP_UTF8) // Convert to UTF8 since OS
{ // doesn't (pre NT 5.0)
unsigned ch; cch = 0; // No converted bytes yet
while(cchWC--) { ch = *pstrWC++; // Get Unicode char
if(ch <= 127) // It's ASCII
{ cch++; if(cch < cchMB) *pstrMB++ = ch; // One more converted byte
if(!ch) // Quit on NULL termination
break; continue; } if(ch <= 0x7FF) // Need 2 bytes of form:
{ // 110bbbbb 10bbbbbb
cch += 2; if(cch < cchMB) // Store lead byte
*pstrMB++ = 0xC0 + (ch >> 6); } else if(IN_RANGE(UTF16_LEAD, ch, 0xDBFF)) { // Unicode surrogate pair
cch += 4; // Need 4 bytes of form:
if(cch < cchMB) // 11110bbb 10bbbbbb 10bbbbbb
{ // 10bbbbbb
AssertSz(IN_RANGE(UTF16_TRAIL, *pstrWC, 0xDFFF), "CW32System::WCTMB: illegal surrogate pair"); cchWC--; ch = ((ch & 0x3FF) << 10) + (*pstrWC++ & 0x3FF) + 0x10000; *pstrMB++ = 0xF0 + (ch >> 18); *pstrMB++ = 0x80 + (ch >> 12 & 0x3F); *pstrMB++ = 0x80 + (ch >> 6 & 0x3F); } } else // Need 3 bytes of form:
{ // 1110bbbb 10bbbbbb
cch += 3; // 10bbbbbb
if(cch < cchMB) // Store lead byte followed by
{ // first trail byte
*pstrMB++ = 0xE0 + (ch >> 12); *pstrMB++ = 0x80 + (ch >> 6 & 0x3F); } } if(cch < cchMB) // Store final UTF-8 byte
*pstrMB++ = 0x80 + (ch & 0x3F); } } else if(CodePage != CP_SYMBOL) { fNoCodePage = TRUE; // Default codepage not on OS
if(CodePage >= 0) // Might be...
{ cch = WideCharToMultiByte(CodePage, dwFlags, pstrWC, cchWC, pstrMB, cchMB, pchDefault, pfUsedDef); if(cch > 0) fNoCodePage = FALSE; // Found codepage on system
} } if(pfNoCodePage) *pfNoCodePage = fNoCodePage;
// Early exit if we are just testing for CodePage
if (fTestCodePage) return cch;
// SYMBOL_CHARSET, fIsDBCS or conversion failed: low bytes of words ->
// bytes
if(cch <= 0) { // Return multibyte count for full conversion. cchWC is correct for
// single-byte charsets like the 125x's
if(cchMB <= 0) { return cchWC >= 0 ? cchWC : wcslen(pstrWC); }
char chDefault = 0; BOOL fUseDefaultChar = (pfUsedDef || pchDefault) && CodePage != CP_SYMBOL;
if(fUseDefaultChar) { // determine a default char for our home-grown conversion
if(pchDefault) { chDefault = *pchDefault; } else { static char chSysDef = 0; static BOOL fGotSysDef = FALSE;
// 0x2022 is a math symbol with no conversion to ANSI
const WCHAR szCantConvert[] = { 0x2022 }; BOOL fUsedDef;
if(!fGotSysDef) { fGotSysDef = TRUE;
if(!(WideCharToMultiByte (CP_ACP, 0, szCantConvert, 1, &chSysDef, 1, NULL, &fUsedDef) == 1 && fUsedDef)) { AssertSz(0, "WCTMB(): Unable to determine what the " "system uses as its default replacement " "character."); chSysDef = '?'; } } chDefault = chSysDef; } }
int cchWCMax = cchWC;
// If negative, use NULL termination of pstrMB
if(cchWC < 0) { cchWCMax = tomForward; }
cchWCMax = min(cchWCMax, cchMB);
for(cch = 0; (cchWC < 0 ? *pstrWC : 1) && cch < cchWCMax; cch++) { // TODO(BradO): Should this be 0x7F in some conversion cases?
if(fUseDefaultChar && *pstrWC > 0xFF) { if(pfUsedDef) { *pfUsedDef = TRUE; } *pstrMB = chDefault; } else { *pstrMB = (BYTE)*pstrWC; } pstrMB++; pstrWC++; }
if(cchWC < 0 && cch < cchMB) { *pstrMB = 0; cch++; } } return cch; } /*
* CW32System::VerifyFEString(cpg, pstrWC, cchWC, fTestInputCpg) * * @mfunc * Verify if the input cpg can handle the pstrWC. * If not, select another FE cpg. * * @rdesc * New CodePage for the pstrWC */ #define NUMBER_OF_CHARS 64
int CW32System::VerifyFEString( INT cpg, //@parm cpg to format the pstrWC
LPCWSTR pstrWC, //@parm WideChar string to test
int cchWC, //@parm Count for pstrWC
BOOL fTestInputCpg) //@parm test the input cpg only
{ if (cchWC <=0) return cpg;
int cpgNew = cpg; BOOL fUsedDef; int cchMB = cchWC * sizeof(WCHAR); CTempCharBuf tcb; char *pstrMB = tcb.GetBuf(cchMB); CTempWcharBuf twcb; WCHAR *pstrWchar = twcb.GetBuf(cchWC); static int aiCpg[4] = { CP_JAPAN, CP_KOREAN, CP_CHINESE_TRAD, CP_CHINESE_SIM };
if (pstrMB) { int cchConverted = WCTMB(cpg, 0, pstrWC, cchWC, pstrMB, cchMB, NULL, &fUsedDef, NULL, TRUE);
if (cchConverted > 0 && !fUsedDef && IsFEFontInSystem(cpg)) { cchConverted = MBTWC(cpg, 0, pstrMB, cchConverted, pstrWchar, cchWC, NULL);
if (cchConverted == cchWC && memcmp(pstrWC, pstrWchar, cchMB) == 0) goto Exit; // Found it
} if (fTestInputCpg) // Only need to test the input cpg
cpgNew = -1; // Indicate cpg doesn't support the string
else { // If no conversion or if the default character is used or
// no such FE font in system,
// it means that this cpg may not be the right choice.
// Let's try other FE cpg.
for (int i=0; i < 4; i++) { if (cpg != aiCpg[i]) { cchConverted = WCTMB(aiCpg[i], 0, pstrWC, cchWC, pstrMB, cchMB, NULL, &fUsedDef, NULL, TRUE);
if (cchConverted > 0 && !fUsedDef && IsFEFontInSystem(aiCpg[i])) { cchConverted = MBTWC(aiCpg[i], 0, pstrMB, cchConverted, pstrWchar, cchWC, NULL);
if (cchConverted == cchWC && memcmp(pstrWC, pstrWchar, cchMB) == 0) { cpgNew = aiCpg[i]; // Found it
break; } } } } } }
Exit:
return cpgNew; }
int __cdecl CW32System::sprintf(char * buff, char *fmt, ...) { va_list marker;
va_start(marker, fmt); int cb = W32->WvsprintfA(0x07FFFFFFF, buff, fmt, marker); va_end(marker);
return cb; }
//NOTE: Keep this at the end because we want any allocations in w32sys.cpp to be validated
//just like the rest of RichEdit.
/////////////////////////////// Memory mamagement /////////////////////////////////
#ifdef DEBUG
#undef PvAlloc
#undef PvReAlloc
#undef FreePv
#undef new
MST vrgmst[100];
typedef struct tagPVH //PV Header
{ char *szFile; int line; tagPVH *ppvhNext; int cbAlloc; //On Win'95, the size returned is not the size allocated.
int magicPvh; //Should be last
} PVH; #define cbPvh (sizeof(PVH))
typedef struct //PV Tail { int magicPvt; //Must be first
} PVT;
#define cbPvt (sizeof(PVT))
#define cbPvDebug (cbPvh + cbPvt)
void *vpHead = 0;
/*
* CW32System::UpdateMst(void) * * @mfunc Fills up the vrgmst structure with summary information about our memory * usage. * * @rdesc * void */ void UpdateMst(void) { W32->ZeroMemory(vrgmst, sizeof(vrgmst));
PVH *ppvh; MST *pmst;
ppvh = (PVH*) vpHead;
while (ppvh != 0) { pmst = vrgmst;
//Look for entry in list...
while (pmst->szFile) { if (strcmp(pmst->szFile, ppvh->szFile) == 0) { pmst->cbAlloc += ppvh->cbAlloc; break; } pmst++; }
if (pmst->szFile == 0) { pmst->szFile = ppvh->szFile; pmst->cbAlloc = ppvh->cbAlloc; }
ppvh = ppvh->ppvhNext; } }
/*
* PvDebugValidate(void) * * @func Verifies the the node is proper. Pass in a pointer to the users data * (after the header node.) * * @rdesc * void */ void PvDebugValidate(void *pv) { PVH *ppvh; PVT *ppvt;
ppvh = (PVH*) ((char*) pv - cbPvh); ppvt = (PVT*) ((char*) pv + ppvh->cbAlloc);
AssertSz(ppvh->magicPvh == 0x12345678, "PvDebugValidate: header bytes are corrupt"); AssertSz(ppvt->magicPvt == 0xfedcba98, "PvDebugValidate: tail bytes are corrupt"); }
/*
* CW32System::PvSet(pv, szFile, line) * * @mfunc Sets a different module and line number for * * @rdesc * void */ void CW32System::PvSet(void *pv, char *szFile, int line) { if (pv == 0) return;
PvDebugValidate(pv); PVH *ppvh = (PVH*) ((char*) pv - cbPvh);
ppvh->szFile = szFile; ppvh->line = line; } /*
* CW32System::PvAllocDebug(cb, uiMemFlags, szFile, line) * * @mfunc Allocates a generic (void*) pointer. This is a debug only routine which * tracks the allocation. * * @rdesc * void */ void* CW32System::PvAllocDebug(ULONG cb, UINT uiMemFlags, char *szFile, int line) { void *pv;
pv = PvAlloc(cb + cbPvDebug, uiMemFlags); if (!pv) return 0;
PVH *ppvh; PVT *ppvt;
ppvt = (PVT*) ((char*) pv + cb + cbPvh); ppvh = (PVH*) pv;
ZeroMemory(ppvh, sizeof(PVH)); ppvh->magicPvh = 0x12345678; ppvt->magicPvt = 0xfedcba98; ppvh->szFile = szFile; ppvh->line = line; ppvh->cbAlloc = cb;
ppvh->ppvhNext = (PVH*) vpHead; vpHead = pv;
return (char*) pv + cbPvh; }
/*
* CW32System::PvReAllocDebug(pv, cb, szFile, line) * * @mfunc ReAllocates a generic (void*) pointer. This is a debug only routine which * tracks the allocation. * * @rdesc * void */ void* CW32System::PvReAllocDebug(void *pv, ULONG cb, char *szFile, int line) { void *pvNew; PVH *ppvh, *ppvhHead, *ppvhTail; PVT *ppvt; ppvh = (PVH*) ((char*) pv - cbPvh);
if (!pv) return PvAllocDebug(cb, 0, szFile, line);
PvDebugValidate(pv);
pvNew = PvReAlloc((char*) pv - cbPvh, cb + cbPvDebug);
if (!pvNew) return 0;
ppvt = (PVT*) ((char*) pvNew + cb + cbPvh); ppvh = (PVH*) pvNew; ppvh->cbAlloc = cb;
//Put the new trailer bytes in.
ppvt->magicPvt = 0xfedcba98;
//Make the pointer list up to date again
if (pv != pvNew) { ppvhTail = 0; ppvhHead = (PVH*) vpHead;
while ((char*)ppvhHead != (char*)pv - cbPvh) { AssertSz(ppvhHead, "entry not found in list."); ppvhTail = ppvhHead; ppvhHead = (PVH*) ppvhHead->ppvhNext; }
if (ppvhTail == 0) vpHead = pvNew; else ppvhTail->ppvhNext = (PVH*) pvNew; }
return (char*) pvNew + cbPvh; }
/*
* CW32System::FreePvDebug(pv) * * @mfunc Returns a pointer when you are done with it. * * @rdesc * void */ void CW32System::FreePvDebug(void *pv) { if (!pv) return;
PvDebugValidate(pv);
PVH *ppvhHead, *ppvhTail, *ppvh;
AssertSz(vpHead, "Deleting from empty free list.");
ppvh = (PVH*) ((char*) pv - cbPvh); //Search and remove the entry from the list
ppvhTail = 0; ppvhHead = (PVH*) vpHead;
while ((char*) ppvhHead != ((char*) pv - cbPvh)) { AssertSz(ppvhHead, "entry not found in list."); ppvhTail = ppvhHead; ppvhHead = (PVH*) ppvhHead->ppvhNext; }
if (ppvhTail == 0) vpHead = ppvhHead->ppvhNext; else ppvhTail->ppvhNext = ppvhHead->ppvhNext;
FreePv((char*) pv - cbPvh); }
/*
* CatchLeaks(void) * * @func Displays any memory leaks in a dialog box. * * @rdesc * void */ void CatchLeaks(void) { PVH *ppvh; char szLeak[512];
ppvh = (PVH*) vpHead; while (ppvh != 0) { wsprintfA(szLeak, "Memory Leak of %d bytes: -- File: %s, Line: %d", ppvh->cbAlloc, ppvh->szFile, ppvh->line); if (NULL != pfnAssert) { // if we have an assert hook, give the user a chance to process the leak message
if (pfnAssert(szLeak, ppvh->szFile, &ppvh->line)) { // hook returned true, show the message box
MessageBoxA(NULL, szLeak, "", MB_OK); } } else { MessageBoxA(NULL, szLeak, "", MB_OK); } ppvh = ppvh->ppvhNext; } }
void* _cdecl operator new (size_t size, char *szFile, int line) { TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "new");
return W32->PvAllocDebug(size, GMEM_ZEROINIT, szFile, line); }
void _cdecl operator delete (void* pv) { TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "delete");
W32->FreePvDebug(pv); }
#else //DEBUG
void* _cdecl operator new (size_t size) { TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "new");
return W32->PvAlloc(size, GMEM_ZEROINIT); }
void _cdecl operator delete (void* pv) { TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "delete");
W32->FreePv(pv); }
#endif //DEBUG
/*
* PvAlloc (cbBuf, uiMemFlags) * * @mfunc memory allocation. Similar to GlobalAlloc. * * @comm The only flag of interest is GMEM_ZEROINIT, which * specifies that memory should be zeroed after allocation. */ PVOID CW32System::PvAlloc( ULONG cbBuf, //@parm Count of bytes to allocate
UINT uiMemFlags) //@parm Flags controlling allocation
{ TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "PvAlloc"); void * pv = LocalAlloc(LMEM_FIXED, cbBuf);
if( pv && (uiMemFlags & GMEM_ZEROINIT) ) ZeroMemory(pv, cbBuf); return pv; }
/*
* PvReAlloc (pvBuf, cbBuf) * * @mfunc memory reallocation. * */ PVOID CW32System::PvReAlloc( PVOID pvBuf, //@parm Buffer to reallocate
DWORD cbBuf) //@parm New size of buffer
{ TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "PvReAlloc");
if(pvBuf) return LocalReAlloc(pvBuf, cbBuf, LMEM_MOVEABLE);
return LocalAlloc(LMEM_FIXED, cbBuf); }
/*
* FreePv (pvBuf) * * @mfunc frees memory * * @rdesc void */ void CW32System::FreePv( PVOID pvBuf) //@parm Buffer to free
{ TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "FreePv");
if(pvBuf) LocalFree(pvBuf); }
/*
* Mirroring API (only in BiDi Win98 and NT5 upward) * * @mfunc Get/Set DC mirroring effect * */
DWORD WINAPI GetLayoutStub(HDC hdc) { return 0; }
DWORD WINAPI SetLayoutStub(HDC hdc, DWORD dwLayout) { return 0; }
DWORD WINAPI GetLayoutInit(HDC hdc) { CLock lock; HINSTANCE hMod = ::GetModuleHandleA("GDI32.DLL"); Assert(hMod);
W32->_pfnGetLayout = (PFN_GETLAYOUT)GetProcAddress(hMod, "GetLayout");
if (!W32->_pfnGetLayout) W32->_pfnGetLayout = &GetLayoutStub;
return W32->_pfnGetLayout(hdc); }
DWORD WINAPI SetLayoutInit(HDC hdc, DWORD dwLayout) { CLock lock; HINSTANCE hMod = ::GetModuleHandleA("GDI32.DLL"); Assert(hMod);
W32->_pfnSetLayout = (PFN_SETLAYOUT)GetProcAddress(hMod, "SetLayout");
if (!W32->_pfnSetLayout) W32->_pfnSetLayout = &SetLayoutStub;
return W32->_pfnSetLayout(hdc, dwLayout); }
PFN_GETLAYOUT CW32System::_pfnGetLayout = &GetLayoutInit; PFN_SETLAYOUT CW32System::_pfnSetLayout = &SetLayoutInit;
|