/* * @doc INTERNAL * * @module w32sys.cpp - thin layer over Win32 services * * History: * 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 } // ô ê â 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

. Also returns script index * in *piCharRep * * @rdesc * CharSet for code page

*/ 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

* * @rdesc * Code page for character repertoire

*/ 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

. * * @rdesc * Font signature mask for character repertoire

*/ 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

* * @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

* * @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; }