windows-nt/Source/XPSP1/NT/shell/ext/mlang/mlang.cpp
2020-09-26 16:20:57 +08:00

1028 lines
34 KiB
C++

#include "private.h"
#include "mlmain.h"
#include "cpdetect.h"
#include "codepage.h"
STDAPI CMultiLanguage::GetNumberOfCodePageInfo(UINT *pcCodePage)
{
if (NULL != m_pMimeDatabase)
return m_pMimeDatabase->GetNumberOfCodePageInfo(pcCodePage);
else
return E_FAIL;
}
STDAPI CMultiLanguage::GetCodePageInfo(UINT uiCodePage, PMIMECPINFO pcpInfo)
{
if (NULL != m_pMimeDatabase)
return m_pMimeDatabase->GetCodePageInfo(uiCodePage, GetSystemDefaultLangID(), pcpInfo);
else
return E_FAIL;
}
STDAPI CMultiLanguage::GetFamilyCodePage(UINT uiCodePage, UINT *puiFamilyCodePage)
{
HRESULT hr = S_OK;
int idx = 0;
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetFamilyCodePage called."));
while(MimeCodePage[idx].uiCodePage)
{
if ((uiCodePage == MimeCodePage[idx].uiCodePage) &&
(MimeCodePage[idx].dwFlags & dwMimeSource))
break;
idx++;
}
if (MimeCodePage[idx].uiCodePage)
{
if (MimeCodePage[idx].uiFamilyCodePage)
*puiFamilyCodePage = MimeCodePage[idx].uiFamilyCodePage;
else
*puiFamilyCodePage = uiCodePage;
}
else
{
hr = E_FAIL;
*puiFamilyCodePage = 0;
}
return hr;
}
STDAPI CMultiLanguage::EnumCodePages(DWORD grfFlags, IEnumCodePage **ppEnumCodePage)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::EnumCodePages called."));
*ppEnumCodePage = NULL;
// Return IE4 MIME DB data in IMultiLanguage
CEnumCodePage *pCEnumCodePage = new CEnumCodePage(grfFlags, GetSystemDefaultLangID(), MIMECONTF_MIME_IE4);
if (NULL != pCEnumCodePage)
{
HRESULT hr = pCEnumCodePage->QueryInterface(IID_IEnumCodePage, (void**)ppEnumCodePage);
pCEnumCodePage->Release();
return hr;
}
return E_OUTOFMEMORY;
}
STDAPI CMultiLanguage2::EnumCodePages(DWORD grfFlags, LANGID LangId, IEnumCodePage **ppEnumCodePage)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::EnumCodePages called."));
*ppEnumCodePage = NULL;
CEnumCodePage *pCEnumCodePage = new CEnumCodePage(grfFlags, LangId, dwMimeSource);
if (NULL != pCEnumCodePage)
{
HRESULT hr = pCEnumCodePage->QueryInterface(IID_IEnumCodePage, (void**)ppEnumCodePage);
pCEnumCodePage->Release();
return hr;
}
return E_OUTOFMEMORY;
}
STDAPI CMultiLanguage2::EnumScripts(DWORD dwFlags, LANGID LangId, IEnumScript **ppEnumScript)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::EnumScripts called."));
*ppEnumScript = NULL;
CEnumScript *pCEnumScript = new CEnumScript(dwFlags, LangId, dwMimeSource);
if (NULL != pCEnumScript)
{
HRESULT hr = pCEnumScript->QueryInterface(IID_IEnumScript, (void**)ppEnumScript);
pCEnumScript->Release();
return hr;
}
return E_OUTOFMEMORY;
}
STDAPI CMultiLanguage::GetCharsetInfo(BSTR Charset, PMIMECSETINFO pcsetInfo)
{
if (NULL != m_pMimeDatabase)
return m_pMimeDatabase->GetCharsetInfo(Charset, pcsetInfo);
else
return E_FAIL;
}
STDAPI CMultiLanguage::IsConvertible(DWORD dwSrcEncoding, DWORD dwDstEncoding)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::IsConvertINetStringAvailable called."));
return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
}
STDAPI CMultiLanguage::ConvertString(LPDWORD lpdwMode, DWORD dwSrcEncoding, DWORD dwDstEncoding, BYTE *pSrcStr, UINT *pcSrcSize, BYTE *pDstStr, UINT *pcDstSize)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::ConvertStringEx called."));
return ConvertINetString(lpdwMode, dwSrcEncoding, dwDstEncoding, (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
}
STDAPI CMultiLanguage::ConvertStringToUnicode(LPDWORD lpdwMode, DWORD dwEncoding, CHAR *pSrcStr, UINT *pcSrcSize, WCHAR *pDstStr, UINT *pcDstSize)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::ConvertStringToUnicode called."));
return ConvertINetMultiByteToUnicode(lpdwMode, dwEncoding, (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPWSTR)pDstStr, (LPINT)pcDstSize);
}
STDAPI CMultiLanguage::ConvertStringFromUnicode(LPDWORD lpdwMode, DWORD dwEncoding, WCHAR *pSrcStr, UINT *pcSrcSize, CHAR *pDstStr, UINT *pcDstSize)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::ConvertStringFromUnicode called."));
return ConvertINetUnicodeToMultiByte(lpdwMode, dwEncoding, (LPCWSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
}
STDAPI CMultiLanguage::ConvertStringReset(void)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::Reset called."));
return ConvertINetReset();
}
STDAPI CMultiLanguage::GetRfc1766FromLcid(LCID Locale, BSTR *pbstrRfc1766)
{
HRESULT hr = E_INVALIDARG;
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetRfc1766FromLcid called."));
if (NULL != pbstrRfc1766)
{
WCHAR wsz[MAX_RFC1766_NAME];
hr = LcidToRfc1766W(Locale, wsz, ARRAYSIZE(wsz));
if (SUCCEEDED(hr))
*pbstrRfc1766 = SysAllocString(wsz);
else
*pbstrRfc1766 = NULL;
}
return hr;
}
STDAPI CMultiLanguage::GetLcidFromRfc1766(PLCID pLocale, BSTR bstrRfc1766)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetLcidFromRfc1766 called."));
return Rfc1766ToLcidW(pLocale, bstrRfc1766);
}
STDAPI CMultiLanguage::EnumRfc1766(IEnumRfc1766 **ppEnumRfc1766)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::EnumRfc1766 called."));
*ppEnumRfc1766 = NULL;
CEnumRfc1766 *pCEnumRfc1766 = new CEnumRfc1766(dwMimeSource,GetSystemDefaultLangID());
if (NULL != pCEnumRfc1766)
{
HRESULT hr = pCEnumRfc1766->QueryInterface(IID_IEnumRfc1766, (void**)ppEnumRfc1766);
pCEnumRfc1766->Release();
return hr;
}
return E_OUTOFMEMORY;
}
STDAPI CMultiLanguage2::EnumRfc1766(LANGID LangId, IEnumRfc1766 **ppEnumRfc1766)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::EnumRfc1766 called."));
*ppEnumRfc1766 = NULL;
CEnumRfc1766 *pCEnumRfc1766 = new CEnumRfc1766(dwMimeSource, LangId);
if (NULL != pCEnumRfc1766)
{
HRESULT hr = pCEnumRfc1766->QueryInterface(IID_IEnumRfc1766, (void**)ppEnumRfc1766);
pCEnumRfc1766->Release();
return hr;
}
return E_OUTOFMEMORY;
}
STDAPI CMultiLanguage::GetRfc1766Info(LCID Locale, PRFC1766INFO pRfc1766Info)
{
UINT i;
HRESULT hr = E_INVALIDARG;
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetRfc1766Info called."));
if (NULL != pRfc1766Info)
{
for (i = 0; i < g_cRfc1766; i++)
{
if (MimeRfc1766[i].LcId == Locale)
break;
}
if (i < g_cRfc1766)
{
pRfc1766Info->lcid = MimeRfc1766[i].LcId;
MLStrCpyNW(pRfc1766Info->wszRfc1766, MimeRfc1766[i].szRfc1766, MAX_RFC1766_NAME);
_LoadStringExW(g_hInst, MimeRfc1766[i].uidLCID, pRfc1766Info->wszLocaleName,
MAX_LOCALE_NAME, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
hr = S_OK;
}
else
hr = E_FAIL;
}
return hr;
}
STDAPI CMultiLanguage2::GetRfc1766Info(LCID Locale, LANGID LangId, PRFC1766INFO pRfc1766Info)
{
UINT i;
HRESULT hr = E_INVALIDARG;
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::GetRfc1766Info called."));
if (NULL != pRfc1766Info)
{
for (i = 0; i < g_cRfc1766; i++)
{
if (MimeRfc1766[i].LcId == Locale)
break;
}
if (i < g_cRfc1766)
{
if (!LangId)
LangId = GetSystemDefaultLangID();
pRfc1766Info->lcid = MimeRfc1766[i].LcId;
MLStrCpyNW(pRfc1766Info->wszRfc1766, MimeRfc1766[i].szRfc1766, MAX_RFC1766_NAME);
if (!_LoadStringExW(g_hInst, MimeRfc1766[i].uidLCID, pRfc1766Info->wszLocaleName,
MAX_LOCALE_NAME, LangId))
{
_LoadStringExW(g_hInst, MimeRfc1766[i].uidLCID, pRfc1766Info->wszLocaleName,
MAX_LOCALE_NAME, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
}
hr = S_OK;
}
else
hr = E_FAIL;
}
return hr;
}
STDAPI CMultiLanguage::CreateConvertCharset(UINT uiSrcCodePage, UINT uiDstCodePage, DWORD dwProperty, IMLangConvertCharset **ppMLangConvertCharset)
{
HRESULT hr;
IClassFactory* pClassObj;
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::CreateCharsetConvert called."));
if (SUCCEEDED(hr = _Module.GetClassObject(CLSID_CMLangConvertCharset, IID_IClassFactory, (void**)&pClassObj)))
{
hr = pClassObj->CreateInstance(NULL, IID_IMLangConvertCharset, (void**)ppMLangConvertCharset);
pClassObj->Release();
}
if (ppMLangConvertCharset && FAILED(hr))
*ppMLangConvertCharset = NULL;
if (NULL != *ppMLangConvertCharset)
hr = (*ppMLangConvertCharset)->Initialize(uiSrcCodePage, uiDstCodePage, dwProperty);
return hr;
}
STDAPI CMultiLanguage2::ConvertStringInIStream(LPDWORD lpdwMode, DWORD dwFlag, WCHAR *lpFallBack, DWORD dwSrcEncoding, DWORD dwDstEncoding, IStream *pstmIn, IStream *pstmOut)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::ConvertStringInIStream called."));
return ConvertINetStringInIStream(lpdwMode,dwSrcEncoding,dwDstEncoding,pstmIn,pstmOut,dwFlag,lpFallBack);
}
STDAPI CMultiLanguage2::ConvertStringToUnicodeEx(LPDWORD lpdwMode, DWORD dwEncoding, CHAR *pSrcStr, UINT *pcSrcSize, WCHAR *pDstStr, UINT *pcDstSize, DWORD dwFlag, WCHAR *lpFallBack)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::ConvertBufferStringToUnicodeEx called."));
return ConvertINetMultiByteToUnicodeEx(lpdwMode, dwEncoding, (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPWSTR)pDstStr, (LPINT)pcDstSize, dwFlag, lpFallBack);
}
STDAPI CMultiLanguage2::ConvertStringFromUnicodeEx(LPDWORD lpdwMode, DWORD dwEncoding, WCHAR *pSrcStr, UINT *pcSrcSize, CHAR *pDstStr, UINT *pcDstSize, DWORD dwFlag, WCHAR *lpFallBack)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::ConvertBufferStringFromUnicodeEx called."));
return ConvertINetUnicodeToMultiByteEx(lpdwMode, dwEncoding, (LPCWSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize, dwFlag, lpFallBack);
}
STDAPI CMultiLanguage2::DetectCodepageInIStream(DWORD dwFlag, DWORD uiPrefWinCodepage, IStream *pstmIn, DetectEncodingInfo *lpEncoding, INT *pnScores)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::DetectCodepageInIStream called. "));
return _DetectCodepageInIStream(dwFlag, uiPrefWinCodepage, pstmIn, lpEncoding, pnScores);
}
STDAPI CMultiLanguage2::DetectInputCodepage(DWORD dwFlag, DWORD uiPrefWinCodepage, CHAR *pSrcStr, INT *pcSrcSize, DetectEncodingInfo *lpEncoding, INT *pnScores)
{
DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::DetectInputCodepage called. "));
return _DetectInputCodepage(dwFlag, uiPrefWinCodepage, pSrcStr, pcSrcSize, lpEncoding, pnScores);
}
STDAPI CMultiLanguage2::ValidateCodePage(UINT uiCodePage, HWND hwnd)
{
return ValidateCodePageEx(uiCodePage, hwnd, 0);
}
// this is private function to serve both for IML2 and IML3
STDAPI CMultiLanguage2::ValidateCodePageEx(UINT uiCodePage, HWND hwnd, DWORD dwfIODControl)
{
MIMECPINFO cpInfo;
CLSID clsid;
UINT uiFamCp;
HRESULT hr;
DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::ValidateCodePage called. "));
if (NULL != g_pMimeDatabase)
hr = g_pMimeDatabase->GetCodePageInfo(uiCodePage, 0x409, &cpInfo);
else
hr = E_OUTOFMEMORY;
if (FAILED(hr))
return E_INVALIDARG;
EnterCriticalSection(&g_cs);
if (NULL == g_pCpMRU)
if (g_pCpMRU = new CCpMRU)
g_pCpMRU->Init();
LeaveCriticalSection(&g_cs);
if (g_pCpMRU && g_pCpMRU->dwCpMRUEnable)
g_pCpMRU->UpdateCPMRU(uiCodePage);
if (cpInfo.dwFlags & MIMECONTF_VALID)
return S_OK;
// always handle family codepage because a caller
// of this function is not generally aware if
// the codepage is primary one. i.e., they can
// call with cp=20268 to validate the entire 1251
// family.
//
uiFamCp = cpInfo.uiFamilyCodePage;
// Bug 394904, IOD won't be able to get us gb18030 support,
// so we won't ask UrlMon for CHS langpack if gb2312 is valid
if (uiCodePage == CP_18030)
{
g_pMimeDatabase->GetCodePageInfo(uiFamCp, 0x409, &cpInfo);
if (cpInfo.dwFlags & MIMECONTF_VALID)
return S_FALSE;
}
// Ignore IOD check on NT5
if (g_bIsNT5)
{
// Currently, NT5 doesn't install 20127 and 28605 NLS files.
// We should prevent langpack installation loop and let clients resolve
// them with CP_ACP in case of 20127 and 28605 validation.
// This hack can be removed once NT5 bundles these NLS files by default.
if ((uiCodePage == CP_20127 || uiCodePage == CP_ISO_8859_15) && IsValidCodePage(uiFamCp))
return E_FAIL;
hr = IsNTLangpackAvailable(uiFamCp);
if (hr != S_OK)
return hr;
}
else
{
// check if JIT langpack is enabled.
//
hr = EnsureIEStatus();
if (hr == S_OK)
{
if (!m_pIEStat || m_pIEStat->IsJITEnabled() != TRUE)
{
// the codepage is neither valid or installable
return S_FALSE;
}
}
}
if (hwnd == NULL)
{
hwnd = GetForegroundWindow();
}
// Special handling for NT.
if (g_bIsNT5)
{
DWORD dwInstallLpk = 1;
HKEY hkey;
DWORD dwAction = 0;
// HKCR\\Software\\Microsoft\internet explorer\\international
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER,
REGSTR_PATH_INTERNATIONAL,
NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwAction))
{
DWORD dwType = REG_DWORD;
DWORD dwSize = sizeof(DWORD);
if (ERROR_SUCCESS != RegQueryValueEx(hkey, REG_KEY_NT5LPK, 0, &dwType, (LPBYTE)&dwInstallLpk, &dwSize))
{
dwInstallLpk = 1;
RegSetValueEx(hkey, REG_KEY_NT5LPK, 0, REG_DWORD, (LPBYTE)&dwInstallLpk, sizeof(dwInstallLpk));
}
RegCloseKey(hkey);
}
hr = S_FALSE;
// Pops up NT5 langpack dialog box if langpack is enabled or user selects it from encoding menu
if (dwInstallLpk || (dwfIODControl & CPIOD_FORCE_PROMPT))
{
LPCDLGTEMPLATE pTemplate;
HRSRC hrsrc;
INT_PTR iRet;
LANGID LangId = GetNT5UILanguage();
dwInstallLpk |= uiFamCp << 16;
// Load correct resource to match NT5 UI language
hrsrc = FindResourceExW(g_hInst, (LPCWSTR) RT_DIALOG, (LPCWSTR) MAKEINTRESOURCE(IDD_DIALOG_LPK), LangId);
ULONG_PTR uCookie = 0;
SHActivateContext(&uCookie);
// Pack LPARAM, code page value in HIWORD, installation flag in LOWORD
if (hrsrc &&
(pTemplate = (LPCDLGTEMPLATE)LoadResource(g_hInst, hrsrc)))
{
iRet = DialogBoxIndirectParamW(g_hInst, pTemplate,
hwnd, LangpackDlgProc, (LPARAM) dwInstallLpk);
}
else
iRet = DialogBoxParamW(g_hInst, (LPCWSTR) MAKEINTRESOURCE(IDD_DIALOG_LPK), hwnd, LangpackDlgProc, (LPARAM) dwInstallLpk);
if (iRet)
{
hr = _InstallNT5Langpack(hwnd, uiFamCp);
if (S_OK == hr)
{
WCHAR wszLangInstall[MAX_PATH];
WCHAR wszNT5LangPack[1024];
// Fall back to English (US) if we don't have a specific language resource
if (!_LoadStringExW(g_hInst, IDS_LANGPACK_INSTALL, wszLangInstall, ARRAYSIZE(wszLangInstall), LangId) ||
!_LoadStringExW(g_hInst, IDS_NT5_LANGPACK, wszNT5LangPack, ARRAYSIZE(wszNT5LangPack), LangId))
{
LangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
_LoadStringExW(g_hInst, IDS_LANGPACK_INSTALL, wszLangInstall, ARRAYSIZE(wszLangInstall), LangId);
_LoadStringExW(g_hInst, IDS_NT5_LANGPACK, wszNT5LangPack, ARRAYSIZE(wszNT5LangPack), LangId);
}
MessageBoxW(hwnd, wszNT5LangPack, wszLangInstall, MB_OK);
}
}
if (uCookie)
{
SHDeactivateContext(uCookie);
}
}
goto SKIP_IELANGPACK;
}
// Initiate JIT using CLSID give to the langpack
hr = _GetJITClsIDForCodePage(uiFamCp, &clsid);
if (SUCCEEDED(hr))
{
hr = InstallIEFeature(hwnd, &clsid, dwfIODControl);
}
// if JIT returns S_OK, we now have everything installed
// then we'll validate the codepage and add font
// NOTE: there can be more than codepage to validate here,
// for example, PE langpack contains more than one
// NLS file to get greek, cyrillic and Turkish at the
// same time.
if (hr == S_OK)
{
hr = _ValidateCPInfo(uiFamCp);
if (SUCCEEDED(hr))
{
_AddFontForCP(uiFamCp);
}
}
SKIP_IELANGPACK:
return hr;
}
// IMultiLanguage2::GetCodePageDescription
//
// Provide native code page description in UNICODE.
// If not resource is vailable for the specified LCID,
// we'll try the primary language first, then English.
// In this case, we'll return S_FALSE to caller.
STDAPI CMultiLanguage2::GetCodePageDescription(
UINT uiCodePage, // Specifies the required code page for description.
LCID lcid, // Specifies locale ID for prefered language.
LPWSTR lpWideCharStr, // Points to a buffer that receives the code page description.
int cchWideChar) // Specifies the size, in wide characters, of the buffer
// pointed by lpWideCharStr.
{
HRESULT hr = E_FAIL;
UINT CountCPId;
UINT i = 0, j = 0;
g_pMimeDatabase->GetNumberOfCodePageInfo(&CountCPId);
if (cchWideChar == 0)
{
return E_INVALIDARG;
}
while (i < CountCPId)
{
if (MimeCodePage[j].dwFlags & dwMimeSource)
{
if ((MimeCodePage[j].uiCodePage == uiCodePage))
{
if (_LoadStringExW(g_hInst, MimeCodePage[j].uidDescription, lpWideCharStr,
cchWideChar, LANGIDFROMLCID(lcid)))
{
hr = S_OK;
}
else // Resource not find in the specificed language
{
if (_LoadStringExW(g_hInst, MimeCodePage[j].uidDescription, lpWideCharStr,
cchWideChar, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)))
{
hr = S_FALSE;
}
}
break;
}
i++;
}
j++;
}
if (i >= CountCPId) // Code page description is not available in MLANG
{
hr = E_INVALIDARG;
}
return (hr);
}
STDAPI CMultiLanguage2::IsCodePageInstallable(UINT uiCodePage)
{
MIMECPINFO cpInfo;
UINT uiFamCp;
HRESULT hr;
DebugMsg(DM_TRACE, TEXT("CMultiLanguage::IsCPInstallable called. "));
if (NULL != g_pMimeDatabase)
hr = g_pMimeDatabase->GetCodePageInfo(uiCodePage, 0x409, &cpInfo);
else
hr = E_OUTOFMEMORY;
if (FAILED(hr))
return E_INVALIDARG;
// if it's already valid, no need to check if it's installable
if (cpInfo.dwFlags & MIMECONTF_VALID)
{
hr = S_OK;
}
else
{
uiFamCp = cpInfo.uiFamilyCodePage;
// it is currently not valid, if NT5, ignore IOD check
if (g_bIsNT5)
{
hr = IsNTLangpackAvailable(uiFamCp);
}
else
{
// now check to see if the cp can be IOD
hr = EnsureIEStatus();
// we'll return FALSE if we couldn't get IOD status
if (hr == S_OK)
{
if (!m_pIEStat || !m_pIEStat->IsJITEnabled())
hr = S_FALSE;
}
// then see if we have langpack for
// the family codepage
if (hr == S_OK)
{
CLSID clsid;
// clsid is just used for place holder
hr = _GetJITClsIDForCodePage(uiFamCp, &clsid);
}
}
}
return hr;
}
STDAPI CMultiLanguage2::SetMimeDBSource(MIMECONTF dwSource)
{
if ((dwSource != MIMECONTF_MIME_IE4) &&
(dwSource != MIMECONTF_MIME_LATEST) &&
(dwSource != MIMECONTF_MIME_REGISTRY))
{
return E_INVALIDARG;
}
if (dwSource & MIMECONTF_MIME_REGISTRY)
{
EnterCriticalSection(&g_cs);
if (!g_pMimeDatabaseReg)
{
g_pMimeDatabaseReg = new CMimeDatabaseReg;
}
LeaveCriticalSection(&g_cs);
}
dwMimeSource = dwSource;
if (NULL != m_pMimeDatabase)
m_pMimeDatabase->SetMimeDBSource(dwSource);
return S_OK;
}
CMultiLanguage2::CMultiLanguage2(void)
{
DllAddRef();
CComCreator< CComPolyObject< CMultiLanguage > >::CreateInstance( NULL, IID_IMultiLanguage, (void **)&m_pIML );
m_pMimeDatabase = new CMimeDatabase;
dwMimeSource = MIMECONTF_MIME_LATEST;
if (m_pMimeDatabase)
m_pMimeDatabase->SetMimeDBSource(MIMECONTF_MIME_LATEST);
m_pIEStat = NULL;
}
CMultiLanguage2::~CMultiLanguage2(void)
{
if (m_pIML)
{
m_pIML->Release();
m_pIML = NULL;
}
if (m_pMimeDatabase)
{
delete m_pMimeDatabase;
}
if (m_pIEStat)
{
delete m_pIEStat;
}
DllRelease();
}
STDAPI CMultiLanguage2::GetNumberOfCodePageInfo(UINT *pcCodePage)
{
if (dwMimeSource & MIMECONTF_MIME_REGISTRY)
{
if (NULL != g_pMimeDatabaseReg)
return g_pMimeDatabaseReg->GetNumberOfCodePageInfo(pcCodePage);
else
return E_FAIL;
}
else
{
if (NULL != m_pMimeDatabase)
return m_pMimeDatabase->GetNumberOfCodePageInfo(pcCodePage);
else
return E_FAIL;
}
}
STDAPI CMultiLanguage2::GetNumberOfScripts(UINT *pnScripts)
{
if (pnScripts)
*pnScripts = g_cScript;
return NOERROR;
}
STDAPI CMultiLanguage2::GetCodePageInfo(UINT uiCodePage, LANGID LangId, PMIMECPINFO pcpInfo)
{
if (dwMimeSource & MIMECONTF_MIME_REGISTRY)
{
if (NULL != g_pMimeDatabaseReg)
return g_pMimeDatabaseReg->GetCodePageInfo(uiCodePage, pcpInfo);
else
return E_FAIL;
}
else
{
if (m_pMimeDatabase)
return m_pMimeDatabase->GetCodePageInfo(uiCodePage, LangId, pcpInfo);
else
return E_FAIL;
}
}
// Optimized for performance
// Skip unecessary resource loading
STDAPI CMultiLanguage2::GetFamilyCodePage(UINT uiCodePage, UINT *puiFamilyCodePage)
{
HRESULT hr = S_OK;
int idx = 0;
if (puiFamilyCodePage)
*puiFamilyCodePage = 0;
else
return E_INVALIDARG;
DebugMsg(DM_TRACE, TEXT("CMultiLanguage2::GetFamilyCodePage called."));
// Keep registry version IE4 implementation
if (dwMimeSource & MIMECONTF_MIME_REGISTRY)
{
if (NULL != g_pMimeDatabaseReg)
{
MIMECPINFO cpInfo;
hr = g_pMimeDatabaseReg->GetCodePageInfo(uiCodePage, &cpInfo);
if (S_OK == hr)
*puiFamilyCodePage = cpInfo.uiFamilyCodePage;
}
}
else
{
while(MimeCodePage[idx].uiCodePage)
{
if ((uiCodePage == MimeCodePage[idx].uiCodePage) &&
(MimeCodePage[idx].dwFlags & dwMimeSource))
break;
idx++;
}
if (MimeCodePage[idx].uiCodePage)
{
if (MimeCodePage[idx].uiFamilyCodePage)
*puiFamilyCodePage = MimeCodePage[idx].uiFamilyCodePage;
else
*puiFamilyCodePage = uiCodePage;
}
else
{
hr = E_FAIL;
}
}
return hr;
}
STDAPI CMultiLanguage2::GetCharsetInfo(BSTR Charset, PMIMECSETINFO pcsetInfo)
{
if (dwMimeSource & MIMECONTF_MIME_REGISTRY)
{
if (NULL != g_pMimeDatabaseReg)
return g_pMimeDatabaseReg->GetCharsetInfo(Charset, pcsetInfo);
else
return E_FAIL;
}
if (NULL != m_pMimeDatabase)
return m_pMimeDatabase->GetCharsetInfo(Charset, pcsetInfo);
else
return E_FAIL;
}
//
// System default code page stack
//
// We support following code pages for outbound encoding detection
// Windows : 1252, 1250, 1251, 1253, 1254, 1257, 1258, 1256, 1255, 874, 932, 949, 950, 936
// Unicode : 65001, 65000, 1200
// ISO : 28591, 28592, 20866, 21866, 28595, 28597, 28593, 28594, 28596, 28598, 38598, 28605, 28599
// Others : 20127, 50220, 50221, 50222, 51932, 51949, 50225, 52936
//
// Default priorities
// 20127 > Windows single byte code page> ISO > Windows DBCS code page > Others > Unicode
//
UINT SysPreCp[] =
{20127,
1252, 1250, 1251, 1253, 1254, 1257, 1258, 1256, 1255, 874,
28591, 28592, 20866, 21866, 28595, 28597, 28593, 28594, 28596, 28598, 38598, 28605, 28599,
932, 949, 950, 936,
50220, 50221, 50222, 51932, 51949, 50225, 52936,
65001, 65000, 1200 };
//
// IMultiLanguage3
// Outbound encoding detection for plain Unicode text encoding detection
// We ride on CMultiLanguage2 class to implement this funciton
//
STDAPI CMultiLanguage2::DetectOutboundCodePage(
DWORD dwFlags, // Flags control our behaviour
LPCWSTR lpWideCharStr, // Source Unicode string
UINT cchWideChar, // Source Unicode character size
UINT* puiPreferredCodePages, // Preferred code page array
UINT nPreferredCodePages, // Number of preferred code pages
UINT* puiDetectedCodePages, // Detected code page arrayNumber of detected code pages
UINT* pnDetectedCodePages, // [in] Maxium number of code pages we can return
// [out] Num of detected code pages
WCHAR* lpSpecialChar // Optional NULL terminated Unicode string for client specified special chars
)
{
DWORD dwCodePages = 0, dwCodePagesExt = 0;
LONG lNum1 = 0, lNum2 = 0;
HRESULT hr = E_FAIL;
UINT ui;
DWORD dwStrFlags;
LPWSTR lpwszTmp = NULL;
// Parameter checks
if (!cchWideChar || !lpWideCharStr || !puiDetectedCodePages || !*pnDetectedCodePages)
return E_INVALIDARG;
// We need extra buffer to perform best fit char filtering
if (dwFlags & MLDETECTF_FILTER_SPECIALCHAR)
lpwszTmp = (LPWSTR) LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*cchWideChar);
// String sniffing for CJK, HINDI and BESTFIT
dwStrFlags = OutBoundDetectPreScan((WCHAR *)lpWideCharStr, cchWideChar, lpwszTmp, lpSpecialChar);
hr = GetStrCodePagesEx(lpwszTmp? lpwszTmp:lpWideCharStr, cchWideChar, 0, &dwCodePages, &lNum1, CPBITS_WINDOWS|CPBITS_STRICT);
if (SUCCEEDED(hr))
hr = GetStrCodePagesEx(lpwszTmp? lpwszTmp:lpWideCharStr, cchWideChar, 0, &dwCodePagesExt,&lNum2, CPBITS_EXTENDED|CPBITS_STRICT);
// Clear bits if it is not a complete pass
if ((UINT)lNum1 != cchWideChar)
dwCodePages = 0;
if ((UINT)lNum2 != cchWideChar)
dwCodePagesExt = 0;
if (lpwszTmp)
LocalFree(lpwszTmp);
// If Hindi, we don't return any non-Unicode code pages since there is no offical ones
// and we don't recomment client to render Hindi text in ANSI
if (dwStrFlags & (FS_HINDI|FS_PUA))
{
dwCodePages = 0;
dwCodePagesExt = 0;
}
dwCodePagesExt |= FS_MLANG_65001;
dwCodePagesExt |= FS_MLANG_65000;
dwCodePagesExt |= FS_MLANG_1200;
if (dwCodePagesExt & FS_MLANG_28598)
dwCodePagesExt |= FS_MLANG_38598;
if (dwCodePagesExt & FS_MLANG_50220)
dwCodePagesExt |= FS_MLANG_50221|FS_MLANG_50222;
if (SUCCEEDED(hr))
{
DWORD dwTempCodePages;
DWORD dwTempCodePages2;
UINT nCp = 0;
// Pick preferred code pages first
if (nPreferredCodePages && puiPreferredCodePages)
for (ui=0; nCp<*pnDetectedCodePages && (dwCodePages | dwCodePagesExt) && ui<nPreferredCodePages; ui++)
{
if (S_OK == CodePageToCodePagesEx(puiPreferredCodePages[ui], &dwTempCodePages, &dwTempCodePages2))
{
if (dwTempCodePages & dwCodePages)
{
puiDetectedCodePages[nCp] = puiPreferredCodePages[ui];
dwCodePages &= ~dwTempCodePages;
nCp++;
}
else if (dwTempCodePages2 & dwCodePagesExt)
{
puiDetectedCodePages[nCp] = puiPreferredCodePages[ui];
dwCodePagesExt &= ~dwTempCodePages2;
nCp++;
}
}
}
// Fill in non-preferred code pages if we still have space in destination buffer
if (!((dwFlags & MLDETECTF_PREFERRED_ONLY) && nPreferredCodePages && puiPreferredCodePages))
{
for (ui=0; nCp<*pnDetectedCodePages && (dwCodePages | dwCodePagesExt) && ui < sizeof(SysPreCp)/sizeof(UINT); ui++)
{
if (S_OK == CodePageToCodePagesEx(SysPreCp[ui], &dwTempCodePages, &dwTempCodePages2))
{
if (dwTempCodePages & dwCodePages)
{
puiDetectedCodePages[nCp] = SysPreCp[ui];
dwCodePages &= ~dwTempCodePages;
nCp++;
}
else if (dwTempCodePages2 & dwCodePagesExt)
{
puiDetectedCodePages[nCp] = SysPreCp[ui];
dwCodePagesExt &= ~dwTempCodePages2;
nCp++;
}
}
}
}
// Smart adjustment for DBCS
// If string doesn't contains CJK characters, we bump up UTF8
if (!(dwFlags & MLDETECTF_PRESERVE_ORDER) && !(dwStrFlags & FS_CJK) && (puiDetectedCodePages[0] == 932||
puiDetectedCodePages[0] == 936||puiDetectedCodePages[0] == 950||puiDetectedCodePages[0] == 949))
{
for (ui = 1; ui < nCp; ui++)
{
if (puiDetectedCodePages[ui] == 65001) //Swap
{
MoveMemory((LPVOID)(puiDetectedCodePages+1), (LPVOID)(puiDetectedCodePages), ui*sizeof(UINT));
puiDetectedCodePages[0] = 65001;
break;
}
}
}
// Check validation
if (dwFlags & MLDETECTF_VALID || dwFlags & MLDETECTF_VALID_NLS)
{
MIMECPINFO cpInfo;
UINT * puiBuffer = puiDetectedCodePages;
if (!g_pMimeDatabase)
BuildGlobalObjects();
if (g_pMimeDatabase)
{
for (ui = 0; ui < nCp; ui++)
{
if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(puiDetectedCodePages[ui], 0x0409, &cpInfo)))
{
if ((cpInfo.dwFlags & MIMECONTF_VALID) ||
((cpInfo.dwFlags & MIMECONTF_VALID_NLS) && (dwFlags & MLDETECTF_VALID_NLS)))
{
// In place adjustment
*puiBuffer = puiDetectedCodePages[ui];
puiBuffer++;
}
}
}
nCp =(UINT) (puiBuffer-puiDetectedCodePages);
}
}
// Be nice, clean up detection buffer for client
if (nCp < *pnDetectedCodePages)
ZeroMemory(&puiDetectedCodePages[nCp], *pnDetectedCodePages-nCp);
*pnDetectedCodePages = nCp;
}
return hr;
}
// IStream object
STDAPI CMultiLanguage2::DetectOutboundCodePageInIStream(
DWORD dwFlags, // Detection flags
IStream* pStmIn, // IStream object pointer
UINT* puiPreferredCodePages, // Preferred code page array
UINT nPreferredCodePages, // Num of preferred code pages
UINT* puiDetectedCodePages, // Buffer for detection result
UINT* pnDetectedCodePages, // [in] Maxium number of code pages we can return
// [out] Num of detected code pages
WCHAR* lpSpecialChar // Optional NULL terminated Unicode string for client specified special chars
)
{
HRESULT hr;
LARGE_INTEGER libOrigin = { 0, 0 };
ULARGE_INTEGER ulPos = {0, 0};
ULONG ulSrcSize;
CHAR *pStr;
// Get buffer size
hr = pStmIn->Seek(libOrigin, STREAM_SEEK_END,&ulPos);
if (SUCCEEDED(hr))
{
ulSrcSize = ulPos.LowPart ;
if (pStr=(char *)LocalAlloc(LPTR, ulSrcSize))
{
// Reset the pointer
hr = pStmIn->Seek(libOrigin, STREAM_SEEK_SET, NULL);
if (S_OK == hr)
{
hr = pStmIn->Read(pStr, ulSrcSize, &ulSrcSize);
if (S_OK == hr)
hr = DetectOutboundCodePage(dwFlags, (LPCWSTR)pStr, ulSrcSize/sizeof(WCHAR), puiPreferredCodePages,
nPreferredCodePages, puiDetectedCodePages, pnDetectedCodePages, lpSpecialChar);
}
LocalFree(pStr);
}
else
hr = E_OUTOFMEMORY;
}
return hr;
}