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.
2180 lines
63 KiB
2180 lines
63 KiB
// --------------------------------------------------------------------------------
|
|
// 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;
|