windows-nt/Source/XPSP1/NT/windows/richedit/re41/w32sys.cpp
2020-09-26 16:20:57 +08:00

2652 lines
67 KiB
C++
Raw Blame History

/*
* @doc INTERNAL
*
* @module w32sys.cpp - thin layer over Win32 services
*
* History: <nl>
* 1/22/97 joseogl Created
*
* Copyright (c) 1995-2000 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"
//
//Cache of Type 1 data. See also clasifyc.cpp and rgbCharClass in
//rtflex.cpp.
// Used by GetStringTypeEx
//
const unsigned short rgctype1Ansi[256] = {
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, //0x00
0x0020, 0x0068, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020, //0x08
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, //0x10
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, //0x18
0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, //0x20
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, //0x28
0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, //0x30
0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, //0x38
0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101, //0x40
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, //0x48
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, //0x50
0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, //0x58
0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102, //0x60
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, //0x68
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, //0x70
0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020, //0x78
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, //0x80
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, //0x88
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, //0x90
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, //0x98
0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, //0xA0
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, //0xA8
0x0010, 0x0010, 0x0014, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010, //0xB0
0x0010, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, //0xB8
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, //0xC0
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, //0xC8
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0010, //0xD0
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0102, //0xD8
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, //0xE0
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, //0xE8
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, //0xF0
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102};//0xF8
//
//Cache of Type 3 data.
//
const unsigned short rgctype3Ansi[256] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, //0x00
0x0000, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, //0x08
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, //0x10
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, //0x18
0x0048, 0x0048, 0x0448, 0x0048, 0x0448, 0x0048, 0x0048, 0x0440, //0x20
0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0440, 0x0048, 0x0448, //0x28
0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, //0x30
0x0040, 0x0040, 0x0048, 0x0048, 0x0048, 0x0448, 0x0048, 0x0048, //0x38
0x0448, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, //0x40
0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, //0x48
0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, //0x50
0x8040, 0x8040, 0x8040, 0x0048, 0x0448, 0x0048, 0x0448, 0x0448, //0x58
0x0448, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, //0x60
0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, //0x68
0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, //0x70
0x8040, 0x8040, 0x8040, 0x0048, 0x0048, 0x0048, 0x0448, 0x0000, //0x78
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, //0x80
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, //0x88
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, //0x90
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, //0x98
0x0008, 0x0008, 0x0048, 0x0048, 0x0008, 0x0048, 0x0048, 0x0008, //0xA0
0x0408, 0x0008, 0x0400, 0x0008, 0x0048, 0x0408, 0x0008, 0x0448, //0xA8
0x0008, 0x0008, 0x0000, 0x0000, 0x0408, 0x0008, 0x0008, 0x0008, //0xB0
0x0408, 0x0000, 0x0400, 0x0008, 0x0000, 0x0000, 0x0000, 0x0008, //0xB8
0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8000, 0x8003, //0xC0
0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, //0xC8
0x8000, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x0008, //0xD0
0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8000, 0x8000, //0xD8
0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8000, 0x8003, //0xE0
0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, //0xE8
0x8000, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, //0xF0
0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8003, 0x8000, 0x8003};//0xF8
// Include the appropriate implementation.
#include W32INCLUDE
#if 0
// Could be one of.
// This list is here to allow the dependency generator to work.
#include "w32win32.cpp"
#include "w32wince.cpp"
#endif
ASSERTDATA
/*
* rgCodePage, rgCharSet, rgFontSig
*
* Locally used arrays that contain CodePage, CharSet, and FontSig info
* and indexed by iCharRep, the character repertoire index. When a char
* repertoire has a CharSet and CodePage, it has an entry in rgCharSet
* and in rgCodePage. Unicode-only repertoires follow the CharSet
* repertoires in the rgFontSig table. It is essential to keep these
* three tables in sync and they used to be combined into a single table.
* They are separate here to save on RAM.
*/
static const WORD rgCodePage[] =
{
// 0 1 2 3 4 5 6 7 8 9
1252, 1250, 1251, 1253, 1254, 1255, 1256, 1257, 1258, 0,
42, 874, 932, 936, 949, 950, 437, 850, 10000
};
static const BYTE rgCharSet[] =
{
// 0 1 2 3
ANSI_CHARSET, EASTEUROPE_CHARSET, RUSSIAN_CHARSET, GREEK_CHARSET,
TURKISH_CHARSET, HEBREW_CHARSET, ARABIC_CHARSET, BALTIC_CHARSET,
VIETNAMESE_CHARSET, DEFAULT_CHARSET, SYMBOL_CHARSET, THAI_CHARSET,
SHIFTJIS_CHARSET, GB2312_CHARSET, HANGUL_CHARSET, CHINESEBIG5_CHARSET,
PC437_CHARSET, OEM_CHARSET, MAC_CHARSET
};
#define CCHARSET ARRAY_SIZE(rgCharSet)
#define CCODEPAGE ARRAY_SIZE(rgCodePage)
#define LANG_PRC MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
#define LANG_SINGAPORE MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE)
const BYTE rgCharRepfromLID[] = {
// Char Repertoire PLID primary language
// --------------------------------------------
DEFAULT_INDEX, // 00 - undefined
ARABIC_INDEX, // 01 - Arabic
RUSSIAN_INDEX, // 02 - Bulgarian
ANSI_INDEX, // 03 - Catalan
GB2312_INDEX, // 04 - PRC, Singapore (Taiwan, Hong Kong SAR, Macau SAR are 950)
EASTEUROPE_INDEX, // 05 - Czech
ANSI_INDEX, // 06 - Danish
ANSI_INDEX, // 07 - German
GREEK_INDEX, // 08 - Greek
ANSI_INDEX, // 09 - English
ANSI_INDEX, // 0A - Spanish
ANSI_INDEX, // 0B - Finnish
ANSI_INDEX, // 0C - French
HEBREW_INDEX, // 0D - Hebrew
EASTEUROPE_INDEX, // 0E - Hungarian
ANSI_INDEX, // 0F - Icelandic
ANSI_INDEX, // 10 - Italian
SHIFTJIS_INDEX, // 11 - Japan
HANGUL_INDEX, // 12 - Korea
ANSI_INDEX, // 13 - Dutch
ANSI_INDEX, // 14 - Norwegian
EASTEUROPE_INDEX, // 15 - Polish
ANSI_INDEX, // 16 - Portuguese
DEFAULT_INDEX, // 17 - Rhaeto-Romanic
EASTEUROPE_INDEX, // 18 - Romanian
RUSSIAN_INDEX, // 19 - Russian
EASTEUROPE_INDEX, // 1A - Croatian
EASTEUROPE_INDEX, // 1B - Slovak
EASTEUROPE_INDEX, // 1C - Albanian
ANSI_INDEX, // 1D - Swedish
THAI_INDEX, // 1E - Thai
TURKISH_INDEX, // 1F - Turkish
ARABIC_INDEX, // 20 - Urdu
ANSI_INDEX, // 21 - Indonesian
RUSSIAN_INDEX, // 22 - Ukranian
RUSSIAN_INDEX, // 23 - Byelorussian
EASTEUROPE_INDEX, // 24 - Slovenian
BALTIC_INDEX, // 25 - Estonia
BALTIC_INDEX, // 26 - Latvian
BALTIC_INDEX, // 27 - Lithuanian
DEFAULT_INDEX, // 28 - Tajik - Tajikistan (undefined)
ARABIC_INDEX, // 29 - Farsi
VIET_INDEX, // 2A - Vietnanese
ARMENIAN_INDEX, // 2B - Armenian (Unicode only)
TURKISH_INDEX, // 2C - Azeri (Latin, can be Cyrillic...)
ANSI_INDEX, // 2D - Basque
DEFAULT_INDEX, // 2E - Sorbian
RUSSIAN_INDEX, // 2F - fyro Macedonian
ANSI_INDEX, // 30 - Sutu
ANSI_INDEX, // 31 - Tsonga
ANSI_INDEX, // 32 - Tswana
ANSI_INDEX, // 33 - Venda
ANSI_INDEX, // 34 - Xhosa
ANSI_INDEX, // 35 - Zulu
ANSI_INDEX, // 36 - Africaans
GEORGIAN_INDEX, // 37 - Georgian (Unicode only)
ANSI_INDEX, // 38 - Faerose
DEVANAGARI_INDEX, // 39 - Hindi (Indic)
ANSI_INDEX, // 3A - Maltese
ANSI_INDEX, // 3B - Sami
ANSI_INDEX, // 3C - Gaelic
HEBREW_INDEX, // 3D - Yiddish
ANSI_INDEX, // 3E - Malaysian
RUSSIAN_INDEX, // 3F - Kazakh
ANSI_INDEX, // 40 - Kirghiz
ANSI_INDEX, // 41 - Swahili
ANSI_INDEX, // 42 - Turkmen
TURKISH_INDEX, // 43 - Uzbek (Latin, can be Cyrillic...)
ANSI_INDEX, // 44 - Tatar
BENGALI_INDEX, // 45 - Bengali (Indic)
GURMUKHI_INDEX, // 46 - Punjabi(Gurmukhi) (Indic)
GUJARATI_INDEX, // 47 - Gujarati (Indic)
ORIYA_INDEX, // 48 - Oriya (Indic)
TAMIL_INDEX, // 49 - Tamil (Indic)
TELUGU_INDEX, // 4A - Telugu (Indic)
KANNADA_INDEX, // 4B - Kannada (Indic)
MALAYALAM_INDEX, // 4C - Malayalam (Indic)
BENGALI_INDEX, // 4D - Assamese (Indic)
DEVANAGARI_INDEX, // 4E - Marathi (Indic)
DEVANAGARI_INDEX, // 4F - Sanskrit (Indic)
MONGOLIAN_INDEX, // 50 - Mongolian (Mongolia)
TIBETAN_INDEX, // 51 - Tibetan (Tibet)
ANSI_INDEX, // 52 - Welsh (Wales)
KHMER_INDEX, // 53 - Khmer (Cambodia)
LAO_INDEX, // 54 - Lao (Lao)
MYANMAR_INDEX, // 55 - Burmese (Myanmar)
ANSI_INDEX, // 56 - Gallego (Portugal)
DEVANAGARI_INDEX, // 57 - Konkani (Indic)
BENGALI_INDEX, // 58 - Manipuri (Indic)
GURMUKHI_INDEX, // 59 - Sindhi (Indic)
SYRIAC_INDEX, // 5A - Syriac (Syria)
SINHALA_INDEX, // 5B - Sinhalese (Sri Lanka)
CHEROKEE_INDEX, // 5C - Cherokee
ABORIGINAL_INDEX, // 5D - Inuktitut
ETHIOPIC_INDEX, // 5E - Amharic (Ethiopic)
DEFAULT_INDEX, // 5F - Tamazight (Berber/Arabic) also Latin
DEFAULT_INDEX, // 60 - Kashmiri
DEVANAGARI_INDEX, // 61 - Nepali (Nepal)
ANSI_INDEX, // 62 - Frisian (Netherlands)
ARABIC_INDEX, // 63 - Pashto (Afghanistan)
ANSI_INDEX, // 64 - Filipino
THAANA_INDEX // 65 - Maldivian (Maldives (Thaana))
};
#define CLID ARRAY_SIZE(rgCharRepfromLID)
#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;
_fLoadAIMM10 = FALSE;
_pIMEShare = NULL;
_icr3DDarkShadow = COLOR_WINDOWFRAME;
if(_dwMajorVersion >= VERS4)
_icr3DDarkShadow = COLOR_3DDKSHADOW;
}
_syslcid = GetSystemDefaultLCID();
_ACP = ::GetACP();
#ifndef NOMAGELLAN
// BUG FIX #6089
// we need this for backward compatibility of mouse wheel
_MSMouseRoller = RegisterWindowMessageA(MSH_MOUSEWHEEL);
#endif
#ifndef NOFEPROCESSING
// Register IME messages
_MSIMEMouseMsg = RegisterWindowMessageA("MSIMEMouseOperation");
_MSIMEDocFeedMsg = RegisterWindowMessageA("MSIMEDocumentFeed");
_MSIMEQueryPositionMsg = RegisterWindowMessageA("MSIMEQueryPosition");
_MSIMEServiceMsg = RegisterWindowMessageA("MSIMEService");
// Check Reconvert 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; // For reconversion
_MSIMEReconvertRequestMsg = 0; // For reconversion request
}
#endif
}
CW32System::~CW32System()
{
if (_arTmpDisplayAttrib)
{
delete _arTmpDisplayAttrib;
_arTmpDisplayAttrib = NULL;
}
FreeOle();
if (_hdcScreen)
DeleteDC(_hdcScreen);
if (_hDefaultFont)
DeleteObject(_hDefaultFont);
}
/////////////////////////////// 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 CW32System::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 CW32System::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 */
}
char * __cdecl CW32System::strrchr (
const char * string,
int ch
)
{
char *start = (char *)string;
while (*string++) /* find end of string */
;
/* search towards front */
while (--string != start && *string != (char)ch)
;
if (*string == (char)ch) /* char found ? */
return( (char *)string );
return(NULL);
}
#endif
// This function in the runtime traps virtual method calls
int __cdecl _purecall()
{
AssertSz(FALSE, "Fatal Error : Virtual method called in RichEdit");
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
BYTE CW32System::_fLRMorRLM;
BYTE CW32System::_fHaveIMMProcs;
BYTE CW32System::_fHaveIMMEShare;
BYTE CW32System::_fHaveAIMM;
BYTE CW32System::_fLoadAIMM10;
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;
CTmpDisplayAttrArray* CW32System::_arTmpDisplayAttrib;
// CW32System static system parameter members
BOOL CW32System::_fSysParamsOk;
BOOL CW32System::_fUsePalette;
INT CW32System::_dupSystemFont;
INT CW32System::_dvpSystemFont;
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;
DWORD CW32System::_dwNumKeyPad;
WORD CW32System::_fFEFontInfo;
BYTE CW32System::_bDigitSubstMode;
BYTE CW32System::_bCharSetSys;
HCURSOR CW32System::_hcurSizeNS;
HCURSOR CW32System::_hcurSizeWE;
HCURSOR CW32System::_hcurSizeNWSE;
HCURSOR CW32System::_hcurSizeNESW;
LONG CW32System::_cLineScroll;
HFONT CW32System::_hSystemFont;
HFONT CW32System::_hDefaultFont;
HKL CW32System::_hklCurrent;
HKL CW32System::_hkl[NCHARREPERTOIRES];
INT CW32System::_sysiniflags;
UINT CW32System::_ACP;
DWORD CW32System::_cRefs;
#ifndef NODRAFTMODE
CW32System::DraftModeFontInfo CW32System::_draftModeFontInfo;
#endif
/*
* 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 RichEdit 1.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::CharRepFromLID (lid, fPlane2)
*
* @mfunc Maps a language ID to a character repertoire
*
* @rdesc returns character repertoire (writing system) corresponding to LID
*
* @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.
*/
UINT CW32System::CharRepFromLID(
WORD lid, //@parm Language ID to map to code page
BOOL fPlane2) //@parm TRUE if plane-2 CharRep needed
{
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 RUSSIAN_INDEX;
}
if(j >= CLID) // Most languages above table
return ANSI_INDEX;
}
j = rgCharRepfromLID[j]; // Translate PLID to CharRep
if(!IsFECharRep(j))
return j;
if(j == GB2312_INDEX && lid != LANG_PRC && lid != LANG_SINGAPORE)
j = BIG5_INDEX; // Taiwan, Hong Kong SAR, Macau SAR
return fPlane2 ? j + JPN2_INDEX - SHIFTJIS_INDEX : j;
}
/*
* CW32System::GetLocaleCharRep ()
*
* @mfunc Maps an LCID for thread to a Char repertoire
*
* @rdesc returns Code Page
*/
UINT CW32System::GetLocaleCharRep()
{
#ifdef DEBUG
UINT cpg = W32->DebugDefaultCpg();
if (cpg)
return CharRepFromCodePage(cpg);
#endif
LCID lcid;
#ifdef UNDER_CE
lcid = ::GetSystemDefaultLCID();
#else
lcid = GetThreadLocale();
#endif
return CharRepFromLID(LOWORD(lcid));
}
/*
* 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::GetKeyboardCharRep ()
*
* @mfunc Gets Code Page for keyboard active on current thread
*
* @rdesc returns Code Page
*/
UINT CW32System::GetKeyboardCharRep(DWORD dwMakeAPICall)
{
return CharRepFromLID((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(
WCHAR 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(
WCHAR 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
}
// <09> <20> <09>
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 Asia country/region.
*
* @rdesc
* TRUE iff lcid is for a East Asia 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 Asia country/region.
*
* @rdesc
* TRUE iff charset may be for a East Asia 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 FE 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(
WCHAR 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);
}
typedef struct {
WCHAR codepoint;
WORD CharFlags;
BYTE runlength;
} Data_125X;
/*
* CW32System::GetCharFlags125x(ch)
*
* @mfunc
* Returns char flags for ch as defined in FontSigFromCharRep() 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
*/
QWORD 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 FLATIN1 | FLATIN2 | FCYRILLIC | FGREEK | FTURKISH |
FHEBREW | FARABIC | FBALTIC | FVIETNAMESE;
// Easy check for missing codes
if(ch > 0x2122)
return 0;
if(IN_RANGE(0xA0, ch, 0xFF))
return (QWORD)(DWORD)(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 (QWORD)(DWORD)(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 DBCS.
* 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\win9x. 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
WCHAR 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::CharSetFromCharRep(iCharRep)
*
* @func
* Map character repertoire index to bCharSet for GDI
*/
BYTE CW32System::CharSetFromCharRep(
LONG iCharRep)
{
return (unsigned)iCharRep < CCHARSET ? rgCharSet[iCharRep] : DEFAULT_CHARSET;
}
/*
* CW32System::GetCharSet(nCP, piCharRep)
*
* @func
* Get character set for code page <p nCP>. Also returns script index
* in *piCharRep
*
* @rdesc
* CharSet for code page <p nCP>
*/
BYTE CW32System::GetCharSet(
INT nCP, //@parm Code page or index
int *piCharRep) //@parm Out parm to receive index
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "GetCharSet");
if(nCP < CCHARSET) // nCP is already an index
{
nCP = max(nCP, 0);
if(piCharRep)
*piCharRep = nCP;
return rgCharSet[nCP];
}
Assert(CCODEPAGE == CCHARSET && CCODEPAGE == NCHARSETS);
for(int i = 0; i < CCODEPAGE && rgCodePage[i] != nCP; i++)
;
if(i == CCODEPAGE) // Didn't find it
i = -1;
if (piCharRep)
*piCharRep = i;
return i >= 0 ? rgCharSet[i] : 0;
}
/*
* CW32System::MatchFECharRep(qwCharFlags, qwFontSig)
*
* @func
* Get a FE character set for a FE char
*
* @rdesc
* Char repertoire
*/
BYTE CW32System::MatchFECharRep(
QWORD qwCharFlags, //@parm Char flags
QWORD qwFontSig) //@parm Font Signature
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::MatchFECharSet");
if (qwCharFlags & qwFontSig & FFE) // Perfect match
goto Exit;
if (!(qwFontSig & FFE)) // Not a FE font
goto Exit;
if (qwCharFlags & (FCHINESE | FBIG5))
{
if (qwFontSig & FBIG5)
return BIG5_INDEX;
if (qwFontSig & FHANGUL)
return HANGUL_INDEX;
if (qwFontSig & FKANA)
return SHIFTJIS_INDEX;
}
Exit:
return CharRepFromFontSig(qwCharFlags);
}
/*
* CW32System::CodePageFromCharRep(iCharRep)
*
* @func
* Get code page for character repertoire <p iCharRep>
*
* @rdesc
* Code page for character repertoire <p iCharRep>
*/
INT CW32System::CodePageFromCharRep(
LONG iCharRep) //@parm CharSet
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "GetCodePage");
return ((unsigned)iCharRep < CCODEPAGE) ? rgCodePage[iCharRep] : 0;
}
/*
* CW32System::FontSigFromCharRep(iCharRep)
*
* @func
* Get font signature bits for character repertoire <p iCharRep>.
*
* @rdesc
* Font signature mask for character repertoire <p bCharSet>
*/
QWORD CW32System::FontSigFromCharRep(
LONG iCharRep)
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::FontSigFromCharRep");
if(iCharRep <= BIG5_INDEX)
{
if (iCharRep != ANSI_INDEX)
return (DWORD)(FHILATIN1 << iCharRep);
return FLATIN1;
}
union
{
QWORD qw; // Endian-dependent way of
DWORD dw[2]; // avoiding 64-bit left shifts
};
qw = 0;
if(IN_RANGE(ARMENIAN_INDEX, iCharRep, NCHARREPERTOIRES))
{
dw[1] = (DWORD)(FARMENIAN >> 32) << (iCharRep - ARMENIAN_INDEX);
if(IN_RANGE(JPN2_INDEX, iCharRep, CHT2_INDEX))
dw[0] |= FSURROGATE;
}
else if(IN_RANGE(PC437_INDEX, iCharRep, MAC_INDEX))
dw[0] = FHILATIN1;
return qw;
}
/*
* CW32System::CharRepFontSig(qwFontSig, fFirstAvailable)
*
* @func
* Get char repertoire from font signature bit[s]. If fFirstAvailable
* = TRUE, then the CharRep corresponding to the lowest-order nonzero
* bit in qwFontSig is used. If fFirstAvailable is FALSE, the CharRep
* is that corresponding to qwFontSig provided qwFontSig is a single bit.
*/
LONG CW32System::CharRepFontSig(
QWORD qwFontSig, //@parm Font signature to match
BOOL fFirstAvailable) //@parm TRUE matches 1st available; else exact
{
DWORD dw;
INT i;
union
{
QWORD qwFS; // Endian-dependent way of
DWORD dwFS[2]; // avoiding 64-bit shifts
};
DWORD *pdw = &dwFS[0];
qwFS = qwFontSig;
if(*pdw & 0x00FFFF00) // Check for everything less
{ // math
dw = FHILATIN1;
for(i = ANSI_INDEX; i <= BIG5_INDEX; i++, dw <<= 1)
{
if(dw & *pdw)
return (fFirstAvailable || dw == *pdw) ? i : -1;
}
}
pdw++; // Endian dependent
if(*pdw) // High word of qw
{
dw = FARMENIAN >> 32;
for(i = ARMENIAN_INDEX; i <= NCHARREPERTOIRES; i++, dw <<= 1)
{
if(dw & *pdw)
return (fFirstAvailable || dw == *pdw) ? i : -1;
}
}
return fFirstAvailable || (qwFontSig & FASCII) ? ANSI_INDEX : -1;
}
/*
* CW32System::CharRepFromCharSet(bCharSet)
*
* @func
* Get character repertoire from bCharSet
*
* @rdesc
* character repertoire corresponding to <p bCharSet>
*
* @devnote
* Linear search
*/
LONG CW32System::CharRepFromCharSet(
BYTE bCharSet)
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::ScriptIndexFromCharSet");
Assert(CCHARSET == CCODEPAGE);
for (int i = 0; i < CCHARSET; i++)
{
if(rgCharSet[i] == bCharSet)
return i;
}
return -1; // Not found
}
/*
* CW32System::CharRepFromCodePage(CodePage)
*
* @func
* Get character repertoire from bCharSet
*
* @rdesc
* character repertoire corresponding to <p bCharSet>
*
* @devnote
* Linear search
*/
INT CW32System::CharRepFromCodePage(
LONG CodePage)
{
TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::ScriptIndexFromCharSet");
for (int i = 0; i < CCODEPAGE; i++)
{
if(rgCodePage[i] == CodePage)
return i;
}
return -1; // Not found
}
/*
* CW32System::GetScreenDC()
*
* @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 && HIWORD(wparam) != CP_UBE)
{
// 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(
WCHAR 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::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)
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)
{
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;
}
/*
* CW32System::GetSizeCursor(void)
*
* @mfunc
* Get the sizing cursor (double arrow) specified by
* the resource id. If the cursors are not loaded
* load them and cache them.
* parameters:
* idcur - cursor resource id.
*
* @rdesc
* Handle to cursor or null if failure. Returns NULL if
* idcur is null.
*/
HCURSOR CW32System::GetSizeCursor(
LPTSTR idcur)
{
if(!idcur )
return NULL;
//If any cursor isn't loaded, try loading it.
if(!_hcurSizeNS)
_hcurSizeNS = LoadCursor(NULL, IDC_SIZENS);
if(!_hcurSizeWE)
_hcurSizeWE = LoadCursor(NULL, IDC_SIZEWE);
if(!_hcurSizeNWSE)
_hcurSizeNWSE = LoadCursor(NULL, IDC_SIZENWSE);
if(!_hcurSizeNESW)
_hcurSizeNESW = LoadCursor(NULL, IDC_SIZENESW);
//Return cursor corresponding to id passed in.
if(idcur == IDC_SIZENS && _hcurSizeNS)
return _hcurSizeNS;
if(idcur == IDC_SIZEWE && _hcurSizeWE)
return _hcurSizeWE;
if(idcur == IDC_SIZENWSE && _hcurSizeNWSE)
return _hcurSizeNWSE;
if(idcur == IDC_SIZENESW && _hcurSizeNESW)
return _hcurSizeNESW;
AssertSz(FALSE, "Failure loading sizing cursor.");
return NULL;
}
/*
* 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)
{
#ifndef NOCOMPLEXSCRIPTS
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);
#else
return 0;
#endif
}
DWORD WINAPI SetLayoutInit(HDC hdc, DWORD dwLayout)
{
#ifndef NOCOMPLEXSCRIPTS
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);
#else
return 0;
#endif
}
PFN_GETLAYOUT CW32System::_pfnGetLayout = &GetLayoutInit;
PFN_SETLAYOUT CW32System::_pfnSetLayout = &SetLayoutInit;
ICustomTextOut *g_pcto;
STDAPI SetCustomTextOutHandlerEx(ICustomTextOut **ppcto, DWORD dwFlags)
{
g_pcto = *ppcto;
return S_OK;
}