Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2986 lines
69 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module w32sys.cpp - thin layer over Win32 services
  5. *
  6. * History: <nl>
  7. * 1/22/97 joseogl Created
  8. *
  9. * Copyright (c) 1995-1998 Microsoft Corporation. All rights reserved.
  10. */
  11. // This prevents the "W32->" prefix from being prepended to our identifiers.
  12. #define W32SYS_CPP
  13. #include "_common.h"
  14. #include "_host.h"
  15. #include "_font.h"
  16. #include "_edit.h"
  17. #include <malloc.h>
  18. // Include the appropriate implementation.
  19. #if defined(PEGASUS)
  20. #include "w32wince.cpp"
  21. #else
  22. #include "w32win32.cpp"
  23. #endif
  24. ASSERTDATA
  25. /*
  26. * @struct CPGCHAR |
  27. * Locally used variable that contains code-page and char-set info
  28. */
  29. typedef struct _cpgcharset
  30. {
  31. INT nCodePage; // @field Code page
  32. BYTE bCharSet; // @field Character set
  33. DWORD dwFontSig; // @field Font signature bits
  34. } CPGCHAR;
  35. static const CPGCHAR rgCpgCharSet[NCHARSETS] =
  36. {
  37. {1252, ANSI_CHARSET, fLATIN1>>8}, // fLATIN1 has 3 bits
  38. {0, DEFAULT_CHARSET, 0x00000000}, // Not reliably implemented...
  39. {CP_SYMBOL,SYMBOL_CHARSET, 0x00004000}, // No trans, except WORD -> BYTE
  40. {437, PC437_CHARSET, 0x00000000}, // United States IBM
  41. {850, OEM_CHARSET, 0x00000400}, // IBM Multilingual
  42. {1250, EASTEUROPE_CHARSET, 0x00000002}, // Eastern Europe
  43. {1255, HEBREW_CHARSET, 0x00000020}, // Hebrew
  44. {1256, ARABIC_CHARSET, 0x00000040}, // Arabic
  45. {932, SHIFTJIS_CHARSET, 0x00020000}, // Japanese
  46. {1251, RUSSIAN_CHARSET, 0x00000004}, // Russian
  47. {936, GB2312_CHARSET, 0x00040000}, // PRC
  48. {949, HANGEUL_CHARSET, 0x00080000}, // Hangul
  49. {1361, JOHAB_CHARSET, 0x00000000}, // JOHAB
  50. {950, CHINESEBIG5_CHARSET, 0x00100000}, // Chinese
  51. {1253, GREEK_CHARSET, 0x00000008}, // Greek
  52. {1254, TURKISH_CHARSET, 0x00000010}, // Turkish
  53. {1257, BALTIC_CHARSET, 0x00000080}, // Estonia, Lithuania, Latvia
  54. {1258, VIETNAMESE_CHARSET, 0x00000100}, // Vietnamese
  55. {874, THAI_CHARSET, 0x00010000}, // Thai
  56. {CP_DEVANAGARI,DEVANAGARI_CHARSET,0x00200000}, // Devanagari
  57. {CP_TAMIL, TAMIL_CHARSET, 0x00400000}, // Tamil
  58. {CP_GEORGIAN, GEORGIAN_CHARSET, 0x00800000}, // Georgian
  59. {CP_ARMENIAN, ARMENIAN_CHARSET, 0x00000200}, // Armenian
  60. {10000, MAC_CHARSET, 0x00000000} // Most popular Mac (English, etc.)
  61. };
  62. #define cCpgCharSet ARRAY_SIZE(rgCpgCharSet)
  63. #define LANG_TAIWAN MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
  64. const WORD CodePageTable[] = {
  65. /* CodePage PLID primary language
  66. ------------------------------------- */
  67. 0, // 00 - undefined
  68. 1256, // 01 - Arabic
  69. 1251, // 02 - Bulgarian
  70. 1252, // 03 - Catalan
  71. 950, // 04 - Taiwan (Hong Kong, PRC, and Singapore are 936)
  72. 1250, // 05 - Czech
  73. 1252, // 06 - Danish
  74. 1252, // 07 - German
  75. 1253, // 08 - Greek
  76. 1252, // 09 - English
  77. 1252, // 0a - Spanish
  78. 1252, // 0b - Finnish
  79. 1252, // 0c - French
  80. 1255, // 0d - Hebrew
  81. 1250, // 0e - Hungarian
  82. 1252, // 0f - Icelandic
  83. 1252, // 10 - Italian
  84. 932, // 11 - Japan
  85. 949, // 12 - Korea
  86. 1252, // 13 - Dutch
  87. 1252, // 14 - Norwegian
  88. 1250, // 15 - Polish
  89. 1252, // 16 - Portuguese
  90. 0, // 17 - Rhaeto-Romanic
  91. 1250, // 18 - Romanian
  92. 1251, // 19 - Russian
  93. 1250, // 1a - Croatian
  94. 1250, // 1b - Slovak
  95. 1250, // 1c - Albanian
  96. 1252, // 1d - Swedish
  97. 874, // 1e - Thai
  98. 1254, // 1f - Turkish
  99. 1256, // 20 - Urdu
  100. 1252, // 21 - Indonesian
  101. 1251, // 22 - Ukranian
  102. 1251, // 23 - Byelorussian
  103. 1250, // 24 - Slovenian
  104. 1257, // 25 - Estonia
  105. 1257, // 26 - Latvian
  106. 1257, // 27 - Lithuanian
  107. 0, // 28 - Tajik - Tajikistan (undefined)
  108. 1256, // 29 - Farsi
  109. 1258, // 2a - Vietnanese
  110. CP_ARMENIAN,// 2b - Armenian (Unicode only)
  111. 1254, // 2c - Azeri (Latin, can be Cyrillic...)
  112. 1252, // 2d - Basque
  113. 0, // 2e - Sorbian
  114. 1251, // 2f - FYRO Macedonian
  115. 1252, // 30 - Sutu
  116. 1252, // 31 - Tsonga
  117. 1252, // 32 - Tswana
  118. 1252, // 33 - Venda
  119. 1252, // 34 - Xhosa
  120. 1252, // 35 - Zulu
  121. 1252, // 36 - Africaans
  122. CP_GEORGIAN,// 37 - Georgian (Unicode only)
  123. 1252, // 38 - Faerose
  124. CP_DEVANAGARI,// 39 - Hindi (Indic)
  125. 1252, // 3a - Maltese
  126. 1252, // 3b - Sami
  127. 1252, // 3c - Gaelic
  128. 1255, // 3d - Yiddish
  129. 1252, // 3e - Malaysian
  130. 1251, // 3f - Kazakh
  131. 1252, // 40 - Kirghiz
  132. 1252, // 41 - Swahili
  133. 1252, // 42 - Turkmen
  134. 1254, // 43 - Uzbek (Latin, can be Cyrillic...)
  135. 1251 // 44 - Tatar
  136. // 45 - Bengali (Indic)
  137. // 46 - Punjabi(Gurmukhi) (Indic)
  138. // 47 - Gujarati (Indic)
  139. // 48 - Oriya (Indic)
  140. // 49 - Tamil (Indic)
  141. // 4a - Telugu (Indic)
  142. // 4b - Kannada (Indic)
  143. // 4c - Malayalam (Indic)
  144. // 4d - Assamese (Indic)
  145. // 4e - Marathi (Indic)
  146. // 4f - Sanskrit (Indic)
  147. // 50* Mongolian - Mongolia
  148. // 51* Tibetan - Tibet
  149. // 52* Welsh - Wales
  150. // 53* Khmer - Cambodia
  151. // 54* Lao - Lao
  152. // 55* Burmese - Mayanmar
  153. // 56* Gallego - Portugal
  154. // 57 - Konkani (Indic)
  155. // 58* Manipuri (Indic)
  156. // 59* Sindhi (Indic)
  157. // 5a
  158. // 5b
  159. // 5c
  160. // 5d
  161. // 5e
  162. // 5f
  163. // 60* Kashmiri
  164. // 61* Nepali - Nepal
  165. // 62* Frisian - Netherlands
  166. // 63* Pashto - Afghanistan
  167. };
  168. #define nCodePageTable ARRAY_SIZE(CodePageTable)
  169. #define lidAzeriCyrillic 0x82C
  170. #define lidSerbianCyrillic 0xC1A
  171. #define lidUzbekCyrillic 0x843
  172. // Our interface pointer
  173. CW32System *W32;
  174. CW32System::CW32System( )
  175. {
  176. if(GetVersion(&_dwPlatformId, &_dwMajorVersion, &_dwMinorVersion))
  177. {
  178. _fHaveAIMM = FALSE;
  179. _fHaveIMMEShare = FALSE;
  180. _fHaveIMMProcs = FALSE;
  181. _pIMEShare = NULL;
  182. _icr3DDarkShadow = COLOR_WINDOWFRAME;
  183. if(_dwMajorVersion >= VERS4)
  184. _icr3DDarkShadow = COLOR_3DDKSHADOW;
  185. }
  186. _syslcid = GetSystemDefaultLCID();
  187. _ACP = ::GetACP();
  188. // BUG FIX #6089
  189. // we need this for backward compatibility of mouse wheel
  190. _MSMouseRoller = RegisterWindowMessageA(MSH_MOUSEWHEEL);
  191. // Register private messages for MSIME98
  192. _MSIMEMouseMsg = RegisterWindowMessageA("MSIMEMouseOperation");
  193. _MSIMEDocFeedMsg = RegisterWindowMessageA("MSIMEDocumentFeed");
  194. _MSIMEQueryPositionMsg = RegisterWindowMessageA("MSIMEQueryPosition");
  195. _MSIMEServiceMsg = RegisterWindowMessageA("MSIMEService");
  196. // get MSIME Reconvert private messages unless we are running in NT5
  197. if (_dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ||
  198. (_dwPlatformId == VER_PLATFORM_WIN32_NT && _dwMajorVersion <= 4))
  199. {
  200. _MSIMEReconvertMsg = RegisterWindowMessageA("MSIMEReconvert");
  201. _MSIMEReconvertRequestMsg = RegisterWindowMessageA("MSIMEReconvertRequest");
  202. }
  203. else
  204. {
  205. _MSIMEReconvertMsg = 0; // private message for reconversion
  206. _MSIMEReconvertRequestMsg = 0; // private message for reconversion request
  207. }
  208. }
  209. CW32System::~CW32System()
  210. {
  211. FreeIME();
  212. FreeOle();
  213. if (_hdcScreen)
  214. DeleteDC(_hdcScreen);
  215. }
  216. /////////////////////////////// Memory and CRT utility functions /////////////////////////////////
  217. extern "C" {
  218. #ifdef NOCRTOBJS
  219. // Havinf these functions defined here helps eliminate the dependency on the CRT
  220. // Some function definitions copied from CRT sources.
  221. // Typically, it is better to get the objs for these objects from the CRT
  222. // without dragging in the whole thing.
  223. /***
  224. *int memcmp(buf1, buf2, count) - compare memory for lexical order
  225. *
  226. *Purpose:
  227. * Compares count bytes of memory starting at buf1 and buf2
  228. * and find if equal or which one is first in lexical order.
  229. *
  230. *Entry:
  231. * void *buf1, *buf2 - pointers to memory sections to compare
  232. * size_t count - length of sections to compare
  233. *
  234. *Exit:
  235. * returns < 0 if buf1 < buf2
  236. * returns 0 if buf1 == buf2
  237. * returns > 0 if buf1 > buf2
  238. *
  239. *Exceptions:
  240. *
  241. *******************************************************************************/
  242. int __cdecl memcmp (
  243. const void * buf1,
  244. const void * buf2,
  245. size_t count
  246. )
  247. {
  248. if (!count)
  249. return(0);
  250. while ( --count && *(char *)buf1 == *(char *)buf2 ) {
  251. buf1 = (char *)buf1 + 1;
  252. buf2 = (char *)buf2 + 1;
  253. }
  254. return( *((unsigned char *)buf1) - *((unsigned char *)buf2) );
  255. }
  256. /***
  257. *char *memset(dst, val, count) - sets "count" bytes at "dst" to "val"
  258. *
  259. *Purpose:
  260. * Sets the first "count" bytes of the memory starting
  261. * at "dst" to the character value "val".
  262. *
  263. *Entry:
  264. * void *dst - pointer to memory to fill with val
  265. * int val - value to put in dst bytes
  266. * size_t count - number of bytes of dst to fill
  267. *
  268. *Exit:
  269. * returns dst, with filled bytes
  270. *
  271. *Exceptions:
  272. *
  273. *******************************************************************************/
  274. void * __cdecl memset (
  275. void *dst,
  276. int val,
  277. size_t count
  278. )
  279. {
  280. void *start = dst;
  281. while (count--) {
  282. *(char *)dst = (char)val;
  283. dst = (char *)dst + 1;
  284. }
  285. return(start);
  286. }
  287. /***
  288. *memcpy - Copy source buffer to destination buffer
  289. *
  290. *Purpose:
  291. * memcpy() copies a source memory buffer to a destination memory buffer.
  292. * This routine does NOT recognize overlapping buffers, and thus can lead
  293. * to propogation.
  294. *
  295. * For cases where propogation must be avoided, memmove() must be used.
  296. *
  297. *Entry:
  298. * void *dst = pointer to destination buffer
  299. * const void *src = pointer to source buffer
  300. * size_t count = number of bytes to copy
  301. *
  302. *Exit:
  303. * Returns a pointer to the destination buffer
  304. *
  305. *Exceptions:
  306. *******************************************************************************/
  307. void * __cdecl memcpy (
  308. void * dst,
  309. const void * src,
  310. size_t count
  311. )
  312. {
  313. void * ret = dst;
  314. /*
  315. * copy from lower addresses to higher addresses
  316. */
  317. while (count--) {
  318. *(char *)dst = *(char *)src;
  319. dst = (char *)dst + 1;
  320. src = (char *)src + 1;
  321. }
  322. return(ret);
  323. }
  324. void * __cdecl memmove(void *dst, const void *src, size_t count)
  325. {
  326. void * ret = dst;
  327. if (dst <= src || (char *)dst >= ((char *)src + count)) {
  328. /*
  329. * Non-Overlapping Buffers
  330. * copy from lower addresses to higher addresses
  331. */
  332. while (count--) {
  333. *(char *)dst = *(char *)src;
  334. dst = (char *)dst + 1;
  335. src = (char *)src + 1;
  336. }
  337. }
  338. else
  339. {
  340. /*
  341. * Overlapping Buffers
  342. * copy from higher addresses to lower addresses
  343. */
  344. dst = (char *)dst + count - 1;
  345. src = (char *)src + count - 1;
  346. while (count--) {
  347. *(char *)dst = *(char *)src;
  348. dst = (char *)dst - 1;
  349. src = (char *)src - 1;
  350. }
  351. }
  352. return(ret);
  353. }
  354. /***
  355. *strlen - return the length of a null-terminated string
  356. *
  357. *Purpose:
  358. * Finds the length in bytes of the given string, not including
  359. * the final null character.
  360. *
  361. *Entry:
  362. * const char * str - string whose length is to be computed
  363. *
  364. *Exit:
  365. * length of the string "str", exclusive of the final null byte
  366. *
  367. *Exceptions:
  368. *
  369. *******************************************************************************/
  370. size_t __cdecl strlen (
  371. const char * str
  372. )
  373. {
  374. const char *eos = str;
  375. while( *eos++ ) ;
  376. return( (int)(eos - str - 1) );
  377. }
  378. #endif
  379. #ifdef DEBUG
  380. // These functions are only used for RTF logging
  381. /***
  382. *strcmp - compare two strings, returning less than, equal to, or greater than
  383. *
  384. *Purpose:
  385. * STRCMP compares two strings and returns an integer
  386. * to indicate whether the first is less than the second, the two are
  387. * equal, or whether the first is greater than the second.
  388. *
  389. * Comparison is done byte by byte on an UNSIGNED basis, which is to
  390. * say that Null (0) is less than any other character (1-255).
  391. *
  392. *Entry:
  393. * const char * src - string for left-hand side of comparison
  394. * const char * dst - string for right-hand side of comparison
  395. *
  396. *Exit:
  397. * returns -1 if src < dst
  398. * returns 0 if src == dst
  399. * returns +1 if src > dst
  400. *
  401. *Exceptions:
  402. *
  403. *******************************************************************************/
  404. int __cdecl strcmp (
  405. const char * src,
  406. const char * dst
  407. )
  408. {
  409. int ret = 0 ;
  410. while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
  411. ++src, ++dst;
  412. if ( ret < 0 )
  413. ret = -1 ;
  414. else if ( ret > 0 )
  415. ret = 1 ;
  416. return( ret );
  417. }
  418. /***
  419. *char *strcat(dst, src) - concatenate (append) one string to another
  420. *
  421. *Purpose:
  422. * Concatenates src onto the end of dest. Assumes enough
  423. * space in dest.
  424. *
  425. *Entry:
  426. * char *dst - string to which "src" is to be appended
  427. * const char *src - string to be appended to the end of "dst"
  428. *
  429. *Exit:
  430. * The address of "dst"
  431. *
  432. *Exceptions:
  433. *
  434. *******************************************************************************/
  435. char * __cdecl strcat (
  436. char * dst,
  437. const char * src
  438. )
  439. {
  440. char * cp = dst;
  441. while( *cp )
  442. cp++; /* find end of dst */
  443. while( *cp++ = *src++ ) ; /* Copy src to end of dst */
  444. return( dst ); /* return dst */
  445. }
  446. #endif
  447. // This function in the runtime traps virtial base calls
  448. int __cdecl _purecall()
  449. {
  450. MessageBox(NULL,TEXT("Fatal Error : Vrtual base call in RichEdit"),NULL, MB_OK);
  451. PostQuitMessage (0);
  452. return 0;
  453. }
  454. // To avoid brionging in floating point lib
  455. extern int _fltused = 1;
  456. } // end of extern "C" block
  457. size_t CW32System::wcslen(const wchar_t *wcs)
  458. {
  459. const wchar_t *eos = wcs;
  460. while( *eos++ ) ;
  461. return( (size_t)(eos - wcs - 1) );
  462. }
  463. wchar_t * CW32System::wcscpy(wchar_t * dst, const wchar_t * src)
  464. {
  465. wchar_t * cp = dst;
  466. while( *cp++ = *src++ )
  467. ; /* Copy src over dst */
  468. return( dst );
  469. }
  470. int CW32System::wcscmp(const wchar_t * src, const wchar_t * dst)
  471. {
  472. int ret = 0;
  473. while( ! (ret = (int)(*src - *dst)) && *dst)
  474. ++src, ++dst;
  475. if ( ret < 0 )
  476. ret = -1 ;
  477. else if ( ret > 0 )
  478. ret = 1 ;
  479. return( ret );
  480. }
  481. int CW32System::wcsicmp(const wchar_t * src, const wchar_t * dst)
  482. {
  483. int ret = 0;
  484. wchar_t s,d;
  485. do
  486. {
  487. s = ((*src <= L'Z') && (*dst >= L'A'))
  488. ? *src - L'A' + L'a'
  489. : *src;
  490. d = ((*dst <= L'Z') && (*dst >= L'A'))
  491. ? *dst - L'A' + L'a'
  492. : *dst;
  493. src++;
  494. dst++;
  495. } while (!(ret = (int)(s - d)) && d);
  496. if ( ret < 0 )
  497. ret = -1 ;
  498. else if ( ret > 0 )
  499. ret = 1 ;
  500. return( ret );
  501. }
  502. wchar_t * CW32System::wcsncpy (wchar_t * dest, const wchar_t * source, size_t count)
  503. {
  504. wchar_t *start = dest;
  505. while (count && (*dest++ = *source++)) /* copy string */
  506. count--;
  507. if (count) /* pad out with zeroes */
  508. while (--count)
  509. *dest++ = L'\0';
  510. return(start);
  511. }
  512. int CW32System::wcsnicmp (const wchar_t * first, const wchar_t * last, size_t count)
  513. {
  514. wchar_t f,l;
  515. int result = 0;
  516. if ( count ) {
  517. do {
  518. f = ((*first <= L'Z') && (*first >= L'A'))
  519. ? *first - L'A' + L'a'
  520. : *first;
  521. l = ((*last <= L'Z') && (*last >= L'A'))
  522. ? *last - L'A' + L'a'
  523. : *last;
  524. first++;
  525. last++;
  526. } while ( (--count) && f && (f == l) );
  527. result = (int)(f - l);
  528. }
  529. return result;
  530. }
  531. unsigned long CW32System::strtoul(const char *nptr)
  532. {
  533. const char *p;
  534. char c;
  535. unsigned long number;
  536. unsigned digval;
  537. unsigned long maxval;
  538. p = nptr; /* p is our scanning pointer */
  539. number = 0; /* start with zero */
  540. c = *p++; /* read char */
  541. while ( c == ' ' || c == '\t' )
  542. c = *p++; /* skip whitespace */
  543. if (c == '-') {
  544. return 0;
  545. }
  546. /* if our number exceeds this, we will overflow on multiply */
  547. maxval = ULONG_MAX / 10;
  548. for (;;) { /* exit in middle of loop */
  549. /* convert c to value */
  550. digval = (unsigned char) c;
  551. if ( digval >= '0' && digval <= '9' )
  552. digval = c - '0';
  553. else
  554. return number;
  555. /* we now need to compute number = number * base + digval,
  556. but we need to know if overflow occured. This requires
  557. a tricky pre-check. */
  558. if (number < maxval || (number == maxval &&
  559. (unsigned long)digval <= ULONG_MAX % 10)) {
  560. /* we won't overflow, go ahead and multiply */
  561. number = number * 10 + digval;
  562. }
  563. else
  564. return 0;
  565. c = *p++; /* read next digit */
  566. }
  567. }
  568. // CW32System static members
  569. BOOL CW32System::_fLRMorRLM;
  570. BOOL CW32System::_fHaveIMMProcs;
  571. BOOL CW32System::_fHaveIMMEShare;
  572. BOOL CW32System::_fHaveAIMM;
  573. UINT CW32System::_fRegisteredXBox;
  574. DWORD CW32System::_dwPlatformId;
  575. LCID CW32System::_syslcid;
  576. DWORD CW32System::_dwMajorVersion;
  577. DWORD CW32System::_dwMinorVersion;
  578. INT CW32System::_icr3DDarkShadow;
  579. UINT CW32System::_MSIMEMouseMsg;
  580. UINT CW32System::_MSIMEReconvertMsg;
  581. UINT CW32System::_MSIMEReconvertRequestMsg;
  582. UINT CW32System::_MSIMEDocFeedMsg;
  583. UINT CW32System::_MSIMEQueryPositionMsg;
  584. UINT CW32System::_MSIMEServiceMsg;
  585. UINT CW32System::_MSMouseRoller;
  586. HDC CW32System::_hdcScreen;
  587. CIMEShare* CW32System::_pIMEShare;
  588. // CW32System static system parameter members
  589. BOOL CW32System::_fSysParamsOk;
  590. BOOL CW32System::_fUsePalette;
  591. INT CW32System::_xWidthSys;
  592. INT CW32System::_yHeightSys;
  593. INT CW32System::_ySysFontLeading;
  594. LONG CW32System::_xPerInchScreenDC;
  595. LONG CW32System::_yPerInchScreenDC;
  596. INT CW32System::_cxBorder;
  597. INT CW32System::_cyBorder;
  598. INT CW32System::_cxVScroll;
  599. INT CW32System::_cyHScroll;
  600. LONG CW32System::_dxSelBar;
  601. INT CW32System::_cxDoubleClk;
  602. INT CW32System::_cyDoubleClk;
  603. INT CW32System::_DCT;
  604. WORD CW32System::_nScrollInset;
  605. WORD CW32System::_nScrollDelay;
  606. WORD CW32System::_nScrollInterval;
  607. WORD CW32System::_nScrollHAmount;
  608. WORD CW32System::_nScrollVAmount;
  609. WORD CW32System::_nDragDelay;
  610. WORD CW32System::_nDragMinDist;
  611. WORD CW32System::_wDeadKey;
  612. WORD CW32System::_wKeyboardFlags;
  613. WORD CW32System::_wNumKeyPad;
  614. WORD CW32System::_fFEFontInfo;
  615. BYTE CW32System::_bDigitSubstMode;
  616. BYTE CW32System::_bSysCharSet;
  617. HCURSOR CW32System::_hcurSizeNS;
  618. HCURSOR CW32System::_hcurSizeWE;
  619. HCURSOR CW32System::_hcurSizeNWSE;
  620. HCURSOR CW32System::_hcurSizeNESW;
  621. LONG CW32System::_cLineScroll;
  622. HFONT CW32System::_hSystemFont;
  623. HKL CW32System::_hklCurrent;
  624. HKL CW32System::_hkl[NCHARSETS];
  625. INT CW32System::_sysiniflags;
  626. UINT CW32System::_ACP;
  627. DWORD CW32System::_cRefs;
  628. /*
  629. * CW32System::MbcsFromUnicode(pstr, cch, pwstr, cwch, codepage, flags)
  630. *
  631. * @mfunc
  632. * Converts a string to MBCS from Unicode. If cwch equals -1, the string
  633. * is assumed to be NULL terminated. -1 is supplied as a default argument.
  634. *
  635. * @rdesc
  636. * If [pstr] is NULL or [cch] is 0, 0 is returned. Otherwise, the number
  637. * of characters converted, including the terminating NULL, is returned
  638. * (note that converting the empty string will return 1). If the
  639. * conversion fails, 0 is returned.
  640. *
  641. * @devnote
  642. * Modifies pstr
  643. */
  644. int CW32System::MbcsFromUnicode(
  645. LPSTR pstr, //@parm Buffer for MBCS string
  646. int cch, //@parm Size of MBCS buffer, incl space for NULL terminator
  647. LPCWSTR pwstr, //@parm Unicode string to convert
  648. int cwch, //@parm # chars in Unicode string, incl NULL terminator
  649. UINT codepage, //@parm Code page to use (CP_ACP is default)
  650. UN_FLAGS flags) //@parm Indicates if WCH_EMBEDDING should be handled specially
  651. {
  652. TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CW32System::MbcsFromUnicode");
  653. LONG i;
  654. LPWSTR pwstrtemp;
  655. CTempWcharBuf twcb;
  656. Assert(cch >= 0 && pwstr && (cwch == -1 || cwch > 0));
  657. if(!pstr || !cch)
  658. return 0;
  659. // If we have to convert WCH_EMBEDDINGs, scan through and turn
  660. // them into spaces. This is necessary for richedit1.0 compatibity,
  661. // as WideCharToMultiByte will turn WCH_EMBEDDING into a '?'
  662. if(flags == UN_CONVERT_WCH_EMBEDDING)
  663. {
  664. if(cwch == -1)
  665. cwch = wcslen(pwstr) + 1;
  666. pwstrtemp = twcb.GetBuf(cwch);
  667. if(pwstrtemp)
  668. {
  669. for(i = 0; i < cwch; i++)
  670. {
  671. pwstrtemp[i] = pwstr[i];
  672. if(pwstr[i] == WCH_EMBEDDING)
  673. pwstrtemp[i] = L' ';
  674. }
  675. pwstr = pwstrtemp;
  676. }
  677. }
  678. return WCTMB(codepage, 0, pwstr, cwch, pstr, cch, NULL, NULL, NULL);
  679. }
  680. /*
  681. * CW32System::UnicodeFromMbcs(pwstr, cwch, pstr, cch, uiCodePage)
  682. *
  683. * @mfunc
  684. * Converts a string to Unicode from MBCS. If cch equals -1, the string
  685. * is assumed to be NULL terminated. -1 is supplied as a default
  686. * argument.
  687. *
  688. * @rdesc
  689. * If [pwstr] is NULL or [cwch] is 0, 0 is returned. Otherwise,
  690. * the number of characters converted, including the terminating
  691. * NULL, is returned (note that converting the empty string will
  692. * return 1). If the conversion fails, 0 is returned.
  693. *
  694. * @devnote
  695. * Modifies: [pwstr]
  696. */
  697. int CW32System::UnicodeFromMbcs(
  698. LPWSTR pwstr, //@parm Buffer for Unicode string
  699. int cwch, //@parm Size of Unicode buffer, incl space for NULL terminator
  700. LPCSTR pstr, //@parm MBCS string to convert
  701. int cch, //@parm # chars in MBCS string, incl NULL terminator
  702. UINT uiCodePage) //@parm Code page to use (CP_ACP is default)
  703. {
  704. TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CW32System::UnicodeFromMbcs");
  705. Assert(pstr && cwch >= 0 && (cch == -1 || cch >= 0));
  706. if(!pwstr || !cwch)
  707. return 0;
  708. if(cch >= 3 && IsUTF8BOM((BYTE *)pstr))
  709. {
  710. uiCodePage = CP_UTF8; // UTF-8 BOM file
  711. cch -= 3; // Eat the BOM
  712. pstr += 3;
  713. }
  714. return MBTWC(uiCodePage, 0, pstr, cch, pwstr, cwch, NULL);
  715. }
  716. /*
  717. * CW32System::TextHGlobalAtoW (hglobalA)
  718. *
  719. * @func
  720. * translates a unicode string contained in an hglobal and
  721. * wraps the ansi version in another hglobal
  722. *
  723. * @devnote
  724. * does *not* free the incoming hglobal
  725. */
  726. HGLOBAL CW32System::TextHGlobalAtoW(HGLOBAL hglobalA)
  727. {
  728. TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CW32System::TextHGlobalAtoW");
  729. if(!hglobalA)
  730. return NULL;
  731. HGLOBAL hnew;
  732. LPSTR pstr = (LPSTR)GlobalLock(hglobalA);
  733. DWORD dwSize = GlobalSize(hglobalA);
  734. LONG cbSize = (dwSize + 1) * sizeof(WCHAR);
  735. hnew = GlobalAlloc(GMEM_FIXED, cbSize);
  736. if(hnew)
  737. {
  738. LPWSTR pwstr = (LPWSTR)GlobalLock(hnew);
  739. UnicodeFromMbcs(pwstr, dwSize + 1, pstr);
  740. GlobalUnlock(hnew);
  741. }
  742. GlobalUnlock(hglobalA);
  743. return hnew;
  744. }
  745. /*
  746. * CW32System::TextHGlobalWtoA(hglobalW)
  747. *
  748. * @func
  749. * converts a unicode text hglobal into a newly allocated
  750. * allocated hglobal with ANSI data
  751. *
  752. * @devnote
  753. * does *NOT* free the incoming hglobal
  754. */
  755. HGLOBAL CW32System::TextHGlobalWtoA(
  756. HGLOBAL hglobalW )
  757. {
  758. TRACEBEGIN(TRCSUBSYSUTIL, TRCSCOPEINTERN, "CW32System::TextHGlobalWtoA");
  759. if(!hglobalW)
  760. return NULL;
  761. HGLOBAL hnew = NULL;
  762. LPWSTR pwstr = (LPWSTR)GlobalLock(hglobalW);
  763. DWORD dwSize = GlobalSize(hglobalW);
  764. LONG cbSize = (dwSize * 2) * sizeof(CHAR);
  765. hnew = GlobalAlloc(GMEM_FIXED, cbSize);
  766. if( hnew )
  767. {
  768. LPSTR pstr = (LPSTR)GlobalLock(hnew);
  769. MbcsFromUnicode(pstr, cbSize, pwstr );
  770. GlobalUnlock(hnew);
  771. }
  772. GlobalUnlock(hglobalW);
  773. return hnew;
  774. }
  775. /*
  776. * CW32System::ConvertLanguageIDtoCodePage (lid)
  777. *
  778. * @mfunc Maps a language ID to a Code Page
  779. *
  780. * @rdesc returns Code Page
  781. *
  782. * @devnote:
  783. * This routine takes advantage of the fact that except for Chinese,
  784. * the code page is determined uniquely by the primary language ID,
  785. * which is given by the low-order 10 bits of the lcid.
  786. *
  787. * The WORD CodePageTable could be replaced by a BYTE with the addition
  788. * of a couple of if's and the BYTE table replaced by a nibble table
  789. * with the addition of a shift and a mask. Since the table is only
  790. * 96 bytes long, it seems that the simplicity of using actual code page
  791. * values is worth the extra bytes.
  792. */
  793. UINT CW32System::ConvertLanguageIDtoCodePage(
  794. WORD lid) //@parm Language ID to map to code page
  795. {
  796. UINT j = PRIMARYLANGID(lid); // j = primary language (PLID)
  797. if(j >= LANG_CROATIAN) // PLID = 0x1a
  798. {
  799. if (lid == lidSerbianCyrillic || // Special case for LID = 0xc1a
  800. lid == lidAzeriCyrillic ||
  801. lid == lidUzbekCyrillic)
  802. {
  803. return 1251; // Use Cyrillic code page
  804. }
  805. if(j >= nCodePageTable) // Most languages above table
  806. { // take 1252
  807. if (j == 0x57 || j == 0x61 || IN_RANGE(0x4e, j, 0x4f))
  808. return CP_DEVANAGARI;
  809. if (j == 0x49)
  810. return CP_TAMIL;
  811. return 1252;
  812. }
  813. }
  814. j = CodePageTable[j]; // Translate PLID to code page
  815. if(j != 950 || lid == LANG_TAIWAN) // All but China (except for Taiwan)
  816. return j;
  817. return 936; // Hong Kong SAR, Singapore, and PRC
  818. }
  819. /*
  820. * CW32System::GetLocaleLCID ()
  821. *
  822. * @mfunc Maps an LCID for thread to a Code Page
  823. *
  824. * @rdesc returns Code Page
  825. */
  826. LCID CW32System::GetLocaleLCID()
  827. {
  828. return GetThreadLocale();
  829. }
  830. /*
  831. * CW32System::GetLocaleCodePage ()
  832. *
  833. * @mfunc Maps an LCID for thread to a Code Page
  834. *
  835. * @rdesc returns Code Page
  836. */
  837. UINT CW32System::GetLocaleCodePage()
  838. {
  839. #ifdef DEBUG
  840. UINT cpg = W32->DebugDefaultCpg();
  841. if (cpg)
  842. return cpg;
  843. #endif
  844. return W32->ConvertLanguageIDtoCodePage(GetThreadLocale());
  845. }
  846. /*
  847. * CW32System::GetKeyboardLCID ()
  848. *
  849. * @mfunc Gets LCID for keyboard active on current thread
  850. *
  851. * @rdesc returns Code Page
  852. */
  853. LCID CW32System::GetKeyboardLCID(DWORD dwMakeAPICall)
  854. {
  855. return (WORD)GetKeyboardLayout(dwMakeAPICall);
  856. }
  857. /*
  858. * CW32System::GetKeyboardCodePage ()
  859. *
  860. * @mfunc Gets Code Page for keyboard active on current thread
  861. *
  862. * @rdesc returns Code Page
  863. */
  864. UINT CW32System::GetKeyboardCodePage(DWORD dwMakeAPICall)
  865. {
  866. return W32->ConvertLanguageIDtoCodePage((WORD)GetKeyboardLayout(dwMakeAPICall));
  867. }
  868. /*
  869. * CW32System::InitKeyboardFlags ()
  870. *
  871. * @mfunc
  872. * Initializes keyboard flags. Used when control gains focus. Note that
  873. * Win95 doesn't support VK_RSHIFT, so if either shift key is pressed
  874. * when focus is regained, it'll be assumed to be the left shift.
  875. */
  876. void CW32System::InitKeyboardFlags()
  877. {
  878. _wKeyboardFlags = 0;
  879. if(GetKeyState(VK_SHIFT) < 0)
  880. SetKeyboardFlag(GetKeyState(VK_RSHIFT) < 0 ? RSHIFT : LSHIFT);
  881. }
  882. /*
  883. * CW32System::GetKeyboardFlag (dwKeyMask, wKey)
  884. *
  885. * @mfunc
  886. * Return whether wKey is depressed. Check with OS for agreement.
  887. * If OS says it isn't depressed, reset our internal flags. In
  888. * any event, return TRUE/FALSE in agreement with the system (bad
  889. * client may have eaten keystrokes, thereby destabilizing our
  890. * internal keyboard state.
  891. *
  892. * @rdesc
  893. * TRUE iff wKey is depressed
  894. */
  895. BOOL CW32System::GetKeyboardFlag (
  896. WORD dwKeyMask, //@parm _wKeyboardFlags mask like ALT, CTRL, or SHIFT
  897. WORD wKey) //@parm VK_xxx like VK_MENU, VK_CONTROL, or VK_SHIFT
  898. {
  899. BOOL fFlag = (GetKeyboardFlags() & dwKeyMask) != 0;
  900. if(fFlag ^ ((GetKeyState(wKey) & 0x8000) != 0))
  901. {
  902. // System doesn't agree with our internal state
  903. // (bad client ate a WM_KEYDOWN)
  904. if(fFlag)
  905. {
  906. ResetKeyboardFlag(dwKeyMask);
  907. return FALSE;
  908. }
  909. // Don't set an internal _wKeyboardFlag since we check for it
  910. // anyhow and client might not send WM_KEYUP either
  911. return TRUE;
  912. }
  913. return fFlag;
  914. }
  915. /*
  916. * CW32System::IsAlef(ch)
  917. *
  918. * @func
  919. * Used to determine if base character is a Arabic-type Alef.
  920. *
  921. * @rdesc
  922. * TRUE iff the base character is an Arabic-type Alef.
  923. *
  924. * @comm
  925. * AlefWithMaddaAbove, AlefWithHamzaAbove, AlefWithHamzaBelow,
  926. * and Alef are valid matches.
  927. */
  928. BOOL CW32System::IsAlef(
  929. TCHAR ch)
  930. {
  931. return IN_RANGE(0x622, ch, 0x627) && ch != 0x624 && ch != 0x626;
  932. }
  933. /*
  934. * CW32System::IsBiDiLcid(lcid)
  935. *
  936. * @func
  937. * Return TRUE if lcid corresponds to an RTL language
  938. *
  939. * @rdesc
  940. * TRUE if lcid corresponds to an RTL language
  941. */
  942. BOOL CW32System::IsBiDiLcid(
  943. LCID lcid)
  944. {
  945. return
  946. PRIMARYLANGID(lcid) == LANG_ARABIC ||
  947. PRIMARYLANGID(lcid) == LANG_HEBREW ||
  948. PRIMARYLANGID(lcid) == LANG_URDU ||
  949. PRIMARYLANGID(lcid) == LANG_FARSI;
  950. }
  951. /*
  952. * CW32System::IsIndicLcid(lcid)
  953. *
  954. * @func
  955. * Return TRUE if lcid corresponds to an Indic language
  956. *
  957. * @rdesc
  958. * TRUE if lcid corresponds to an Indic language
  959. */
  960. BOOL CW32System::IsIndicLcid(
  961. LCID lcid)
  962. {
  963. WORD wLangId = PRIMARYLANGID(lcid);
  964. return
  965. wLangId == LANG_HINDI ||
  966. wLangId == LANG_KONKANI ||
  967. wLangId == LANG_NEPALI ||
  968. IN_RANGE(LANG_BENGALI, wLangId, LANG_SANSKRIT);
  969. }
  970. /*
  971. * CW32System::IsIndicKbdInstalled()
  972. *
  973. * @func
  974. * Return TRUE if any Indic kbd installed
  975. */
  976. bool CW32System::IsIndicKbdInstalled()
  977. {
  978. for (int i = INDIC_FIRSTINDEX; i <= INDIC_LASTINDEX; i++)
  979. if (_hkl[i] != 0)
  980. return true;
  981. return false;
  982. }
  983. /*
  984. * CW32System::IsComplexScriptLcid(lcid)
  985. *
  986. * @func
  987. * Return TRUE if lcid corresponds to any complex script locales
  988. *
  989. */
  990. BOOL CW32System::IsComplexScriptLcid(
  991. LCID lcid)
  992. {
  993. return IsBiDiLcid(lcid) ||
  994. PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_THAI ||
  995. PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_VIETNAMESE ||
  996. IsIndicLcid(lcid);
  997. }
  998. /*
  999. * CW32System::IsBiDiDiacritic(ch)
  1000. *
  1001. * @func Used to determine if character is a Arabic or Hebrew diacritic.
  1002. *
  1003. * @rdesc TRUE iff character is a diacritic
  1004. */
  1005. BOOL CW32System::IsBiDiDiacritic(
  1006. TCHAR ch)
  1007. {
  1008. return IN_RANGE(0x64B, ch, 0x670) && (ch <= 0x652 || ch == 0x670) || // Arabic
  1009. IN_RANGE(0x591, ch, 0x5C4) && (ch != 0x5A2 && ch != 0x5BA && // Hebrew
  1010. ch != 0x5BE && ch != 0x5C0 && ch != 0x5C3);
  1011. }
  1012. /*
  1013. * CW32System::IsVietCdmSequenceValid(ch1, ch2)
  1014. *
  1015. * @mfunc
  1016. * Check if ch2 can follow ch1 in case ch2 is a combining diacritic mark (CDM).
  1017. * Main use is for Vietnamese users (Chau Vu provides the logic below).
  1018. *
  1019. * @rdesc
  1020. * TRUE if ch2 can follow ch1
  1021. */
  1022. BOOL CW32System::IsVietCdmSequenceValid(
  1023. WCHAR ch1,
  1024. WCHAR ch2)
  1025. {
  1026. if (!IN_RANGE(0x300, ch2, 0x323) || // Fast out
  1027. !IN_RANGE(0x300, ch2, 0x301) && ch2 != 0x303 && ch2 != 0x309 && ch2 != 0x323)
  1028. {
  1029. return TRUE; // Not Vietnamese tone mark
  1030. }
  1031. // � � �
  1032. static const BYTE vowels[] = {0xF4, 0xEA, 0xE2, 'y', 'u', 'o', 'i', 'e', 'a'};
  1033. for(int i = ARRAY_SIZE(vowels); i--; )
  1034. if((ch1 | 0x20) == vowels[i]) // Vietnamese tone mark follows
  1035. return TRUE; // vowel
  1036. return IN_RANGE(0x102, ch1, 0x103) || // A-breve, a-breve
  1037. IN_RANGE(0x1A0, ch1, 0x1A1) || // O-horn, o-horn
  1038. IN_RANGE(0x1AF, ch1, 0x1B0); // U-horn, u-horn
  1039. }
  1040. /*
  1041. * CW32System::IsFELCID(lcid)
  1042. *
  1043. * @mfunc
  1044. * Returns TRUE iff lcid is for a East Asian country/region.
  1045. *
  1046. * @rdesc
  1047. * TRUE iff lcid is for a East Asian country/region.
  1048. */
  1049. bool CW32System::IsFELCID(
  1050. LCID lcid)
  1051. {
  1052. switch(PRIMARYLANGID(LANGIDFROMLCID(lcid)))
  1053. {
  1054. case LANG_CHINESE:
  1055. case LANG_JAPANESE:
  1056. case LANG_KOREAN:
  1057. return true;
  1058. }
  1059. return false;
  1060. }
  1061. /*
  1062. * CW32System::IsFECharSet(bCharSet)
  1063. *
  1064. * @mfunc
  1065. * Returns TRUE iff charset may be for a East Asian country/region.
  1066. *
  1067. * @rdesc
  1068. * TRUE iff charset may be for a East Asian country/region.
  1069. *
  1070. */
  1071. BOOL CW32System::IsFECharSet(
  1072. BYTE bCharSet)
  1073. {
  1074. switch(bCharSet)
  1075. {
  1076. case CHINESEBIG5_CHARSET:
  1077. case SHIFTJIS_CHARSET:
  1078. case HANGEUL_CHARSET:
  1079. case JOHAB_CHARSET:
  1080. case GB2312_CHARSET:
  1081. return TRUE;
  1082. }
  1083. return FALSE;
  1084. }
  1085. /*
  1086. * CW32System::Is8BitCodePage(CodePage)
  1087. *
  1088. * @mfunc
  1089. * Returns TRUE iff the codepage is 8-bit
  1090. */
  1091. BOOL CW32System::Is8BitCodePage(
  1092. unsigned CodePage)
  1093. {
  1094. if(!CodePage)
  1095. CodePage = GetACP();
  1096. return IN_RANGE(1250, CodePage, 1258) || CodePage == 874;
  1097. }
  1098. /*
  1099. * CW32System::IsFECodePageFont(dwFontCodePageSig)
  1100. *
  1101. * @mfunc
  1102. * Returns TRUE iff the font codepage signature reveals only East Asian support
  1103. */
  1104. BOOL CW32System::IsFECodePageFont(
  1105. DWORD dwFontCodePageSig)
  1106. {
  1107. DWORD dwFE = 0x001e0000; // Shift-JIS + PRC + Hangeul + Taiwan
  1108. DWORD dwOthers = 0x000101fc; // The rest of the world except for Latin-1 and Latin-2
  1109. return (dwFontCodePageSig & dwFE) && !(dwFontCodePageSig & dwOthers);
  1110. }
  1111. /*
  1112. * CW32System::IsRTLChar(ch)
  1113. *
  1114. * @mfunc
  1115. * Returns TRUE iff ch Arabic or Hebrew
  1116. *
  1117. * @rdesc
  1118. * TRUE iff ch is Arabic or Hebrew
  1119. */
  1120. BOOL IsRTLChar(
  1121. TCHAR ch)
  1122. {
  1123. // Remark: what about Arabic Presentation Forms?
  1124. // (0xFB50 - 0xFDFF, 0xFE70 - 0xFEFF)
  1125. return IN_RANGE(0x590, ch, 0x6FF) || ch == RTLMARK;
  1126. }
  1127. /*
  1128. * CW32System::IsRTLCharSet(bCharSet)
  1129. *
  1130. * @mfunc
  1131. * Returns TRUE iff charset is Arabic or Hebrew
  1132. *
  1133. * @rdesc
  1134. * TRUE iff charset may be for Arabic or Hebrew
  1135. */
  1136. BOOL CW32System::IsRTLCharSet(
  1137. BYTE bCharSet)
  1138. {
  1139. return IN_RANGE(HEBREW_CHARSET, bCharSet, ARABIC_CHARSET);
  1140. }
  1141. /*
  1142. * CW32System::IsZWG(ch, bCharSet)
  1143. *
  1144. * @mfunc
  1145. * Determines whether a single-byte character is a zero-width glyph
  1146. * or not. Requires a charset.
  1147. *
  1148. * @rdesc
  1149. * TRUE if the character is a zero-width glyph, FALSE otherwise.
  1150. */
  1151. BOOL CW32System::IsZWG(
  1152. char ch,
  1153. BYTE bCharSet)
  1154. {
  1155. if(IN_RANGE(0x9D, ch, 0x9E))
  1156. return bCharSet == ARABIC_CHARSET;
  1157. if(IN_RANGE(0xFD, ch, 0xFE))
  1158. return IN_RANGE(HEBREW_CHARSET, bCharSet, ARABIC_CHARSET);
  1159. return FALSE;
  1160. }
  1161. typedef struct {
  1162. WCHAR codepoint;
  1163. WORD CharFlags;
  1164. BYTE runlength;
  1165. } Data_125X;
  1166. /*
  1167. * CW32System::GetCharFlags125x(ch)
  1168. *
  1169. * @mfunc
  1170. * Returns char flags for ch as defined in rgCpgCharSet for 125x
  1171. * codepages. Bit 0: 1252, bit 1: 1250, bit 2: 1251, else bit x:
  1172. * 125x (for 1253 - 1258).
  1173. *
  1174. * @rdesc
  1175. * 125x char flags for ch
  1176. */
  1177. DWORD CW32System::GetCharFlags125x(
  1178. WCHAR ch) //@parm Char to examine
  1179. {
  1180. static const WORD rgCpgMask[] = {
  1181. 0x1FF, // 0xA0
  1182. 0x131, // 0xA1
  1183. 0x1F1, // 0xA2
  1184. 0x1F9, // 0xA3
  1185. 0x1DF, // 0xA4
  1186. 0x179, // 0xA5
  1187. 0x1FF, // 0xA6
  1188. 0x1FF, // 0xA7
  1189. 0x1FB, // 0xA8
  1190. 0x1FF, // 0xA9
  1191. 0x111, // 0xAA
  1192. 0x1FF, // 0xAB
  1193. 0x1FF, // 0xAC
  1194. 0x1FF, // 0xAD
  1195. 0x1FF, // 0xAE
  1196. 0x1F1, // 0xAF
  1197. 0x1FF, // 0xB0
  1198. 0x1FF, // 0xB1
  1199. 0x1F9, // 0xB2
  1200. 0x1F9, // 0xB3
  1201. 0x1F3, // 0xB4
  1202. 0x1FF, // 0xB5
  1203. 0x1FF, // 0xB6
  1204. 0x1FF, // 0xB7
  1205. 0x1F3, // 0xB8
  1206. 0x1F1, // 0xB9
  1207. 0x111, // 0xBA
  1208. 0x1FF, // 0xBB
  1209. 0x1F1, // 0xBC
  1210. 0x1F9, // 0xBD
  1211. 0x1F1, // 0xBE
  1212. 0x131, // 0xBF
  1213. 0x111, // 0xC0
  1214. 0x113, // 0xC1
  1215. 0x113, // 0xC2
  1216. 0x011, // 0xC3
  1217. 0x193, // 0xC4
  1218. 0x191, // 0xC5
  1219. 0x191, // 0xC6
  1220. 0x113, // 0xC7
  1221. 0x111, // 0xC8
  1222. 0x193, // 0xC9
  1223. 0x111, // 0xCA
  1224. 0x113, // 0xCB
  1225. 0x011, // 0xCC
  1226. 0x113, // 0xCD
  1227. 0x113, // 0xCE
  1228. 0x111, // 0xCF
  1229. 0x001, // 0xD0
  1230. 0x111, // 0xD1
  1231. 0x011, // 0xD2
  1232. 0x193, // 0xD3
  1233. 0x113, // 0xD4
  1234. 0x091, // 0xD5
  1235. 0x193, // 0xD6
  1236. 0x1F3, // 0xD7
  1237. 0x191, // 0xD8
  1238. 0x111, // 0xD9
  1239. 0x113, // 0xDA
  1240. 0x111, // 0xDB
  1241. 0x193, // 0xDC
  1242. 0x003, // 0xDD
  1243. 0x001, // 0xDE
  1244. 0x193, // 0xDF
  1245. 0x151, // 0xE0
  1246. 0x113, // 0xE1
  1247. 0x153, // 0xE2
  1248. 0x011, // 0xE3
  1249. 0x193, // 0xE4
  1250. 0x191, // 0xE5
  1251. 0x191, // 0xE6
  1252. 0x153, // 0xE7
  1253. 0x151, // 0xE8
  1254. 0x1D3, // 0xE9
  1255. 0x151, // 0xEA
  1256. 0x153, // 0xEB
  1257. 0x011, // 0xEC
  1258. 0x113, // 0xED
  1259. 0x153, // 0xEE
  1260. 0x151, // 0xEF
  1261. 0x001, // 0xF0
  1262. 0x111, // 0xF1
  1263. 0x011, // 0xF2
  1264. 0x193, // 0xF3
  1265. 0x153, // 0xF4
  1266. 0x091, // 0xF5
  1267. 0x193, // 0xF6
  1268. 0x1F3, // 0xF7
  1269. 0x191, // 0xF8
  1270. 0x151, // 0xF9
  1271. 0x113, // 0xFA
  1272. 0x151, // 0xFB
  1273. 0x1D3, // 0xFC
  1274. 0x003, // 0xFD
  1275. 0x001, // 0xFE
  1276. 0x111 // 0xFF
  1277. };
  1278. static const Data_125X Table_125X[] = {
  1279. { 0x100, 0x080, 2},
  1280. { 0x102, 0x102, 2},
  1281. { 0x104, 0x082, 4},
  1282. { 0x10c, 0x082, 2},
  1283. { 0x10e, 0x002, 2},
  1284. { 0x110, 0x102, 2},
  1285. { 0x112, 0x080, 2},
  1286. { 0x116, 0x080, 2},
  1287. { 0x118, 0x082, 2},
  1288. { 0x11a, 0x002, 2},
  1289. { 0x11e, 0x010, 2},
  1290. { 0x122, 0x080, 2},
  1291. { 0x12a, 0x080, 2},
  1292. { 0x12e, 0x080, 2},
  1293. { 0x130, 0x010, 2},
  1294. { 0x136, 0x080, 2},
  1295. { 0x139, 0x002, 2},
  1296. { 0x13b, 0x080, 2},
  1297. { 0x13d, 0x002, 2},
  1298. { 0x141, 0x082, 4},
  1299. { 0x145, 0x080, 2},
  1300. { 0x147, 0x002, 2},
  1301. { 0x14c, 0x080, 2},
  1302. { 0x150, 0x002, 2},
  1303. { 0x152, 0x151, 2},
  1304. { 0x154, 0x002, 2},
  1305. { 0x156, 0x080, 2},
  1306. { 0x158, 0x002, 2},
  1307. { 0x15a, 0x082, 2},
  1308. { 0x15e, 0x012, 2},
  1309. { 0x160, 0x093, 2},
  1310. { 0x162, 0x002, 4},
  1311. { 0x16a, 0x080, 2},
  1312. { 0x16e, 0x002, 4},
  1313. { 0x172, 0x080, 2},
  1314. { 0x178, 0x111, 1},
  1315. { 0x179, 0x082, 4},
  1316. { 0x17d, 0x083, 2},
  1317. { 0x192, 0x179, 1},
  1318. { 0x1A0, 0x100, 2},
  1319. { 0x1AF, 0x100, 2},
  1320. { 0x2c6, 0x171, 1},
  1321. { 0x2c7, 0x082, 1},
  1322. { 0x2d8, 0x002, 1},
  1323. { 0x2d9, 0x082, 1},
  1324. { 0x2db, 0x082, 1},
  1325. { 0x2dc, 0x131, 1},
  1326. { 0x2dd, 0x002, 1},
  1327. { 0x300, 0x100, 2},
  1328. { 0x303, 0x100, 1},
  1329. { 0x309, 0x100, 1},
  1330. { 0x323, 0x100, 1},
  1331. { 0x384, 0x008, 3},
  1332. { 0x388, 0x008, 3},
  1333. { 0x38c, 0x008, 1},
  1334. { 0x38e, 0x008, 20},
  1335. { 0x3a3, 0x008, 44},
  1336. { 0x401, 0x004, 12},
  1337. { 0x40e, 0x004, 66},
  1338. { 0x451, 0x004, 12},
  1339. { 0x45e, 0x004, 2},
  1340. { 0x490, 0x004, 2},
  1341. { 0x5b0, 0x020, 20},
  1342. { 0x5d0, 0x020, 27},
  1343. { 0x5F0, 0x020, 5},
  1344. { 0x60c, 0x040, 1},
  1345. { 0x61b, 0x040, 1},
  1346. { 0x61f, 0x040, 1},
  1347. { 0x621, 0x040, 26},
  1348. { 0x640, 0x040, 19},
  1349. { 0x679, 0x040, 1},
  1350. { 0x67e, 0x040, 1},
  1351. { 0x686, 0x040, 1},
  1352. { 0x688, 0x040, 1},
  1353. { 0x691, 0x040, 1},
  1354. { 0x698, 0x040, 1},
  1355. { 0x6a9, 0x040, 1},
  1356. { 0x6af, 0x040, 1},
  1357. { 0x6ba, 0x040, 1},
  1358. { 0x6be, 0x040, 1},
  1359. { 0x6c1, 0x040, 1},
  1360. { 0x6d2, 0x040, 1},
  1361. {0x200c, 0x040, 2},
  1362. {0x200e, 0x060, 2},
  1363. {0x2013, 0x1ff, 2},
  1364. {0x2015, 0x008, 1},
  1365. {0x2018, 0x1ff, 3},
  1366. {0x201c, 0x1ff, 3},
  1367. {0x2020, 0x1ff, 3},
  1368. {0x2026, 0x1ff, 1},
  1369. {0x2030, 0x1ff, 1},
  1370. {0x2039, 0x1ff, 2},
  1371. {0x20AA, 0x020, 1},
  1372. {0x20AB, 0x100, 1},
  1373. {0x20AC, 0x1ff, 1},
  1374. {0x2116, 0x004, 1},
  1375. {0x2122, 0x1ff, 1}
  1376. };
  1377. // Easy check for ASCII
  1378. if(ch <= 0x7f)
  1379. return 0x1ff00;
  1380. // Easy check for missing codes
  1381. if(ch > 0x2122)
  1382. return 0;
  1383. if(IN_RANGE(0xA0, ch, 0xFF))
  1384. return rgCpgMask[ch - 0xA0] << 8;
  1385. // Perform binary search to find entry in table
  1386. int low = 0;
  1387. int high = ARRAY_SIZE(Table_125X) - 1;
  1388. int middle;
  1389. int midval;
  1390. int runlength;
  1391. while(low <= high)
  1392. {
  1393. middle = (high + low) / 2;
  1394. midval = Table_125X[middle].codepoint;
  1395. if(midval > ch)
  1396. high = middle - 1;
  1397. else
  1398. low = middle + 1;
  1399. runlength = Table_125X[middle].runlength;
  1400. if(ch >= midval && ch <= midval + runlength - 1)
  1401. return Table_125X[middle].CharFlags << 8;
  1402. }
  1403. return 0;
  1404. }
  1405. /*
  1406. * CW32System::IsUTF8BOM(pstr)
  1407. *
  1408. * @mfunc
  1409. * Return TRUE if pstr points at a UTF-8 BOM
  1410. *
  1411. * @rdesc
  1412. * TRUE iff pstr points at a UTF-8 BOM
  1413. */
  1414. BOOL CW32System::IsUTF8BOM(
  1415. BYTE *pstr)
  1416. {
  1417. BYTE *pstrUtf8BOM = szUTF8BOM;
  1418. for(LONG i = 3; i--; )
  1419. if(*pstr++ != *pstrUtf8BOM++)
  1420. return FALSE;
  1421. return TRUE;
  1422. }
  1423. /*
  1424. * CW32System::GetTrailBytesCount(ach, cpg)
  1425. *
  1426. * @mfunc
  1427. * Returns number of trail bytes iff the byte ach is a lead byte for the code page cpg.
  1428. *
  1429. * @rdesc
  1430. * count of trail bytes if ach is lead byte for cpg
  1431. *
  1432. * @comm
  1433. * This is needed to support CP_UTF8 as well as DBC.
  1434. * This function potentially doesn't support as many code pages as the
  1435. * Win32 IsDBCSLeadByte() function (and it might not be as up-to-date).
  1436. * An AssertSz() is included to compare the results when the code page
  1437. * is supported by the system.
  1438. *
  1439. * Reference: \\sparrow\sysnls\cptable\win95. See code-page txt files
  1440. * in subdirectories windows\txt and others\txt.
  1441. */
  1442. int CW32System::GetTrailBytesCount(BYTE ach, UINT cpg)
  1443. {
  1444. if(ach < 0x81) // Smallest known lead
  1445. return 0; // byte = 0x81:
  1446. // early out
  1447. BOOL bDBLeadByte = FALSE; // Variable to check
  1448. // result with system
  1449. // ifdef DEBUG
  1450. if (cpg == CP_UTF8)
  1451. {
  1452. int cTrailBytes = 0; // Number of trail bytes for CP_UTF8(0 - 3)
  1453. if (ach >= 0x0F0) // Handle 4-byte form for 16 UTF-16 planes
  1454. cTrailBytes = 3; // above the BMP) expect:
  1455. // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
  1456. else if (ach >= 0x0E0) // Need at least 3 bytes of form
  1457. cTrailBytes = 2; // 1110bbbb 10bbbbbb 10bbbbbb
  1458. else if (ach >= 0x0C0) // Need at least 2 bytes of form
  1459. cTrailBytes = 1; // 110bbbbb 10bbbbbb
  1460. return cTrailBytes;
  1461. }
  1462. else if(cpg > 950)
  1463. {
  1464. if(cpg < 1361) // E.g., the 125x's are
  1465. return 0; // SBCSs: early out
  1466. else if(cpg == 1361) // Korean Johab
  1467. bDBLeadByte = IN_RANGE(0x84, ach, 0xd3) || // 0x84 <= ach <= 0xd3
  1468. IN_RANGE(0xd8, ach, 0xde) || // 0xd8 <= ach <= 0xde
  1469. IN_RANGE(0xe0, ach, 0xf9); // 0xe0 <= ach <= 0xf9
  1470. else if(cpg == 10001) // Mac Japanese
  1471. goto JIS;
  1472. else if(cpg == 10002) // Mac Trad Chinese (Big5)
  1473. bDBLeadByte = ach <= 0xfe;
  1474. else if(cpg == 10003) // Mac Korean
  1475. bDBLeadByte = IN_RANGE(0xa1, ach, 0xac) || // 0xa1 <= ach <= 0xac
  1476. IN_RANGE(0xb0, ach, 0xc8) || // 0xb0 <= ach <= 0xc8
  1477. IN_RANGE(0xca, ach, 0xfd); // 0xca <= ach <= 0xfd
  1478. else if(cpg == 10008) // Mac Simplified Chinese
  1479. bDBLeadByte = IN_RANGE(0xa1, ach, 0xa9) || // 0xa1 <= ach <= 0xa9
  1480. IN_RANGE(0xb0, ach, 0xf7); // 0xb0 <= ach <= 0xf7
  1481. }
  1482. else if (cpg >= 932) // cpg <= 950
  1483. {
  1484. if(cpg == 950 || cpg == 949 || cpg == 936) // Chinese (Taiwan, HK),
  1485. bDBLeadByte = ach <= 0xfe; // Korean Ext Wansung,
  1486. // PRC GBK: 0x81 - 0xfe
  1487. else if(cpg == 932) // Japanese
  1488. JIS: bDBLeadByte = ach <= 0x9f || IN_RANGE(0xe0, ach, 0xfc);
  1489. }
  1490. #ifdef DEBUG
  1491. TCHAR ch;
  1492. static BYTE asz[2] = {0xe0, 0xe0}; // All code pages above
  1493. // if cpg == 0, fRet will FALSE but IsDBCSLeadByteEx may succeed.
  1494. if ( cpg && cpg != CP_SYMBOL && cpg != CP_UTF8)
  1495. {
  1496. // If system supports cpg, then fRet should agree with system result
  1497. AssertSz(MultiByteToWideChar(cpg, 0, (char *)asz, 2, &ch, 1) <= 0 ||
  1498. bDBLeadByte == IsDBCSLeadByteEx(cpg, ach),
  1499. "bDBLeadByte differs from IsDBCSLeadByteEx()");
  1500. }
  1501. #endif
  1502. return bDBLeadByte ? 1 : 0;
  1503. }
  1504. /*
  1505. * CW32System::GetGdiCharSet(bCharSet)
  1506. *
  1507. * @func
  1508. * Map CHARFORMAT charset to GDI charset (charset used in CreateFont)
  1509. */
  1510. BYTE CW32System::GetGdiCharSet(BYTE bCharSet)
  1511. {
  1512. return IsPrivateCharSet(bCharSet) ? DEFAULT_CHARSET : bCharSet;
  1513. }
  1514. /*
  1515. * CW32System::GetCharSet(nCP, pScriptIndex)
  1516. *
  1517. * @func
  1518. * Get character set for code page <p nCP>. Also returns script index
  1519. * in *pScriptIndex
  1520. *
  1521. * @rdesc
  1522. * CharSet for code page <p nCP>
  1523. */
  1524. BYTE CW32System::GetCharSet(
  1525. INT nCP, //@parm Code page or index
  1526. int *pScriptIndex) //@parm Out parm to receive index
  1527. {
  1528. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "GetCharSet");
  1529. if(nCP < NCHARSETS) // nCP is already an index
  1530. {
  1531. nCP = max(nCP, 0);
  1532. if(pScriptIndex)
  1533. *pScriptIndex = nCP;
  1534. return rgCpgCharSet[nCP].bCharSet;
  1535. }
  1536. const CPGCHAR * pcpgchar = rgCpgCharSet;
  1537. for (int i = 0; i < cCpgCharSet; i++, ++pcpgchar)
  1538. {
  1539. if(pcpgchar->nCodePage == nCP)
  1540. break;
  1541. }
  1542. if(i == cCpgCharSet)
  1543. i = -1;
  1544. if (pScriptIndex)
  1545. *pScriptIndex = i;
  1546. return i >= 0 ? pcpgchar->bCharSet : 0;
  1547. }
  1548. /*
  1549. * CW32System::MatchFECharSet(dwCharInfo, dwFontSig)
  1550. *
  1551. * @func
  1552. * Get a FE character set for a FE char
  1553. *
  1554. * @rdesc
  1555. * CharSet
  1556. */
  1557. BYTE CW32System::MatchFECharSet(
  1558. DWORD dwCharInfo, //@parm Char Info
  1559. DWORD dwFontSig) //@parm Font Signature
  1560. {
  1561. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::MatchFECharSet");
  1562. // Convert Font Signature to our internal char info
  1563. dwFontSig = (dwFontSig << 8) & ~0x00ffff;
  1564. // Get rid of lower word
  1565. dwCharInfo &= ~0x00ffff;
  1566. if (dwCharInfo & dwFontSig & (fKANA | fCHINESE | fHANGUL | fBIG5)) // Perfect match
  1567. goto Exit;
  1568. if (!(dwFontSig & (fKANA | fCHINESE | fHANGUL | fBIG5))) // Not a FE font
  1569. goto Exit;
  1570. if (dwCharInfo & (fCHINESE | fBIG5))
  1571. {
  1572. if (dwFontSig & fBIG5)
  1573. return CHINESEBIG5_CHARSET;
  1574. if (dwFontSig & fHANGUL)
  1575. return HANGEUL_CHARSET;
  1576. if (dwFontSig & fKANA)
  1577. return SHIFTJIS_CHARSET;
  1578. }
  1579. Exit:
  1580. return GetCharSet(W32->ScriptIndexFromFontSig(dwCharInfo >> 8), NULL);
  1581. }
  1582. /*
  1583. * CW32System::GetCodePage(bCharSet)
  1584. *
  1585. * @func
  1586. * Get code page for character set <p bCharSet>
  1587. *
  1588. * @rdesc
  1589. * Code page for character set <p bCharSet>
  1590. */
  1591. INT CW32System::GetCodePage(
  1592. BYTE bCharSet) //@parm CharSet
  1593. {
  1594. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "GetCodePage");
  1595. const CPGCHAR *pcpgchar = rgCpgCharSet;
  1596. for (int i = 0; i < cCpgCharSet ; i++, ++pcpgchar)
  1597. {
  1598. if (pcpgchar->bCharSet == bCharSet)
  1599. return pcpgchar->nCodePage;
  1600. }
  1601. return 0;
  1602. }
  1603. /*
  1604. * CW32System::GetFontSig(wCharSet)
  1605. *
  1606. * @func
  1607. * Get font signature bits for character set <p wCharSet>. If
  1608. * wCharSet > 256, treat as a codepage
  1609. *
  1610. * @rdesc
  1611. * Font signature mask for character set (or codepage) <p bCharSet>
  1612. */
  1613. DWORD CW32System::GetFontSig(
  1614. WORD wCharSet)
  1615. {
  1616. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::GetFontSig");
  1617. const CPGCHAR * pcpgchar = rgCpgCharSet;
  1618. BOOL fCodePage = wCharSet > 255;
  1619. for (int i = 0; i < cCpgCharSet; i++)
  1620. {
  1621. if(wCharSet == (WORD)(fCodePage ? pcpgchar->nCodePage : pcpgchar->bCharSet))
  1622. return pcpgchar->dwFontSig;
  1623. ++pcpgchar;
  1624. }
  1625. return 0;
  1626. }
  1627. /*
  1628. * CW32System::GetFirstAvailCharSet(DWORD dwFontSig)
  1629. *
  1630. * @func
  1631. * Get first available charset from font signature bits
  1632. */
  1633. BYTE CW32System::GetFirstAvailCharSet(
  1634. DWORD dwFontSig)
  1635. {
  1636. const CPGCHAR * pcpgchar = rgCpgCharSet;
  1637. for (int i = 0; i < cCpgCharSet; i++)
  1638. {
  1639. if(pcpgchar->dwFontSig & dwFontSig)
  1640. return pcpgchar->bCharSet;
  1641. ++pcpgchar;
  1642. }
  1643. return ANSI_CHARSET;
  1644. }
  1645. /*
  1646. * CW32System::GetFontSigFromScript(iScript)
  1647. *
  1648. * @func
  1649. * Get font signature bits for script <p iScript>
  1650. *
  1651. * @rdesc
  1652. * Font signature mask for script <p iScript>
  1653. */
  1654. DWORD CW32System::GetFontSigFromScript(
  1655. int iScript)
  1656. {
  1657. return rgCpgCharSet[iScript].dwFontSig;
  1658. }
  1659. /*
  1660. * CW32System::ScriptIndexFromFontSig(dwFontSig)
  1661. *
  1662. * @func
  1663. * Get script index from font signature
  1664. *
  1665. * @rdesc
  1666. * Script index from font signature <p dwFontSig>
  1667. *
  1668. * @devnote
  1669. * Linear search
  1670. */
  1671. LONG CW32System::ScriptIndexFromFontSig(
  1672. DWORD dwFontSig)
  1673. {
  1674. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::ScriptIndexFromFontSig");
  1675. const CPGCHAR *pcpgchar = rgCpgCharSet;
  1676. for (int i = 0; i < cCpgCharSet; i++, ++pcpgchar)
  1677. {
  1678. if(pcpgchar->dwFontSig == dwFontSig)
  1679. return i;
  1680. }
  1681. return -1; // Not found
  1682. }
  1683. /*
  1684. * CW32System::ScriptIndexFromCharSet(bCharSet)
  1685. *
  1686. * @func
  1687. * Get script index from bCharSet
  1688. *
  1689. * @rdesc
  1690. * Script index character set <p bCharSet>
  1691. *
  1692. * @devnote
  1693. * Linear search
  1694. */
  1695. LONG CW32System::ScriptIndexFromCharSet(
  1696. BYTE bCharSet)
  1697. {
  1698. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::ScriptIndexFromCharSet");
  1699. const CPGCHAR *pcpgchar = rgCpgCharSet;
  1700. for (int i = 0; i < cCpgCharSet; i++, ++pcpgchar)
  1701. {
  1702. if(pcpgchar->bCharSet == bCharSet)
  1703. return i;
  1704. }
  1705. return -1; // Not found
  1706. }
  1707. /*
  1708. * CW32System::IsCharSetValid(bCharSet)
  1709. *
  1710. * @func
  1711. * Return TRUE iff <p bCharSet> is a valid character set index
  1712. *
  1713. * @rdesc
  1714. * TRUE iff <p bCharSet> is a valid character set index
  1715. */
  1716. BOOL CW32System::IsCharSetValid(
  1717. BYTE bCharSet) //@parm CharSet
  1718. {
  1719. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::IsCharSetValid");
  1720. return ScriptIndexFromCharSet(bCharSet) >= 0;
  1721. }
  1722. /*
  1723. * CW32System::GetScreenDC(void)
  1724. *
  1725. * @mfunc
  1726. * Returns you a default screen DC which richedit caches for its lifetime.
  1727. *
  1728. * Note, you need to serialize access to DCs, so make sure its used in the
  1729. * renderer and measurer or otherwise protected by a CLock.
  1730. *
  1731. * @rdesc
  1732. * Screen HDC if succeeded.
  1733. */
  1734. HDC CW32System::GetScreenDC()
  1735. {
  1736. if (!_hdcScreen)
  1737. _hdcScreen = CreateIC(L"DISPLAY", NULL, NULL, NULL);;
  1738. //Verify DC validity
  1739. Assert(GetDeviceCaps(_hdcScreen, LOGPIXELSX));
  1740. return _hdcScreen;
  1741. }
  1742. /*
  1743. * CW32System::GetTextMetrics(hdc, &lf, &tm)
  1744. *
  1745. * @mfunc
  1746. * CreateFontIndirect(lf), select into hdc, and get TEXTMETRICS
  1747. *
  1748. * @rdesc
  1749. * TRUE if succeeded and selected facename is same as lf.lfFaceName
  1750. */
  1751. BOOL CW32System::GetTextMetrics(
  1752. HDC hdc,
  1753. LOGFONT & lf,
  1754. TEXTMETRIC &tm)
  1755. {
  1756. HFONT hfont = CreateFontIndirect(&lf);
  1757. if(!hfont)
  1758. return FALSE;
  1759. HFONT hfontOld = SelectFont(hdc, hfont);
  1760. WCHAR szFaceName[LF_FACESIZE + 1];
  1761. BOOL fRet = GetTextFace(hdc, LF_FACESIZE, szFaceName) &&
  1762. !wcsicmp(lf.lfFaceName, szFaceName) &&
  1763. W32->GetTextMetrics(hdc, &tm);
  1764. SelectFont(hdc, hfontOld);
  1765. DeleteObject(hfont);
  1766. return fRet;
  1767. }
  1768. /*
  1769. * CW32System::ValidateStreamWparam(wparam)
  1770. *
  1771. * @mfunc
  1772. * Examine lparam to see if hiword is a valid codepage. If not set it
  1773. * to 0 and turn off SF_USECODEPAGE flag
  1774. *
  1775. * @rdesc
  1776. * Validated lparam
  1777. */
  1778. WPARAM CW32System::ValidateStreamWparam(
  1779. WPARAM wparam) //@parm EM_STREAMIN/OUT wparam
  1780. {
  1781. TRACEBEGIN(TRCSUBSYSRTFR, TRCSCOPEINTERN, "CW32System::ValidateStreamWparam");
  1782. if ((wparam & SF_USECODEPAGE) && !IsValidCodePage(HIWORD(wparam)) &&
  1783. HIWORD(wparam) != CP_UTF8)
  1784. {
  1785. // Invalid codepage, so reset codepage parameters
  1786. wparam &= 0xFFFF & ~SF_USECODEPAGE;
  1787. }
  1788. return wparam;
  1789. }
  1790. /*
  1791. * CW32System::MECharClass(ch)
  1792. *
  1793. * @func
  1794. * return ME character type for purposes of CharSet stamping. Values
  1795. * are:
  1796. *
  1797. * 0: Arabic (specific RTL)
  1798. * 1: Hebrew (specific RTL)
  1799. * 2: RTL (generic RTL, e.g., RTL mark)
  1800. * 3: LTR
  1801. * 4: EOP or start/end of text
  1802. * 5: ASCII digit
  1803. * 6: punctuation and neutrals
  1804. *
  1805. * @rdesc
  1806. * ME character class
  1807. */
  1808. CC CW32System::MECharClass(
  1809. TCHAR ch)
  1810. {
  1811. AssertSz(CC_NEUTRAL > CC_ASCIIDIGIT && CC_ASCIIDIGIT > CC_EOP &&
  1812. CC_EOP > CC_LTR && CC_LTR > CC_RTL && CC_RTL > CC_ARABIC,
  1813. "CW32System::MECharClass: invalid CC values");
  1814. // Work down Unicode values from large to small. Use nested if
  1815. // statements to reduce the number executed.
  1816. // Remark: what about Arabic Presentation Forms?
  1817. // (0xFB50 - 0xFDFF, 0xFE70 - 0xFEFF)
  1818. if(ch >= 0x700)
  1819. {
  1820. if(IN_RANGE(ENQUAD, ch, RTLMARK))
  1821. { // ENQUAD thru RTLMARK
  1822. if(ch == RTLMARK) // Maybe add more Unicode general
  1823. return CC_RTL; // punctuation?
  1824. if(IN_RANGE(ZWNJ, ch, ZWJ)) // ZWNJ & ZWJ are handled as Arabic,
  1825. return CC_ARABIC; // even though they actually shouldn't
  1826. // affect layout.
  1827. if(ch < ZWNJ)
  1828. return CC_NEUTRAL; // Various blanks are neutral
  1829. }
  1830. return CC_LTR;
  1831. }
  1832. if(ch >= 0x40)
  1833. {
  1834. if(ch >= 0x590)
  1835. return (ch >= 0x600) ? CC_ARABIC : CC_HEBREW;
  1836. if(IN_RANGE(0x7B, (ch | 0x20), 0x7F) || ch == 0x60 || ch == 0x40)
  1837. return CC_NEUTRAL; // [\]^_{|}~`@
  1838. return CC_LTR;
  1839. }
  1840. if(ch >= 0x20)
  1841. {
  1842. if(IN_RANGE(0x30, ch, 0x39))
  1843. return CC_ASCIIDIGIT;
  1844. return CC_NEUTRAL;
  1845. }
  1846. Assert(ch < 0x20);
  1847. if((1 << ch) & 0x00003201) /* IsASCIIEOP(ch) || ch == TAB || !ch */
  1848. return CC_EOP;
  1849. return CC_LTR;
  1850. }
  1851. /*
  1852. * CW32System::ScriptIndexFromChar (ch)
  1853. *
  1854. * @mfunc
  1855. * Returns index into CharSet/CodePage table rgCpgCharSet corresponding
  1856. * to the Unicode character ch provided such an assignment is
  1857. * reasonably unambiguous, that is, the currently assigned Unicode
  1858. * characters in various ranges have Windows code-page equivalents.
  1859. * Ambiguous or impossible assignments return UNKNOWN_INDEX, which
  1860. * means that the character can only be represented by Unicode in this
  1861. * simple model. Note that the UNKNOWN_INDEX, HAN_INDEX, and FE_INDEX
  1862. * are negative values, i.e., they imply further processing to figure
  1863. * out what (if any) charset index to use. Other indices may also
  1864. * require run processing, such as the blank in BiDi text. We need
  1865. * to mark our right-to-left runs with an Arabic or Hebrew char set,
  1866. * while we mark left-to-right runs with a left-to-right char set.
  1867. *
  1868. * If the index has the FE_FLAG bit set, then the character is some kind
  1869. * of FE "DBCS" character, like a Han, Kana, or Hangul character.
  1870. * FE_INDEX, HAN_INDEX, HANGUL_INDEX, and SHIFTJIS_INDEX all have this
  1871. * flag set.
  1872. *
  1873. * @rdesc
  1874. * Script index in low word, and possible some extra flags, like
  1875. * FE_FLAG in high word
  1876. */
  1877. LONG CW32System::ScriptIndexFromChar(
  1878. TCHAR ch) //@parm Unicode character to examine
  1879. {
  1880. if(ch < 256)
  1881. return ANSI_INDEX;
  1882. if(ch < 0x700)
  1883. {
  1884. if(ch >= 0x600)
  1885. return ARABIC_INDEX;
  1886. if(ch > 0x590)
  1887. return HEBREW_INDEX;
  1888. if(ch < 0x500)
  1889. {
  1890. if(ch >= 0x400)
  1891. return RUSSIAN_INDEX;
  1892. if(ch >= 0x370)
  1893. return GREEK_INDEX;
  1894. }
  1895. }
  1896. else if(ch < 0x2500)
  1897. {
  1898. if(IN_RANGE(0xE00, ch, 0xE7F)) // Thai
  1899. return THAI_INDEX;
  1900. }
  1901. else if(ch < 0xAC00)
  1902. {
  1903. if(ch >= 0x3400) // CJK Ideographs
  1904. return HAN_INDEX;
  1905. if(ch >= 0x3100)
  1906. return FE_INDEX;
  1907. if(ch > 0x3040) // Katakana and Hiragana
  1908. return SHIFTJIS_INDEX;
  1909. if(ch >= 0x3000)
  1910. return FE_INDEX;
  1911. }
  1912. else if(ch < 0xD800)
  1913. return HANGUL_INDEX;
  1914. else if(ch > 0xFF00)
  1915. {
  1916. if(ch < 0xFF65) // Fullwidth ASCII and halfwidth
  1917. return HAN_INDEX; // CJK punctuation
  1918. if(ch < 0xFFA0) // Halfwidth Katakana
  1919. return SHIFTJIS_INDEX;
  1920. if(ch < 0xFFE0) // Halfwidth Jamo
  1921. return HANGUL_INDEX;
  1922. if(ch < 0xFFEF) // Fullwidth punctuation and currency
  1923. return HAN_INDEX; // signs; halfwidth forms, arrows
  1924. } // and shapes
  1925. return UNKNOWN_INDEX;
  1926. }
  1927. /*
  1928. * CW32System::MBTWC (CodePage, dwFlags, pstrMB, cchMB, pstrWC, cchWC, pfNoCodePage)
  1929. *
  1930. * @mfunc
  1931. * Convert MultiByte (MB) string pstrMB of length cchMB to WideChar (WC)
  1932. * string pstrWC of length cchWC according to the flags dwFlags and code
  1933. * page CodePage. If CodePage = SYMBOL_CODEPAGE
  1934. * (usually for SYMBOL_CHARSET strings),
  1935. * convert each byte in pstrMB to a wide char with a zero high byte
  1936. * and a low byte equal to the MultiByte string byte, i.e., no
  1937. * translation other than a zero extend into the high byte. Else call
  1938. * the Win32 MultiByteToWideChar() function.
  1939. *
  1940. * @rdesc
  1941. * Count of characters converted
  1942. */
  1943. int CW32System::MBTWC(
  1944. INT CodePage, //@parm Code page to use for conversion
  1945. DWORD dwFlags, //@parm Flags to guide conversion
  1946. LPCSTR pstrMB, //@parm MultiByte string to convert to WideChar
  1947. int cchMB, //@parm Count of chars (bytes) in pstrMB or -1
  1948. LPWSTR pstrWC, //@parm WideChar string to receive converted chars
  1949. int cchWC, //@parm Max count for pstrWC or 0 to get cch needed
  1950. LPBOOL pfNoCodePage) //@parm Out parm to receive whether code page is on system
  1951. {
  1952. BOOL fNoCodePage = FALSE; // Default code page is on OS
  1953. int cch = -1;
  1954. if(CodePage == CP_UTF8)
  1955. {
  1956. DWORD ch,ch1;
  1957. for(cch = 0; cchMB--; )
  1958. {
  1959. ch = ch1 = *(BYTE *)pstrMB++;
  1960. Assert(ch < 256);
  1961. if(ch > 127 && cchMB && IN_RANGE(0x80, *(BYTE *)pstrMB, 0xBF))
  1962. {
  1963. // Need at least 2 bytes of form 110bbbbb 10bbbbbb
  1964. ch1 = ((ch1 & 0x1F) << 6) + (*pstrMB++ & 0x3F);
  1965. cchMB--;
  1966. if(ch >= 0xE0 && cchMB && IN_RANGE(0x80, *(BYTE *)pstrMB, 0xBF))
  1967. {
  1968. // Need at least 3 bytes of form 1110bbbb 10bbbbbb 10bbbbbb
  1969. ch1 = (ch1 << 6) + (*pstrMB++ & 0x3F);
  1970. cchMB--;
  1971. if (ch >= 0xF0 && cchMB && IN_RANGE(0x80, *(BYTE *)pstrMB, 0xBF))
  1972. {
  1973. // Handle 4-byte form for 16 UTF-16 planes above the
  1974. // BMP) expect: 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
  1975. ch1 = ((ch1 & 0x7FFF) << 6) + (*(BYTE *)pstrMB++ & 0x3F)
  1976. - 0x10000; // Subtract offset for BMP
  1977. if(ch1 <= 0xFFFFF) // Fits in 20 bits
  1978. {
  1979. cch++; // Two 16-bit surrogate codes
  1980. if(cch < cchWC)
  1981. *pstrWC++ = UTF16_LEAD + (ch1 >> 10);
  1982. ch1 = (ch1 & 0x3FF) + UTF16_TRAIL;
  1983. cchMB--;
  1984. }
  1985. else ch1 = '?';
  1986. }
  1987. }
  1988. }
  1989. cch++;
  1990. if(cch < cchWC)
  1991. *pstrWC++ = ch1;
  1992. if(!ch)
  1993. break;
  1994. }
  1995. }
  1996. else if(CodePage != CP_SYMBOL) // Not SYMBOL_CHARSET
  1997. {
  1998. fNoCodePage = TRUE; // Default codepage isn't on OS
  1999. if(CodePage >= 0) // Might be..
  2000. {
  2001. cch = MultiByteToWideChar(
  2002. CodePage, dwFlags, pstrMB, cchMB, pstrWC, cchWC);
  2003. if(cch > 0)
  2004. fNoCodePage = FALSE; // Codepage is on OS
  2005. }
  2006. }
  2007. if(pfNoCodePage)
  2008. *pfNoCodePage = fNoCodePage;
  2009. if(cch <= 0)
  2010. {
  2011. // SYMBOL_CHARSET or conversion failed: bytes -> words with
  2012. // high bytes of 0. Return count for full conversion
  2013. if(cchWC <= 0)
  2014. return cchMB >= 0 ? cchMB : (strlen(pstrMB) + 1);
  2015. int cchMBMax = cchMB;
  2016. if(cchMB < 0) // If negative, use NULL termination
  2017. cchMBMax = tomForward; // of pstrMB
  2018. cchMBMax = min(cchMBMax, cchWC);
  2019. for(cch = 0; (cchMB < 0 ? *pstrMB : 1) && cch < cchMBMax; cch++)
  2020. {
  2021. *pstrWC++ = (unsigned char)*pstrMB++;
  2022. }
  2023. // NULL-terminate the WC string if the MB string was NULL-terminated,
  2024. // and if there is room in the WC buffer.
  2025. if(cchMB < 0 && cch < cchWC)
  2026. {
  2027. *pstrWC = 0;
  2028. cch++;
  2029. }
  2030. }
  2031. return cch;
  2032. }
  2033. /*
  2034. * CW32System::WCTMB (CodePage, dwFlags, pstrWC, cchWC, pstrMB, cchMB,
  2035. * pchDefault, pfUsedDef, pfNoCodePage, fTestCodePage)
  2036. *
  2037. * @mfunc
  2038. * Convert WideChar (WC) string pstrWC of length cchWC to MultiByte (MB)
  2039. * string pstrMB of length cchMB according to the flags dwFlags and code
  2040. * page CodePage. If CodePage = SYMBOL_CODEPAGE
  2041. * (usually for SYMBOL_CHARSET strings),
  2042. * convert each character in pstrWC to a byte, discarding the high byte.
  2043. * Else call the Win32 WideCharToMultiByte() function.
  2044. *
  2045. * @rdesc
  2046. * Count of bytes stored in target string pstrMB
  2047. */
  2048. int CW32System::WCTMB(
  2049. INT CodePage, //@parm Code page to use for conversion
  2050. DWORD dwFlags, //@parm Flags to guide conversion
  2051. LPCWSTR pstrWC, //@parm WideChar string to convert
  2052. int cchWC, //@parm Count for pstrWC or -1 to use NULL termination
  2053. LPSTR pstrMB, //@parm MultiByte string to receive converted chars
  2054. int cchMB, //@parm Count of chars (bytes) in pstrMB or 0
  2055. LPCSTR pchDefault, //@parm Default char to use if conversion fails
  2056. LPBOOL pfUsedDef, //@parm Out parm to receive whether default char used
  2057. LPBOOL pfNoCodePage, //@parm Out parm to receive whether code page is on system
  2058. BOOL fTestCodePage)//@parm Test CodePage could handle the pstrWC
  2059. {
  2060. int cch = -1; // No chars converted yet
  2061. BOOL fNoCodePage = FALSE; // Default code page is on OS
  2062. if(pfUsedDef) // Default that all chars can be
  2063. *pfUsedDef = FALSE; // converted
  2064. #ifndef WC_NO_BEST_FIT_CHARS
  2065. #define WC_NO_BEST_FIT_CHARS 0x400
  2066. #endif
  2067. if (_dwPlatformId == VER_PLATFORM_WIN32_NT &&
  2068. _dwMajorVersion > 4 && !dwFlags)
  2069. {
  2070. dwFlags = WC_NO_BEST_FIT_CHARS;
  2071. }
  2072. if(CodePage == CP_UTF8) // Convert to UTF8 since OS
  2073. { // doesn't (pre NT 5.0)
  2074. unsigned ch;
  2075. cch = 0; // No converted bytes yet
  2076. while(cchWC--)
  2077. {
  2078. ch = *pstrWC++; // Get Unicode char
  2079. if(ch <= 127) // It's ASCII
  2080. {
  2081. cch++;
  2082. if(cch < cchMB)
  2083. *pstrMB++ = ch; // One more converted byte
  2084. if(!ch) // Quit on NULL termination
  2085. break;
  2086. continue;
  2087. }
  2088. if(ch <= 0x7FF) // Need 2 bytes of form:
  2089. { // 110bbbbb 10bbbbbb
  2090. cch += 2;
  2091. if(cch < cchMB) // Store lead byte
  2092. *pstrMB++ = 0xC0 + (ch >> 6);
  2093. }
  2094. else if(IN_RANGE(UTF16_LEAD, ch, 0xDBFF))
  2095. { // Unicode surrogate pair
  2096. cch += 4; // Need 4 bytes of form:
  2097. if(cch < cchMB) // 11110bbb 10bbbbbb 10bbbbbb
  2098. { // 10bbbbbb
  2099. AssertSz(IN_RANGE(UTF16_TRAIL, *pstrWC, 0xDFFF),
  2100. "CW32System::WCTMB: illegal surrogate pair");
  2101. cchWC--;
  2102. ch = ((ch & 0x3FF) << 10) + (*pstrWC++ & 0x3FF) + 0x10000;
  2103. *pstrMB++ = 0xF0 + (ch >> 18);
  2104. *pstrMB++ = 0x80 + (ch >> 12 & 0x3F);
  2105. *pstrMB++ = 0x80 + (ch >> 6 & 0x3F);
  2106. }
  2107. }
  2108. else // Need 3 bytes of form:
  2109. { // 1110bbbb 10bbbbbb
  2110. cch += 3; // 10bbbbbb
  2111. if(cch < cchMB) // Store lead byte followed by
  2112. { // first trail byte
  2113. *pstrMB++ = 0xE0 + (ch >> 12);
  2114. *pstrMB++ = 0x80 + (ch >> 6 & 0x3F);
  2115. }
  2116. }
  2117. if(cch < cchMB) // Store final UTF-8 byte
  2118. *pstrMB++ = 0x80 + (ch & 0x3F);
  2119. }
  2120. }
  2121. else if(CodePage != CP_SYMBOL)
  2122. {
  2123. fNoCodePage = TRUE; // Default codepage not on OS
  2124. if(CodePage >= 0) // Might be...
  2125. {
  2126. cch = WideCharToMultiByte(CodePage, dwFlags,
  2127. pstrWC, cchWC, pstrMB, cchMB, pchDefault, pfUsedDef);
  2128. if(cch > 0)
  2129. fNoCodePage = FALSE; // Found codepage on system
  2130. }
  2131. }
  2132. if(pfNoCodePage)
  2133. *pfNoCodePage = fNoCodePage;
  2134. // Early exit if we are just testing for CodePage
  2135. if (fTestCodePage)
  2136. return cch;
  2137. // SYMBOL_CHARSET, fIsDBCS or conversion failed: low bytes of words ->
  2138. // bytes
  2139. if(cch <= 0)
  2140. {
  2141. // Return multibyte count for full conversion. cchWC is correct for
  2142. // single-byte charsets like the 125x's
  2143. if(cchMB <= 0)
  2144. {
  2145. return cchWC >= 0 ? cchWC : wcslen(pstrWC);
  2146. }
  2147. char chDefault = 0;
  2148. BOOL fUseDefaultChar = (pfUsedDef || pchDefault) && CodePage != CP_SYMBOL;
  2149. if(fUseDefaultChar)
  2150. {
  2151. // determine a default char for our home-grown conversion
  2152. if(pchDefault)
  2153. {
  2154. chDefault = *pchDefault;
  2155. }
  2156. else
  2157. {
  2158. static char chSysDef = 0;
  2159. static BOOL fGotSysDef = FALSE;
  2160. // 0x2022 is a math symbol with no conversion to ANSI
  2161. const WCHAR szCantConvert[] = { 0x2022 };
  2162. BOOL fUsedDef;
  2163. if(!fGotSysDef)
  2164. {
  2165. fGotSysDef = TRUE;
  2166. if(!(WideCharToMultiByte
  2167. (CP_ACP, 0, szCantConvert, 1, &chSysDef, 1, NULL,
  2168. &fUsedDef) == 1 && fUsedDef))
  2169. {
  2170. AssertSz(0, "WCTMB(): Unable to determine what the "
  2171. "system uses as its default replacement "
  2172. "character.");
  2173. chSysDef = '?';
  2174. }
  2175. }
  2176. chDefault = chSysDef;
  2177. }
  2178. }
  2179. int cchWCMax = cchWC;
  2180. // If negative, use NULL termination of pstrMB
  2181. if(cchWC < 0)
  2182. {
  2183. cchWCMax = tomForward;
  2184. }
  2185. cchWCMax = min(cchWCMax, cchMB);
  2186. for(cch = 0; (cchWC < 0 ? *pstrWC : 1) && cch < cchWCMax; cch++)
  2187. {
  2188. // TODO(BradO): Should this be 0x7F in some conversion cases?
  2189. if(fUseDefaultChar && *pstrWC > 0xFF)
  2190. {
  2191. if(pfUsedDef)
  2192. {
  2193. *pfUsedDef = TRUE;
  2194. }
  2195. *pstrMB = chDefault;
  2196. }
  2197. else
  2198. {
  2199. *pstrMB = (BYTE)*pstrWC;
  2200. }
  2201. pstrMB++;
  2202. pstrWC++;
  2203. }
  2204. if(cchWC < 0 && cch < cchMB)
  2205. {
  2206. *pstrMB = 0;
  2207. cch++;
  2208. }
  2209. }
  2210. return cch;
  2211. }
  2212. /*
  2213. * CW32System::VerifyFEString(cpg, pstrWC, cchWC, fTestInputCpg)
  2214. *
  2215. * @mfunc
  2216. * Verify if the input cpg can handle the pstrWC.
  2217. * If not, select another FE cpg.
  2218. *
  2219. * @rdesc
  2220. * New CodePage for the pstrWC
  2221. */
  2222. #define NUMBER_OF_CHARS 64
  2223. int CW32System::VerifyFEString(
  2224. INT cpg, //@parm cpg to format the pstrWC
  2225. LPCWSTR pstrWC, //@parm WideChar string to test
  2226. int cchWC, //@parm Count for pstrWC
  2227. BOOL fTestInputCpg) //@parm test the input cpg only
  2228. {
  2229. if (cchWC <=0)
  2230. return cpg;
  2231. int cpgNew = cpg;
  2232. BOOL fUsedDef;
  2233. int cchMB = cchWC * sizeof(WCHAR);
  2234. CTempCharBuf tcb;
  2235. char *pstrMB = tcb.GetBuf(cchMB);
  2236. CTempWcharBuf twcb;
  2237. WCHAR *pstrWchar = twcb.GetBuf(cchWC);
  2238. static int aiCpg[4] =
  2239. { CP_JAPAN, CP_KOREAN, CP_CHINESE_TRAD, CP_CHINESE_SIM };
  2240. if (pstrMB)
  2241. {
  2242. int cchConverted = WCTMB(cpg, 0, pstrWC, cchWC, pstrMB, cchMB, NULL,
  2243. &fUsedDef, NULL, TRUE);
  2244. if (cchConverted > 0 && !fUsedDef && IsFEFontInSystem(cpg))
  2245. {
  2246. cchConverted = MBTWC(cpg, 0, pstrMB, cchConverted, pstrWchar, cchWC, NULL);
  2247. if (cchConverted == cchWC && memcmp(pstrWC, pstrWchar, cchMB) == 0)
  2248. goto Exit; // Found it
  2249. }
  2250. if (fTestInputCpg) // Only need to test the input cpg
  2251. cpgNew = -1; // Indicate cpg doesn't support the string
  2252. else
  2253. {
  2254. // If no conversion or if the default character is used or
  2255. // no such FE font in system,
  2256. // it means that this cpg may not be the right choice.
  2257. // Let's try other FE cpg.
  2258. for (int i=0; i < 4; i++)
  2259. {
  2260. if (cpg != aiCpg[i])
  2261. {
  2262. cchConverted = WCTMB(aiCpg[i], 0, pstrWC, cchWC, pstrMB, cchMB, NULL,
  2263. &fUsedDef, NULL, TRUE);
  2264. if (cchConverted > 0 && !fUsedDef && IsFEFontInSystem(aiCpg[i]))
  2265. {
  2266. cchConverted = MBTWC(aiCpg[i], 0, pstrMB, cchConverted, pstrWchar, cchWC, NULL);
  2267. if (cchConverted == cchWC && memcmp(pstrWC, pstrWchar, cchMB) == 0)
  2268. {
  2269. cpgNew = aiCpg[i]; // Found it
  2270. break;
  2271. }
  2272. }
  2273. }
  2274. }
  2275. }
  2276. }
  2277. Exit:
  2278. return cpgNew;
  2279. }
  2280. int __cdecl CW32System::sprintf(char * buff, char *fmt, ...)
  2281. {
  2282. va_list marker;
  2283. va_start(marker, fmt);
  2284. int cb = W32->WvsprintfA(0x07FFFFFFF, buff, fmt, marker);
  2285. va_end(marker);
  2286. return cb;
  2287. }
  2288. //NOTE: Keep this at the end because we want any allocations in w32sys.cpp to be validated
  2289. //just like the rest of RichEdit.
  2290. /////////////////////////////// Memory mamagement /////////////////////////////////
  2291. #ifdef DEBUG
  2292. #undef PvAlloc
  2293. #undef PvReAlloc
  2294. #undef FreePv
  2295. #undef new
  2296. MST vrgmst[100];
  2297. typedef struct tagPVH //PV Header
  2298. {
  2299. char *szFile;
  2300. int line;
  2301. tagPVH *ppvhNext;
  2302. int cbAlloc; //On Win'95, the size returned is not the size allocated.
  2303. int magicPvh; //Should be last
  2304. } PVH;
  2305. #define cbPvh (sizeof(PVH))
  2306. typedef struct //PV Tail
  2307. {
  2308. int magicPvt; //Must be first
  2309. } PVT;
  2310. #define cbPvt (sizeof(PVT))
  2311. #define cbPvDebug (cbPvh + cbPvt)
  2312. void *vpHead = 0;
  2313. /*
  2314. * CW32System::UpdateMst(void)
  2315. *
  2316. * @mfunc Fills up the vrgmst structure with summary information about our memory
  2317. * usage.
  2318. *
  2319. * @rdesc
  2320. * void
  2321. */
  2322. void UpdateMst(void)
  2323. {
  2324. W32->ZeroMemory(vrgmst, sizeof(vrgmst));
  2325. PVH *ppvh;
  2326. MST *pmst;
  2327. ppvh = (PVH*) vpHead;
  2328. while (ppvh != 0)
  2329. {
  2330. pmst = vrgmst;
  2331. //Look for entry in list...
  2332. while (pmst->szFile)
  2333. {
  2334. if (strcmp(pmst->szFile, ppvh->szFile) == 0)
  2335. {
  2336. pmst->cbAlloc += ppvh->cbAlloc;
  2337. break;
  2338. }
  2339. pmst++;
  2340. }
  2341. if (pmst->szFile == 0)
  2342. {
  2343. pmst->szFile = ppvh->szFile;
  2344. pmst->cbAlloc = ppvh->cbAlloc;
  2345. }
  2346. ppvh = ppvh->ppvhNext;
  2347. }
  2348. }
  2349. /*
  2350. * PvDebugValidate(void)
  2351. *
  2352. * @func Verifies the the node is proper. Pass in a pointer to the users data
  2353. * (after the header node.)
  2354. *
  2355. * @rdesc
  2356. * void
  2357. */
  2358. void PvDebugValidate(void *pv)
  2359. {
  2360. PVH *ppvh;
  2361. PVT *ppvt;
  2362. ppvh = (PVH*) ((char*) pv - cbPvh);
  2363. ppvt = (PVT*) ((char*) pv + ppvh->cbAlloc);
  2364. AssertSz(ppvh->magicPvh == 0x12345678, "PvDebugValidate: header bytes are corrupt");
  2365. AssertSz(ppvt->magicPvt == 0xfedcba98, "PvDebugValidate: tail bytes are corrupt");
  2366. }
  2367. /*
  2368. * CW32System::PvSet(pv, szFile, line)
  2369. *
  2370. * @mfunc Sets a different module and line number for
  2371. *
  2372. * @rdesc
  2373. * void
  2374. */
  2375. void CW32System::PvSet(void *pv, char *szFile, int line)
  2376. {
  2377. if (pv == 0)
  2378. return;
  2379. PvDebugValidate(pv);
  2380. PVH *ppvh = (PVH*) ((char*) pv - cbPvh);
  2381. ppvh->szFile = szFile;
  2382. ppvh->line = line;
  2383. }
  2384. /*
  2385. * CW32System::PvAllocDebug(cb, uiMemFlags, szFile, line)
  2386. *
  2387. * @mfunc Allocates a generic (void*) pointer. This is a debug only routine which
  2388. * tracks the allocation.
  2389. *
  2390. * @rdesc
  2391. * void
  2392. */
  2393. void* CW32System::PvAllocDebug(ULONG cb, UINT uiMemFlags, char *szFile, int line)
  2394. {
  2395. void *pv;
  2396. pv = PvAlloc(cb + cbPvDebug, uiMemFlags);
  2397. if (!pv)
  2398. return 0;
  2399. PVH *ppvh;
  2400. PVT *ppvt;
  2401. ppvt = (PVT*) ((char*) pv + cb + cbPvh);
  2402. ppvh = (PVH*) pv;
  2403. ZeroMemory(ppvh, sizeof(PVH));
  2404. ppvh->magicPvh = 0x12345678;
  2405. ppvt->magicPvt = 0xfedcba98;
  2406. ppvh->szFile = szFile;
  2407. ppvh->line = line;
  2408. ppvh->cbAlloc = cb;
  2409. ppvh->ppvhNext = (PVH*) vpHead;
  2410. vpHead = pv;
  2411. return (char*) pv + cbPvh;
  2412. }
  2413. /*
  2414. * CW32System::PvReAllocDebug(pv, cb, szFile, line)
  2415. *
  2416. * @mfunc ReAllocates a generic (void*) pointer. This is a debug only routine which
  2417. * tracks the allocation.
  2418. *
  2419. * @rdesc
  2420. * void
  2421. */
  2422. void* CW32System::PvReAllocDebug(void *pv, ULONG cb, char *szFile, int line)
  2423. {
  2424. void *pvNew;
  2425. PVH *ppvh, *ppvhHead, *ppvhTail;
  2426. PVT *ppvt;
  2427. ppvh = (PVH*) ((char*) pv - cbPvh);
  2428. if (!pv)
  2429. return PvAllocDebug(cb, 0, szFile, line);
  2430. PvDebugValidate(pv);
  2431. pvNew = PvReAlloc((char*) pv - cbPvh, cb + cbPvDebug);
  2432. if (!pvNew)
  2433. return 0;
  2434. ppvt = (PVT*) ((char*) pvNew + cb + cbPvh);
  2435. ppvh = (PVH*) pvNew;
  2436. ppvh->cbAlloc = cb;
  2437. //Put the new trailer bytes in.
  2438. ppvt->magicPvt = 0xfedcba98;
  2439. //Make the pointer list up to date again
  2440. if (pv != pvNew)
  2441. {
  2442. ppvhTail = 0;
  2443. ppvhHead = (PVH*) vpHead;
  2444. while ((char*)ppvhHead != (char*)pv - cbPvh)
  2445. {
  2446. AssertSz(ppvhHead, "entry not found in list.");
  2447. ppvhTail = ppvhHead;
  2448. ppvhHead = (PVH*) ppvhHead->ppvhNext;
  2449. }
  2450. if (ppvhTail == 0)
  2451. vpHead = pvNew;
  2452. else
  2453. ppvhTail->ppvhNext = (PVH*) pvNew;
  2454. }
  2455. return (char*) pvNew + cbPvh;
  2456. }
  2457. /*
  2458. * CW32System::FreePvDebug(pv)
  2459. *
  2460. * @mfunc Returns a pointer when you are done with it.
  2461. *
  2462. * @rdesc
  2463. * void
  2464. */
  2465. void CW32System::FreePvDebug(void *pv)
  2466. {
  2467. if (!pv)
  2468. return;
  2469. PvDebugValidate(pv);
  2470. PVH *ppvhHead, *ppvhTail, *ppvh;
  2471. AssertSz(vpHead, "Deleting from empty free list.");
  2472. ppvh = (PVH*) ((char*) pv - cbPvh);
  2473. //Search and remove the entry from the list
  2474. ppvhTail = 0;
  2475. ppvhHead = (PVH*) vpHead;
  2476. while ((char*) ppvhHead != ((char*) pv - cbPvh))
  2477. {
  2478. AssertSz(ppvhHead, "entry not found in list.");
  2479. ppvhTail = ppvhHead;
  2480. ppvhHead = (PVH*) ppvhHead->ppvhNext;
  2481. }
  2482. if (ppvhTail == 0)
  2483. vpHead = ppvhHead->ppvhNext;
  2484. else
  2485. ppvhTail->ppvhNext = ppvhHead->ppvhNext;
  2486. FreePv((char*) pv - cbPvh);
  2487. }
  2488. /*
  2489. * CatchLeaks(void)
  2490. *
  2491. * @func Displays any memory leaks in a dialog box.
  2492. *
  2493. * @rdesc
  2494. * void
  2495. */
  2496. void CatchLeaks(void)
  2497. {
  2498. PVH *ppvh;
  2499. char szLeak[512];
  2500. ppvh = (PVH*) vpHead;
  2501. while (ppvh != 0)
  2502. {
  2503. wsprintfA(szLeak, "Memory Leak of %d bytes: -- File: %s, Line: %d", ppvh->cbAlloc, ppvh->szFile, ppvh->line);
  2504. if (NULL != pfnAssert)
  2505. {
  2506. // if we have an assert hook, give the user a chance to process the leak message
  2507. if (pfnAssert(szLeak, ppvh->szFile, &ppvh->line))
  2508. {
  2509. // hook returned true, show the message box
  2510. MessageBoxA(NULL, szLeak, "", MB_OK);
  2511. }
  2512. }
  2513. else
  2514. {
  2515. MessageBoxA(NULL, szLeak, "", MB_OK);
  2516. }
  2517. ppvh = ppvh->ppvhNext;
  2518. }
  2519. }
  2520. void* _cdecl operator new (size_t size, char *szFile, int line)
  2521. {
  2522. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "new");
  2523. return W32->PvAllocDebug(size, GMEM_ZEROINIT, szFile, line);
  2524. }
  2525. void _cdecl operator delete (void* pv)
  2526. {
  2527. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "delete");
  2528. W32->FreePvDebug(pv);
  2529. }
  2530. #else //DEBUG
  2531. void* _cdecl operator new (size_t size)
  2532. {
  2533. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "new");
  2534. return W32->PvAlloc(size, GMEM_ZEROINIT);
  2535. }
  2536. void _cdecl operator delete (void* pv)
  2537. {
  2538. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "delete");
  2539. W32->FreePv(pv);
  2540. }
  2541. #endif //DEBUG
  2542. /*
  2543. * PvAlloc (cbBuf, uiMemFlags)
  2544. *
  2545. * @mfunc memory allocation. Similar to GlobalAlloc.
  2546. *
  2547. * @comm The only flag of interest is GMEM_ZEROINIT, which
  2548. * specifies that memory should be zeroed after allocation.
  2549. */
  2550. PVOID CW32System::PvAlloc(
  2551. ULONG cbBuf, //@parm Count of bytes to allocate
  2552. UINT uiMemFlags) //@parm Flags controlling allocation
  2553. {
  2554. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "PvAlloc");
  2555. void * pv = LocalAlloc(LMEM_FIXED, cbBuf);
  2556. if( pv && (uiMemFlags & GMEM_ZEROINIT) )
  2557. ZeroMemory(pv, cbBuf);
  2558. return pv;
  2559. }
  2560. /*
  2561. * PvReAlloc (pvBuf, cbBuf)
  2562. *
  2563. * @mfunc memory reallocation.
  2564. *
  2565. */
  2566. PVOID CW32System::PvReAlloc(
  2567. PVOID pvBuf, //@parm Buffer to reallocate
  2568. DWORD cbBuf) //@parm New size of buffer
  2569. {
  2570. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "PvReAlloc");
  2571. if(pvBuf)
  2572. return LocalReAlloc(pvBuf, cbBuf, LMEM_MOVEABLE);
  2573. return LocalAlloc(LMEM_FIXED, cbBuf);
  2574. }
  2575. /*
  2576. * FreePv (pvBuf)
  2577. *
  2578. * @mfunc frees memory
  2579. *
  2580. * @rdesc void
  2581. */
  2582. void CW32System::FreePv(
  2583. PVOID pvBuf) //@parm Buffer to free
  2584. {
  2585. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "FreePv");
  2586. if(pvBuf)
  2587. LocalFree(pvBuf);
  2588. }
  2589. /*
  2590. * Mirroring API (only in BiDi Win98 and NT5 upward)
  2591. *
  2592. * @mfunc Get/Set DC mirroring effect
  2593. *
  2594. */
  2595. DWORD WINAPI GetLayoutStub(HDC hdc)
  2596. {
  2597. return 0;
  2598. }
  2599. DWORD WINAPI SetLayoutStub(HDC hdc, DWORD dwLayout)
  2600. {
  2601. return 0;
  2602. }
  2603. DWORD WINAPI GetLayoutInit(HDC hdc)
  2604. {
  2605. CLock lock;
  2606. HINSTANCE hMod = ::GetModuleHandleA("GDI32.DLL");
  2607. Assert(hMod);
  2608. W32->_pfnGetLayout = (PFN_GETLAYOUT)GetProcAddress(hMod, "GetLayout");
  2609. if (!W32->_pfnGetLayout)
  2610. W32->_pfnGetLayout = &GetLayoutStub;
  2611. return W32->_pfnGetLayout(hdc);
  2612. }
  2613. DWORD WINAPI SetLayoutInit(HDC hdc, DWORD dwLayout)
  2614. {
  2615. CLock lock;
  2616. HINSTANCE hMod = ::GetModuleHandleA("GDI32.DLL");
  2617. Assert(hMod);
  2618. W32->_pfnSetLayout = (PFN_SETLAYOUT)GetProcAddress(hMod, "SetLayout");
  2619. if (!W32->_pfnSetLayout)
  2620. W32->_pfnSetLayout = &SetLayoutStub;
  2621. return W32->_pfnSetLayout(hdc, dwLayout);
  2622. }
  2623. PFN_GETLAYOUT CW32System::_pfnGetLayout = &GetLayoutInit;
  2624. PFN_SETLAYOUT CW32System::_pfnSetLayout = &SetLayoutInit;