Windows2003-3790/inetcore/outlookexpress/inetcomm/mimeole/internat.cpp
2020-09-30 16:53:55 +02:00

2181 lines
63 KiB
C++

// --------------------------------------------------------------------------------
// Internat.cpp
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
// Steven J. Bailey
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "dllmain.h"
#include "internat.h"
#include "variantx.h"
#include "containx.h"
#include "symcache.h"
#include "icoint.h"
#include "mlang.h"
#include "demand.h"
#include "strconst.h"
#include "mimeapi.h"
#include "shlwapi.h"
#include "shlwapip.h"
#include "qstrcmpi.h"
// In rfc1522.cpp
BOOL FContainsExtended(LPPROPSTRINGA pStringA, ULONG *pcExtended);
// --------------------------------------------------------------------------------
// Global Default Charset - This is only used if mlang is not installed
// --------------------------------------------------------------------------------
INETCSETINFO CIntlGlobals::mg_rDefaultCharset = {
"ISO-8859-1",
NULL,
1252,
28591,
0
};
// --------------------------------------------------------------------------------
// InitInternational
// --------------------------------------------------------------------------------
void InitInternational(void)
{
// Allocate g_pInternat
g_pInternat = new CMimeInternational;
if (NULL == g_pInternat)
{
AssertSz(FALSE, "Unable to allocate g_pInternat.");
return;
}
CIntlGlobals::Init();
}
// --------------------------------------------------------------------------------
// CMimeInternational::CMimeInternational
// --------------------------------------------------------------------------------
CMimeInternational::CMimeInternational(void)
{
// Var Init
m_cRef = 1;
ZeroMemory(&m_cst, sizeof(CSTABLE));
ZeroMemory(&m_cpt, sizeof(CPTABLE));
// Init HCHARSET tagger, don't let it be zero
m_wTag = LOWORD(GetTickCount());
while(m_wTag == 0 || m_wTag == 0xffff)
m_wTag++;
// BUGS - temporary solution for MLANG new API - m_dwConvState
m_dwConvState = 0 ;
}
// --------------------------------------------------------------------------------
// CMimeInternational::~CMimeInternational
// --------------------------------------------------------------------------------
CMimeInternational::~CMimeInternational(void)
{
// Clean up globals
CIntlGlobals::Term();
// Free data
_FreeInetCsetTable();
_FreeCodePageTable();
}
// --------------------------------------------------------------------------------
// CMimeInternational::QueryInterface
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::QueryInterface(REFIID riid, LPVOID *ppv)
{
// check params
if (ppv == NULL)
return TrapError(E_INVALIDARG);
// Find IID
if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
else if (IID_IMimeInternational == riid)
*ppv = (IMimeInternational *)this;
else
{
*ppv = NULL;
return TrapError(E_NOINTERFACE);
}
// AddRef It
((IUnknown *)*ppv)->AddRef();
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// CMimeInternational::AddRef
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CMimeInternational::AddRef(void)
{
// Raid 26762
DllAddRef();
return (ULONG)InterlockedIncrement(&m_cRef);
}
// --------------------------------------------------------------------------------
// CMimeInternational::Release
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CMimeInternational::Release(void)
{
// Raid 26762
LONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
delete this;
else
DllRelease();
return (ULONG)cRef;
}
// -------------------------------------------------------------------------
// CMimeInternational::_FreeInetCsetTable
// -------------------------------------------------------------------------
void CMimeInternational::_FreeInetCsetTable(void)
{
// Free Each Charset
for (ULONG i=0; i<m_cst.cCharsets; i++)
g_pMalloc->Free((LPVOID)m_cst.prgpCharset[i]);
// Free the Array
SafeMemFree(m_cst.prgpCharset);
// Clear the Table
ZeroMemory(&m_cst, sizeof(CSTABLE));
}
// -------------------------------------------------------------------------
// CMimeInternational::_FreeCodePageTable
// -------------------------------------------------------------------------
void CMimeInternational::_FreeCodePageTable(void)
{
// Free Each Charset
for (ULONG i=0; i<m_cpt.cPages; i++)
g_pMalloc->Free((LPVOID)m_cpt.prgpPage[i]);
// Free the Array
SafeMemFree(m_cpt.prgpPage);
// Clear the Table
ZeroMemory(&m_cpt, sizeof(CPTABLE));
}
// -------------------------------------------------------------------------
// CMimeInternational::HrOpenCharset
// -------------------------------------------------------------------------
HRESULT CMimeInternational::HrOpenCharset(LPCSTR pszCharset, LPINETCSETINFO *ppCharset)
{
// Locals
HRESULT hr=S_OK;
LONG lUpper,
lLower,
lMiddle,
nCompare;
ULONG i;
BOOL fExcLock;
fExcLock = FALSE;
// Invalid Arg
Assert(pszCharset && ppCharset);
// Init
*ppCharset = NULL;
// Thread Safety
m_lock.ShareLock();
again:
// Do we have anything yet
if (m_cst.cCharsets > 0)
{
// Set lLower and lUpper
lLower = 0;
lUpper = m_cst.cCharsets - 1;
// Do binary search / insert
while (lLower <= lUpper)
{
// Compute middle record to compare against
lMiddle = (LONG)((lLower + lUpper) / 2);
// Get string to compare against
i = m_cst.prgpCharset[lMiddle]->dwReserved1;
// Do compare
nCompare = OEMstrcmpi(pszCharset, m_cst.prgpCharset[i]->szName);
// If Equal, then were done
if (nCompare == 0)
{
*ppCharset = m_cst.prgpCharset[i];
goto exit;
}
// Compute upper and lower
if (nCompare > 0)
lLower = lMiddle + 1;
else
lUpper = lMiddle - 1;
}
}
if(FALSE == fExcLock)
{
m_lock.ShareUnlock(); //Release the Sharelock before
m_lock.ExclusiveLock(); //getting the exclusive lock
fExcLock = TRUE;
//during the change of lock the value might have changed
//check it again
goto again;
}
// Not found, lets open the registry
CHECKHR(hr = _HrReadCsetInfo(pszCharset, ppCharset));
exit:
// Thread Safety
if(TRUE==fExcLock)
m_lock.ExclusiveUnlock();
else
m_lock.ShareUnlock();
// Done
return hr;
}
// -------------------------------------------------------------------------
// CMimeInternational::_HrReadCsetInfo
// -------------------------------------------------------------------------
HRESULT CMimeInternational::_HrReadCsetInfo(LPCSTR pszCharset, LPINETCSETINFO *ppCharset)
{
// Locals
HRESULT hr=S_OK;
LPINETCSETINFO pCharset=NULL;
IMultiLanguage *pMLang1 = NULL;
IMultiLanguage2 *pMLang2 = NULL;
MIMECSETINFO mciInfo;
BSTR strCharset = NULL;
int iRes;
// Invalid Arg
Assert(pszCharset && ppCharset);
// Init
*ppCharset = NULL;
// Try to create an IMultiLanguage2 interface
// If we are in OE5 compat mode...
if (TRUE == ISFLAGSET(g_dwCompatMode, MIMEOLE_COMPAT_MLANG2))
{
hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage2, (LPVOID *) &pMLang2);
if (!SUCCEEDED(hr))
{
// Ok that failed, so lets try to create an IMultiLanaguage interface
hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage, (LPVOID *) &pMLang1);
if (!SUCCEEDED(hr))
{
TrapError(hr);
goto exit;
}
}
}
else
{
// Ok that failed, so lets try to create an IMultiLanaguage interface
hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage, (LPVOID *) &pMLang1);
if (!SUCCEEDED(hr))
{
TrapError(hr);
goto exit;
}
}
// MLANG wants the charset name as a BSTR, so we need to convert it from ANSI...
strCharset = SysAllocStringLen(NULL,lstrlen(pszCharset));
if (!strCharset)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
iRes = MultiByteToWideChar(CP_ACP,0,pszCharset,-1,strCharset,SysStringLen(strCharset)+1);
if (iRes == 0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
TrapError(hr);
goto exit;
}
// Use pMLang2
if (pMLang2)
{
// Use mlang2
hr = pMLang2->GetCharsetInfo(strCharset, &mciInfo);
if (!SUCCEEDED(hr))
{
TrapError(hr);
hr = MIME_E_NOT_FOUND;
goto exit;
}
}
else
{
// Now just call MLANG to get the info...
hr = pMLang1->GetCharsetInfo(strCharset, &mciInfo);
if (!SUCCEEDED(hr))
{
TrapError(hr);
hr = MIME_E_NOT_FOUND;
goto exit;
}
}
// Add a new entry into the language table
if (m_cst.cCharsets + 1 >= m_cst.cAlloc)
{
// Reallocate the array
CHECKHR(hr = HrRealloc((LPVOID *)&m_cst.prgpCharset, sizeof(LPINETCSETINFO) * (m_cst.cAlloc + 5)));
// Increment Alloc
m_cst.cAlloc += 5;
}
// Allocate a Charset
CHECKALLOC(pCharset = (LPINETCSETINFO)g_pMalloc->Alloc(sizeof(INETCSETINFO)));
// Initialize
ZeroMemory(pCharset, sizeof(INETCSETINFO));
// Set Sort Index
pCharset->dwReserved1 = m_cst.cCharsets;
// Set HCharset
pCharset->hCharset = HCSETMAKE(m_cst.cCharsets);
// Read Data
StrCpyN(pCharset->szName, pszCharset, ARRAYSIZE(pCharset->szName));
pCharset->cpiInternet = mciInfo.uiInternetEncoding;
pCharset->cpiWindows = mciInfo.uiCodePage;
// Readability
m_cst.prgpCharset[m_cst.cCharsets] = pCharset;
// Return it
*ppCharset = pCharset;
// Don't Free It
pCharset = NULL;
// Increment Count
m_cst.cCharsets++;
// Let Sort the cset table
_QuickSortCsetInfo(0, m_cst.cCharsets - 1);
exit:
// Cleanup
SafeRelease(pMLang1);
SafeRelease(pMLang2);
if (strCharset)
{
SysFreeString(strCharset);
}
SafeMemFree(pCharset);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::_QuickSortCsetInfo
// --------------------------------------------------------------------------------
void CMimeInternational::_QuickSortCsetInfo(long left, long right)
{
// Locals
register long i, j;
DWORD k, temp;
i = left;
j = right;
k = m_cst.prgpCharset[(i + j) / 2]->dwReserved1;
do
{
while(OEMstrcmpi(m_cst.prgpCharset[m_cst.prgpCharset[i]->dwReserved1]->szName, m_cst.prgpCharset[k]->szName) < 0 && i < right)
i++;
while (OEMstrcmpi(m_cst.prgpCharset[m_cst.prgpCharset[j]->dwReserved1]->szName, m_cst.prgpCharset[k]->szName) > 0 && j > left)
j--;
if (i <= j)
{
temp = m_cst.prgpCharset[i]->dwReserved1;
m_cst.prgpCharset[i]->dwReserved1 = m_cst.prgpCharset[j]->dwReserved1;
m_cst.prgpCharset[j]->dwReserved1 = temp;
i++; j--;
}
} while (i <= j);
if (left < j)
_QuickSortCsetInfo(left, j);
if (i < right)
_QuickSortCsetInfo(i, right);
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrOpenCharset
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrOpenCharset(HCHARSET hCharset, LPINETCSETINFO *ppCharset)
{
// Invalid Arg
Assert(hCharset && ppCharset);
// Init
*ppCharset = NULL;
// Invalid Handle
if (HCSETVALID(hCharset) == FALSE)
return TrapError(MIME_E_INVALID_HANDLE);
// Deref
*ppCharset = PCsetFromHCset(hCharset);
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrFindCodePage
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrFindCodePage(CODEPAGEID cpiCodePage, LPCODEPAGEINFO *ppCodePage)
{
// Locals
HRESULT hr=S_OK;
LONG lUpper,
lLower,
lMiddle,
nCompare;
BOOL fExcLock;
fExcLock = FALSE;
// Invalid Arg
Assert(ppCodePage);
// Init
*ppCodePage = NULL;
// Thread Safety
m_lock.ShareLock();
again:
// Do We have anything yet
if (m_cpt.cPages > 0)
{
// Set lLower and lUpper
lLower = 0;
lUpper = m_cpt.cPages - 1;
// Do binary search / insert
while (lLower <= lUpper)
{
// Compute middle record to compare against
lMiddle = (LONG)((lLower + lUpper) / 2);
// If Equal, then were done
if (cpiCodePage == m_cpt.prgpPage[lMiddle]->cpiCodePage)
{
*ppCodePage = m_cpt.prgpPage[lMiddle];
goto exit;
}
// Compute upper and lower
if (cpiCodePage > m_cpt.prgpPage[lMiddle]->cpiCodePage)
lLower = lMiddle + 1;
else
lUpper = lMiddle - 1;
}
}
if(FALSE == fExcLock)
{
m_lock.ShareUnlock(); //Release the Sharelock before
m_lock.ExclusiveLock(); //getting the exclusive lock
fExcLock = TRUE;
//during the change of lock the value might have changed
//check it again
goto again;
}
// Not found, lets open the registry
CHECKHR(hr = _HrReadPageInfo(cpiCodePage, ppCodePage));
exit:
// Thread Safety
if(TRUE==fExcLock)
m_lock.ExclusiveUnlock();
else
m_lock.ShareUnlock();
// Done
return hr;
}
HRESULT convert_mimecpinfo_element(LPCWSTR pszFrom,
LPSTR pszTo,
DWORD cchTo,
DWORD& refdwFlags,
DWORD dwFlag) {
HRESULT hr = S_OK;
int iRes;
if (pszFrom[0]) {
iRes = WideCharToMultiByte(CP_ACP,
0,
pszFrom,
-1,
pszTo,
cchTo,
NULL,
NULL);
if (iRes == 0) {
hr = HRESULT_FROM_WIN32(GetLastError());
if (SUCCEEDED(hr)) {
hr = E_FAIL;
}
} else {
FLAGSET(refdwFlags,dwFlag);
}
}
return (hr);
}
#define CONVERT_MIMECPINFO_ELEMENT(__FROM__,__TO__,__FLAG__) \
hr = convert_mimecpinfo_element(cpinfo.__FROM__, \
pCodePage->__TO__, \
sizeof(pCodePage->__TO__)/sizeof(pCodePage->__TO__[0]), \
pCodePage->dwMask, \
__FLAG__); \
if (!SUCCEEDED(hr)) { \
TrapError(hr); \
goto exit; \
}
// -------------------------------------------------------------------------
// CMimeInternational::_HrReadPageInfo
// -------------------------------------------------------------------------
HRESULT CMimeInternational::_HrReadPageInfo(CODEPAGEID cpiCodePage, LPCODEPAGEINFO *ppCodePage)
{
// Locals
HRESULT hr=S_OK;
LPCODEPAGEINFO pCodePage=NULL;
MIMECPINFO cpinfo;
IMultiLanguage *pMLang1=NULL;
IMultiLanguage2 *pMLang2=NULL;
int iRes;
// Invalid Arg
Assert(ppCodePage);
// Init
*ppCodePage = NULL;
// Try to create an IMultiLanguage2 interface
// If we are in OE5 compat mode...
if (TRUE == ISFLAGSET(g_dwCompatMode, MIMEOLE_COMPAT_MLANG2))
{
hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage2, (LPVOID *) &pMLang2);
if (!SUCCEEDED(hr))
{
// Ok that failed, so lets try to create an IMultiLanaguage interface
hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage, (LPVOID *) &pMLang1);
if (!SUCCEEDED(hr))
{
TrapError(hr);
goto exit;
}
}
}
else
{
hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage, (LPVOID *) &pMLang1);
if (!SUCCEEDED(hr))
{
TrapError(hr);
goto exit;
}
}
// Use mlang2 ?
if (pMLang2)
{
// use mlang2
hr = pMLang2->GetCodePageInfo(cpiCodePage, MLGetUILanguage(), &cpinfo);
if (!SUCCEEDED(hr))
{
TrapError(hr);
hr = MIME_E_NOT_FOUND; // tbd - MLang doesn't define good error codes, so...
goto exit;
}
}
// Otherwise use ie4 mlang
else
{
// use mlang1
hr = pMLang1->GetCodePageInfo(cpiCodePage, &cpinfo);
if (!SUCCEEDED(hr))
{
TrapError(hr);
hr = MIME_E_NOT_FOUND; // tbd - MLang doesn't define good error codes, so...
goto exit;
}
}
// Add a new entry into the language table
if (m_cpt.cPages + 1 >= m_cpt.cAlloc)
{
// Reallocate the array
CHECKHR(hr = HrRealloc((LPVOID *)&m_cpt.prgpPage, sizeof(LPCODEPAGEINFO) * (m_cpt.cAlloc + 5)));
// Increment Alloc
m_cpt.cAlloc += 5;
}
// Allocate Code Page Structure
CHECKALLOC(pCodePage = (LPCODEPAGEINFO)g_pMalloc->Alloc(sizeof(CODEPAGEINFO)));
// Initialize
ZeroMemory(pCodePage, sizeof(CODEPAGEINFO));
// Set Sort Index
pCodePage->dwReserved1 = m_cpt.cPages;
// Set Charset
pCodePage->cpiCodePage = cpiCodePage;
// IsValidCodePage
pCodePage->fIsValidCodePage = IsValidCodePage(cpiCodePage);
// Default
pCodePage->ulMaxCharSize = 1;
// Raid 43508: GetCPInfo faults in Kernal when passed an invalid codepage on Win95
// if (pCodePage->fIsValidCodePage && GetCPInfo(pCodePage->cpiCodePage, &cpinfo))
if (IsDBCSCodePage(cpiCodePage) || CP_UNICODE == cpiCodePage)
pCodePage->ulMaxCharSize = 2;
// c_szDescription
CONVERT_MIMECPINFO_ELEMENT(wszDescription,szName,ILM_NAME)
// c_szBodyCharset
CONVERT_MIMECPINFO_ELEMENT(wszBodyCharset,szBodyCset,ILM_BODYCSET)
// c_szHeaderCharset
CONVERT_MIMECPINFO_ELEMENT(wszHeaderCharset,szHeaderCset,ILM_HEADERCSET)
// c_szWebCharset
CONVERT_MIMECPINFO_ELEMENT(wszWebCharset,szWebCset,ILM_WEBCSET)
// c_szFixedWidthFont
CONVERT_MIMECPINFO_ELEMENT(wszFixedWidthFont,szFixedFont,ILM_FIXEDFONT)
// c_szProportionalFont
CONVERT_MIMECPINFO_ELEMENT(wszProportionalFont,szVariableFont,ILM_VARIABLEFONT)
// Set the Family CodePage
pCodePage->cpiFamily = cpinfo.uiFamilyCodePage;
// The family codepage is valid
FLAGSET(pCodePage->dwMask,ILM_FAMILY);
// See if this is an internet codepage
if (cpinfo.uiFamilyCodePage != cpinfo.uiCodePage)
pCodePage->fInternetCP = TRUE;
// c_szMailMimeEncoding
// tbd - not supported by IMultiLanguage
pCodePage->ietMailDefault = IET_BINARY;
// c_szNewsMimeEncoding
// tbd - not supported by IMultiLanguage
pCodePage->ietNewsDefault = IET_BINARY;
// Readability
m_cpt.prgpPage[m_cpt.cPages] = pCodePage;
// Return it
*ppCodePage = pCodePage;
// Don't Free It
pCodePage = NULL;
// Increment Count
m_cpt.cPages++;
// Let Sort the lang table
_QuickSortPageInfo(0, m_cpt.cPages - 1);
exit:
// Cleanup
SafeRelease(pMLang1);
SafeRelease(pMLang2);
SafeMemFree(pCodePage);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::_QuickSortPageInfo
// --------------------------------------------------------------------------------
void CMimeInternational::_QuickSortPageInfo(long left, long right)
{
// Locals
register long i, j;
DWORD k, temp;
i = left;
j = right;
k = m_cpt.prgpPage[(i + j) / 2]->dwReserved1;
do
{
while(m_cpt.prgpPage[m_cpt.prgpPage[i]->dwReserved1]->cpiCodePage < m_cpt.prgpPage[k]->cpiCodePage && i < right)
i++;
while (m_cpt.prgpPage[m_cpt.prgpPage[j]->dwReserved1]->cpiCodePage > m_cpt.prgpPage[k]->cpiCodePage && j > left)
j--;
if (i <= j)
{
temp = m_cpt.prgpPage[i]->dwReserved1;
m_cpt.prgpPage[i]->dwReserved1 = m_cpt.prgpPage[j]->dwReserved1;
m_cpt.prgpPage[j]->dwReserved1 = temp;
i++; j--;
}
} while (i <= j);
if (left < j)
_QuickSortPageInfo(left, j);
if (i < right)
_QuickSortPageInfo(i, right);
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrOpenCharset
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrOpenCharset(CODEPAGEID cpiCodePage, CHARSETTYPE ctCsetType, LPINETCSETINFO *ppCharset)
{
// Locals
HRESULT hr=S_OK;
LPCODEPAGEINFO pCodePage;
// Invalid Arg
Assert(ppCharset);
// Init
*ppCharset = NULL;
// Get the body charset
CHECKHR(hr = HrFindCodePage(cpiCodePage, &pCodePage));
// CHARSET_HEADER
if (CHARSET_HEADER == ctCsetType)
{
// MIME_E_NO_DATA
if (!ISFLAGSET(pCodePage->dwMask, ILM_HEADERCSET) || FIsEmptyA(pCodePage->szHeaderCset))
{
hr = MIME_E_NO_DATA;
goto exit;
}
// Find the Handle
CHECKHR(hr = HrOpenCharset(pCodePage->szHeaderCset, ppCharset));
}
// CHARSET_WEB
else if (CHARSET_WEB == ctCsetType)
{
// MIME_E_NO_DATA
if (!ISFLAGSET(pCodePage->dwMask, ILM_WEBCSET) || FIsEmptyA(pCodePage->szWebCset))
{
hr = MIME_E_NO_DATA;
goto exit;
}
// Find the Handle
CHECKHR(hr = HrOpenCharset(pCodePage->szWebCset, ppCharset));
}
// CHARSET_BODY
else if (CHARSET_BODY == ctCsetType)
{
// MIME_E_NO_DATA
if (!ISFLAGSET(pCodePage->dwMask, ILM_BODYCSET) || FIsEmptyA(pCodePage->szBodyCset))
{
hr = MIME_E_NO_DATA;
goto exit;
}
// Find the Handle
CHECKHR(hr = HrOpenCharset(pCodePage->szBodyCset, ppCharset));
}
// Error
else
{
hr = TrapError(MIME_E_INVALID_CHARSET_TYPE);
goto exit;
}
exit:
// Done
return hr;
}
// -------------------------------------------------------------------------
// CMimeInternational::GetCodePageCharset
// -------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::GetCodePageCharset(CODEPAGEID cpiCodePage, CHARSETTYPE ctCsetType, LPHCHARSET phCharset)
{
// Locals
HRESULT hr=S_OK;
LPINETCSETINFO pCharset;
// Invalid Arg
if (NULL == phCharset)
return TrapError(E_INVALIDARG);
// Init
*phCharset = NULL;
// Call Method
CHECKHR(hr = HrOpenCharset(cpiCodePage, ctCsetType, &pCharset));
// Return the Handle
*phCharset = pCharset->hCharset;
exit:
// Done
return hr;
}
// -------------------------------------------------------------------------
// CMimeInternational::SetDefaultCharset
// -------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::SetDefaultCharset(HCHARSET hCharset)
{
// Locals
HRESULT hr=S_OK;
LPINETCSETINFO pCharset;
LPINETCSETINFO pDefHeadCset;
// Invalid Arg
if (NULL == hCharset)
return TrapError(E_INVALIDARG);
// Thread Safety
m_lock.ExclusiveLock();
// Bad Handle
if (HCSETVALID(hCharset) == FALSE)
{
hr = TrapError(MIME_E_INVALID_HANDLE);
goto exit;
}
// Get Charset Info
pCharset = PCsetFromHCset(hCharset);
// Get g_hSysBodyCset and g_hSysHeadCset
if (FAILED(g_pInternat->HrOpenCharset(pCharset->cpiInternet, CHARSET_HEADER, &pDefHeadCset)))
pDefHeadCset = pCharset;
// Set Globals
CIntlGlobals::SetDefBodyCset(pCharset);
CIntlGlobals::SetDefHeadCset(pDefHeadCset);
exit:
// Thread Safety
m_lock.ExclusiveUnlock();
// Done
return hr;
}
// -------------------------------------------------------------------------
// CMimeInternational::GetDefaultCharset
// -------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::GetDefaultCharset(LPHCHARSET phCharset)
{
// Invalid Arg
if (NULL == phCharset)
return TrapError(E_INVALIDARG);
// NOT SET YET
if (NULL == CIntlGlobals::GetDefBodyCset())
return TrapError(E_FAIL);
// Return g_hDefBodyCset
*phCharset = CIntlGlobals::GetDefBodyCset()->hCharset;
// Done
return S_OK;
}
// -------------------------------------------------------------------------
// CMimeInternational::FindCharset
// -------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::FindCharset(LPCSTR pszCharset, LPHCHARSET phCharset)
{
// Locals
HRESULT hr=S_OK;
LPINETCSETINFO pCharset;
// Invalid Arg
if (NULL == pszCharset || NULL == phCharset)
return TrapError(E_INVALIDARG);
// Init
*phCharset = NULL;
// Find CsetInfo
CHECKHR(hr = HrOpenCharset(pszCharset, &pCharset));
// Return Charset Handles
*phCharset = pCharset->hCharset;
exit:
// Done
return hr;
}
// -------------------------------------------------------------------------
// CMimeInternational::GetCharsetInfo
// -------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::GetCharsetInfo(HCHARSET hCharset, LPINETCSETINFO pCsetInfo)
{
// Invalid Arg
if (NULL == hCharset || NULL == pCsetInfo)
return TrapError(E_INVALIDARG);
// Bad Handle
if (HCSETVALID(hCharset) == FALSE)
return TrapError(MIME_E_INVALID_HANDLE);
// Copy the data
CopyMemory(pCsetInfo, PCsetFromHCset(hCharset), sizeof(INETCSETINFO));
// Done
return S_OK;
}
// -------------------------------------------------------------------------
// CMimeInternational::GetCodePageInfo
// -------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::GetCodePageInfo(CODEPAGEID cpiCodePage, LPCODEPAGEINFO pCodePage)
{
// Locals
HRESULT hr=S_OK;
LPCODEPAGEINFO pInfo;
// Invalid Arg
if (NULL == pCodePage)
return TrapError(E_INVALIDARG);
// Default the code page to CP_ACP if 0...
if (CP_ACP == cpiCodePage)
cpiCodePage = GetACP();
// Get Language Info
CHECKHR(hr = HrFindCodePage(cpiCodePage, &pInfo));
// Copy the data
CopyMemory(pCodePage, pInfo, sizeof(CODEPAGEINFO));
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::CanConvertCodePages
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::CanConvertCodePages(CODEPAGEID cpiSource, CODEPAGEID cpiDest)
{
// Locals
HRESULT hr=S_OK;
// Can Encode
if (S_OK != IsConvertINetStringAvailable(cpiSource, cpiDest))
{
hr = S_FALSE;
goto exit;
}
// BUGS - temporary solution for MLANG new API - m_dwConvState
m_dwConvState = 0 ;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::ConvertBuffer
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::ConvertBuffer(CODEPAGEID cpiSource, CODEPAGEID cpiDest,
LPBLOB pIn, LPBLOB pOut, ULONG *pcbRead)
{
// Locals
HRESULT hr=S_OK;
INT cbOut;
INT cbIn;
// Invalid Arg
if (NULL == pIn || NULL == pIn->pBlobData || NULL == pOut)
return TrapError(E_INVALIDARG);
// Init Out
pOut->pBlobData = NULL;
pOut->cbSize = 0;
cbIn = pIn->cbSize;
// Raid-63765: INETCOMM needs to call MLANG even if Src == Dst for charset set conversion
#if 0
if (cpiSource == cpiDest)
{
// Allocated
CHECKALLOC(pOut->pBlobData = (LPBYTE)g_pMalloc->Alloc(pIn->cbSize));
// Copy Memory
CopyMemory(pOut->pBlobData, pIn->pBlobData, pIn->cbSize);
// Set Size
pOut->cbSize = pIn->cbSize;
// Set pcbRead
if (pcbRead)
*pcbRead = pIn->cbSize;
// Done
goto exit;
}
#endif
// BUGS - temporary solution for MLANG new API - m_dwConvState
// Check the size of the buffer
ConvertINetString(&m_dwConvState, cpiSource, cpiDest, (LPCSTR)pIn->pBlobData, &cbIn, NULL, &cbOut);
// If something to convert...
if (0 == cbOut)
{
hr = E_FAIL;
goto exit;
}
// Allocate the buffer
CHECKHR(hr = HrAlloc((LPVOID *)&pOut->pBlobData, max(cbIn, cbOut) + 1));
// BUGS - temporary solution for MLANG new API - m_dwConvState
// Do the actual convertion
hr = ConvertINetString(&m_dwConvState, cpiSource, cpiDest, (LPCSTR)pIn->pBlobData, &cbIn, (LPSTR)pOut->pBlobData, (LPINT)&cbOut);
if ( hr == S_FALSE ) // propagate the charset conflict return value
hr = MIME_S_CHARSET_CONFLICT ;
// Set Out Size
if (pcbRead)
*pcbRead = cbIn;
// Set Out Size
pOut->cbSize = cbOut;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::ConvertString
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::ConvertString(CODEPAGEID cpiSource, CODEPAGEID cpiDest,
LPPROPVARIANT pIn, LPPROPVARIANT pOut)
{
// Locals
HRESULT hr=S_OK;
MIMEVARIANT rSource;
MIMEVARIANT rDest;
// Invalid Arg
if (NULL == pIn || NULL == pOut)
return TrapError(E_INVALIDARG);
// VT_LPSTR
if (VT_LPSTR == pIn->vt)
{
// Setup Source
rSource.type = MVT_STRINGA;
rSource.rStringA.pszVal = pIn->pszVal;
rSource.rStringA.cchVal = lstrlen(pIn->pszVal);
}
// VT_LPWSTR
else if (VT_LPWSTR == pIn->vt)
{
// Setup Source
rSource.type = MVT_STRINGW;
rSource.rStringW.pszVal = pIn->pwszVal;
rSource.rStringW.cchVal = lstrlenW(pIn->pwszVal);
}
// E_INVALIDARG
else
{
hr = TrapError(E_INVALIDARG);
goto exit;
}
// VT_LPSTR
if (VT_LPSTR == pOut->vt)
rDest.type = MVT_STRINGA;
// VT_LPWSTR
else if (VT_LPWSTR == pOut->vt)
rDest.type = MVT_STRINGW;
// CP_UNICODE
else if (CP_UNICODE == cpiDest)
{
pOut->vt = VT_LPWSTR;
rDest.type = MVT_STRINGW;
}
// Multibyte
else
{
pOut->vt = VT_LPSTR;
rDest.type = MVT_STRINGA;
}
// HrConvertString
hr = HrConvertString(cpiSource, cpiDest, &rSource, &rDest);
if (FAILED(hr))
goto exit;
// VT_LPSTR
if (VT_LPSTR == pOut->vt)
{
// Set Dest
Assert(ISSTRINGA(&rDest));
pOut->pszVal = rDest.rStringA.pszVal;
}
// VT_LPWSTR
else
{
// Set Dest
Assert(ISSTRINGW(&rDest));
pOut->pwszVal = rDest.rStringW.pszVal;
}
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrValidateCodepages
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrValidateCodepages(LPMIMEVARIANT pSource, LPMIMEVARIANT pDest,
LPBYTE *ppbSource, ULONG *pcbSource, CODEPAGEID *pcpiSource, CODEPAGEID *pcpiDest)
{
// Locals
HRESULT hr=S_OK;
CODEPAGEID cpiSource=(*pcpiSource);
CODEPAGEID cpiDest=(*pcpiDest);
LPBYTE pbSource;
ULONG cbSource;
// Invalid ARg
Assert(pcpiSource && pcpiDest);
// MVT_STRINGA
if (MVT_STRINGA == pSource->type)
{
// E_INVALIDARG
if (ISVALIDSTRINGA(&pSource->rStringA) == FALSE)
{
hr = TrapError(E_INVALIDARG);
goto exit;
}
// cpiSource should not be unicode
cpiSource = (CP_UNICODE == cpiSource) ? GetACP() : cpiSource;
// Init Out
cbSource = pSource->rStringA.cchVal;
// Set Source
pbSource = (LPBYTE)pSource->rStringA.pszVal;
}
// MVT_STRINGW
else if (MVT_STRINGW == pSource->type)
{
// E_INVALIDARG
if (ISVALIDSTRINGW(&pSource->rStringW) == FALSE)
{
hr = TrapError(E_INVALIDARG);
goto exit;
}
// cpiSource should be Unicode
cpiSource = CP_UNICODE;
// Init Out
cbSource = (pSource->rStringW.cchVal * sizeof(WCHAR));
// Set Source
pbSource = (LPBYTE)pSource->rStringW.pszVal;
}
// E_INVALIDARG
else
{
hr = TrapError(E_INVALIDARG);
goto exit;
}
// MVT_STRINGA
if (MVT_STRINGA == pDest->type)
{
// cpiDest shoudl not be unicode
cpiDest = (CP_UNICODE == cpiDest) ? GetACP() : ((CP_JAUTODETECT == cpiDest) ? 932 : cpiDest);
}
// MVT_STRINGW
else if (MVT_STRINGW == pDest->type)
{
// Destination is Unicode
cpiDest = CP_UNICODE;
}
// E_INVALIDARG
else
{
hr = TrapError(E_INVALIDARG);
goto exit;
}
// Set Return Values
if (pcpiSource)
*pcpiSource = cpiSource;
if (pcpiDest)
*pcpiDest = cpiDest;
if (ppbSource)
*ppbSource = pbSource;
if (pcbSource)
*pcbSource = cbSource;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrConvertString
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrConvertString(CODEPAGEID cpiSource, CODEPAGEID cpiDest,
LPMIMEVARIANT pSource, LPMIMEVARIANT pDest)
{
// Locals
HRESULT hr=S_OK;
INT cbNeeded=0;
INT cbDest;
INT cbSource;
LPBYTE pbSource;
LPBYTE pbDest=NULL;
// Invalid Arg
if (NULL == pSource || NULL == pDest)
return TrapError(E_INVALIDARG);
// Adjust the Codepages
CHECKHR(hr = HrValidateCodepages(pSource, pDest, &pbSource, (ULONG *)&cbSource, &cpiSource, &cpiDest));
// Raid-63765: INETCOMM needs to call MLANG even if Src == Dst for charset set conversion
#if 0
if (cpiSource == cpiDest)
{
// Copy the variant
CHECKHR(hr = HrMimeVariantCopy(0, pSource, pDest));
// Done
goto exit;
}
#endif
// Check the size of the buffer
if (FAILED(ConvertINetString(NULL, cpiSource, cpiDest, (LPCSTR)pbSource, &cbSource, NULL, &cbNeeded)) ||
(0 == cbNeeded && cbSource > 0))
{
hr = E_FAIL;
goto exit;
}
// MVT_STRINGA
if (MVT_STRINGA == pDest->type)
{
// Allocate the buffer
CHECKALLOC(pDest->rStringA.pszVal = (LPSTR)g_pMalloc->Alloc(cbNeeded + sizeof(CHAR)));
// Set Dest
pbDest = (LPBYTE)pDest->rStringA.pszVal;
}
// Allocate unicode
else
{
// Allocate the buffer
CHECKALLOC(pDest->rStringW.pszVal = (LPWSTR)g_pMalloc->Alloc(cbNeeded + sizeof(WCHAR)));
// Set Dest
pbDest = (LPBYTE)pDest->rStringW.pszVal;
}
// Set cbOut
cbDest = cbNeeded;
// Do the actual convertion
if (FAILED(ConvertINetString(NULL, cpiSource, cpiDest, (LPCSTR)pbSource, &cbSource, (LPSTR)pbDest, &cbDest)))
{
hr = E_FAIL;
goto exit;
}
// Better not have grown
Assert(cbDest <= cbNeeded);
// MVT_STRINGA
if (MVT_STRINGA == pDest->type)
{
// Save Size
pDest->rStringA.cchVal = cbDest;
// Pound in a Null
pDest->rStringA.pszVal[pDest->rStringA.cchVal] = '\0';
// Validate the String
Assert(ISSTRINGA(pDest));
}
// MVT_STRINGW
else
{
// Save Size
pDest->rStringW.cchVal = (cbDest / 2);
// Pound in a Null
pDest->rStringW.pszVal[pDest->rStringW.cchVal] = L'\0';
// Validate the String
Assert(ISSTRINGW(pDest));
}
// Success
pbDest = NULL;
exit:
// Cleanup
SafeMemFree(pbDest);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrEncodeHeader
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrEncodeHeader(LPINETCSETINFO pCharset, LPRFC1522INFO pRfc1522Info,
LPMIMEVARIANT pSource, LPMIMEVARIANT pDest)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszNarrow=NULL;
LPSTR pszRfc1522=NULL;
BOOL fRfc1522Used=FALSE;
BOOL fRfc1522Tried=FALSE;
MIMEVARIANT rRedirected;
// Invalid Arg
Assert(pSource && (MVT_STRINGA == pSource->type || MVT_STRINGW == pSource->type));
Assert(pDest && MVT_STRINGA == pDest->type);
// ZeroInit
ZeroMemory(&rRedirected, sizeof(MIMEVARIANT));
// Default hCharset
if (NULL == pCharset)
pCharset = CIntlGlobals::GetDefHeadCset();
// No Charset..
if (NULL == pCharset)
{
hr = TrapError(E_FAIL);
goto exit;
}
// Init
if (pRfc1522Info)
pRfc1522Info->fRfc1522Used = FALSE;
// Raid-62535: MimeOle always 1521 encodes headers when header value is Unicode
// If source is unicode and were not using a UTF character set to encode with, then convert to multibyte
if (MVT_STRINGW == pSource->type && CP_UNICODE != pCharset->cpiWindows)
{
// Setup MimeVariant
rRedirected.type = MVT_STRINGA;
// Convert to pCharset->cpiWindows
CHECKHR(hr = HrWideCharToMultiByte(pCharset->cpiWindows, &pSource->rStringW, &rRedirected.rStringA));
// Reset pSource
pSource = &rRedirected;
}
// Decode
if ((65000 == pCharset->cpiInternet || 65001 == pCharset->cpiInternet) ||
(NULL == pRfc1522Info || ((FALSE == pRfc1522Info->fAllow8bit) && (TRUE == pRfc1522Info->fRfc1522Allowed))))
{
// Locals
CODEPAGEID cpiSource=pCharset->cpiWindows;
CODEPAGEID cpiDest=pCharset->cpiInternet;
// Adjust the Codepages
CHECKHR(hr = HrValidateCodepages(pSource, pDest, NULL, NULL, &cpiSource, &cpiDest));
// We Tried rfc1522
fRfc1522Tried = TRUE;
// 1522 Encode this dude
if (SUCCEEDED(HrRfc1522Encode(pSource, pDest, cpiSource, cpiDest, pCharset->szName, &pszRfc1522)))
{
// We used Rfc1522
fRfc1522Used = TRUE;
// Return Information
if (pRfc1522Info)
{
pRfc1522Info->fRfc1522Used = TRUE;
pRfc1522Info->hRfc1522Cset = pCharset->hCharset;
}
// Setup rStringA
pDest->rStringA.pszVal = pszRfc1522;
pDest->rStringA.cchVal = lstrlen(pszRfc1522);
pszRfc1522 = NULL;
}
}
// If we didn't use RFC 1522, then do a convert string
if (FALSE == fRfc1522Used)
{
// If UTF-7 or UTF-8 and source is ANSI with no 8bit, just dup it
if (65000 == pCharset->cpiInternet || 65001 == pCharset->cpiInternet)
{
// Source is ansi
if (MVT_STRINGA == pSource->type)
{
// Locals
ULONG c;
// No 8bit
if (FALSE == FContainsExtended(&pSource->rStringA, &c))
{
// Convert
hr = HrConvertString(pCharset->cpiWindows, pCharset->cpiWindows, pSource, pDest);
// Were Done
goto exit;
}
// We must not have tried 1522, because thats what we should have done
Assert(fRfc1522Tried == FALSE);
}
}
// Do the charset conversion
hr = HrConvertString(pCharset->cpiWindows, pCharset->cpiInternet, pSource, pDest);
if (FAILED(hr))
goto exit;
}
exit:
// Cleanup
SafeMemFree(pszRfc1522);
MimeVariantFree(&rRedirected);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrDecodeHeader
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrDecodeHeader(LPINETCSETINFO pCharset, LPRFC1522INFO pRfc1522Info,
LPMIMEVARIANT pSource, LPMIMEVARIANT pDest)
{
// Locals
HRESULT hr=S_OK;
LPINETCSETINFO pRfc1522Charset=NULL;
PROPSTRINGA rTempA;
LPSTR pszRfc1522=NULL;
LPSTR pszNarrow=NULL;
MIMEVARIANT rSource;
CHAR szRfc1522Cset[CCHMAX_CSET_NAME];
// Invalid Arg
Assert(pSource && (MVT_STRINGA == pSource->type || MVT_STRINGW == pSource->type));
Assert(pDest && (MVT_STRINGA == pDest->type || MVT_STRINGW == pDest->type));
// Copy Source
CopyMemory(&rSource, pSource, sizeof(MIMEVARIANT));
// MVT_STRINGW
if (MVT_STRINGW == pSource->type)
{
// Better be a valid string
Assert(ISVALIDSTRINGW(&pSource->rStringW));
// Conversion
CHECKHR(hr = HrWideCharToMultiByte(CP_ACP, &pSource->rStringW, &rTempA));
// Free This
pszNarrow = rTempA.pszVal;
// Update rSource
rSource.type = MVT_STRINGA;
rSource.rStringA.pszVal = rTempA.pszVal;
rSource.rStringA.cchVal = rTempA.cchVal;
}
// Decode
if (NULL == pRfc1522Info || TRUE == pRfc1522Info->fRfc1522Allowed)
{
// Perform rfc1522 decode...
if (SUCCEEDED(MimeOleRfc1522Decode(rSource.rStringA.pszVal, szRfc1522Cset, ARRAYSIZE(szRfc1522Cset), &pszRfc1522)))
{
// It was encoded...
if (pRfc1522Info)
pRfc1522Info->fRfc1522Used = TRUE;
// Look up the charset
if (SUCCEEDED(HrOpenCharset(szRfc1522Cset, &pRfc1522Charset)) && pRfc1522Info)
{
// Return in the Info Struct
pRfc1522Info->hRfc1522Cset = pRfc1522Charset->hCharset;
}
// Reset Source
rSource.rStringA.pszVal = pszRfc1522;
rSource.rStringA.cchVal = lstrlen(pszRfc1522);
// No pCharset
if (NULL == pCharset)
pCharset = pRfc1522Charset;
}
// No Rfc1522
else if (pRfc1522Info)
{
pRfc1522Info->fRfc1522Used = FALSE;
pRfc1522Info->hRfc1522Cset = NULL;
}
}
// Charset is Still Null, use Default
if (NULL == pCharset)
pCharset = CIntlGlobals::GetDefHeadCset();
// No Charset..
if (NULL == pCharset)
{
hr = TrapError(E_FAIL);
goto exit;
}
// Convert the String
hr = HrConvertString(pCharset->cpiInternet, pCharset->cpiWindows, &rSource, pDest);
if (FAILED(hr))
{
// If it was rfc1522 decoded, then return it and a warning
if (pszRfc1522)
{
// pszRfc1522 should be in rSource
Assert(rSource.rStringA.pszVal == pszRfc1522);
// Return MVT_STRINGA
if (MVT_STRINGA == pDest->type)
{
pDest->rStringA.pszVal = rSource.rStringA.pszVal;
pDest->rStringA.cchVal = rSource.rStringA.cchVal;
pszRfc1522 = NULL;
}
// MVT_STRINGW
else
{
CHECKHR(hr = HrMultiByteToWideChar(CP_ACP, &rSource.rStringA, &pDest->rStringW));
pszRfc1522 = NULL;
}
// This is not a failure, but just a warning
hr = MIME_S_NO_CHARSET_CONVERT;
}
// Done
goto exit;
}
exit:
// Cleanup
SafeMemFree(pszNarrow);
SafeMemFree(pszRfc1522);
// Done
return hr;
}
//---------------------------------------------------------------------------------
// Function: MLANG_ConvertInetReset
//
// Purpose:
// This function is a wrapper function for MLANG.DLL's ConvertInetReset.
//
// Returns:
// Same as for MLANG.DLL's ConvertInetReset.
//---------------------------------------------------------------------------------
HRESULT CMimeInternational::MLANG_ConvertInetReset(void)
{
HRESULT hrResult;
// a stub for now
return S_OK;
} // MLANG_ConvertInetReset
//---------------------------------------------------------------------------------
// Function: MLANG_ConvertInetString
//
// Purpose:
// This function is a wrapper function which passes its arguments through to
// MLANG's ConvertInetString.
//
// Arguments:
// Same as for MLANG.DLL's ConvertInetString.
//
// Returns:
// Same as for MLANG.DLL's ConvertInetString.
//---------------------------------------------------------------------------------
HRESULT CMimeInternational::MLANG_ConvertInetString(CODEPAGEID cpiSource,
CODEPAGEID cpiDest,
LPCSTR pSourceStr,
LPINT pnSizeOfSourceStr,
LPSTR pDestinationStr,
LPINT pnSizeOfDestBuffer)
{
HRESULT hrResult;
// Codify Assumptions
Assert(sizeof(UCHAR) == sizeof(char));
// Pass the arguments through
return ConvertINetString(NULL, cpiSource, cpiDest, (LPCSTR)pSourceStr, pnSizeOfSourceStr, (LPSTR) pDestinationStr, pnSizeOfDestBuffer);
} // MLANG_ConvertInetString
// --------------------------------------------------------------------------------
// CMimeInternational::DecodeHeader ANSI -> (ANSI or UNICODE)
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::DecodeHeader(HCHARSET hCharset, LPCSTR pszData,
LPPROPVARIANT pDecoded, LPRFC1522INFO pRfc1522Info)
{
// Locals
HRESULT hr=S_OK;
MIMEVARIANT rSource;
MIMEVARIANT rDest;
// Invalid Arg
if (NULL == pszData || NULL == pDecoded || (VT_LPSTR != pDecoded->vt && VT_LPWSTR != pDecoded->vt))
return TrapError(E_INVALIDARG);
// Setup Source
rSource.type = MVT_STRINGA;
rSource.rStringA.pszVal = (LPSTR)pszData;
rSource.rStringA.cchVal = lstrlen(pszData);
// Setup Destination
rDest.type = (VT_LPSTR == pDecoded->vt) ? MVT_STRINGA : MVT_STRINGW;
// Valid Charset
if (hCharset && HCSETVALID(hCharset) == FALSE)
{
hr = TrapError(MIME_E_INVALID_HANDLE);
goto exit;
}
// HrDecodeHeader
hr = HrDecodeHeader((NULL == hCharset) ? NULL : PCsetFromHCset(hCharset), pRfc1522Info, &rSource, &rDest);
if (FAILED(hr))
goto exit;
// Put rDest into pDecoded
if (MVT_STRINGA == rDest.type)
pDecoded->pszVal = rDest.rStringA.pszVal;
else
pDecoded->pwszVal = rDest.rStringW.pszVal;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::EncodeHeader
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::EncodeHeader(HCHARSET hCharset, LPPROPVARIANT pData,
LPSTR *ppszEncoded, LPRFC1522INFO pRfc1522Info)
{
// Locals
HRESULT hr=S_OK;
MIMEVARIANT rSource;
MIMEVARIANT rDest;
// Invalid Arg
if (NULL == pData || NULL == ppszEncoded || (VT_LPSTR != pData->vt && VT_LPWSTR != pData->vt))
return TrapError(E_INVALIDARG);
// Init
*ppszEncoded = NULL;
// VT_LPSTR
if (VT_LPSTR == pData->vt)
{
rSource.type = MVT_STRINGA;
rSource.rStringA.pszVal = pData->pszVal;
rSource.rStringA.cchVal = lstrlen(pData->pszVal);
}
// VT_LPWSTR
else
{
rSource.type = MVT_STRINGW;
rSource.rStringW.pszVal = pData->pwszVal;
rSource.rStringW.cchVal = lstrlenW(pData->pwszVal);
}
// Setup Destination
rDest.type = MVT_STRINGA;
// Valid Charset
if (hCharset && HCSETVALID(hCharset) == FALSE)
{
hr = TrapError(MIME_E_INVALID_HANDLE);
goto exit;
}
// HrDecodeHeader
hr = HrEncodeHeader((NULL == hCharset) ? NULL : PCsetFromHCset(hCharset), pRfc1522Info, &rSource, &rDest);
if (FAILED(hr))
goto exit;
// Put rDest into pDecoded
*ppszEncoded = rDest.rStringA.pszVal;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::Rfc1522Decode
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::Rfc1522Decode(LPCSTR pszValue, LPSTR pszCharset, ULONG cchmax, LPSTR *ppszDecoded)
{
return MimeOleRfc1522Decode(pszValue, pszCharset, cchmax, ppszDecoded);
}
// --------------------------------------------------------------------------------
// CMimeInternational::Rfc1522Encode
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeInternational::Rfc1522Encode(LPCSTR pszValue, HCHARSET hCharset, LPSTR *ppszEncoded)
{
return MimeOleRfc1522Encode(pszValue, hCharset, ppszEncoded);
}
// --------------------------------------------------------------------------------
// CMimeInternational::FIsValidHandle
// --------------------------------------------------------------------------------
BOOL CMimeInternational::FIsValidHandle(HCHARSET hCharset)
{
m_lock.ShareLock();
BOOL f = HCSETVALID(hCharset);
m_lock.ShareUnlock();
return f;
}
// --------------------------------------------------------------------------------
// CMimeInternational::IsDBCSCharset
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::IsDBCSCharset(HCHARSET hCharset)
{
// Locals
HRESULT hr=S_OK;
LPINETCSETINFO pCsetInfo;
// Invlaid Handle
if (HCSETVALID(hCharset) == FALSE)
{
hr = TrapError(MIME_E_INVALID_HANDLE);
goto exit;
}
// Get the charset info
pCsetInfo = PCsetFromHCset(hCharset);
// Special Cases
if (pCsetInfo->cpiWindows == CP_JAUTODETECT ||
pCsetInfo->cpiWindows == CP_KAUTODETECT ||
pCsetInfo->cpiWindows == CP_ISO2022JPESC ||
pCsetInfo->cpiWindows == CP_ISO2022JPSIO)
{
hr = S_OK;
goto exit;
}
// Is Windows Code Page DBCS ?
hr = (IsDBCSCodePage(pCsetInfo->cpiWindows) == TRUE) ? S_OK : S_FALSE;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrEncodeProperty
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrEncodeProperty(LPVARIANTCONVERT pConvert, LPMIMEVARIANT pSource,
LPMIMEVARIANT pDest)
{
// Locals
HRESULT hr=S_OK;
RFC1522INFO rRfc1522Info;
MIMEVARIANT rSource;
// Invalid Arg
Assert(pConvert && pConvert->pSymbol && pConvert->pCharset && pConvert->pOptions && pSource && pDest);
Assert(ISFLAGSET(pConvert->pSymbol->dwFlags, MPF_INETCSET));
Assert(pConvert->ietSource == IET_ENCODED || pConvert->ietSource == IET_DECODED);
// Init
ZeroMemory(&rSource, sizeof(MIMEVARIANT));
// Setup Rfc1522 Info
ZeroMemory(&rRfc1522Info, sizeof(RFC1522INFO));
rRfc1522Info.fRfc1522Allowed = ISFLAGSET(pConvert->pSymbol->dwFlags, MPF_RFC1522);
rRfc1522Info.fAllow8bit = (SAVE_RFC1521 == pConvert->pOptions->savetype) ? pConvert->pOptions->fAllow8bit : TRUE;
// If Property is Encoded, decode it first
if (IET_ENCODED == pConvert->ietSource)
{
// Set rSource.type
rSource.type = pDest->type;
// Decode It
hr = HrDecodeHeader(pConvert->pCharset, &rRfc1522Info, pSource, &rSource);
if (FAILED(hr))
goto exit;
}
// Otherwise, use pSource as rSource
else
{
// Setup Source
CopyMemory(&rSource, pSource, sizeof(MIMEVARIANT));
rSource.fCopy = TRUE;
}
// HrEncodeHeader
hr = HrEncodeHeader(pConvert->pCharset, &rRfc1522Info, &rSource, pDest);
if (FAILED(hr))
goto exit;
// Set PRSTATE_RFC1511
if (rRfc1522Info.fRfc1522Used)
FLAGSET(pConvert->dwState, PRSTATE_RFC1522);
exit:
// Cleanup
MimeVariantFree(&rSource);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrDecodeProperty
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrDecodeProperty(LPVARIANTCONVERT pConvert, LPMIMEVARIANT pSource,
LPMIMEVARIANT pDest)
{
// Locals
RFC1522INFO rRfc1522Info;
// Invalid Arg
Assert(pConvert && pConvert->pSymbol && pConvert->pCharset && pConvert->pOptions && pSource && pDest);
Assert(ISFLAGSET(pConvert->pSymbol->dwFlags, MPF_INETCSET) && pConvert->ietSource == IET_ENCODED);
// Setup Rfc1522 Info
ZeroMemory(&rRfc1522Info, sizeof(RFC1522INFO));
rRfc1522Info.fRfc1522Allowed = ISFLAGSET(pConvert->pSymbol->dwFlags, MPF_RFC1522);
rRfc1522Info.fAllow8bit = (SAVE_RFC1521 == pConvert->pOptions->savetype) ? pConvert->pOptions->fAllow8bit : TRUE;
// HrDecodeHeader
return HrDecodeHeader(pConvert->pCharset, &rRfc1522Info, pSource, pDest);
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrWideCharToMultiByte
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrWideCharToMultiByte(CODEPAGEID cpiCodePage, LPCPROPSTRINGW pStringW,
LPPROPSTRINGA pStringA)
{
// Locals
HRESULT hr=S_OK;
// Invalid Arg
Assert(ISVALIDSTRINGW(pStringW) && pStringA);
// Adjust cpiCodePage
if (CP_UNICODE == cpiCodePage)
cpiCodePage = CP_ACP;
// Init
pStringA->pszVal = NULL;
pStringA->cchVal = 0;
// Determine how much space is needed for translated widechar
pStringA->cchVal = ::WideCharToMultiByte(cpiCodePage, 0, pStringW->pszVal, pStringW->cchVal, NULL, 0, NULL, NULL);
if (pStringA->cchVal == 0 && pStringW->cchVal != 0)
{
DOUTL(4, "WideCharToMultiByte Failed - CodePageID = %d, GetLastError = %d\n", cpiCodePage, GetLastError());
// WideCharToMultiByte failed for some other reason than cpiCodePage being a bad codepage
if (TRUE == IsValidCodePage(cpiCodePage))
{
hr = TrapError(E_FAIL);
goto exit;
}
// Reset cpiCodePage to a valid codepage
cpiCodePage = CP_ACP;
// Use the system acp
pStringA->cchVal = ::WideCharToMultiByte(cpiCodePage, 0, pStringW->pszVal, pStringW->cchVal, NULL, 0, NULL, NULL);
if (pStringA->cchVal == 0)
{
hr = TrapError(E_FAIL);
goto exit;
}
}
// Allocate It
CHECKALLOC(pStringA->pszVal = (LPSTR)g_pMalloc->Alloc((pStringA->cchVal + 1)));
// Do the actual translation
pStringA->cchVal = ::WideCharToMultiByte(cpiCodePage, 0, pStringW->pszVal, pStringW->cchVal, pStringA->pszVal, pStringA->cchVal + 1, NULL, NULL);
if (pStringA->cchVal == 0 && pStringW->cchVal != 0)
{
DOUTL(4, "WideCharToMultiByte Failed - CodePageID = %d, GetLastError = %d\n", cpiCodePage, GetLastError());
hr = TrapError(E_FAIL);
goto exit;
}
// Insert the Null
pStringA->pszVal[pStringA->cchVal] = '\0';
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CMimeInternational::HrMultiByteToWideChar
// --------------------------------------------------------------------------------
HRESULT CMimeInternational::HrMultiByteToWideChar(CODEPAGEID cpiCodePage, LPCPROPSTRINGA pStringA,
LPPROPSTRINGW pStringW)
{
// Locals
HRESULT hr=S_OK;
// Invalid Arg
// Bad codepage is okay and will be dealt with below
Assert(ISVALIDSTRINGA(pStringA) && pStringW);
// Adjust cpiCodePage
if (CP_UNICODE == cpiCodePage)
cpiCodePage = CP_ACP;
// Init
pStringW->pszVal = NULL;
pStringW->cchVal = 0;
// Determine how much space is needed for translated widechar
pStringW->cchVal = ::MultiByteToWideChar(cpiCodePage, MB_PRECOMPOSED, pStringA->pszVal, pStringA->cchVal, NULL, 0);
if (pStringW->cchVal == 0 && pStringA->cchVal != 0)
{
DOUTL(4, "MultiByteToWideChar Failed - CodePageID = %d, GetLastError = %d\n", cpiCodePage, GetLastError());
// MultiByteToWideChar failed for some other reason than cpiCodePage being a bad codepage
if (TRUE == IsValidCodePage(cpiCodePage))
{
hr = TrapError(E_FAIL);
goto exit;
}
// Reset cpiCodePage to a valid codepage
cpiCodePage = CP_ACP;
// Use the system acp
pStringW->cchVal = ::MultiByteToWideChar(cpiCodePage, MB_PRECOMPOSED, pStringA->pszVal, pStringA->cchVal, NULL, 0);
if (pStringW->cchVal == 0)
{
hr = TrapError(E_FAIL);
goto exit;
}
}
// Allocate It
CHECKALLOC(pStringW->pszVal = (LPWSTR)g_pMalloc->Alloc((pStringW->cchVal + 1) * sizeof(WCHAR)));
// Do the actual translation
pStringW->cchVal = ::MultiByteToWideChar(cpiCodePage, MB_PRECOMPOSED, pStringA->pszVal, pStringA->cchVal, pStringW->pszVal, pStringW->cchVal + 1);
if (pStringW->cchVal == 0 && pStringA->cchVal != 0)
{
DOUTL(4, "MultiByteToWideChar Failed - CodePageID = %d, GetLastError = %d\n", cpiCodePage, GetLastError());
hr = TrapError(E_FAIL);
goto exit;
}
// Insert the Null
pStringW->pszVal[pStringW->cchVal] = L'\0';
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
void CIntlGlobals::Init()
{
mg_bInit = FALSE;
InitializeCriticalSection(&mg_cs);
mg_pDefBodyCset = NULL;
mg_pDefHeadCset = NULL;
}
void CIntlGlobals::Term()
{
DeleteCriticalSection(&mg_cs);
}
void CIntlGlobals::DoInit()
{
if (!mg_bInit)
{
EnterCriticalSection(&mg_cs);
if (!mg_bInit)
{
// Locals
CODEPAGEID cpiSystem;
// Get the system codepage
cpiSystem = GetACP();
// Get the default body charset
if (FAILED(g_pInternat->HrOpenCharset(cpiSystem, CHARSET_BODY, &mg_pDefBodyCset)))
mg_pDefBodyCset = &mg_rDefaultCharset;
// Get the Default Header Charset
if (FAILED(g_pInternat->HrOpenCharset(cpiSystem, CHARSET_HEADER, &mg_pDefHeadCset)))
mg_pDefHeadCset = mg_pDefBodyCset;
mg_bInit = TRUE;
}
LeaveCriticalSection(&mg_cs);
}
}
LPINETCSETINFO CIntlGlobals::GetDefBodyCset()
{
DoInit();
Assert(mg_pDefBodyCset);
return (mg_pDefBodyCset);
}
LPINETCSETINFO CIntlGlobals::GetDefHeadCset()
{
DoInit();
Assert(mg_pDefHeadCset);
return (mg_pDefHeadCset);
}
LPINETCSETINFO CIntlGlobals::GetDefaultCharset()
{
DoInit();
return (&mg_rDefaultCharset);
}
void CIntlGlobals::SetDefBodyCset(LPINETCSETINFO pCharset)
{
DoInit();
mg_pDefBodyCset = pCharset;
}
void CIntlGlobals::SetDefHeadCset(LPINETCSETINFO pCharset)
{
DoInit();
mg_pDefHeadCset = pCharset;
}
BOOL CIntlGlobals::mg_bInit = FALSE;
LPINETCSETINFO CIntlGlobals::mg_pDefBodyCset = NULL;
LPINETCSETINFO CIntlGlobals::mg_pDefHeadCset = NULL;
CRITICAL_SECTION CIntlGlobals::mg_cs;