Leaked source code of windows server 2003
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.

908 lines
30 KiB

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