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.

1027 lines
35 KiB

  1. #include "private.h"
  2. #include "mlmain.h"
  3. #include "cpdetect.h"
  4. #include "codepage.h"
  5. STDAPI CMultiLanguage::GetNumberOfCodePageInfo(UINT *pcCodePage)
  6. {
  7. if (NULL != m_pMimeDatabase)
  8. return m_pMimeDatabase->GetNumberOfCodePageInfo(pcCodePage);
  9. else
  10. return E_FAIL;
  11. }
  12. STDAPI CMultiLanguage::GetCodePageInfo(UINT uiCodePage, PMIMECPINFO pcpInfo)
  13. {
  14. if (NULL != m_pMimeDatabase)
  15. return m_pMimeDatabase->GetCodePageInfo(uiCodePage, GetSystemDefaultLangID(), pcpInfo);
  16. else
  17. return E_FAIL;
  18. }
  19. STDAPI CMultiLanguage::GetFamilyCodePage(UINT uiCodePage, UINT *puiFamilyCodePage)
  20. {
  21. HRESULT hr = S_OK;
  22. int idx = 0;
  23. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetFamilyCodePage called."));
  24. while(MimeCodePage[idx].uiCodePage)
  25. {
  26. if ((uiCodePage == MimeCodePage[idx].uiCodePage) &&
  27. (MimeCodePage[idx].dwFlags & dwMimeSource))
  28. break;
  29. idx++;
  30. }
  31. if (MimeCodePage[idx].uiCodePage)
  32. {
  33. if (MimeCodePage[idx].uiFamilyCodePage)
  34. *puiFamilyCodePage = MimeCodePage[idx].uiFamilyCodePage;
  35. else
  36. *puiFamilyCodePage = uiCodePage;
  37. }
  38. else
  39. {
  40. hr = E_FAIL;
  41. *puiFamilyCodePage = 0;
  42. }
  43. return hr;
  44. }
  45. STDAPI CMultiLanguage::EnumCodePages(DWORD grfFlags, IEnumCodePage **ppEnumCodePage)
  46. {
  47. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::EnumCodePages called."));
  48. *ppEnumCodePage = NULL;
  49. // Return IE4 MIME DB data in IMultiLanguage
  50. CEnumCodePage *pCEnumCodePage = new CEnumCodePage(grfFlags, GetSystemDefaultLangID(), MIMECONTF_MIME_IE4);
  51. if (NULL != pCEnumCodePage)
  52. {
  53. HRESULT hr = pCEnumCodePage->QueryInterface(IID_IEnumCodePage, (void**)ppEnumCodePage);
  54. pCEnumCodePage->Release();
  55. return hr;
  56. }
  57. return E_OUTOFMEMORY;
  58. }
  59. STDAPI CMultiLanguage2::EnumCodePages(DWORD grfFlags, LANGID LangId, IEnumCodePage **ppEnumCodePage)
  60. {
  61. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::EnumCodePages called."));
  62. *ppEnumCodePage = NULL;
  63. CEnumCodePage *pCEnumCodePage = new CEnumCodePage(grfFlags, LangId, dwMimeSource);
  64. if (NULL != pCEnumCodePage)
  65. {
  66. HRESULT hr = pCEnumCodePage->QueryInterface(IID_IEnumCodePage, (void**)ppEnumCodePage);
  67. pCEnumCodePage->Release();
  68. return hr;
  69. }
  70. return E_OUTOFMEMORY;
  71. }
  72. STDAPI CMultiLanguage2::EnumScripts(DWORD dwFlags, LANGID LangId, IEnumScript **ppEnumScript)
  73. {
  74. DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::EnumScripts called."));
  75. *ppEnumScript = NULL;
  76. CEnumScript *pCEnumScript = new CEnumScript(dwFlags, LangId, dwMimeSource);
  77. if (NULL != pCEnumScript)
  78. {
  79. HRESULT hr = pCEnumScript->QueryInterface(IID_IEnumScript, (void**)ppEnumScript);
  80. pCEnumScript->Release();
  81. return hr;
  82. }
  83. return E_OUTOFMEMORY;
  84. }
  85. STDAPI CMultiLanguage::GetCharsetInfo(BSTR Charset, PMIMECSETINFO pcsetInfo)
  86. {
  87. if (NULL != m_pMimeDatabase)
  88. return m_pMimeDatabase->GetCharsetInfo(Charset, pcsetInfo);
  89. else
  90. return E_FAIL;
  91. }
  92. STDAPI CMultiLanguage::IsConvertible(DWORD dwSrcEncoding, DWORD dwDstEncoding)
  93. {
  94. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::IsConvertINetStringAvailable called."));
  95. return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
  96. }
  97. STDAPI CMultiLanguage::ConvertString(LPDWORD lpdwMode, DWORD dwSrcEncoding, DWORD dwDstEncoding, BYTE *pSrcStr, UINT *pcSrcSize, BYTE *pDstStr, UINT *pcDstSize)
  98. {
  99. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::ConvertStringEx called."));
  100. return ConvertINetString(lpdwMode, dwSrcEncoding, dwDstEncoding, (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
  101. }
  102. STDAPI CMultiLanguage::ConvertStringToUnicode(LPDWORD lpdwMode, DWORD dwEncoding, CHAR *pSrcStr, UINT *pcSrcSize, WCHAR *pDstStr, UINT *pcDstSize)
  103. {
  104. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::ConvertStringToUnicode called."));
  105. return ConvertINetMultiByteToUnicode(lpdwMode, dwEncoding, (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPWSTR)pDstStr, (LPINT)pcDstSize);
  106. }
  107. STDAPI CMultiLanguage::ConvertStringFromUnicode(LPDWORD lpdwMode, DWORD dwEncoding, WCHAR *pSrcStr, UINT *pcSrcSize, CHAR *pDstStr, UINT *pcDstSize)
  108. {
  109. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::ConvertStringFromUnicode called."));
  110. return ConvertINetUnicodeToMultiByte(lpdwMode, dwEncoding, (LPCWSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
  111. }
  112. STDAPI CMultiLanguage::ConvertStringReset(void)
  113. {
  114. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::Reset called."));
  115. return ConvertINetReset();
  116. }
  117. STDAPI CMultiLanguage::GetRfc1766FromLcid(LCID Locale, BSTR *pbstrRfc1766)
  118. {
  119. HRESULT hr = E_INVALIDARG;
  120. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetRfc1766FromLcid called."));
  121. if (NULL != pbstrRfc1766)
  122. {
  123. WCHAR wsz[MAX_RFC1766_NAME];
  124. hr = LcidToRfc1766W(Locale, wsz, ARRAYSIZE(wsz));
  125. if (SUCCEEDED(hr))
  126. *pbstrRfc1766 = SysAllocString(wsz);
  127. else
  128. *pbstrRfc1766 = NULL;
  129. }
  130. return hr;
  131. }
  132. STDAPI CMultiLanguage::GetLcidFromRfc1766(PLCID pLocale, BSTR bstrRfc1766)
  133. {
  134. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetLcidFromRfc1766 called."));
  135. return Rfc1766ToLcidW(pLocale, bstrRfc1766);
  136. }
  137. STDAPI CMultiLanguage::EnumRfc1766(IEnumRfc1766 **ppEnumRfc1766)
  138. {
  139. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::EnumRfc1766 called."));
  140. *ppEnumRfc1766 = NULL;
  141. CEnumRfc1766 *pCEnumRfc1766 = new CEnumRfc1766(dwMimeSource,GetSystemDefaultLangID());
  142. if (NULL != pCEnumRfc1766)
  143. {
  144. HRESULT hr = pCEnumRfc1766->QueryInterface(IID_IEnumRfc1766, (void**)ppEnumRfc1766);
  145. pCEnumRfc1766->Release();
  146. return hr;
  147. }
  148. return E_OUTOFMEMORY;
  149. }
  150. STDAPI CMultiLanguage2::EnumRfc1766(LANGID LangId, IEnumRfc1766 **ppEnumRfc1766)
  151. {
  152. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::EnumRfc1766 called."));
  153. *ppEnumRfc1766 = NULL;
  154. CEnumRfc1766 *pCEnumRfc1766 = new CEnumRfc1766(dwMimeSource, LangId);
  155. if (NULL != pCEnumRfc1766)
  156. {
  157. HRESULT hr = pCEnumRfc1766->QueryInterface(IID_IEnumRfc1766, (void**)ppEnumRfc1766);
  158. pCEnumRfc1766->Release();
  159. return hr;
  160. }
  161. return E_OUTOFMEMORY;
  162. }
  163. STDAPI CMultiLanguage::GetRfc1766Info(LCID Locale, PRFC1766INFO pRfc1766Info)
  164. {
  165. UINT i;
  166. HRESULT hr = E_INVALIDARG;
  167. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetRfc1766Info called."));
  168. if (NULL != pRfc1766Info)
  169. {
  170. for (i = 0; i < g_cRfc1766; i++)
  171. {
  172. if (MimeRfc1766[i].LcId == Locale)
  173. break;
  174. }
  175. if (i < g_cRfc1766)
  176. {
  177. pRfc1766Info->lcid = MimeRfc1766[i].LcId;
  178. MLStrCpyNW(pRfc1766Info->wszRfc1766, MimeRfc1766[i].szRfc1766, MAX_RFC1766_NAME);
  179. _LoadStringExW(g_hInst, MimeRfc1766[i].uidLCID, pRfc1766Info->wszLocaleName,
  180. MAX_LOCALE_NAME, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
  181. hr = S_OK;
  182. }
  183. else
  184. hr = E_FAIL;
  185. }
  186. return hr;
  187. }
  188. STDAPI CMultiLanguage2::GetRfc1766Info(LCID Locale, LANGID LangId, PRFC1766INFO pRfc1766Info)
  189. {
  190. UINT i;
  191. HRESULT hr = E_INVALIDARG;
  192. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetRfc1766Info called."));
  193. if (NULL != pRfc1766Info)
  194. {
  195. for (i = 0; i < g_cRfc1766; i++)
  196. {
  197. if (MimeRfc1766[i].LcId == Locale)
  198. break;
  199. }
  200. if (i < g_cRfc1766)
  201. {
  202. if (!LangId)
  203. LangId = GetSystemDefaultLangID();
  204. pRfc1766Info->lcid = MimeRfc1766[i].LcId;
  205. MLStrCpyNW(pRfc1766Info->wszRfc1766, MimeRfc1766[i].szRfc1766, MAX_RFC1766_NAME);
  206. if (!_LoadStringExW(g_hInst, MimeRfc1766[i].uidLCID, pRfc1766Info->wszLocaleName,
  207. MAX_LOCALE_NAME, LangId))
  208. {
  209. _LoadStringExW(g_hInst, MimeRfc1766[i].uidLCID, pRfc1766Info->wszLocaleName,
  210. MAX_LOCALE_NAME, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
  211. }
  212. hr = S_OK;
  213. }
  214. else
  215. hr = E_FAIL;
  216. }
  217. return hr;
  218. }
  219. STDAPI CMultiLanguage::CreateConvertCharset(UINT uiSrcCodePage, UINT uiDstCodePage, DWORD dwProperty, IMLangConvertCharset **ppMLangConvertCharset)
  220. {
  221. HRESULT hr;
  222. IClassFactory* pClassObj;
  223. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::CreateCharsetConvert called."));
  224. if (SUCCEEDED(hr = _Module.GetClassObject(CLSID_CMLangConvertCharset, IID_IClassFactory, (void**)&pClassObj)))
  225. {
  226. hr = pClassObj->CreateInstance(NULL, IID_IMLangConvertCharset, (void**)ppMLangConvertCharset);
  227. pClassObj->Release();
  228. }
  229. if (ppMLangConvertCharset && FAILED(hr))
  230. *ppMLangConvertCharset = NULL;
  231. if (NULL != *ppMLangConvertCharset)
  232. hr = (*ppMLangConvertCharset)->Initialize(uiSrcCodePage, uiDstCodePage, dwProperty);
  233. return hr;
  234. }
  235. STDAPI CMultiLanguage2::ConvertStringInIStream(LPDWORD lpdwMode, DWORD dwFlag, WCHAR *lpFallBack, DWORD dwSrcEncoding, DWORD dwDstEncoding, IStream *pstmIn, IStream *pstmOut)
  236. {
  237. DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::ConvertStringInIStream called."));
  238. return ConvertINetStringInIStream(lpdwMode,dwSrcEncoding,dwDstEncoding,pstmIn,pstmOut,dwFlag,lpFallBack);
  239. }
  240. STDAPI CMultiLanguage2::ConvertStringToUnicodeEx(LPDWORD lpdwMode, DWORD dwEncoding, CHAR *pSrcStr, UINT *pcSrcSize, WCHAR *pDstStr, UINT *pcDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  241. {
  242. DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::ConvertBufferStringToUnicodeEx called."));
  243. return ConvertINetMultiByteToUnicodeEx(lpdwMode, dwEncoding, (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPWSTR)pDstStr, (LPINT)pcDstSize, dwFlag, lpFallBack);
  244. }
  245. STDAPI CMultiLanguage2::ConvertStringFromUnicodeEx(LPDWORD lpdwMode, DWORD dwEncoding, WCHAR *pSrcStr, UINT *pcSrcSize, CHAR *pDstStr, UINT *pcDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  246. {
  247. DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::ConvertBufferStringFromUnicodeEx called."));
  248. return ConvertINetUnicodeToMultiByteEx(lpdwMode, dwEncoding, (LPCWSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize, dwFlag, lpFallBack);
  249. }
  250. STDAPI CMultiLanguage2::DetectCodepageInIStream(DWORD dwFlag, DWORD uiPrefWinCodepage, IStream *pstmIn, DetectEncodingInfo *lpEncoding, INT *pnScores)
  251. {
  252. DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::DetectCodepageInIStream called. "));
  253. return _DetectCodepageInIStream(dwFlag, uiPrefWinCodepage, pstmIn, lpEncoding, pnScores);
  254. }
  255. STDAPI CMultiLanguage2::DetectInputCodepage(DWORD dwFlag, DWORD uiPrefWinCodepage, CHAR *pSrcStr, INT *pcSrcSize, DetectEncodingInfo *lpEncoding, INT *pnScores)
  256. {
  257. DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::DetectInputCodepage called. "));
  258. return _DetectInputCodepage(dwFlag, uiPrefWinCodepage, pSrcStr, pcSrcSize, lpEncoding, pnScores);
  259. }
  260. STDAPI CMultiLanguage2::ValidateCodePage(UINT uiCodePage, HWND hwnd)
  261. {
  262. return ValidateCodePageEx(uiCodePage, hwnd, 0);
  263. }
  264. // this is private function to serve both for IML2 and IML3
  265. STDAPI CMultiLanguage2::ValidateCodePageEx(UINT uiCodePage, HWND hwnd, DWORD dwfIODControl)
  266. {
  267. MIMECPINFO cpInfo;
  268. CLSID clsid;
  269. UINT uiFamCp;
  270. HRESULT hr;
  271. DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::ValidateCodePage called. "));
  272. if (NULL != g_pMimeDatabase)
  273. hr = g_pMimeDatabase->GetCodePageInfo(uiCodePage, 0x409, &cpInfo);
  274. else
  275. hr = E_OUTOFMEMORY;
  276. if (FAILED(hr))
  277. return E_INVALIDARG;
  278. EnterCriticalSection(&g_cs);
  279. if (NULL == g_pCpMRU)
  280. if (g_pCpMRU = new CCpMRU)
  281. g_pCpMRU->Init();
  282. LeaveCriticalSection(&g_cs);
  283. if (g_pCpMRU && g_pCpMRU->dwCpMRUEnable)
  284. g_pCpMRU->UpdateCPMRU(uiCodePage);
  285. if (cpInfo.dwFlags & MIMECONTF_VALID)
  286. return S_OK;
  287. // always handle family codepage because a caller
  288. // of this function is not generally aware if
  289. // the codepage is primary one. i.e., they can
  290. // call with cp=20268 to validate the entire 1251
  291. // family.
  292. //
  293. uiFamCp = cpInfo.uiFamilyCodePage;
  294. // Bug 394904, IOD won't be able to get us gb18030 support,
  295. // so we won't ask UrlMon for CHS langpack if gb2312 is valid
  296. if (uiCodePage == CP_18030)
  297. {
  298. g_pMimeDatabase->GetCodePageInfo(uiFamCp, 0x409, &cpInfo);
  299. if (cpInfo.dwFlags & MIMECONTF_VALID)
  300. return S_FALSE;
  301. }
  302. // Ignore IOD check on NT5
  303. if (g_bIsNT5)
  304. {
  305. // Currently, NT5 doesn't install 20127 and 28605 NLS files.
  306. // We should prevent langpack installation loop and let clients resolve
  307. // them with CP_ACP in case of 20127 and 28605 validation.
  308. // This hack can be removed once NT5 bundles these NLS files by default.
  309. if ((uiCodePage == CP_20127 || uiCodePage == CP_ISO_8859_15) && IsValidCodePage(uiFamCp))
  310. return E_FAIL;
  311. hr = IsNTLangpackAvailable(uiFamCp);
  312. if (hr != S_OK)
  313. return hr;
  314. }
  315. else
  316. {
  317. // check if JIT langpack is enabled.
  318. //
  319. hr = EnsureIEStatus();
  320. if (hr == S_OK)
  321. {
  322. if (!m_pIEStat || m_pIEStat->IsJITEnabled() != TRUE)
  323. {
  324. // the codepage is neither valid or installable
  325. return S_FALSE;
  326. }
  327. }
  328. }
  329. if (hwnd == NULL)
  330. {
  331. hwnd = GetForegroundWindow();
  332. }
  333. // Special handling for NT.
  334. if (g_bIsNT5)
  335. {
  336. DWORD dwInstallLpk = 1;
  337. HKEY hkey;
  338. DWORD dwAction = 0;
  339. // HKCR\\Software\\Microsoft\internet explorer\\international
  340. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER,
  341. REGSTR_PATH_INTERNATIONAL,
  342. NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwAction))
  343. {
  344. DWORD dwType = REG_DWORD;
  345. DWORD dwSize = sizeof(DWORD);
  346. if (ERROR_SUCCESS != RegQueryValueEx(hkey, REG_KEY_NT5LPK, 0, &dwType, (LPBYTE)&dwInstallLpk, &dwSize))
  347. {
  348. dwInstallLpk = 1;
  349. RegSetValueEx(hkey, REG_KEY_NT5LPK, 0, REG_DWORD, (LPBYTE)&dwInstallLpk, sizeof(dwInstallLpk));
  350. }
  351. RegCloseKey(hkey);
  352. }
  353. hr = S_FALSE;
  354. // Pops up NT5 langpack dialog box if langpack is enabled or user selects it from encoding menu
  355. if (dwInstallLpk || (dwfIODControl & CPIOD_FORCE_PROMPT))
  356. {
  357. LPCDLGTEMPLATE pTemplate;
  358. HRSRC hrsrc;
  359. INT_PTR iRet;
  360. LANGID LangId = GetNT5UILanguage();
  361. dwInstallLpk |= uiFamCp << 16;
  362. // Load correct resource to match NT5 UI language
  363. hrsrc = FindResourceExW(g_hInst, (LPCWSTR) RT_DIALOG, (LPCWSTR) MAKEINTRESOURCE(IDD_DIALOG_LPK), LangId);
  364. ULONG_PTR uCookie = 0;
  365. SHActivateContext(&uCookie);
  366. // Pack LPARAM, code page value in HIWORD, installation flag in LOWORD
  367. if (hrsrc &&
  368. (pTemplate = (LPCDLGTEMPLATE)LoadResource(g_hInst, hrsrc)))
  369. {
  370. iRet = DialogBoxIndirectParamW(g_hInst, pTemplate,
  371. hwnd, LangpackDlgProc, (LPARAM) dwInstallLpk);
  372. }
  373. else
  374. iRet = DialogBoxParamW(g_hInst, (LPCWSTR) MAKEINTRESOURCE(IDD_DIALOG_LPK), hwnd, LangpackDlgProc, (LPARAM) dwInstallLpk);
  375. if (iRet)
  376. {
  377. hr = _InstallNT5Langpack(hwnd, uiFamCp);
  378. if (S_OK == hr)
  379. {
  380. WCHAR wszLangInstall[MAX_PATH];
  381. WCHAR wszNT5LangPack[1024];
  382. // Fall back to English (US) if we don't have a specific language resource
  383. if (!_LoadStringExW(g_hInst, IDS_LANGPACK_INSTALL, wszLangInstall, ARRAYSIZE(wszLangInstall), LangId) ||
  384. !_LoadStringExW(g_hInst, IDS_NT5_LANGPACK, wszNT5LangPack, ARRAYSIZE(wszNT5LangPack), LangId))
  385. {
  386. LangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
  387. _LoadStringExW(g_hInst, IDS_LANGPACK_INSTALL, wszLangInstall, ARRAYSIZE(wszLangInstall), LangId);
  388. _LoadStringExW(g_hInst, IDS_NT5_LANGPACK, wszNT5LangPack, ARRAYSIZE(wszNT5LangPack), LangId);
  389. }
  390. MessageBoxW(hwnd, wszNT5LangPack, wszLangInstall, MB_OK);
  391. }
  392. }
  393. if (uCookie)
  394. {
  395. SHDeactivateContext(uCookie);
  396. }
  397. }
  398. goto SKIP_IELANGPACK;
  399. }
  400. // Initiate JIT using CLSID give to the langpack
  401. hr = _GetJITClsIDForCodePage(uiFamCp, &clsid);
  402. if (SUCCEEDED(hr))
  403. {
  404. hr = InstallIEFeature(hwnd, &clsid, dwfIODControl);
  405. }
  406. // if JIT returns S_OK, we now have everything installed
  407. // then we'll validate the codepage and add font
  408. // NOTE: there can be more than codepage to validate here,
  409. // for example, PE langpack contains more than one
  410. // NLS file to get greek, cyrillic and Turkish at the
  411. // same time.
  412. if (hr == S_OK)
  413. {
  414. hr = _ValidateCPInfo(uiFamCp);
  415. if (SUCCEEDED(hr))
  416. {
  417. _AddFontForCP(uiFamCp);
  418. }
  419. }
  420. SKIP_IELANGPACK:
  421. return hr;
  422. }
  423. // IMultiLanguage2::GetCodePageDescription
  424. //
  425. // Provide native code page description in UNICODE.
  426. // If not resource is vailable for the specified LCID,
  427. // we'll try the primary language first, then English.
  428. // In this case, we'll return S_FALSE to caller.
  429. STDAPI CMultiLanguage2::GetCodePageDescription(
  430. UINT uiCodePage, // Specifies the required code page for description.
  431. LCID lcid, // Specifies locale ID for prefered language.
  432. LPWSTR lpWideCharStr, // Points to a buffer that receives the code page description.
  433. int cchWideChar) // Specifies the size, in wide characters, of the buffer
  434. // pointed by lpWideCharStr.
  435. {
  436. HRESULT hr = E_FAIL;
  437. UINT CountCPId;
  438. UINT i = 0, j = 0;
  439. g_pMimeDatabase->GetNumberOfCodePageInfo(&CountCPId);
  440. if (cchWideChar == 0)
  441. {
  442. return E_INVALIDARG;
  443. }
  444. while (i < CountCPId)
  445. {
  446. if (MimeCodePage[j].dwFlags & dwMimeSource)
  447. {
  448. if ((MimeCodePage[j].uiCodePage == uiCodePage))
  449. {
  450. if (_LoadStringExW(g_hInst, MimeCodePage[j].uidDescription, lpWideCharStr,
  451. cchWideChar, LANGIDFROMLCID(lcid)))
  452. {
  453. hr = S_OK;
  454. }
  455. else // Resource not find in the specificed language
  456. {
  457. if (_LoadStringExW(g_hInst, MimeCodePage[j].uidDescription, lpWideCharStr,
  458. cchWideChar, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)))
  459. {
  460. hr = S_FALSE;
  461. }
  462. }
  463. break;
  464. }
  465. i++;
  466. }
  467. j++;
  468. }
  469. if (i >= CountCPId) // Code page description is not available in MLANG
  470. {
  471. hr = E_INVALIDARG;
  472. }
  473. return (hr);
  474. }
  475. STDAPI CMultiLanguage2::IsCodePageInstallable(UINT uiCodePage)
  476. {
  477. MIMECPINFO cpInfo;
  478. UINT uiFamCp;
  479. HRESULT hr;
  480. DebugMsg(DM_TRACE, TEXT("CMultiLanguage::IsCPInstallable called. "));
  481. if (NULL != g_pMimeDatabase)
  482. hr = g_pMimeDatabase->GetCodePageInfo(uiCodePage, 0x409, &cpInfo);
  483. else
  484. hr = E_OUTOFMEMORY;
  485. if (FAILED(hr))
  486. return E_INVALIDARG;
  487. // if it's already valid, no need to check if it's installable
  488. if (cpInfo.dwFlags & MIMECONTF_VALID)
  489. {
  490. hr = S_OK;
  491. }
  492. else
  493. {
  494. uiFamCp = cpInfo.uiFamilyCodePage;
  495. // it is currently not valid, if NT5, ignore IOD check
  496. if (g_bIsNT5)
  497. {
  498. hr = IsNTLangpackAvailable(uiFamCp);
  499. }
  500. else
  501. {
  502. // now check to see if the cp can be IOD
  503. hr = EnsureIEStatus();
  504. // we'll return FALSE if we couldn't get IOD status
  505. if (hr == S_OK)
  506. {
  507. if (!m_pIEStat || !m_pIEStat->IsJITEnabled())
  508. hr = S_FALSE;
  509. }
  510. // then see if we have langpack for
  511. // the family codepage
  512. if (hr == S_OK)
  513. {
  514. CLSID clsid;
  515. // clsid is just used for place holder
  516. hr = _GetJITClsIDForCodePage(uiFamCp, &clsid);
  517. }
  518. }
  519. }
  520. return hr;
  521. }
  522. STDAPI CMultiLanguage2::SetMimeDBSource(MIMECONTF dwSource)
  523. {
  524. if ((dwSource != MIMECONTF_MIME_IE4) &&
  525. (dwSource != MIMECONTF_MIME_LATEST) &&
  526. (dwSource != MIMECONTF_MIME_REGISTRY))
  527. {
  528. return E_INVALIDARG;
  529. }
  530. if (dwSource & MIMECONTF_MIME_REGISTRY)
  531. {
  532. EnterCriticalSection(&g_cs);
  533. if (!g_pMimeDatabaseReg)
  534. {
  535. g_pMimeDatabaseReg = new CMimeDatabaseReg;
  536. }
  537. LeaveCriticalSection(&g_cs);
  538. }
  539. dwMimeSource = dwSource;
  540. if (NULL != m_pMimeDatabase)
  541. m_pMimeDatabase->SetMimeDBSource(dwSource);
  542. return S_OK;
  543. }
  544. CMultiLanguage2::CMultiLanguage2(void)
  545. {
  546. DllAddRef();
  547. CComCreator< CComPolyObject< CMultiLanguage > >::CreateInstance( NULL, IID_IMultiLanguage, (void **)&m_pIML );
  548. m_pMimeDatabase = new CMimeDatabase;
  549. dwMimeSource = MIMECONTF_MIME_LATEST;
  550. if (m_pMimeDatabase)
  551. m_pMimeDatabase->SetMimeDBSource(MIMECONTF_MIME_LATEST);
  552. m_pIEStat = NULL;
  553. }
  554. CMultiLanguage2::~CMultiLanguage2(void)
  555. {
  556. if (m_pIML)
  557. {
  558. m_pIML->Release();
  559. m_pIML = NULL;
  560. }
  561. if (m_pMimeDatabase)
  562. {
  563. delete m_pMimeDatabase;
  564. }
  565. if (m_pIEStat)
  566. {
  567. delete m_pIEStat;
  568. }
  569. DllRelease();
  570. }
  571. STDAPI CMultiLanguage2::GetNumberOfCodePageInfo(UINT *pcCodePage)
  572. {
  573. if (dwMimeSource & MIMECONTF_MIME_REGISTRY)
  574. {
  575. if (NULL != g_pMimeDatabaseReg)
  576. return g_pMimeDatabaseReg->GetNumberOfCodePageInfo(pcCodePage);
  577. else
  578. return E_FAIL;
  579. }
  580. else
  581. {
  582. if (NULL != m_pMimeDatabase)
  583. return m_pMimeDatabase->GetNumberOfCodePageInfo(pcCodePage);
  584. else
  585. return E_FAIL;
  586. }
  587. }
  588. STDAPI CMultiLanguage2::GetNumberOfScripts(UINT *pnScripts)
  589. {
  590. if (pnScripts)
  591. *pnScripts = g_cScript;
  592. return NOERROR;
  593. }
  594. STDAPI CMultiLanguage2::GetCodePageInfo(UINT uiCodePage, LANGID LangId, PMIMECPINFO pcpInfo)
  595. {
  596. if (dwMimeSource & MIMECONTF_MIME_REGISTRY)
  597. {
  598. if (NULL != g_pMimeDatabaseReg)
  599. return g_pMimeDatabaseReg->GetCodePageInfo(uiCodePage, pcpInfo);
  600. else
  601. return E_FAIL;
  602. }
  603. else
  604. {
  605. if (m_pMimeDatabase)
  606. return m_pMimeDatabase->GetCodePageInfo(uiCodePage, LangId, pcpInfo);
  607. else
  608. return E_FAIL;
  609. }
  610. }
  611. // Optimized for performance
  612. // Skip unecessary resource loading
  613. STDAPI CMultiLanguage2::GetFamilyCodePage(UINT uiCodePage, UINT *puiFamilyCodePage)
  614. {
  615. HRESULT hr = S_OK;
  616. int idx = 0;
  617. if (puiFamilyCodePage)
  618. *puiFamilyCodePage = 0;
  619. else
  620. return E_INVALIDARG;
  621. DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::GetFamilyCodePage called."));
  622. // Keep registry version IE4 implementation
  623. if (dwMimeSource & MIMECONTF_MIME_REGISTRY)
  624. {
  625. if (NULL != g_pMimeDatabaseReg)
  626. {
  627. MIMECPINFO cpInfo;
  628. hr = g_pMimeDatabaseReg->GetCodePageInfo(uiCodePage, &cpInfo);
  629. if (S_OK == hr)
  630. *puiFamilyCodePage = cpInfo.uiFamilyCodePage;
  631. }
  632. }
  633. else
  634. {
  635. while(MimeCodePage[idx].uiCodePage)
  636. {
  637. if ((uiCodePage == MimeCodePage[idx].uiCodePage) &&
  638. (MimeCodePage[idx].dwFlags & dwMimeSource))
  639. break;
  640. idx++;
  641. }
  642. if (MimeCodePage[idx].uiCodePage)
  643. {
  644. if (MimeCodePage[idx].uiFamilyCodePage)
  645. *puiFamilyCodePage = MimeCodePage[idx].uiFamilyCodePage;
  646. else
  647. *puiFamilyCodePage = uiCodePage;
  648. }
  649. else
  650. {
  651. hr = E_FAIL;
  652. }
  653. }
  654. return hr;
  655. }
  656. STDAPI CMultiLanguage2::GetCharsetInfo(BSTR Charset, PMIMECSETINFO pcsetInfo)
  657. {
  658. if (dwMimeSource & MIMECONTF_MIME_REGISTRY)
  659. {
  660. if (NULL != g_pMimeDatabaseReg)
  661. return g_pMimeDatabaseReg->GetCharsetInfo(Charset, pcsetInfo);
  662. else
  663. return E_FAIL;
  664. }
  665. if (NULL != m_pMimeDatabase)
  666. return m_pMimeDatabase->GetCharsetInfo(Charset, pcsetInfo);
  667. else
  668. return E_FAIL;
  669. }
  670. //
  671. // System default code page stack
  672. //
  673. // We support following code pages for outbound encoding detection
  674. // Windows : 1252, 1250, 1251, 1253, 1254, 1257, 1258, 1256, 1255, 874, 932, 949, 950, 936
  675. // Unicode : 65001, 65000, 1200
  676. // ISO : 28591, 28592, 20866, 21866, 28595, 28597, 28593, 28594, 28596, 28598, 38598, 28605, 28599
  677. // Others : 20127, 50220, 50221, 50222, 51932, 51949, 50225, 52936
  678. //
  679. // Default priorities
  680. // 20127 > Windows single byte code page> ISO > Windows DBCS code page > Others > Unicode
  681. //
  682. UINT SysPreCp[] =
  683. {20127,
  684. 1252, 1250, 1251, 1253, 1254, 1257, 1258, 1256, 1255, 874,
  685. 28591, 28592, 20866, 21866, 28595, 28597, 28593, 28594, 28596, 28598, 38598, 28605, 28599,
  686. 932, 949, 950, 936,
  687. 50220, 50221, 50222, 51932, 51949, 50225, 52936,
  688. 65001, 65000, 1200 };
  689. //
  690. // IMultiLanguage3
  691. // Outbound encoding detection for plain Unicode text encoding detection
  692. // We ride on CMultiLanguage2 class to implement this funciton
  693. //
  694. STDAPI CMultiLanguage2::DetectOutboundCodePage(
  695. DWORD dwFlags, // Flags control our behaviour
  696. LPCWSTR lpWideCharStr, // Source Unicode string
  697. UINT cchWideChar, // Source Unicode character size
  698. UINT* puiPreferredCodePages, // Preferred code page array
  699. UINT nPreferredCodePages, // Number of preferred code pages
  700. UINT* puiDetectedCodePages, // Detected code page arrayNumber of detected code pages
  701. UINT* pnDetectedCodePages, // [in] Maxium number of code pages we can return
  702. // [out] Num of detected code pages
  703. WCHAR* lpSpecialChar // Optional NULL terminated Unicode string for client specified special chars
  704. )
  705. {
  706. DWORD dwCodePages = 0, dwCodePagesExt = 0;
  707. LONG lNum1 = 0, lNum2 = 0;
  708. HRESULT hr = E_FAIL;
  709. UINT ui;
  710. DWORD dwStrFlags;
  711. LPWSTR lpwszTmp = NULL;
  712. // Parameter checks
  713. if (!cchWideChar || !lpWideCharStr || !puiDetectedCodePages || !*pnDetectedCodePages)
  714. return E_INVALIDARG;
  715. // We need extra buffer to perform best fit char filtering
  716. if (dwFlags & MLDETECTF_FILTER_SPECIALCHAR)
  717. lpwszTmp = (LPWSTR) LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*cchWideChar);
  718. // String sniffing for CJK, HINDI and BESTFIT
  719. dwStrFlags = OutBoundDetectPreScan((WCHAR *)lpWideCharStr, cchWideChar, lpwszTmp, lpSpecialChar);
  720. hr = GetStrCodePagesEx(lpwszTmp? lpwszTmp:lpWideCharStr, cchWideChar, 0, &dwCodePages, &lNum1, CPBITS_WINDOWS|CPBITS_STRICT);
  721. if (SUCCEEDED(hr))
  722. hr = GetStrCodePagesEx(lpwszTmp? lpwszTmp:lpWideCharStr, cchWideChar, 0, &dwCodePagesExt,&lNum2, CPBITS_EXTENDED|CPBITS_STRICT);
  723. // Clear bits if it is not a complete pass
  724. if ((UINT)lNum1 != cchWideChar)
  725. dwCodePages = 0;
  726. if ((UINT)lNum2 != cchWideChar)
  727. dwCodePagesExt = 0;
  728. if (lpwszTmp)
  729. LocalFree(lpwszTmp);
  730. // If Hindi, we don't return any non-Unicode code pages since there is no offical ones
  731. // and we don't recomment client to render Hindi text in ANSI
  732. if (dwStrFlags & (FS_HINDI|FS_PUA))
  733. {
  734. dwCodePages = 0;
  735. dwCodePagesExt = 0;
  736. }
  737. dwCodePagesExt |= FS_MLANG_65001;
  738. dwCodePagesExt |= FS_MLANG_65000;
  739. dwCodePagesExt |= FS_MLANG_1200;
  740. if (dwCodePagesExt & FS_MLANG_28598)
  741. dwCodePagesExt |= FS_MLANG_38598;
  742. if (dwCodePagesExt & FS_MLANG_50220)
  743. dwCodePagesExt |= FS_MLANG_50221|FS_MLANG_50222;
  744. if (SUCCEEDED(hr))
  745. {
  746. DWORD dwTempCodePages;
  747. DWORD dwTempCodePages2;
  748. UINT nCp = 0;
  749. // Pick preferred code pages first
  750. if (nPreferredCodePages && puiPreferredCodePages)
  751. for (ui=0; nCp<*pnDetectedCodePages && (dwCodePages | dwCodePagesExt) && ui<nPreferredCodePages; ui++)
  752. {
  753. if (S_OK == CodePageToCodePagesEx(puiPreferredCodePages[ui], &dwTempCodePages, &dwTempCodePages2))
  754. {
  755. if (dwTempCodePages & dwCodePages)
  756. {
  757. puiDetectedCodePages[nCp] = puiPreferredCodePages[ui];
  758. dwCodePages &= ~dwTempCodePages;
  759. nCp++;
  760. }
  761. else if (dwTempCodePages2 & dwCodePagesExt)
  762. {
  763. puiDetectedCodePages[nCp] = puiPreferredCodePages[ui];
  764. dwCodePagesExt &= ~dwTempCodePages2;
  765. nCp++;
  766. }
  767. }
  768. }
  769. // Fill in non-preferred code pages if we still have space in destination buffer
  770. if (!((dwFlags & MLDETECTF_PREFERRED_ONLY) && nPreferredCodePages && puiPreferredCodePages))
  771. {
  772. for (ui=0; nCp<*pnDetectedCodePages && (dwCodePages | dwCodePagesExt) && ui < sizeof(SysPreCp)/sizeof(UINT); ui++)
  773. {
  774. if (S_OK == CodePageToCodePagesEx(SysPreCp[ui], &dwTempCodePages, &dwTempCodePages2))
  775. {
  776. if (dwTempCodePages & dwCodePages)
  777. {
  778. puiDetectedCodePages[nCp] = SysPreCp[ui];
  779. dwCodePages &= ~dwTempCodePages;
  780. nCp++;
  781. }
  782. else if (dwTempCodePages2 & dwCodePagesExt)
  783. {
  784. puiDetectedCodePages[nCp] = SysPreCp[ui];
  785. dwCodePagesExt &= ~dwTempCodePages2;
  786. nCp++;
  787. }
  788. }
  789. }
  790. }
  791. // Smart adjustment for DBCS
  792. // If string doesn't contains CJK characters, we bump up UTF8
  793. if (!(dwFlags & MLDETECTF_PRESERVE_ORDER) && !(dwStrFlags & FS_CJK) && (puiDetectedCodePages[0] == 932||
  794. puiDetectedCodePages[0] == 936||puiDetectedCodePages[0] == 950||puiDetectedCodePages[0] == 949))
  795. {
  796. for (ui = 1; ui < nCp; ui++)
  797. {
  798. if (puiDetectedCodePages[ui] == 65001) //Swap
  799. {
  800. MoveMemory((LPVOID)(puiDetectedCodePages+1), (LPVOID)(puiDetectedCodePages), ui*sizeof(UINT));
  801. puiDetectedCodePages[0] = 65001;
  802. break;
  803. }
  804. }
  805. }
  806. // Check validation
  807. if (dwFlags & MLDETECTF_VALID || dwFlags & MLDETECTF_VALID_NLS)
  808. {
  809. MIMECPINFO cpInfo;
  810. UINT * puiBuffer = puiDetectedCodePages;
  811. if (!g_pMimeDatabase)
  812. BuildGlobalObjects();
  813. if (g_pMimeDatabase)
  814. {
  815. for (ui = 0; ui < nCp; ui++)
  816. {
  817. if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(puiDetectedCodePages[ui], 0x0409, &cpInfo)))
  818. {
  819. if ((cpInfo.dwFlags & MIMECONTF_VALID) ||
  820. ((cpInfo.dwFlags & MIMECONTF_VALID_NLS) && (dwFlags & MLDETECTF_VALID_NLS)))
  821. {
  822. // In place adjustment
  823. *puiBuffer = puiDetectedCodePages[ui];
  824. puiBuffer++;
  825. }
  826. }
  827. }
  828. nCp =(UINT) (puiBuffer-puiDetectedCodePages);
  829. }
  830. }
  831. // Be nice, clean up detection buffer for client
  832. if (nCp < *pnDetectedCodePages)
  833. ZeroMemory(&puiDetectedCodePages[nCp], *pnDetectedCodePages-nCp);
  834. *pnDetectedCodePages = nCp;
  835. }
  836. return hr;
  837. }
  838. // IStream object
  839. STDAPI CMultiLanguage2::DetectOutboundCodePageInIStream(
  840. DWORD dwFlags, // Detection flags
  841. IStream* pStmIn, // IStream object pointer
  842. UINT* puiPreferredCodePages, // Preferred code page array
  843. UINT nPreferredCodePages, // Num of preferred code pages
  844. UINT* puiDetectedCodePages, // Buffer for detection result
  845. UINT* pnDetectedCodePages, // [in] Maxium number of code pages we can return
  846. // [out] Num of detected code pages
  847. WCHAR* lpSpecialChar // Optional NULL terminated Unicode string for client specified special chars
  848. )
  849. {
  850. HRESULT hr;
  851. LARGE_INTEGER libOrigin = { 0, 0 };
  852. ULARGE_INTEGER ulPos = {0, 0};
  853. ULONG ulSrcSize;
  854. CHAR *pStr;
  855. // Get buffer size
  856. hr = pStmIn->Seek(libOrigin, STREAM_SEEK_END,&ulPos);
  857. if (SUCCEEDED(hr))
  858. {
  859. ulSrcSize = ulPos.LowPart ;
  860. if (pStr=(char *)LocalAlloc(LPTR, ulSrcSize))
  861. {
  862. // Reset the pointer
  863. hr = pStmIn->Seek(libOrigin, STREAM_SEEK_SET, NULL);
  864. if (S_OK == hr)
  865. {
  866. hr = pStmIn->Read(pStr, ulSrcSize, &ulSrcSize);
  867. if (S_OK == hr)
  868. hr = DetectOutboundCodePage(dwFlags, (LPCWSTR)pStr, ulSrcSize/sizeof(WCHAR), puiPreferredCodePages,
  869. nPreferredCodePages, puiDetectedCodePages, pnDetectedCodePages, lpSpecialChar);
  870. }
  871. LocalFree(pStr);
  872. }
  873. else
  874. hr = E_OUTOFMEMORY;
  875. }
  876. return hr;
  877. }