mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2651 lines
67 KiB
2651 lines
67 KiB
/*
|
|
* @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
|
|
}
|
|
// ô ê â
|
|
|
|
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;
|
|
}
|