|
|
// --------------------------------------------------------------------------------
// 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;
|