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.

878 lines
28 KiB

  1. #include "private.h"
  2. #ifdef UNIX
  3. /* Convert from little endian to big endian format */
  4. #define CONVERTLONG(a,b,c,d) (((unsigned long )a) + \
  5. ((unsigned long )b << 8) + \
  6. ((unsigned long )c << 16) + \
  7. ((unsigned long )d << 24))
  8. #endif /* UNIX */
  9. //
  10. // Globals
  11. //
  12. CMimeDatabaseReg *g_pMimeDatabaseReg = NULL;
  13. //
  14. // Globals
  15. //
  16. PRFC1766INFOA g_pRfc1766Reg = NULL;
  17. UINT g_cRfc1766Reg = 0, g_cMaxRfc1766 = 0;
  18. //
  19. // Functions
  20. //
  21. void CMimeDatabaseReg::BuildRfc1766Table(void)
  22. {
  23. HKEY hKey = NULL;
  24. DWORD dwIndex, dwType, cInfo, cbMaxValueLen, cbLCID, cb;
  25. TCHAR szLCID[8], sz[MAX_RFC1766_NAME + MAX_LOCALE_NAME + 1];
  26. DebugMsg(DM_TRACE, TEXT("CRfc1766::BuildRfc1766Table called."));
  27. EnterCriticalSection(&g_cs);
  28. if (NULL == g_pRfc1766Reg)
  29. {
  30. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, REGSTR_KEY_MIME_DATABASE_RFC1766, 0, KEY_READ, &hKey))
  31. {
  32. ASSERT(NULL != hKey);
  33. if (ERROR_SUCCESS == RegQueryInfoKey(hKey, NULL, NULL, 0, NULL, NULL, NULL, &cInfo, &cbMaxValueLen, NULL, NULL, NULL))
  34. {
  35. g_pRfc1766Reg = (PRFC1766INFOA)LocalAlloc(LPTR, sizeof(RFC1766INFOA) * cInfo);
  36. if (NULL != g_pRfc1766Reg)
  37. {
  38. g_cRfc1766Reg = 0;
  39. g_cMaxRfc1766 = cInfo;
  40. dwIndex = 0;
  41. while (g_cRfc1766Reg < g_cMaxRfc1766)
  42. {
  43. LONG lRet;
  44. cbLCID = ARRAYSIZE(szLCID) - 2;
  45. cb = sizeof(sz);
  46. lRet = RegEnumValue(hKey, dwIndex++, szLCID + 2, &cbLCID, 0, &dwType, (LPBYTE)sz, &cb);
  47. if (ERROR_SUCCESS == lRet)
  48. {
  49. int iLCID;
  50. szLCID[0] = TEXT('0');
  51. szLCID[1] = TEXT('x');
  52. // StrToInt
  53. if (iLCID = HexToNum(szLCID + 2))
  54. {
  55. g_pRfc1766Reg[g_cRfc1766Reg].lcid = (LCID)iLCID;
  56. if (REG_SZ == dwType)
  57. {
  58. TCHAR *psz = sz;
  59. while (*psz)
  60. {
  61. if (TEXT(';') == *psz)
  62. {
  63. *psz = TEXT('\0');
  64. break;
  65. }
  66. psz = CharNext(psz);
  67. }
  68. lstrcpyn(g_pRfc1766Reg[g_cRfc1766Reg].szRfc1766, sz, MAX_RFC1766_NAME);
  69. lstrcpyn(g_pRfc1766Reg[g_cRfc1766Reg].szLocaleName, psz + 1, MAX_LOCALE_NAME);
  70. g_cRfc1766Reg++;
  71. }
  72. }
  73. }
  74. else if (ERROR_NO_MORE_ITEMS == lRet)
  75. break;
  76. }
  77. }
  78. }
  79. RegCloseKey(hKey);
  80. }
  81. }
  82. LeaveCriticalSection(&g_cs);
  83. }
  84. void CMimeDatabaseReg::FreeRfc1766Table(void)
  85. {
  86. DebugMsg(DM_TRACE, TEXT("CRfc1766::FreeRfc1766Table called."));
  87. EnterCriticalSection(&g_cs);
  88. if (NULL != g_pRfc1766Reg)
  89. {
  90. LocalFree(g_pRfc1766Reg);
  91. g_pRfc1766Reg = NULL;
  92. g_cRfc1766Reg = g_cMaxRfc1766 = 0;
  93. }
  94. LeaveCriticalSection(&g_cs);
  95. }
  96. void CMimeDatabaseReg::EnsureRfc1766Table(void)
  97. {
  98. // Ensure g_pRfc1766 is initialized
  99. if (NULL == g_pRfc1766Reg)
  100. BuildRfc1766Table();
  101. }
  102. STDAPI CMimeDatabaseReg::LcidToRfc1766A(LCID Locale, LPSTR pszRfc1766, int iMaxLength)
  103. {
  104. UINT i;
  105. HRESULT hr = E_INVALIDARG;
  106. EnsureRfc1766Table();
  107. if (NULL != pszRfc1766 && 0 < iMaxLength)
  108. {
  109. for (i = 0; i < g_cRfc1766Reg; i++)
  110. {
  111. if (g_pRfc1766Reg[i].lcid == Locale)
  112. break;
  113. }
  114. if (i < g_cRfc1766Reg)
  115. {
  116. lstrcpyn(pszRfc1766, g_pRfc1766Reg[i].szRfc1766, iMaxLength);
  117. hr = S_OK;
  118. }
  119. else
  120. {
  121. TCHAR sz[MAX_RFC1766_NAME];
  122. if (GetLocaleInfoA(Locale, LOCALE_SABBREVLANGNAME, sz, ARRAYSIZE(sz)))
  123. {
  124. CharLowerA(sz);
  125. if (!lstrcmpA(sz, TEXT("cht")))
  126. lstrcpynA(pszRfc1766, TEXT("zh-cn"), iMaxLength);
  127. else if (!lstrcmpA(sz, TEXT("chs")))
  128. lstrcpynA(pszRfc1766, TEXT("zh-tw"), iMaxLength);
  129. else if (!lstrcmpA(sz, TEXT("jpn")))
  130. lstrcpynA(pszRfc1766, TEXT("ja"), iMaxLength);
  131. else
  132. {
  133. sz[2] = TEXT('\0');
  134. lstrcpynA(pszRfc1766, sz, iMaxLength);
  135. }
  136. hr = S_OK;
  137. }
  138. else
  139. hr = E_FAIL;
  140. }
  141. }
  142. return hr;
  143. }
  144. STDAPI CMimeDatabaseReg::LcidToRfc1766W(LCID Locale, LPWSTR pwszRfc1766, int nChar)
  145. {
  146. HRESULT hr = E_INVALIDARG;
  147. if (NULL != pwszRfc1766 && 0 < nChar)
  148. {
  149. TCHAR sz[MAX_RFC1766_NAME];
  150. hr = LcidToRfc1766A(Locale, (LPSTR)sz, ARRAYSIZE(sz));
  151. if (S_OK == hr)
  152. {
  153. int i;
  154. for (i = 0; i < nChar - 1; i++)
  155. {
  156. pwszRfc1766[i] = (WCHAR)sz[i];
  157. if (L'\0' == pwszRfc1766[i])
  158. break;
  159. }
  160. if (i == nChar - 1)
  161. pwszRfc1766[i] = L'\0';
  162. }
  163. }
  164. return hr;
  165. }
  166. STDAPI CMimeDatabaseReg::Rfc1766ToLcidA(PLCID pLocale, LPCSTR pszRfc1766)
  167. {
  168. UINT i;
  169. HRESULT hr = E_INVALIDARG;
  170. EnsureRfc1766Table();
  171. if (NULL != pLocale && NULL != pszRfc1766)
  172. {
  173. for (i = 0; i < g_cRfc1766Reg; i++)
  174. {
  175. if (!lstrcmpi(g_pRfc1766Reg[i].szRfc1766, pszRfc1766))
  176. break;
  177. }
  178. if (i < g_cRfc1766Reg)
  179. {
  180. *pLocale = g_pRfc1766Reg[i].lcid;
  181. hr = S_OK;
  182. }
  183. else
  184. {
  185. if (2 < lstrlen(pszRfc1766))
  186. {
  187. TCHAR sz[3];
  188. sz[0] = pszRfc1766[0];
  189. sz[1] = pszRfc1766[1];
  190. sz[2] = TEXT('\0');
  191. for (i = 0; i < g_cRfc1766Reg; i++)
  192. {
  193. if (!lstrcmpi(g_pRfc1766Reg[i].szRfc1766, sz))
  194. break;
  195. }
  196. if (i < g_cRfc1766Reg)
  197. {
  198. *pLocale = g_pRfc1766Reg[i].lcid;
  199. hr = S_FALSE;
  200. }
  201. else
  202. hr = E_FAIL;
  203. }
  204. else
  205. hr = E_FAIL;
  206. }
  207. }
  208. return hr;
  209. }
  210. STDAPI CMimeDatabaseReg::Rfc1766ToLcidW(PLCID pLocale, LPCWSTR pwszRfc1766)
  211. {
  212. HRESULT hr = E_INVALIDARG;
  213. if (NULL != pLocale && NULL != pwszRfc1766)
  214. {
  215. int i;
  216. TCHAR sz[MAX_RFC1766_NAME];
  217. for (i = 0; i < MAX_RFC1766_NAME - 1; i++)
  218. {
  219. sz[i] = (TCHAR)pwszRfc1766[i];
  220. if (TEXT('\0') == sz[i])
  221. break;
  222. }
  223. if (i == MAX_RFC1766_NAME -1)
  224. sz[i] = TEXT('\0');
  225. hr = Rfc1766ToLcidA(pLocale, (LPCSTR)sz);
  226. }
  227. return hr;
  228. }
  229. //
  230. // CMimeDatabase implementation
  231. //
  232. CMimeDatabaseReg::CMimeDatabaseReg()
  233. {
  234. DebugMsg(DM_TRACE, TEXT("constructor of CMimeDatabase 0x%08x"), this);
  235. _pCodePage = NULL;
  236. _cCodePage = _cMaxCodePage = 0;
  237. _pCharset = NULL;
  238. _cCharset = _cMaxCharset = 0;
  239. _fAllCPCached = FALSE;
  240. InitializeCriticalSection(&_cs);
  241. }
  242. CMimeDatabaseReg::~CMimeDatabaseReg()
  243. {
  244. DebugMsg(DM_TRACE, TEXT("destructor of CMimeDatabase 0x%08x"), this);
  245. FreeMimeDatabase();
  246. DeleteCriticalSection(&_cs);
  247. }
  248. void CMimeDatabaseReg::BuildCodePageMimeDatabase(void)
  249. {
  250. HKEY hKey = NULL;
  251. DWORD cInfo, cbMaxSubKeyLen;
  252. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::BuildCodePageMimeDatabase called."));
  253. // Open CodePage Mime Database Key
  254. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, REGSTR_KEY_MIME_DATABASE_CODEPAGE, 0, KEY_READ, &hKey))
  255. {
  256. ASSERT(NULL != hKey);
  257. if (ERROR_SUCCESS == RegQueryInfoKey(hKey, NULL, NULL, 0, &cInfo, &cbMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL))
  258. {
  259. if (NULL == _pCodePage)
  260. {
  261. _pCodePage = (PMIMECPINFO)LocalAlloc(LPTR, sizeof(MIMECPINFO) * cInfo);
  262. if (NULL != _pCodePage)
  263. _cMaxCodePage = cInfo;
  264. }
  265. }
  266. RegCloseKey(hKey);
  267. hKey = NULL;
  268. }
  269. }
  270. void CMimeDatabaseReg::BuildCharsetMimeDatabase(void)
  271. {
  272. HKEY hKey = NULL;
  273. DWORD cInfo, cbMaxSubKeyLen;
  274. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::BuildCharsetMimeDatabase called."));
  275. // Open Charset Mime Database Key
  276. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, REGSTR_KEY_MIME_DATABASE_CHARSET, 0, KEY_READ, &hKey))
  277. {
  278. ASSERT(NULL != hKey);
  279. if (ERROR_SUCCESS == RegQueryInfoKey(hKey, NULL, NULL, 0, &cInfo, &cbMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL))
  280. {
  281. if (NULL == _pCharset)
  282. {
  283. _pCharset = (PMIMECSETINFO)LocalAlloc(LPTR, sizeof(MIMECSETINFO) * cInfo);
  284. if (NULL != _pCharset)
  285. _cMaxCharset = cInfo;
  286. }
  287. }
  288. RegCloseKey(hKey);
  289. hKey = NULL;
  290. }
  291. }
  292. void CMimeDatabaseReg::FreeMimeDatabase(void)
  293. {
  294. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::FreeMimeDatabase called."));
  295. EnterCriticalSection(&_cs);
  296. if (NULL != _pCodePage)
  297. {
  298. LocalFree(_pCodePage);
  299. _pCodePage = NULL;
  300. _cCodePage = _cMaxCodePage = 0;
  301. }
  302. if (NULL != _pCharset)
  303. {
  304. LocalFree(_pCharset);
  305. _pCharset = NULL;
  306. _cCharset = _cMaxCharset = 0;
  307. }
  308. LeaveCriticalSection(&_cs);
  309. FreeRfc1766Table();
  310. }
  311. STDAPI CMimeDatabaseReg::EnumCodePageInfo(void)
  312. {
  313. HKEY hKey = NULL;
  314. DWORD dwIndex = 0;
  315. MIMECPINFO CPInfo;
  316. TCHAR szCodePage[15];
  317. HRESULT hr = S_OK;
  318. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::EnumCodePageInfo called."));
  319. EnterCriticalSection(&_cs);
  320. if (FALSE == _fAllCPCached)
  321. {
  322. if (NULL == _pCodePage)
  323. BuildCodePageMimeDatabase();
  324. if (_pCodePage)
  325. {
  326. // Open CodePage Mime Database Key
  327. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, REGSTR_KEY_MIME_DATABASE_CODEPAGE, 0, KEY_READ, &hKey))
  328. {
  329. ASSERT(NULL != hKey);
  330. while (ERROR_SUCCESS == RegEnumKey(hKey, dwIndex++, szCodePage, ARRAYSIZE(szCodePage)))
  331. {
  332. UINT uiCodePage = MLStrToInt(szCodePage);
  333. if (0 <= FindCodePageFromCache(uiCodePage))
  334. continue;
  335. if (TRUE == FindCodePageFromRegistry(uiCodePage, &CPInfo))
  336. {
  337. _pCodePage[_cCodePage] = CPInfo;
  338. _cCodePage++;
  339. }
  340. }
  341. _fAllCPCached = TRUE;
  342. RegCloseKey(hKey);
  343. hKey = NULL;
  344. }
  345. if (0 < _cCodePage)
  346. QSortCodePageInfo(0, _cCodePage-1);
  347. // Fill empty font face field base on its FamilyCodePage
  348. for (UINT i = 0; i < _cCodePage; i++)
  349. {
  350. UINT uiFamily;
  351. WCHAR wszFixed[MAX_MIMEFACE_NAME], wszProp[MAX_MIMEFACE_NAME];
  352. uiFamily = 0;
  353. wszFixed[0] = wszProp[0] = TEXT('\0');
  354. if (TEXT('\0') == _pCodePage[i].wszFixedWidthFont[0] || TEXT('\0') == _pCodePage[i].wszProportionalFont[0])
  355. {
  356. if (uiFamily != _pCodePage[i].uiFamilyCodePage)
  357. {
  358. for (UINT j = 0; j < _cCodePage; j++)
  359. {
  360. if (_pCodePage[i].uiFamilyCodePage == _pCodePage[j].uiCodePage)
  361. {
  362. uiFamily = _pCodePage[j].uiCodePage;
  363. MLStrCpyNW(wszFixed, _pCodePage[j].wszFixedWidthFont, MAX_MIMEFACE_NAME);
  364. MLStrCpyNW(wszProp, _pCodePage[j].wszProportionalFont, MAX_MIMEFACE_NAME);
  365. break;
  366. }
  367. }
  368. }
  369. MLStrCpyNW(_pCodePage[i].wszFixedWidthFont, wszFixed, MAX_MIMEFACE_NAME);
  370. MLStrCpyNW(_pCodePage[i].wszProportionalFont, wszProp, MAX_MIMEFACE_NAME);
  371. }
  372. }
  373. }
  374. else
  375. {
  376. hr = E_OUTOFMEMORY;
  377. }
  378. }
  379. LeaveCriticalSection(&_cs);
  380. return hr;
  381. }
  382. STDAPI CMimeDatabaseReg::GetNumberOfCodePageInfo(UINT *pcCodePage)
  383. {
  384. EnterCriticalSection(&_cs);
  385. if (NULL == _pCodePage)
  386. BuildCodePageMimeDatabase();
  387. *pcCodePage = _cMaxCodePage;
  388. LeaveCriticalSection(&_cs);
  389. return NOERROR;
  390. }
  391. STDAPI CMimeDatabaseReg::GetCodePageInfo(UINT uiCodePage, PMIMECPINFO pcpInfo)
  392. {
  393. int idx;
  394. HRESULT hr = E_FAIL;
  395. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::GetCodePageInfo called."));
  396. if (NULL != pcpInfo)
  397. {
  398. EnterCriticalSection(&_cs);
  399. if (NULL == _pCodePage)
  400. BuildCodePageMimeDatabase();
  401. if (_pCodePage)
  402. {
  403. idx = FindCodePageFromCache(uiCodePage);
  404. if (0 > idx)
  405. {
  406. MIMECPINFO CPInfo = {0};
  407. if (TRUE == FindCodePageFromRegistry(uiCodePage, &CPInfo))
  408. {
  409. if (CPInfo.uiCodePage != CPInfo.uiFamilyCodePage)
  410. {
  411. idx = FindCodePageFromCache(CPInfo.uiFamilyCodePage);
  412. if (0 > idx)
  413. {
  414. MIMECPINFO FamilyCPInfo;
  415. if (TRUE == FindCodePageFromRegistry(CPInfo.uiFamilyCodePage, &FamilyCPInfo))
  416. {
  417. idx = _cCodePage;
  418. _pCodePage[_cCodePage] = FamilyCPInfo;
  419. _cCodePage++;
  420. }
  421. }
  422. MLStrCpyNW(CPInfo.wszFixedWidthFont, _pCodePage[idx].wszFixedWidthFont, MAX_MIMEFACE_NAME);
  423. MLStrCpyNW(CPInfo.wszProportionalFont, _pCodePage[idx].wszProportionalFont, MAX_MIMEFACE_NAME);
  424. }
  425. _pCodePage[_cCodePage] = CPInfo;
  426. _cCodePage++;
  427. QSortCodePageInfo(0, _cCodePage-1);
  428. idx = FindCodePageFromCache(uiCodePage);
  429. }
  430. }
  431. if (0 <= idx)
  432. {
  433. *pcpInfo = _pCodePage[idx];
  434. hr = S_OK;
  435. }
  436. LeaveCriticalSection(&_cs);
  437. }
  438. }
  439. return hr;
  440. }
  441. int CMimeDatabaseReg::FindCodePageFromCache(UINT uiCodePage)
  442. {
  443. UINT i;
  444. int iRet = -1;
  445. for (i = 0; i < _cCodePage; i++)
  446. {
  447. if (_pCodePage[i].uiCodePage == uiCodePage)
  448. {
  449. iRet = i;
  450. break;
  451. }
  452. }
  453. return iRet;
  454. }
  455. BOOL CMimeDatabaseReg::FindCodePageFromRegistry(UINT uiCodePage, PMIMECPINFO pcpInfo)
  456. {
  457. HKEY hKey;
  458. DWORD dw, cb;
  459. TCHAR szKey[256], sz[MAX_MIMECP_NAME];
  460. BOOL fRet = FALSE;
  461. wsprintf(szKey, TEXT("%s\\%d"), REGSTR_KEY_MIME_DATABASE_CODEPAGE, uiCodePage);
  462. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hKey))
  463. {
  464. TCHAR *psz, *pszComma;
  465. CHARSETINFO rCharsetInfo;
  466. pcpInfo->uiCodePage = uiCodePage;
  467. cb = sizeof(dw);
  468. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_FAMILY, 0, NULL, (LPBYTE)&dw, &cb))
  469. pcpInfo->uiFamilyCodePage = (UINT)dw;
  470. else
  471. pcpInfo->uiFamilyCodePage = pcpInfo->uiCodePage;
  472. cb = sizeof(dw);
  473. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_LEVEL, 0, NULL, (LPBYTE)&dw, &cb))
  474. #ifdef UNIX
  475. {
  476. BYTE* px = (BYTE*)&dw;
  477. pcpInfo->dwFlags = CONVERTLONG(px[0], px[1], px[2], px[3]);
  478. }
  479. #else
  480. pcpInfo->dwFlags = dw;
  481. #endif /* UNIX */
  482. else
  483. pcpInfo->dwFlags = 0;
  484. cb = sizeof(sz);
  485. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_DESCRIPTION, NULL, NULL, (LPBYTE)sz, &cb))
  486. MultiByteToWideChar(CP_ACP, 0, sz, -1, pcpInfo->wszDescription, ARRAYSIZE(pcpInfo->wszDescription));
  487. else
  488. {
  489. TCHAR szDef[MAX_MIMECP_NAME];
  490. LoadString(g_hInst, IDS_MIME_LANG_DEFAULT, szDef, ARRAYSIZE(szDef));
  491. wsprintf(sz, szDef, pcpInfo->uiCodePage);
  492. MultiByteToWideChar(CP_ACP, 0, sz, -1, pcpInfo->wszDescription, ARRAYSIZE(pcpInfo->wszDescription));
  493. }
  494. cb = sizeof(sz);
  495. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_FIXEDWIDTHFONT, NULL, NULL, (LPBYTE)sz, &cb))
  496. {
  497. psz = sz;
  498. pszComma = MLStrChr(sz, TEXT(','));
  499. if (NULL != pszComma) // If there are multiple font name
  500. {
  501. if (uiCodePage != g_uACP)
  502. psz = pszComma + 1; // Take right side(English) fontname for non-native codepage info
  503. else
  504. *pszComma = TEXT('\0'); // Take left side(DBCS) fontname for native codepage info
  505. }
  506. if (lstrlen(psz) >= MAX_MIMEFACE_NAME)
  507. psz[MAX_MIMEFACE_NAME-1] = TEXT('\0');
  508. MultiByteToWideChar(CP_ACP, 0, psz, -1, pcpInfo->wszFixedWidthFont, ARRAYSIZE(pcpInfo->wszFixedWidthFont));
  509. }
  510. else
  511. pcpInfo->wszFixedWidthFont[0] = L'\0';
  512. cb = sizeof(sz);
  513. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_PROPORTIONALFONT, NULL, NULL, (LPBYTE)sz, &cb))
  514. {
  515. psz = sz;
  516. pszComma = MLStrChr(sz, TEXT(','));
  517. if (NULL != pszComma) // If there are multiple font name
  518. {
  519. if (uiCodePage != g_uACP)
  520. psz = pszComma + 1; // Take right side(English) fontname for non-native codepage info
  521. else
  522. *pszComma = TEXT('\0'); // Take left side(DBCS) fontname for native codepage info
  523. }
  524. if (lstrlen(psz) >= MAX_MIMEFACE_NAME)
  525. psz[MAX_MIMEFACE_NAME-1] = TEXT('\0');
  526. MultiByteToWideChar(CP_ACP, 0, psz, -1, pcpInfo->wszProportionalFont, ARRAYSIZE(pcpInfo->wszProportionalFont));
  527. }
  528. else
  529. pcpInfo->wszProportionalFont[0] = L'\0';
  530. cb = sizeof(sz);
  531. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_BODYCHARSET, NULL, NULL, (LPBYTE)sz, &cb))
  532. MultiByteToWideChar(CP_ACP, 0, sz, -1, pcpInfo->wszBodyCharset, ARRAYSIZE(pcpInfo->wszBodyCharset));
  533. else
  534. pcpInfo->wszBodyCharset[0] = L'\0';
  535. cb = sizeof(sz);
  536. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_HEADERCHARSET, NULL, NULL, (LPBYTE)sz, &cb))
  537. MultiByteToWideChar(CP_ACP, 0, sz, -1, pcpInfo->wszHeaderCharset, ARRAYSIZE(pcpInfo->wszHeaderCharset));
  538. else
  539. MLStrCpyNW(pcpInfo->wszHeaderCharset, pcpInfo->wszBodyCharset, MAX_MIMECSET_NAME);
  540. cb = sizeof(sz);
  541. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_WEBCHARSET, NULL, NULL, (LPBYTE)sz, &cb))
  542. MultiByteToWideChar(CP_ACP, 0, sz, -1, pcpInfo->wszWebCharset, ARRAYSIZE(pcpInfo->wszWebCharset));
  543. else
  544. MLStrCpyNW(pcpInfo->wszWebCharset, pcpInfo->wszBodyCharset, MAX_MIMECSET_NAME);
  545. cb = sizeof(sz);
  546. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_PRIVCONVERTER, NULL, NULL, (LPBYTE)sz, &cb))
  547. pcpInfo->dwFlags |= MIMECONTF_PRIVCONVERTER;
  548. if (0 != TranslateCharsetInfo(IntToPtr_(LPDWORD, pcpInfo->uiFamilyCodePage), &rCharsetInfo, TCI_SRCCODEPAGE))
  549. pcpInfo->bGDICharset = (BYTE)rCharsetInfo.ciCharset;
  550. else
  551. pcpInfo->bGDICharset = DEFAULT_CHARSET;
  552. if (1200 == pcpInfo->uiFamilyCodePage || 50000 == pcpInfo->uiFamilyCodePage || TRUE == _IsValidCodePage(pcpInfo->uiFamilyCodePage)) // 50000 means user defined
  553. {
  554. if (TRUE == CheckFont(pcpInfo->bGDICharset))
  555. {
  556. if (pcpInfo->uiCodePage == pcpInfo->uiFamilyCodePage || TRUE == _IsValidCodePage(pcpInfo->uiCodePage))
  557. pcpInfo->dwFlags |= MIMECONTF_VALID|MIMECONTF_VALID;
  558. else if (S_OK == IsConvertINetStringAvailable(pcpInfo->uiCodePage, pcpInfo->uiFamilyCodePage))
  559. pcpInfo->dwFlags |= MIMECONTF_VALID|MIMECONTF_VALID;
  560. }
  561. else
  562. {
  563. if (pcpInfo->uiCodePage == pcpInfo->uiFamilyCodePage || TRUE == _IsValidCodePage(pcpInfo->uiCodePage))
  564. pcpInfo->dwFlags |= MIMECONTF_VALID_NLS;
  565. else if (S_OK == IsConvertINetStringAvailable(pcpInfo->uiCodePage, pcpInfo->uiFamilyCodePage))
  566. pcpInfo->dwFlags |= MIMECONTF_VALID_NLS;
  567. }
  568. }
  569. RegCloseKey(hKey);
  570. fRet = TRUE;
  571. }
  572. return fRet;
  573. }
  574. STDAPI CMimeDatabaseReg::GetCodePageInfoWithIndex(UINT uidx, PMIMECPINFO pcpInfo)
  575. {
  576. HRESULT hr = NOERROR;
  577. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::GetCodePageInfoWithIndex called."));
  578. EnterCriticalSection(&_cs);
  579. if (NULL == _pCodePage)
  580. BuildCodePageMimeDatabase();
  581. if (uidx < _cCodePage && _pCodePage)
  582. *pcpInfo = _pCodePage[uidx];
  583. else
  584. hr = E_FAIL;
  585. LeaveCriticalSection(&_cs);
  586. return hr;
  587. }
  588. STDAPI CMimeDatabaseReg::GetCharsetInfo(BSTR Charset, PMIMECSETINFO pcsetInfo)
  589. {
  590. int idx;
  591. HRESULT hr = E_FAIL;
  592. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::GetCharsetInfo called."));
  593. if (NULL != pcsetInfo)
  594. {
  595. EnterCriticalSection(&_cs);
  596. if (NULL == _pCharset)
  597. BuildCharsetMimeDatabase();
  598. if (_pCharset)
  599. {
  600. idx = FindCharsetFromCache(Charset);
  601. if (0 > idx)
  602. idx = FindCharsetFromRegistry(Charset, FALSE);
  603. if (0 <= idx)
  604. {
  605. *pcsetInfo = _pCharset[idx];
  606. hr = S_OK;
  607. }
  608. }
  609. LeaveCriticalSection(&_cs);
  610. }
  611. return hr;
  612. }
  613. int CMimeDatabaseReg::FindCharsetFromCache(BSTR Charset)
  614. {
  615. int iStart, iEnd, iMiddle, iCmpResult, iRet = -1;
  616. iStart = 0;
  617. iEnd = _cCharset - 1;
  618. while (iStart <= iEnd)
  619. {
  620. iMiddle = (iStart + iEnd) / 2;
  621. iCmpResult = MLStrCmpIW(Charset, _pCharset[iMiddle].wszCharset);
  622. if (iCmpResult < 0)
  623. iEnd = iMiddle - 1;
  624. else if (iCmpResult > 0)
  625. iStart = iMiddle + 1;
  626. else
  627. {
  628. iRet = iMiddle;
  629. break;
  630. }
  631. }
  632. return iRet;
  633. }
  634. int CMimeDatabaseReg::FindCharsetFromRegistry(BSTR Charset, BOOL fFromAlias)
  635. {
  636. HKEY hKey;
  637. TCHAR szKey[256], szCharset[MAX_MIMECSET_NAME];
  638. int iRet = -1;
  639. WideCharToMultiByte(CP_ACP, 0, Charset, -1, szCharset, ARRAYSIZE(szCharset), NULL, NULL);
  640. lstrcpy(szKey, REGSTR_KEY_MIME_DATABASE_CHARSET);
  641. lstrcat(szKey, TEXT("\\"));
  642. lstrcat(szKey, szCharset);
  643. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hKey))
  644. {
  645. DWORD cb, dw;
  646. TCHAR sz[MAX_MIMECSET_NAME];
  647. WCHAR wsz[MAX_MIMECSET_NAME];
  648. cb = sizeof(sz);
  649. if (FALSE == fFromAlias && ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_ALIASTO, NULL, NULL, (LPBYTE)sz, &cb))
  650. {
  651. MultiByteToWideChar(CP_ACP, 0, sz, -1, wsz, ARRAYSIZE(wsz));
  652. iRet = FindCharsetFromCache(wsz);
  653. if (0 > iRet)
  654. iRet = FindCharsetFromRegistry(wsz, TRUE);
  655. if (0 <= iRet)
  656. {
  657. MLStrCpyNW(_pCharset[_cCharset].wszCharset, Charset, MAX_MIMECSET_NAME);
  658. _pCharset[_cCharset].uiCodePage = _pCharset[iRet].uiCodePage;
  659. _pCharset[_cCharset].uiInternetEncoding = _pCharset[iRet].uiInternetEncoding;
  660. _cCharset++;
  661. QSortCharsetInfo(0, _cCharset-1);
  662. iRet = FindCharsetFromCache(Charset);
  663. }
  664. }
  665. else
  666. {
  667. MLStrCpyNW(_pCharset[_cCharset].wszCharset, Charset, MAX_MIMECSET_NAME);
  668. cb = sizeof(dw);
  669. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_CODEPAGE, 0, NULL, (LPBYTE)&dw, &cb))
  670. {
  671. _pCharset[_cCharset].uiCodePage = (UINT)dw;
  672. cb = sizeof(dw);
  673. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_INETENCODING, 0, NULL, (LPBYTE)&dw, &cb))
  674. {
  675. _pCharset[_cCharset].uiInternetEncoding = (UINT)dw;
  676. _cCharset++;
  677. QSortCharsetInfo(0, _cCharset-1);
  678. iRet = FindCharsetFromCache(Charset);
  679. }
  680. }
  681. }
  682. RegCloseKey(hKey);
  683. }
  684. return iRet;
  685. }
  686. BOOL CMimeDatabaseReg::CheckFont(BYTE bGDICharset)
  687. {
  688. BOOL fRet = FALSE;
  689. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::CheckFont called."));
  690. if (DEFAULT_CHARSET == bGDICharset)
  691. fRet = TRUE;
  692. else
  693. {
  694. HDC hDC;
  695. LOGFONT lf;
  696. HWND hWnd;
  697. hWnd = GetTopWindow(GetDesktopWindow());
  698. hDC = GetDC(hWnd);
  699. if (NULL != hDC)
  700. {
  701. lf.lfFaceName[0] = TEXT('\0');
  702. lf.lfPitchAndFamily = 0;
  703. lf.lfCharSet = bGDICharset;
  704. EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)EnumFontFamExProc, (LPARAM)&fRet, 0);
  705. }
  706. ReleaseDC(hWnd, hDC);
  707. }
  708. return fRet;
  709. }
  710. void CMimeDatabaseReg::QSortCodePageInfo(LONG left, LONG right)
  711. {
  712. register LONG i, j;
  713. WCHAR k[MAX_MIMECP_NAME];
  714. MIMECPINFO t;
  715. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::QSortCodePageInfo called."));
  716. i = left;
  717. j = right;
  718. MLStrCpyW(k, _pCodePage[(left + right) / 2].wszDescription);
  719. do
  720. {
  721. while(MLStrCmpIW(_pCodePage[i].wszDescription, k) < 0 && i < right)
  722. i++;
  723. while (MLStrCmpIW(_pCodePage[j].wszDescription, k) > 0 && j > left)
  724. j--;
  725. if (i <= j)
  726. {
  727. t = _pCodePage[i];
  728. _pCodePage[i] = _pCodePage[j];
  729. _pCodePage[j] = t;
  730. i++; j--;
  731. }
  732. } while (i <= j);
  733. if (left < j)
  734. QSortCodePageInfo(left, j);
  735. if (i < right)
  736. QSortCodePageInfo(i, right);
  737. }
  738. void CMimeDatabaseReg::QSortCharsetInfo(LONG left, LONG right)
  739. {
  740. register LONG i, j;
  741. WCHAR k[MAX_MIMECSET_NAME];
  742. MIMECSETINFO t;
  743. DebugMsg(DM_TRACE, TEXT("CMimeDatabase::QSortCharsetInfo called."));
  744. i = left;
  745. j = right;
  746. MLStrCpyW(k, _pCharset[(left + right) / 2].wszCharset);
  747. do
  748. {
  749. while(MLStrCmpIW(_pCharset[i].wszCharset, k) < 0 && i < right)
  750. i++;
  751. while (MLStrCmpIW(_pCharset[j].wszCharset, k) > 0 && j > left)
  752. j--;
  753. if (i <= j)
  754. {
  755. t = _pCharset[i];
  756. _pCharset[i] = _pCharset[j];
  757. _pCharset[j] = t;
  758. i++; j--;
  759. }
  760. } while (i <= j);
  761. if (left < j)
  762. QSortCharsetInfo(left, j);
  763. if (i < right)
  764. QSortCharsetInfo(i, right);
  765. }
  766. // validates all cps that are in the same
  767. // family of the given codepage
  768. STDAPI CMimeDatabaseReg::ValidateCP(UINT uiCodePage)
  769. {
  770. UINT i;
  771. if (NULL == _pCodePage)
  772. BuildCodePageMimeDatabase();
  773. //
  774. // just look into already cached codepages
  775. //
  776. for (i = 0; i < _cCodePage; i++)
  777. {
  778. if (_pCodePage[i].uiFamilyCodePage == uiCodePage)
  779. _pCodePage[i].dwFlags |= MIMECONTF_VALID|MIMECONTF_VALID_NLS;
  780. }
  781. return S_OK; // never fail?
  782. }