You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2986 lines
72 KiB
2986 lines
72 KiB
/*
|
|
* @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;
|
|
|