Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2180 lines
63 KiB

  1. // --------------------------------------------------------------------------------
  2. // Internat.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "dllmain.h"
  8. #include "internat.h"
  9. #include "variantx.h"
  10. #include "containx.h"
  11. #include "symcache.h"
  12. #include "icoint.h"
  13. #include "mlang.h"
  14. #include "demand.h"
  15. #include "strconst.h"
  16. #include "mimeapi.h"
  17. #include "shlwapi.h"
  18. #include "shlwapip.h"
  19. #include "qstrcmpi.h"
  20. // In rfc1522.cpp
  21. BOOL FContainsExtended(LPPROPSTRINGA pStringA, ULONG *pcExtended);
  22. // --------------------------------------------------------------------------------
  23. // Global Default Charset - This is only used if mlang is not installed
  24. // --------------------------------------------------------------------------------
  25. INETCSETINFO CIntlGlobals::mg_rDefaultCharset = {
  26. "ISO-8859-1",
  27. NULL,
  28. 1252,
  29. 28591,
  30. 0
  31. };
  32. // --------------------------------------------------------------------------------
  33. // InitInternational
  34. // --------------------------------------------------------------------------------
  35. void InitInternational(void)
  36. {
  37. // Allocate g_pInternat
  38. g_pInternat = new CMimeInternational;
  39. if (NULL == g_pInternat)
  40. {
  41. AssertSz(FALSE, "Unable to allocate g_pInternat.");
  42. return;
  43. }
  44. CIntlGlobals::Init();
  45. }
  46. // --------------------------------------------------------------------------------
  47. // CMimeInternational::CMimeInternational
  48. // --------------------------------------------------------------------------------
  49. CMimeInternational::CMimeInternational(void)
  50. {
  51. // Var Init
  52. m_cRef = 1;
  53. ZeroMemory(&m_cst, sizeof(CSTABLE));
  54. ZeroMemory(&m_cpt, sizeof(CPTABLE));
  55. // Init HCHARSET tagger, don't let it be zero
  56. m_wTag = LOWORD(GetTickCount());
  57. while(m_wTag == 0 || m_wTag == 0xffff)
  58. m_wTag++;
  59. // BUGS - temporary solution for MLANG new API - m_dwConvState
  60. m_dwConvState = 0 ;
  61. }
  62. // --------------------------------------------------------------------------------
  63. // CMimeInternational::~CMimeInternational
  64. // --------------------------------------------------------------------------------
  65. CMimeInternational::~CMimeInternational(void)
  66. {
  67. // Clean up globals
  68. CIntlGlobals::Term();
  69. // Free data
  70. _FreeInetCsetTable();
  71. _FreeCodePageTable();
  72. }
  73. // --------------------------------------------------------------------------------
  74. // CMimeInternational::QueryInterface
  75. // --------------------------------------------------------------------------------
  76. STDMETHODIMP CMimeInternational::QueryInterface(REFIID riid, LPVOID *ppv)
  77. {
  78. // check params
  79. if (ppv == NULL)
  80. return TrapError(E_INVALIDARG);
  81. // Find IID
  82. if (IID_IUnknown == riid)
  83. *ppv = (IUnknown *)this;
  84. else if (IID_IMimeInternational == riid)
  85. *ppv = (IMimeInternational *)this;
  86. else
  87. {
  88. *ppv = NULL;
  89. return TrapError(E_NOINTERFACE);
  90. }
  91. // AddRef It
  92. ((IUnknown *)*ppv)->AddRef();
  93. // Done
  94. return S_OK;
  95. }
  96. // --------------------------------------------------------------------------------
  97. // CMimeInternational::AddRef
  98. // --------------------------------------------------------------------------------
  99. STDMETHODIMP_(ULONG) CMimeInternational::AddRef(void)
  100. {
  101. // Raid 26762
  102. DllAddRef();
  103. return (ULONG)InterlockedIncrement(&m_cRef);
  104. }
  105. // --------------------------------------------------------------------------------
  106. // CMimeInternational::Release
  107. // --------------------------------------------------------------------------------
  108. STDMETHODIMP_(ULONG) CMimeInternational::Release(void)
  109. {
  110. // Raid 26762
  111. LONG cRef = InterlockedDecrement(&m_cRef);
  112. if (0 == cRef)
  113. delete this;
  114. else
  115. DllRelease();
  116. return (ULONG)cRef;
  117. }
  118. // -------------------------------------------------------------------------
  119. // CMimeInternational::_FreeInetCsetTable
  120. // -------------------------------------------------------------------------
  121. void CMimeInternational::_FreeInetCsetTable(void)
  122. {
  123. // Free Each Charset
  124. for (ULONG i=0; i<m_cst.cCharsets; i++)
  125. g_pMalloc->Free((LPVOID)m_cst.prgpCharset[i]);
  126. // Free the Array
  127. SafeMemFree(m_cst.prgpCharset);
  128. // Clear the Table
  129. ZeroMemory(&m_cst, sizeof(CSTABLE));
  130. }
  131. // -------------------------------------------------------------------------
  132. // CMimeInternational::_FreeCodePageTable
  133. // -------------------------------------------------------------------------
  134. void CMimeInternational::_FreeCodePageTable(void)
  135. {
  136. // Free Each Charset
  137. for (ULONG i=0; i<m_cpt.cPages; i++)
  138. g_pMalloc->Free((LPVOID)m_cpt.prgpPage[i]);
  139. // Free the Array
  140. SafeMemFree(m_cpt.prgpPage);
  141. // Clear the Table
  142. ZeroMemory(&m_cpt, sizeof(CPTABLE));
  143. }
  144. // -------------------------------------------------------------------------
  145. // CMimeInternational::HrOpenCharset
  146. // -------------------------------------------------------------------------
  147. HRESULT CMimeInternational::HrOpenCharset(LPCSTR pszCharset, LPINETCSETINFO *ppCharset)
  148. {
  149. // Locals
  150. HRESULT hr=S_OK;
  151. LONG lUpper,
  152. lLower,
  153. lMiddle,
  154. nCompare;
  155. ULONG i;
  156. BOOL fExcLock;
  157. fExcLock = FALSE;
  158. // Invalid Arg
  159. Assert(pszCharset && ppCharset);
  160. // Init
  161. *ppCharset = NULL;
  162. // Thread Safety
  163. m_lock.ShareLock();
  164. again:
  165. // Do we have anything yet
  166. if (m_cst.cCharsets > 0)
  167. {
  168. // Set lLower and lUpper
  169. lLower = 0;
  170. lUpper = m_cst.cCharsets - 1;
  171. // Do binary search / insert
  172. while (lLower <= lUpper)
  173. {
  174. // Compute middle record to compare against
  175. lMiddle = (LONG)((lLower + lUpper) / 2);
  176. // Get string to compare against
  177. i = m_cst.prgpCharset[lMiddle]->dwReserved1;
  178. // Do compare
  179. nCompare = OEMstrcmpi(pszCharset, m_cst.prgpCharset[i]->szName);
  180. // If Equal, then were done
  181. if (nCompare == 0)
  182. {
  183. *ppCharset = m_cst.prgpCharset[i];
  184. goto exit;
  185. }
  186. // Compute upper and lower
  187. if (nCompare > 0)
  188. lLower = lMiddle + 1;
  189. else
  190. lUpper = lMiddle - 1;
  191. }
  192. }
  193. if(FALSE == fExcLock)
  194. {
  195. m_lock.ShareUnlock(); //Release the Sharelock before
  196. m_lock.ExclusiveLock(); //getting the exclusive lock
  197. fExcLock = TRUE;
  198. //during the change of lock the value might have changed
  199. //check it again
  200. goto again;
  201. }
  202. // Not found, lets open the registry
  203. CHECKHR(hr = _HrReadCsetInfo(pszCharset, ppCharset));
  204. exit:
  205. // Thread Safety
  206. if(TRUE==fExcLock)
  207. m_lock.ExclusiveUnlock();
  208. else
  209. m_lock.ShareUnlock();
  210. // Done
  211. return hr;
  212. }
  213. // -------------------------------------------------------------------------
  214. // CMimeInternational::_HrReadCsetInfo
  215. // -------------------------------------------------------------------------
  216. HRESULT CMimeInternational::_HrReadCsetInfo(LPCSTR pszCharset, LPINETCSETINFO *ppCharset)
  217. {
  218. // Locals
  219. HRESULT hr=S_OK;
  220. LPINETCSETINFO pCharset=NULL;
  221. IMultiLanguage *pMLang1 = NULL;
  222. IMultiLanguage2 *pMLang2 = NULL;
  223. MIMECSETINFO mciInfo;
  224. BSTR strCharset = NULL;
  225. int iRes;
  226. // Invalid Arg
  227. Assert(pszCharset && ppCharset);
  228. // Init
  229. *ppCharset = NULL;
  230. // Try to create an IMultiLanguage2 interface
  231. // If we are in OE5 compat mode...
  232. if (TRUE == ISFLAGSET(g_dwCompatMode, MIMEOLE_COMPAT_MLANG2))
  233. {
  234. hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage2, (LPVOID *) &pMLang2);
  235. if (!SUCCEEDED(hr))
  236. {
  237. // Ok that failed, so lets try to create an IMultiLanaguage interface
  238. hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage, (LPVOID *) &pMLang1);
  239. if (!SUCCEEDED(hr))
  240. {
  241. TrapError(hr);
  242. goto exit;
  243. }
  244. }
  245. }
  246. else
  247. {
  248. // Ok that failed, so lets try to create an IMultiLanaguage interface
  249. hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage, (LPVOID *) &pMLang1);
  250. if (!SUCCEEDED(hr))
  251. {
  252. TrapError(hr);
  253. goto exit;
  254. }
  255. }
  256. // MLANG wants the charset name as a BSTR, so we need to convert it from ANSI...
  257. strCharset = SysAllocStringLen(NULL,lstrlen(pszCharset));
  258. if (!strCharset)
  259. {
  260. hr = TrapError(E_OUTOFMEMORY);
  261. goto exit;
  262. }
  263. iRes = MultiByteToWideChar(CP_ACP,0,pszCharset,-1,strCharset,SysStringLen(strCharset)+1);
  264. if (iRes == 0)
  265. {
  266. hr = HRESULT_FROM_WIN32(GetLastError());
  267. if (SUCCEEDED(hr))
  268. {
  269. hr = E_FAIL;
  270. }
  271. TrapError(hr);
  272. goto exit;
  273. }
  274. // Use pMLang2
  275. if (pMLang2)
  276. {
  277. // Use mlang2
  278. hr = pMLang2->GetCharsetInfo(strCharset, &mciInfo);
  279. if (!SUCCEEDED(hr))
  280. {
  281. TrapError(hr);
  282. hr = MIME_E_NOT_FOUND;
  283. goto exit;
  284. }
  285. }
  286. else
  287. {
  288. // Now just call MLANG to get the info...
  289. hr = pMLang1->GetCharsetInfo(strCharset, &mciInfo);
  290. if (!SUCCEEDED(hr))
  291. {
  292. TrapError(hr);
  293. hr = MIME_E_NOT_FOUND;
  294. goto exit;
  295. }
  296. }
  297. // Add a new entry into the language table
  298. if (m_cst.cCharsets + 1 >= m_cst.cAlloc)
  299. {
  300. // Reallocate the array
  301. CHECKHR(hr = HrRealloc((LPVOID *)&m_cst.prgpCharset, sizeof(LPINETCSETINFO) * (m_cst.cAlloc + 5)));
  302. // Increment Alloc
  303. m_cst.cAlloc += 5;
  304. }
  305. // Allocate a Charset
  306. CHECKALLOC(pCharset = (LPINETCSETINFO)g_pMalloc->Alloc(sizeof(INETCSETINFO)));
  307. // Initialize
  308. ZeroMemory(pCharset, sizeof(INETCSETINFO));
  309. // Set Sort Index
  310. pCharset->dwReserved1 = m_cst.cCharsets;
  311. // Set HCharset
  312. pCharset->hCharset = HCSETMAKE(m_cst.cCharsets);
  313. // Read Data
  314. StrCpyN(pCharset->szName, pszCharset, ARRAYSIZE(pCharset->szName));
  315. pCharset->cpiInternet = mciInfo.uiInternetEncoding;
  316. pCharset->cpiWindows = mciInfo.uiCodePage;
  317. // Readability
  318. m_cst.prgpCharset[m_cst.cCharsets] = pCharset;
  319. // Return it
  320. *ppCharset = pCharset;
  321. // Don't Free It
  322. pCharset = NULL;
  323. // Increment Count
  324. m_cst.cCharsets++;
  325. // Let Sort the cset table
  326. _QuickSortCsetInfo(0, m_cst.cCharsets - 1);
  327. exit:
  328. // Cleanup
  329. SafeRelease(pMLang1);
  330. SafeRelease(pMLang2);
  331. if (strCharset)
  332. {
  333. SysFreeString(strCharset);
  334. }
  335. SafeMemFree(pCharset);
  336. // Done
  337. return hr;
  338. }
  339. // --------------------------------------------------------------------------------
  340. // CMimeInternational::_QuickSortCsetInfo
  341. // --------------------------------------------------------------------------------
  342. void CMimeInternational::_QuickSortCsetInfo(long left, long right)
  343. {
  344. // Locals
  345. register long i, j;
  346. DWORD k, temp;
  347. i = left;
  348. j = right;
  349. k = m_cst.prgpCharset[(i + j) / 2]->dwReserved1;
  350. do
  351. {
  352. while(OEMstrcmpi(m_cst.prgpCharset[m_cst.prgpCharset[i]->dwReserved1]->szName, m_cst.prgpCharset[k]->szName) < 0 && i < right)
  353. i++;
  354. while (OEMstrcmpi(m_cst.prgpCharset[m_cst.prgpCharset[j]->dwReserved1]->szName, m_cst.prgpCharset[k]->szName) > 0 && j > left)
  355. j--;
  356. if (i <= j)
  357. {
  358. temp = m_cst.prgpCharset[i]->dwReserved1;
  359. m_cst.prgpCharset[i]->dwReserved1 = m_cst.prgpCharset[j]->dwReserved1;
  360. m_cst.prgpCharset[j]->dwReserved1 = temp;
  361. i++; j--;
  362. }
  363. } while (i <= j);
  364. if (left < j)
  365. _QuickSortCsetInfo(left, j);
  366. if (i < right)
  367. _QuickSortCsetInfo(i, right);
  368. }
  369. // --------------------------------------------------------------------------------
  370. // CMimeInternational::HrOpenCharset
  371. // --------------------------------------------------------------------------------
  372. HRESULT CMimeInternational::HrOpenCharset(HCHARSET hCharset, LPINETCSETINFO *ppCharset)
  373. {
  374. // Invalid Arg
  375. Assert(hCharset && ppCharset);
  376. // Init
  377. *ppCharset = NULL;
  378. // Invalid Handle
  379. if (HCSETVALID(hCharset) == FALSE)
  380. return TrapError(MIME_E_INVALID_HANDLE);
  381. // Deref
  382. *ppCharset = PCsetFromHCset(hCharset);
  383. // Done
  384. return S_OK;
  385. }
  386. // --------------------------------------------------------------------------------
  387. // CMimeInternational::HrFindCodePage
  388. // --------------------------------------------------------------------------------
  389. HRESULT CMimeInternational::HrFindCodePage(CODEPAGEID cpiCodePage, LPCODEPAGEINFO *ppCodePage)
  390. {
  391. // Locals
  392. HRESULT hr=S_OK;
  393. LONG lUpper,
  394. lLower,
  395. lMiddle,
  396. nCompare;
  397. BOOL fExcLock;
  398. fExcLock = FALSE;
  399. // Invalid Arg
  400. Assert(ppCodePage);
  401. // Init
  402. *ppCodePage = NULL;
  403. // Thread Safety
  404. m_lock.ShareLock();
  405. again:
  406. // Do We have anything yet
  407. if (m_cpt.cPages > 0)
  408. {
  409. // Set lLower and lUpper
  410. lLower = 0;
  411. lUpper = m_cpt.cPages - 1;
  412. // Do binary search / insert
  413. while (lLower <= lUpper)
  414. {
  415. // Compute middle record to compare against
  416. lMiddle = (LONG)((lLower + lUpper) / 2);
  417. // If Equal, then were done
  418. if (cpiCodePage == m_cpt.prgpPage[lMiddle]->cpiCodePage)
  419. {
  420. *ppCodePage = m_cpt.prgpPage[lMiddle];
  421. goto exit;
  422. }
  423. // Compute upper and lower
  424. if (cpiCodePage > m_cpt.prgpPage[lMiddle]->cpiCodePage)
  425. lLower = lMiddle + 1;
  426. else
  427. lUpper = lMiddle - 1;
  428. }
  429. }
  430. if(FALSE == fExcLock)
  431. {
  432. m_lock.ShareUnlock(); //Release the Sharelock before
  433. m_lock.ExclusiveLock(); //getting the exclusive lock
  434. fExcLock = TRUE;
  435. //during the change of lock the value might have changed
  436. //check it again
  437. goto again;
  438. }
  439. // Not found, lets open the registry
  440. CHECKHR(hr = _HrReadPageInfo(cpiCodePage, ppCodePage));
  441. exit:
  442. // Thread Safety
  443. if(TRUE==fExcLock)
  444. m_lock.ExclusiveUnlock();
  445. else
  446. m_lock.ShareUnlock();
  447. // Done
  448. return hr;
  449. }
  450. HRESULT convert_mimecpinfo_element(LPCWSTR pszFrom,
  451. LPSTR pszTo,
  452. DWORD cchTo,
  453. DWORD& refdwFlags,
  454. DWORD dwFlag) {
  455. HRESULT hr = S_OK;
  456. int iRes;
  457. if (pszFrom[0]) {
  458. iRes = WideCharToMultiByte(CP_ACP,
  459. 0,
  460. pszFrom,
  461. -1,
  462. pszTo,
  463. cchTo,
  464. NULL,
  465. NULL);
  466. if (iRes == 0) {
  467. hr = HRESULT_FROM_WIN32(GetLastError());
  468. if (SUCCEEDED(hr)) {
  469. hr = E_FAIL;
  470. }
  471. } else {
  472. FLAGSET(refdwFlags,dwFlag);
  473. }
  474. }
  475. return (hr);
  476. }
  477. #define CONVERT_MIMECPINFO_ELEMENT(__FROM__,__TO__,__FLAG__) \
  478. hr = convert_mimecpinfo_element(cpinfo.__FROM__, \
  479. pCodePage->__TO__, \
  480. sizeof(pCodePage->__TO__)/sizeof(pCodePage->__TO__[0]), \
  481. pCodePage->dwMask, \
  482. __FLAG__); \
  483. if (!SUCCEEDED(hr)) { \
  484. TrapError(hr); \
  485. goto exit; \
  486. }
  487. // -------------------------------------------------------------------------
  488. // CMimeInternational::_HrReadPageInfo
  489. // -------------------------------------------------------------------------
  490. HRESULT CMimeInternational::_HrReadPageInfo(CODEPAGEID cpiCodePage, LPCODEPAGEINFO *ppCodePage)
  491. {
  492. // Locals
  493. HRESULT hr=S_OK;
  494. LPCODEPAGEINFO pCodePage=NULL;
  495. MIMECPINFO cpinfo;
  496. IMultiLanguage *pMLang1=NULL;
  497. IMultiLanguage2 *pMLang2=NULL;
  498. int iRes;
  499. // Invalid Arg
  500. Assert(ppCodePage);
  501. // Init
  502. *ppCodePage = NULL;
  503. // Try to create an IMultiLanguage2 interface
  504. // If we are in OE5 compat mode...
  505. if (TRUE == ISFLAGSET(g_dwCompatMode, MIMEOLE_COMPAT_MLANG2))
  506. {
  507. hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage2, (LPVOID *) &pMLang2);
  508. if (!SUCCEEDED(hr))
  509. {
  510. // Ok that failed, so lets try to create an IMultiLanaguage interface
  511. hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage, (LPVOID *) &pMLang1);
  512. if (!SUCCEEDED(hr))
  513. {
  514. TrapError(hr);
  515. goto exit;
  516. }
  517. }
  518. }
  519. else
  520. {
  521. hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage, (LPVOID *) &pMLang1);
  522. if (!SUCCEEDED(hr))
  523. {
  524. TrapError(hr);
  525. goto exit;
  526. }
  527. }
  528. // Use mlang2 ?
  529. if (pMLang2)
  530. {
  531. // use mlang2
  532. hr = pMLang2->GetCodePageInfo(cpiCodePage, MLGetUILanguage(), &cpinfo);
  533. if (!SUCCEEDED(hr))
  534. {
  535. TrapError(hr);
  536. hr = MIME_E_NOT_FOUND; // tbd - MLang doesn't define good error codes, so...
  537. goto exit;
  538. }
  539. }
  540. // Otherwise use ie4 mlang
  541. else
  542. {
  543. // use mlang1
  544. hr = pMLang1->GetCodePageInfo(cpiCodePage, &cpinfo);
  545. if (!SUCCEEDED(hr))
  546. {
  547. TrapError(hr);
  548. hr = MIME_E_NOT_FOUND; // tbd - MLang doesn't define good error codes, so...
  549. goto exit;
  550. }
  551. }
  552. // Add a new entry into the language table
  553. if (m_cpt.cPages + 1 >= m_cpt.cAlloc)
  554. {
  555. // Reallocate the array
  556. CHECKHR(hr = HrRealloc((LPVOID *)&m_cpt.prgpPage, sizeof(LPCODEPAGEINFO) * (m_cpt.cAlloc + 5)));
  557. // Increment Alloc
  558. m_cpt.cAlloc += 5;
  559. }
  560. // Allocate Code Page Structure
  561. CHECKALLOC(pCodePage = (LPCODEPAGEINFO)g_pMalloc->Alloc(sizeof(CODEPAGEINFO)));
  562. // Initialize
  563. ZeroMemory(pCodePage, sizeof(CODEPAGEINFO));
  564. // Set Sort Index
  565. pCodePage->dwReserved1 = m_cpt.cPages;
  566. // Set Charset
  567. pCodePage->cpiCodePage = cpiCodePage;
  568. // IsValidCodePage
  569. pCodePage->fIsValidCodePage = IsValidCodePage(cpiCodePage);
  570. // Default
  571. pCodePage->ulMaxCharSize = 1;
  572. // Raid 43508: GetCPInfo faults in Kernal when passed an invalid codepage on Win95
  573. // if (pCodePage->fIsValidCodePage && GetCPInfo(pCodePage->cpiCodePage, &cpinfo))
  574. if (IsDBCSCodePage(cpiCodePage) || CP_UNICODE == cpiCodePage)
  575. pCodePage->ulMaxCharSize = 2;
  576. // c_szDescription
  577. CONVERT_MIMECPINFO_ELEMENT(wszDescription,szName,ILM_NAME)
  578. // c_szBodyCharset
  579. CONVERT_MIMECPINFO_ELEMENT(wszBodyCharset,szBodyCset,ILM_BODYCSET)
  580. // c_szHeaderCharset
  581. CONVERT_MIMECPINFO_ELEMENT(wszHeaderCharset,szHeaderCset,ILM_HEADERCSET)
  582. // c_szWebCharset
  583. CONVERT_MIMECPINFO_ELEMENT(wszWebCharset,szWebCset,ILM_WEBCSET)
  584. // c_szFixedWidthFont
  585. CONVERT_MIMECPINFO_ELEMENT(wszFixedWidthFont,szFixedFont,ILM_FIXEDFONT)
  586. // c_szProportionalFont
  587. CONVERT_MIMECPINFO_ELEMENT(wszProportionalFont,szVariableFont,ILM_VARIABLEFONT)
  588. // Set the Family CodePage
  589. pCodePage->cpiFamily = cpinfo.uiFamilyCodePage;
  590. // The family codepage is valid
  591. FLAGSET(pCodePage->dwMask,ILM_FAMILY);
  592. // See if this is an internet codepage
  593. if (cpinfo.uiFamilyCodePage != cpinfo.uiCodePage)
  594. pCodePage->fInternetCP = TRUE;
  595. // c_szMailMimeEncoding
  596. // tbd - not supported by IMultiLanguage
  597. pCodePage->ietMailDefault = IET_BINARY;
  598. // c_szNewsMimeEncoding
  599. // tbd - not supported by IMultiLanguage
  600. pCodePage->ietNewsDefault = IET_BINARY;
  601. // Readability
  602. m_cpt.prgpPage[m_cpt.cPages] = pCodePage;
  603. // Return it
  604. *ppCodePage = pCodePage;
  605. // Don't Free It
  606. pCodePage = NULL;
  607. // Increment Count
  608. m_cpt.cPages++;
  609. // Let Sort the lang table
  610. _QuickSortPageInfo(0, m_cpt.cPages - 1);
  611. exit:
  612. // Cleanup
  613. SafeRelease(pMLang1);
  614. SafeRelease(pMLang2);
  615. SafeMemFree(pCodePage);
  616. // Done
  617. return hr;
  618. }
  619. // --------------------------------------------------------------------------------
  620. // CMimeInternational::_QuickSortPageInfo
  621. // --------------------------------------------------------------------------------
  622. void CMimeInternational::_QuickSortPageInfo(long left, long right)
  623. {
  624. // Locals
  625. register long i, j;
  626. DWORD k, temp;
  627. i = left;
  628. j = right;
  629. k = m_cpt.prgpPage[(i + j) / 2]->dwReserved1;
  630. do
  631. {
  632. while(m_cpt.prgpPage[m_cpt.prgpPage[i]->dwReserved1]->cpiCodePage < m_cpt.prgpPage[k]->cpiCodePage && i < right)
  633. i++;
  634. while (m_cpt.prgpPage[m_cpt.prgpPage[j]->dwReserved1]->cpiCodePage > m_cpt.prgpPage[k]->cpiCodePage && j > left)
  635. j--;
  636. if (i <= j)
  637. {
  638. temp = m_cpt.prgpPage[i]->dwReserved1;
  639. m_cpt.prgpPage[i]->dwReserved1 = m_cpt.prgpPage[j]->dwReserved1;
  640. m_cpt.prgpPage[j]->dwReserved1 = temp;
  641. i++; j--;
  642. }
  643. } while (i <= j);
  644. if (left < j)
  645. _QuickSortPageInfo(left, j);
  646. if (i < right)
  647. _QuickSortPageInfo(i, right);
  648. }
  649. // --------------------------------------------------------------------------------
  650. // CMimeInternational::HrOpenCharset
  651. // --------------------------------------------------------------------------------
  652. HRESULT CMimeInternational::HrOpenCharset(CODEPAGEID cpiCodePage, CHARSETTYPE ctCsetType, LPINETCSETINFO *ppCharset)
  653. {
  654. // Locals
  655. HRESULT hr=S_OK;
  656. LPCODEPAGEINFO pCodePage;
  657. // Invalid Arg
  658. Assert(ppCharset);
  659. // Init
  660. *ppCharset = NULL;
  661. // Get the body charset
  662. CHECKHR(hr = HrFindCodePage(cpiCodePage, &pCodePage));
  663. // CHARSET_HEADER
  664. if (CHARSET_HEADER == ctCsetType)
  665. {
  666. // MIME_E_NO_DATA
  667. if (!ISFLAGSET(pCodePage->dwMask, ILM_HEADERCSET) || FIsEmptyA(pCodePage->szHeaderCset))
  668. {
  669. hr = MIME_E_NO_DATA;
  670. goto exit;
  671. }
  672. // Find the Handle
  673. CHECKHR(hr = HrOpenCharset(pCodePage->szHeaderCset, ppCharset));
  674. }
  675. // CHARSET_WEB
  676. else if (CHARSET_WEB == ctCsetType)
  677. {
  678. // MIME_E_NO_DATA
  679. if (!ISFLAGSET(pCodePage->dwMask, ILM_WEBCSET) || FIsEmptyA(pCodePage->szWebCset))
  680. {
  681. hr = MIME_E_NO_DATA;
  682. goto exit;
  683. }
  684. // Find the Handle
  685. CHECKHR(hr = HrOpenCharset(pCodePage->szWebCset, ppCharset));
  686. }
  687. // CHARSET_BODY
  688. else if (CHARSET_BODY == ctCsetType)
  689. {
  690. // MIME_E_NO_DATA
  691. if (!ISFLAGSET(pCodePage->dwMask, ILM_BODYCSET) || FIsEmptyA(pCodePage->szBodyCset))
  692. {
  693. hr = MIME_E_NO_DATA;
  694. goto exit;
  695. }
  696. // Find the Handle
  697. CHECKHR(hr = HrOpenCharset(pCodePage->szBodyCset, ppCharset));
  698. }
  699. // Error
  700. else
  701. {
  702. hr = TrapError(MIME_E_INVALID_CHARSET_TYPE);
  703. goto exit;
  704. }
  705. exit:
  706. // Done
  707. return hr;
  708. }
  709. // -------------------------------------------------------------------------
  710. // CMimeInternational::GetCodePageCharset
  711. // -------------------------------------------------------------------------
  712. STDMETHODIMP CMimeInternational::GetCodePageCharset(CODEPAGEID cpiCodePage, CHARSETTYPE ctCsetType, LPHCHARSET phCharset)
  713. {
  714. // Locals
  715. HRESULT hr=S_OK;
  716. LPINETCSETINFO pCharset;
  717. // Invalid Arg
  718. if (NULL == phCharset)
  719. return TrapError(E_INVALIDARG);
  720. // Init
  721. *phCharset = NULL;
  722. // Call Method
  723. CHECKHR(hr = HrOpenCharset(cpiCodePage, ctCsetType, &pCharset));
  724. // Return the Handle
  725. *phCharset = pCharset->hCharset;
  726. exit:
  727. // Done
  728. return hr;
  729. }
  730. // -------------------------------------------------------------------------
  731. // CMimeInternational::SetDefaultCharset
  732. // -------------------------------------------------------------------------
  733. STDMETHODIMP CMimeInternational::SetDefaultCharset(HCHARSET hCharset)
  734. {
  735. // Locals
  736. HRESULT hr=S_OK;
  737. LPINETCSETINFO pCharset;
  738. LPINETCSETINFO pDefHeadCset;
  739. // Invalid Arg
  740. if (NULL == hCharset)
  741. return TrapError(E_INVALIDARG);
  742. // Thread Safety
  743. m_lock.ExclusiveLock();
  744. // Bad Handle
  745. if (HCSETVALID(hCharset) == FALSE)
  746. {
  747. hr = TrapError(MIME_E_INVALID_HANDLE);
  748. goto exit;
  749. }
  750. // Get Charset Info
  751. pCharset = PCsetFromHCset(hCharset);
  752. // Get g_hSysBodyCset and g_hSysHeadCset
  753. if (FAILED(g_pInternat->HrOpenCharset(pCharset->cpiInternet, CHARSET_HEADER, &pDefHeadCset)))
  754. pDefHeadCset = pCharset;
  755. // Set Globals
  756. CIntlGlobals::SetDefBodyCset(pCharset);
  757. CIntlGlobals::SetDefHeadCset(pDefHeadCset);
  758. exit:
  759. // Thread Safety
  760. m_lock.ExclusiveUnlock();
  761. // Done
  762. return hr;
  763. }
  764. // -------------------------------------------------------------------------
  765. // CMimeInternational::GetDefaultCharset
  766. // -------------------------------------------------------------------------
  767. STDMETHODIMP CMimeInternational::GetDefaultCharset(LPHCHARSET phCharset)
  768. {
  769. // Invalid Arg
  770. if (NULL == phCharset)
  771. return TrapError(E_INVALIDARG);
  772. // NOT SET YET
  773. if (NULL == CIntlGlobals::GetDefBodyCset())
  774. return TrapError(E_FAIL);
  775. // Return g_hDefBodyCset
  776. *phCharset = CIntlGlobals::GetDefBodyCset()->hCharset;
  777. // Done
  778. return S_OK;
  779. }
  780. // -------------------------------------------------------------------------
  781. // CMimeInternational::FindCharset
  782. // -------------------------------------------------------------------------
  783. STDMETHODIMP CMimeInternational::FindCharset(LPCSTR pszCharset, LPHCHARSET phCharset)
  784. {
  785. // Locals
  786. HRESULT hr=S_OK;
  787. LPINETCSETINFO pCharset;
  788. // Invalid Arg
  789. if (NULL == pszCharset || NULL == phCharset)
  790. return TrapError(E_INVALIDARG);
  791. // Init
  792. *phCharset = NULL;
  793. // Find CsetInfo
  794. CHECKHR(hr = HrOpenCharset(pszCharset, &pCharset));
  795. // Return Charset Handles
  796. *phCharset = pCharset->hCharset;
  797. exit:
  798. // Done
  799. return hr;
  800. }
  801. // -------------------------------------------------------------------------
  802. // CMimeInternational::GetCharsetInfo
  803. // -------------------------------------------------------------------------
  804. STDMETHODIMP CMimeInternational::GetCharsetInfo(HCHARSET hCharset, LPINETCSETINFO pCsetInfo)
  805. {
  806. // Invalid Arg
  807. if (NULL == hCharset || NULL == pCsetInfo)
  808. return TrapError(E_INVALIDARG);
  809. // Bad Handle
  810. if (HCSETVALID(hCharset) == FALSE)
  811. return TrapError(MIME_E_INVALID_HANDLE);
  812. // Copy the data
  813. CopyMemory(pCsetInfo, PCsetFromHCset(hCharset), sizeof(INETCSETINFO));
  814. // Done
  815. return S_OK;
  816. }
  817. // -------------------------------------------------------------------------
  818. // CMimeInternational::GetCodePageInfo
  819. // -------------------------------------------------------------------------
  820. STDMETHODIMP CMimeInternational::GetCodePageInfo(CODEPAGEID cpiCodePage, LPCODEPAGEINFO pCodePage)
  821. {
  822. // Locals
  823. HRESULT hr=S_OK;
  824. LPCODEPAGEINFO pInfo;
  825. // Invalid Arg
  826. if (NULL == pCodePage)
  827. return TrapError(E_INVALIDARG);
  828. // Default the code page to CP_ACP if 0...
  829. if (CP_ACP == cpiCodePage)
  830. cpiCodePage = GetACP();
  831. // Get Language Info
  832. CHECKHR(hr = HrFindCodePage(cpiCodePage, &pInfo));
  833. // Copy the data
  834. CopyMemory(pCodePage, pInfo, sizeof(CODEPAGEINFO));
  835. exit:
  836. // Done
  837. return hr;
  838. }
  839. // --------------------------------------------------------------------------------
  840. // CMimeInternational::CanConvertCodePages
  841. // --------------------------------------------------------------------------------
  842. STDMETHODIMP CMimeInternational::CanConvertCodePages(CODEPAGEID cpiSource, CODEPAGEID cpiDest)
  843. {
  844. // Locals
  845. HRESULT hr=S_OK;
  846. // Can Encode
  847. if (S_OK != IsConvertINetStringAvailable(cpiSource, cpiDest))
  848. {
  849. hr = S_FALSE;
  850. goto exit;
  851. }
  852. // BUGS - temporary solution for MLANG new API - m_dwConvState
  853. m_dwConvState = 0 ;
  854. exit:
  855. // Done
  856. return hr;
  857. }
  858. // --------------------------------------------------------------------------------
  859. // CMimeInternational::ConvertBuffer
  860. // --------------------------------------------------------------------------------
  861. STDMETHODIMP CMimeInternational::ConvertBuffer(CODEPAGEID cpiSource, CODEPAGEID cpiDest,
  862. LPBLOB pIn, LPBLOB pOut, ULONG *pcbRead)
  863. {
  864. // Locals
  865. HRESULT hr=S_OK;
  866. INT cbOut;
  867. INT cbIn;
  868. // Invalid Arg
  869. if (NULL == pIn || NULL == pIn->pBlobData || NULL == pOut)
  870. return TrapError(E_INVALIDARG);
  871. // Init Out
  872. pOut->pBlobData = NULL;
  873. pOut->cbSize = 0;
  874. cbIn = pIn->cbSize;
  875. // Raid-63765: INETCOMM needs to call MLANG even if Src == Dst for charset set conversion
  876. #if 0
  877. if (cpiSource == cpiDest)
  878. {
  879. // Allocated
  880. CHECKALLOC(pOut->pBlobData = (LPBYTE)g_pMalloc->Alloc(pIn->cbSize));
  881. // Copy Memory
  882. CopyMemory(pOut->pBlobData, pIn->pBlobData, pIn->cbSize);
  883. // Set Size
  884. pOut->cbSize = pIn->cbSize;
  885. // Set pcbRead
  886. if (pcbRead)
  887. *pcbRead = pIn->cbSize;
  888. // Done
  889. goto exit;
  890. }
  891. #endif
  892. // BUGS - temporary solution for MLANG new API - m_dwConvState
  893. // Check the size of the buffer
  894. ConvertINetString(&m_dwConvState, cpiSource, cpiDest, (LPCSTR)pIn->pBlobData, &cbIn, NULL, &cbOut);
  895. // If something to convert...
  896. if (0 == cbOut)
  897. {
  898. hr = E_FAIL;
  899. goto exit;
  900. }
  901. // Allocate the buffer
  902. CHECKHR(hr = HrAlloc((LPVOID *)&pOut->pBlobData, max(cbIn, cbOut) + 1));
  903. // BUGS - temporary solution for MLANG new API - m_dwConvState
  904. // Do the actual convertion
  905. hr = ConvertINetString(&m_dwConvState, cpiSource, cpiDest, (LPCSTR)pIn->pBlobData, &cbIn, (LPSTR)pOut->pBlobData, (LPINT)&cbOut);
  906. if ( hr == S_FALSE ) // propagate the charset conflict return value
  907. hr = MIME_S_CHARSET_CONFLICT ;
  908. // Set Out Size
  909. if (pcbRead)
  910. *pcbRead = cbIn;
  911. // Set Out Size
  912. pOut->cbSize = cbOut;
  913. exit:
  914. // Done
  915. return hr;
  916. }
  917. // --------------------------------------------------------------------------------
  918. // CMimeInternational::ConvertString
  919. // --------------------------------------------------------------------------------
  920. STDMETHODIMP CMimeInternational::ConvertString(CODEPAGEID cpiSource, CODEPAGEID cpiDest,
  921. LPPROPVARIANT pIn, LPPROPVARIANT pOut)
  922. {
  923. // Locals
  924. HRESULT hr=S_OK;
  925. MIMEVARIANT rSource;
  926. MIMEVARIANT rDest;
  927. // Invalid Arg
  928. if (NULL == pIn || NULL == pOut)
  929. return TrapError(E_INVALIDARG);
  930. // VT_LPSTR
  931. if (VT_LPSTR == pIn->vt)
  932. {
  933. // Setup Source
  934. rSource.type = MVT_STRINGA;
  935. rSource.rStringA.pszVal = pIn->pszVal;
  936. rSource.rStringA.cchVal = lstrlen(pIn->pszVal);
  937. }
  938. // VT_LPWSTR
  939. else if (VT_LPWSTR == pIn->vt)
  940. {
  941. // Setup Source
  942. rSource.type = MVT_STRINGW;
  943. rSource.rStringW.pszVal = pIn->pwszVal;
  944. rSource.rStringW.cchVal = lstrlenW(pIn->pwszVal);
  945. }
  946. // E_INVALIDARG
  947. else
  948. {
  949. hr = TrapError(E_INVALIDARG);
  950. goto exit;
  951. }
  952. // VT_LPSTR
  953. if (VT_LPSTR == pOut->vt)
  954. rDest.type = MVT_STRINGA;
  955. // VT_LPWSTR
  956. else if (VT_LPWSTR == pOut->vt)
  957. rDest.type = MVT_STRINGW;
  958. // CP_UNICODE
  959. else if (CP_UNICODE == cpiDest)
  960. {
  961. pOut->vt = VT_LPWSTR;
  962. rDest.type = MVT_STRINGW;
  963. }
  964. // Multibyte
  965. else
  966. {
  967. pOut->vt = VT_LPSTR;
  968. rDest.type = MVT_STRINGA;
  969. }
  970. // HrConvertString
  971. hr = HrConvertString(cpiSource, cpiDest, &rSource, &rDest);
  972. if (FAILED(hr))
  973. goto exit;
  974. // VT_LPSTR
  975. if (VT_LPSTR == pOut->vt)
  976. {
  977. // Set Dest
  978. Assert(ISSTRINGA(&rDest));
  979. pOut->pszVal = rDest.rStringA.pszVal;
  980. }
  981. // VT_LPWSTR
  982. else
  983. {
  984. // Set Dest
  985. Assert(ISSTRINGW(&rDest));
  986. pOut->pwszVal = rDest.rStringW.pszVal;
  987. }
  988. exit:
  989. // Done
  990. return hr;
  991. }
  992. // --------------------------------------------------------------------------------
  993. // CMimeInternational::HrValidateCodepages
  994. // --------------------------------------------------------------------------------
  995. HRESULT CMimeInternational::HrValidateCodepages(LPMIMEVARIANT pSource, LPMIMEVARIANT pDest,
  996. LPBYTE *ppbSource, ULONG *pcbSource, CODEPAGEID *pcpiSource, CODEPAGEID *pcpiDest)
  997. {
  998. // Locals
  999. HRESULT hr=S_OK;
  1000. CODEPAGEID cpiSource=(*pcpiSource);
  1001. CODEPAGEID cpiDest=(*pcpiDest);
  1002. LPBYTE pbSource;
  1003. ULONG cbSource;
  1004. // Invalid ARg
  1005. Assert(pcpiSource && pcpiDest);
  1006. // MVT_STRINGA
  1007. if (MVT_STRINGA == pSource->type)
  1008. {
  1009. // E_INVALIDARG
  1010. if (ISVALIDSTRINGA(&pSource->rStringA) == FALSE)
  1011. {
  1012. hr = TrapError(E_INVALIDARG);
  1013. goto exit;
  1014. }
  1015. // cpiSource should not be unicode
  1016. cpiSource = (CP_UNICODE == cpiSource) ? GetACP() : cpiSource;
  1017. // Init Out
  1018. cbSource = pSource->rStringA.cchVal;
  1019. // Set Source
  1020. pbSource = (LPBYTE)pSource->rStringA.pszVal;
  1021. }
  1022. // MVT_STRINGW
  1023. else if (MVT_STRINGW == pSource->type)
  1024. {
  1025. // E_INVALIDARG
  1026. if (ISVALIDSTRINGW(&pSource->rStringW) == FALSE)
  1027. {
  1028. hr = TrapError(E_INVALIDARG);
  1029. goto exit;
  1030. }
  1031. // cpiSource should be Unicode
  1032. cpiSource = CP_UNICODE;
  1033. // Init Out
  1034. cbSource = (pSource->rStringW.cchVal * sizeof(WCHAR));
  1035. // Set Source
  1036. pbSource = (LPBYTE)pSource->rStringW.pszVal;
  1037. }
  1038. // E_INVALIDARG
  1039. else
  1040. {
  1041. hr = TrapError(E_INVALIDARG);
  1042. goto exit;
  1043. }
  1044. // MVT_STRINGA
  1045. if (MVT_STRINGA == pDest->type)
  1046. {
  1047. // cpiDest shoudl not be unicode
  1048. cpiDest = (CP_UNICODE == cpiDest) ? GetACP() : ((CP_JAUTODETECT == cpiDest) ? 932 : cpiDest);
  1049. }
  1050. // MVT_STRINGW
  1051. else if (MVT_STRINGW == pDest->type)
  1052. {
  1053. // Destination is Unicode
  1054. cpiDest = CP_UNICODE;
  1055. }
  1056. // E_INVALIDARG
  1057. else
  1058. {
  1059. hr = TrapError(E_INVALIDARG);
  1060. goto exit;
  1061. }
  1062. // Set Return Values
  1063. if (pcpiSource)
  1064. *pcpiSource = cpiSource;
  1065. if (pcpiDest)
  1066. *pcpiDest = cpiDest;
  1067. if (ppbSource)
  1068. *ppbSource = pbSource;
  1069. if (pcbSource)
  1070. *pcbSource = cbSource;
  1071. exit:
  1072. // Done
  1073. return hr;
  1074. }
  1075. // --------------------------------------------------------------------------------
  1076. // CMimeInternational::HrConvertString
  1077. // --------------------------------------------------------------------------------
  1078. HRESULT CMimeInternational::HrConvertString(CODEPAGEID cpiSource, CODEPAGEID cpiDest,
  1079. LPMIMEVARIANT pSource, LPMIMEVARIANT pDest)
  1080. {
  1081. // Locals
  1082. HRESULT hr=S_OK;
  1083. INT cbNeeded=0;
  1084. INT cbDest;
  1085. INT cbSource;
  1086. LPBYTE pbSource;
  1087. LPBYTE pbDest=NULL;
  1088. // Invalid Arg
  1089. if (NULL == pSource || NULL == pDest)
  1090. return TrapError(E_INVALIDARG);
  1091. // Adjust the Codepages
  1092. CHECKHR(hr = HrValidateCodepages(pSource, pDest, &pbSource, (ULONG *)&cbSource, &cpiSource, &cpiDest));
  1093. // Raid-63765: INETCOMM needs to call MLANG even if Src == Dst for charset set conversion
  1094. #if 0
  1095. if (cpiSource == cpiDest)
  1096. {
  1097. // Copy the variant
  1098. CHECKHR(hr = HrMimeVariantCopy(0, pSource, pDest));
  1099. // Done
  1100. goto exit;
  1101. }
  1102. #endif
  1103. // Check the size of the buffer
  1104. if (FAILED(ConvertINetString(NULL, cpiSource, cpiDest, (LPCSTR)pbSource, &cbSource, NULL, &cbNeeded)) ||
  1105. (0 == cbNeeded && cbSource > 0))
  1106. {
  1107. hr = E_FAIL;
  1108. goto exit;
  1109. }
  1110. // MVT_STRINGA
  1111. if (MVT_STRINGA == pDest->type)
  1112. {
  1113. // Allocate the buffer
  1114. CHECKALLOC(pDest->rStringA.pszVal = (LPSTR)g_pMalloc->Alloc(cbNeeded + sizeof(CHAR)));
  1115. // Set Dest
  1116. pbDest = (LPBYTE)pDest->rStringA.pszVal;
  1117. }
  1118. // Allocate unicode
  1119. else
  1120. {
  1121. // Allocate the buffer
  1122. CHECKALLOC(pDest->rStringW.pszVal = (LPWSTR)g_pMalloc->Alloc(cbNeeded + sizeof(WCHAR)));
  1123. // Set Dest
  1124. pbDest = (LPBYTE)pDest->rStringW.pszVal;
  1125. }
  1126. // Set cbOut
  1127. cbDest = cbNeeded;
  1128. // Do the actual convertion
  1129. if (FAILED(ConvertINetString(NULL, cpiSource, cpiDest, (LPCSTR)pbSource, &cbSource, (LPSTR)pbDest, &cbDest)))
  1130. {
  1131. hr = E_FAIL;
  1132. goto exit;
  1133. }
  1134. // Better not have grown
  1135. Assert(cbDest <= cbNeeded);
  1136. // MVT_STRINGA
  1137. if (MVT_STRINGA == pDest->type)
  1138. {
  1139. // Save Size
  1140. pDest->rStringA.cchVal = cbDest;
  1141. // Pound in a Null
  1142. pDest->rStringA.pszVal[pDest->rStringA.cchVal] = '\0';
  1143. // Validate the String
  1144. Assert(ISSTRINGA(pDest));
  1145. }
  1146. // MVT_STRINGW
  1147. else
  1148. {
  1149. // Save Size
  1150. pDest->rStringW.cchVal = (cbDest / 2);
  1151. // Pound in a Null
  1152. pDest->rStringW.pszVal[pDest->rStringW.cchVal] = L'\0';
  1153. // Validate the String
  1154. Assert(ISSTRINGW(pDest));
  1155. }
  1156. // Success
  1157. pbDest = NULL;
  1158. exit:
  1159. // Cleanup
  1160. SafeMemFree(pbDest);
  1161. // Done
  1162. return hr;
  1163. }
  1164. // --------------------------------------------------------------------------------
  1165. // CMimeInternational::HrEncodeHeader
  1166. // --------------------------------------------------------------------------------
  1167. HRESULT CMimeInternational::HrEncodeHeader(LPINETCSETINFO pCharset, LPRFC1522INFO pRfc1522Info,
  1168. LPMIMEVARIANT pSource, LPMIMEVARIANT pDest)
  1169. {
  1170. // Locals
  1171. HRESULT hr=S_OK;
  1172. LPSTR pszNarrow=NULL;
  1173. LPSTR pszRfc1522=NULL;
  1174. BOOL fRfc1522Used=FALSE;
  1175. BOOL fRfc1522Tried=FALSE;
  1176. MIMEVARIANT rRedirected;
  1177. // Invalid Arg
  1178. Assert(pSource && (MVT_STRINGA == pSource->type || MVT_STRINGW == pSource->type));
  1179. Assert(pDest && MVT_STRINGA == pDest->type);
  1180. // ZeroInit
  1181. ZeroMemory(&rRedirected, sizeof(MIMEVARIANT));
  1182. // Default hCharset
  1183. if (NULL == pCharset)
  1184. pCharset = CIntlGlobals::GetDefHeadCset();
  1185. // No Charset..
  1186. if (NULL == pCharset)
  1187. {
  1188. hr = TrapError(E_FAIL);
  1189. goto exit;
  1190. }
  1191. // Init
  1192. if (pRfc1522Info)
  1193. pRfc1522Info->fRfc1522Used = FALSE;
  1194. // Raid-62535: MimeOle always 1521 encodes headers when header value is Unicode
  1195. // If source is unicode and were not using a UTF character set to encode with, then convert to multibyte
  1196. if (MVT_STRINGW == pSource->type && CP_UNICODE != pCharset->cpiWindows)
  1197. {
  1198. // Setup MimeVariant
  1199. rRedirected.type = MVT_STRINGA;
  1200. // Convert to pCharset->cpiWindows
  1201. CHECKHR(hr = HrWideCharToMultiByte(pCharset->cpiWindows, &pSource->rStringW, &rRedirected.rStringA));
  1202. // Reset pSource
  1203. pSource = &rRedirected;
  1204. }
  1205. // Decode
  1206. if ((65000 == pCharset->cpiInternet || 65001 == pCharset->cpiInternet) ||
  1207. (NULL == pRfc1522Info || ((FALSE == pRfc1522Info->fAllow8bit) && (TRUE == pRfc1522Info->fRfc1522Allowed))))
  1208. {
  1209. // Locals
  1210. CODEPAGEID cpiSource=pCharset->cpiWindows;
  1211. CODEPAGEID cpiDest=pCharset->cpiInternet;
  1212. // Adjust the Codepages
  1213. CHECKHR(hr = HrValidateCodepages(pSource, pDest, NULL, NULL, &cpiSource, &cpiDest));
  1214. // We Tried rfc1522
  1215. fRfc1522Tried = TRUE;
  1216. // 1522 Encode this dude
  1217. if (SUCCEEDED(HrRfc1522Encode(pSource, pDest, cpiSource, cpiDest, pCharset->szName, &pszRfc1522)))
  1218. {
  1219. // We used Rfc1522
  1220. fRfc1522Used = TRUE;
  1221. // Return Information
  1222. if (pRfc1522Info)
  1223. {
  1224. pRfc1522Info->fRfc1522Used = TRUE;
  1225. pRfc1522Info->hRfc1522Cset = pCharset->hCharset;
  1226. }
  1227. // Setup rStringA
  1228. pDest->rStringA.pszVal = pszRfc1522;
  1229. pDest->rStringA.cchVal = lstrlen(pszRfc1522);
  1230. pszRfc1522 = NULL;
  1231. }
  1232. }
  1233. // If we didn't use RFC 1522, then do a convert string
  1234. if (FALSE == fRfc1522Used)
  1235. {
  1236. // If UTF-7 or UTF-8 and source is ANSI with no 8bit, just dup it
  1237. if (65000 == pCharset->cpiInternet || 65001 == pCharset->cpiInternet)
  1238. {
  1239. // Source is ansi
  1240. if (MVT_STRINGA == pSource->type)
  1241. {
  1242. // Locals
  1243. ULONG c;
  1244. // No 8bit
  1245. if (FALSE == FContainsExtended(&pSource->rStringA, &c))
  1246. {
  1247. // Convert
  1248. hr = HrConvertString(pCharset->cpiWindows, pCharset->cpiWindows, pSource, pDest);
  1249. // Were Done
  1250. goto exit;
  1251. }
  1252. // We must not have tried 1522, because thats what we should have done
  1253. Assert(fRfc1522Tried == FALSE);
  1254. }
  1255. }
  1256. // Do the charset conversion
  1257. hr = HrConvertString(pCharset->cpiWindows, pCharset->cpiInternet, pSource, pDest);
  1258. if (FAILED(hr))
  1259. goto exit;
  1260. }
  1261. exit:
  1262. // Cleanup
  1263. SafeMemFree(pszRfc1522);
  1264. MimeVariantFree(&rRedirected);
  1265. // Done
  1266. return hr;
  1267. }
  1268. // --------------------------------------------------------------------------------
  1269. // CMimeInternational::HrDecodeHeader
  1270. // --------------------------------------------------------------------------------
  1271. HRESULT CMimeInternational::HrDecodeHeader(LPINETCSETINFO pCharset, LPRFC1522INFO pRfc1522Info,
  1272. LPMIMEVARIANT pSource, LPMIMEVARIANT pDest)
  1273. {
  1274. // Locals
  1275. HRESULT hr=S_OK;
  1276. LPINETCSETINFO pRfc1522Charset=NULL;
  1277. PROPSTRINGA rTempA;
  1278. LPSTR pszRfc1522=NULL;
  1279. LPSTR pszNarrow=NULL;
  1280. MIMEVARIANT rSource;
  1281. CHAR szRfc1522Cset[CCHMAX_CSET_NAME];
  1282. // Invalid Arg
  1283. Assert(pSource && (MVT_STRINGA == pSource->type || MVT_STRINGW == pSource->type));
  1284. Assert(pDest && (MVT_STRINGA == pDest->type || MVT_STRINGW == pDest->type));
  1285. // Copy Source
  1286. CopyMemory(&rSource, pSource, sizeof(MIMEVARIANT));
  1287. // MVT_STRINGW
  1288. if (MVT_STRINGW == pSource->type)
  1289. {
  1290. // Better be a valid string
  1291. Assert(ISVALIDSTRINGW(&pSource->rStringW));
  1292. // Conversion
  1293. CHECKHR(hr = HrWideCharToMultiByte(CP_ACP, &pSource->rStringW, &rTempA));
  1294. // Free This
  1295. pszNarrow = rTempA.pszVal;
  1296. // Update rSource
  1297. rSource.type = MVT_STRINGA;
  1298. rSource.rStringA.pszVal = rTempA.pszVal;
  1299. rSource.rStringA.cchVal = rTempA.cchVal;
  1300. }
  1301. // Decode
  1302. if (NULL == pRfc1522Info || TRUE == pRfc1522Info->fRfc1522Allowed)
  1303. {
  1304. // Perform rfc1522 decode...
  1305. if (SUCCEEDED(MimeOleRfc1522Decode(rSource.rStringA.pszVal, szRfc1522Cset, ARRAYSIZE(szRfc1522Cset), &pszRfc1522)))
  1306. {
  1307. // It was encoded...
  1308. if (pRfc1522Info)
  1309. pRfc1522Info->fRfc1522Used = TRUE;
  1310. // Look up the charset
  1311. if (SUCCEEDED(HrOpenCharset(szRfc1522Cset, &pRfc1522Charset)) && pRfc1522Info)
  1312. {
  1313. // Return in the Info Struct
  1314. pRfc1522Info->hRfc1522Cset = pRfc1522Charset->hCharset;
  1315. }
  1316. // Reset Source
  1317. rSource.rStringA.pszVal = pszRfc1522;
  1318. rSource.rStringA.cchVal = lstrlen(pszRfc1522);
  1319. // No pCharset
  1320. if (NULL == pCharset)
  1321. pCharset = pRfc1522Charset;
  1322. }
  1323. // No Rfc1522
  1324. else if (pRfc1522Info)
  1325. {
  1326. pRfc1522Info->fRfc1522Used = FALSE;
  1327. pRfc1522Info->hRfc1522Cset = NULL;
  1328. }
  1329. }
  1330. // Charset is Still Null, use Default
  1331. if (NULL == pCharset)
  1332. pCharset = CIntlGlobals::GetDefHeadCset();
  1333. // No Charset..
  1334. if (NULL == pCharset)
  1335. {
  1336. hr = TrapError(E_FAIL);
  1337. goto exit;
  1338. }
  1339. // Convert the String
  1340. hr = HrConvertString(pCharset->cpiInternet, pCharset->cpiWindows, &rSource, pDest);
  1341. if (FAILED(hr))
  1342. {
  1343. // If it was rfc1522 decoded, then return it and a warning
  1344. if (pszRfc1522)
  1345. {
  1346. // pszRfc1522 should be in rSource
  1347. Assert(rSource.rStringA.pszVal == pszRfc1522);
  1348. // Return MVT_STRINGA
  1349. if (MVT_STRINGA == pDest->type)
  1350. {
  1351. pDest->rStringA.pszVal = rSource.rStringA.pszVal;
  1352. pDest->rStringA.cchVal = rSource.rStringA.cchVal;
  1353. pszRfc1522 = NULL;
  1354. }
  1355. // MVT_STRINGW
  1356. else
  1357. {
  1358. CHECKHR(hr = HrMultiByteToWideChar(CP_ACP, &rSource.rStringA, &pDest->rStringW));
  1359. pszRfc1522 = NULL;
  1360. }
  1361. // This is not a failure, but just a warning
  1362. hr = MIME_S_NO_CHARSET_CONVERT;
  1363. }
  1364. // Done
  1365. goto exit;
  1366. }
  1367. exit:
  1368. // Cleanup
  1369. SafeMemFree(pszNarrow);
  1370. SafeMemFree(pszRfc1522);
  1371. // Done
  1372. return hr;
  1373. }
  1374. //---------------------------------------------------------------------------------
  1375. // Function: MLANG_ConvertInetReset
  1376. //
  1377. // Purpose:
  1378. // This function is a wrapper function for MLANG.DLL's ConvertInetReset.
  1379. //
  1380. // Returns:
  1381. // Same as for MLANG.DLL's ConvertInetReset.
  1382. //---------------------------------------------------------------------------------
  1383. HRESULT CMimeInternational::MLANG_ConvertInetReset(void)
  1384. {
  1385. HRESULT hrResult;
  1386. // a stub for now
  1387. return S_OK;
  1388. } // MLANG_ConvertInetReset
  1389. //---------------------------------------------------------------------------------
  1390. // Function: MLANG_ConvertInetString
  1391. //
  1392. // Purpose:
  1393. // This function is a wrapper function which passes its arguments through to
  1394. // MLANG's ConvertInetString.
  1395. //
  1396. // Arguments:
  1397. // Same as for MLANG.DLL's ConvertInetString.
  1398. //
  1399. // Returns:
  1400. // Same as for MLANG.DLL's ConvertInetString.
  1401. //---------------------------------------------------------------------------------
  1402. HRESULT CMimeInternational::MLANG_ConvertInetString(CODEPAGEID cpiSource,
  1403. CODEPAGEID cpiDest,
  1404. LPCSTR pSourceStr,
  1405. LPINT pnSizeOfSourceStr,
  1406. LPSTR pDestinationStr,
  1407. LPINT pnSizeOfDestBuffer)
  1408. {
  1409. HRESULT hrResult;
  1410. // Codify Assumptions
  1411. Assert(sizeof(UCHAR) == sizeof(char));
  1412. // Pass the arguments through
  1413. return ConvertINetString(NULL, cpiSource, cpiDest, (LPCSTR)pSourceStr, pnSizeOfSourceStr, (LPSTR) pDestinationStr, pnSizeOfDestBuffer);
  1414. } // MLANG_ConvertInetString
  1415. // --------------------------------------------------------------------------------
  1416. // CMimeInternational::DecodeHeader ANSI -> (ANSI or UNICODE)
  1417. // --------------------------------------------------------------------------------
  1418. STDMETHODIMP CMimeInternational::DecodeHeader(HCHARSET hCharset, LPCSTR pszData,
  1419. LPPROPVARIANT pDecoded, LPRFC1522INFO pRfc1522Info)
  1420. {
  1421. // Locals
  1422. HRESULT hr=S_OK;
  1423. MIMEVARIANT rSource;
  1424. MIMEVARIANT rDest;
  1425. // Invalid Arg
  1426. if (NULL == pszData || NULL == pDecoded || (VT_LPSTR != pDecoded->vt && VT_LPWSTR != pDecoded->vt))
  1427. return TrapError(E_INVALIDARG);
  1428. // Setup Source
  1429. rSource.type = MVT_STRINGA;
  1430. rSource.rStringA.pszVal = (LPSTR)pszData;
  1431. rSource.rStringA.cchVal = lstrlen(pszData);
  1432. // Setup Destination
  1433. rDest.type = (VT_LPSTR == pDecoded->vt) ? MVT_STRINGA : MVT_STRINGW;
  1434. // Valid Charset
  1435. if (hCharset && HCSETVALID(hCharset) == FALSE)
  1436. {
  1437. hr = TrapError(MIME_E_INVALID_HANDLE);
  1438. goto exit;
  1439. }
  1440. // HrDecodeHeader
  1441. hr = HrDecodeHeader((NULL == hCharset) ? NULL : PCsetFromHCset(hCharset), pRfc1522Info, &rSource, &rDest);
  1442. if (FAILED(hr))
  1443. goto exit;
  1444. // Put rDest into pDecoded
  1445. if (MVT_STRINGA == rDest.type)
  1446. pDecoded->pszVal = rDest.rStringA.pszVal;
  1447. else
  1448. pDecoded->pwszVal = rDest.rStringW.pszVal;
  1449. exit:
  1450. // Done
  1451. return hr;
  1452. }
  1453. // --------------------------------------------------------------------------------
  1454. // CMimeInternational::EncodeHeader
  1455. // --------------------------------------------------------------------------------
  1456. STDMETHODIMP CMimeInternational::EncodeHeader(HCHARSET hCharset, LPPROPVARIANT pData,
  1457. LPSTR *ppszEncoded, LPRFC1522INFO pRfc1522Info)
  1458. {
  1459. // Locals
  1460. HRESULT hr=S_OK;
  1461. MIMEVARIANT rSource;
  1462. MIMEVARIANT rDest;
  1463. // Invalid Arg
  1464. if (NULL == pData || NULL == ppszEncoded || (VT_LPSTR != pData->vt && VT_LPWSTR != pData->vt))
  1465. return TrapError(E_INVALIDARG);
  1466. // Init
  1467. *ppszEncoded = NULL;
  1468. // VT_LPSTR
  1469. if (VT_LPSTR == pData->vt)
  1470. {
  1471. rSource.type = MVT_STRINGA;
  1472. rSource.rStringA.pszVal = pData->pszVal;
  1473. rSource.rStringA.cchVal = lstrlen(pData->pszVal);
  1474. }
  1475. // VT_LPWSTR
  1476. else
  1477. {
  1478. rSource.type = MVT_STRINGW;
  1479. rSource.rStringW.pszVal = pData->pwszVal;
  1480. rSource.rStringW.cchVal = lstrlenW(pData->pwszVal);
  1481. }
  1482. // Setup Destination
  1483. rDest.type = MVT_STRINGA;
  1484. // Valid Charset
  1485. if (hCharset && HCSETVALID(hCharset) == FALSE)
  1486. {
  1487. hr = TrapError(MIME_E_INVALID_HANDLE);
  1488. goto exit;
  1489. }
  1490. // HrDecodeHeader
  1491. hr = HrEncodeHeader((NULL == hCharset) ? NULL : PCsetFromHCset(hCharset), pRfc1522Info, &rSource, &rDest);
  1492. if (FAILED(hr))
  1493. goto exit;
  1494. // Put rDest into pDecoded
  1495. *ppszEncoded = rDest.rStringA.pszVal;
  1496. exit:
  1497. // Done
  1498. return hr;
  1499. }
  1500. // --------------------------------------------------------------------------------
  1501. // CMimeInternational::Rfc1522Decode
  1502. // --------------------------------------------------------------------------------
  1503. STDMETHODIMP CMimeInternational::Rfc1522Decode(LPCSTR pszValue, LPSTR pszCharset, ULONG cchmax, LPSTR *ppszDecoded)
  1504. {
  1505. return MimeOleRfc1522Decode(pszValue, pszCharset, cchmax, ppszDecoded);
  1506. }
  1507. // --------------------------------------------------------------------------------
  1508. // CMimeInternational::Rfc1522Encode
  1509. // --------------------------------------------------------------------------------
  1510. STDMETHODIMP CMimeInternational::Rfc1522Encode(LPCSTR pszValue, HCHARSET hCharset, LPSTR *ppszEncoded)
  1511. {
  1512. return MimeOleRfc1522Encode(pszValue, hCharset, ppszEncoded);
  1513. }
  1514. // --------------------------------------------------------------------------------
  1515. // CMimeInternational::FIsValidHandle
  1516. // --------------------------------------------------------------------------------
  1517. BOOL CMimeInternational::FIsValidHandle(HCHARSET hCharset)
  1518. {
  1519. m_lock.ShareLock();
  1520. BOOL f = HCSETVALID(hCharset);
  1521. m_lock.ShareUnlock();
  1522. return f;
  1523. }
  1524. // --------------------------------------------------------------------------------
  1525. // CMimeInternational::IsDBCSCharset
  1526. // --------------------------------------------------------------------------------
  1527. HRESULT CMimeInternational::IsDBCSCharset(HCHARSET hCharset)
  1528. {
  1529. // Locals
  1530. HRESULT hr=S_OK;
  1531. LPINETCSETINFO pCsetInfo;
  1532. // Invlaid Handle
  1533. if (HCSETVALID(hCharset) == FALSE)
  1534. {
  1535. hr = TrapError(MIME_E_INVALID_HANDLE);
  1536. goto exit;
  1537. }
  1538. // Get the charset info
  1539. pCsetInfo = PCsetFromHCset(hCharset);
  1540. // Special Cases
  1541. if (pCsetInfo->cpiWindows == CP_JAUTODETECT ||
  1542. pCsetInfo->cpiWindows == CP_KAUTODETECT ||
  1543. pCsetInfo->cpiWindows == CP_ISO2022JPESC ||
  1544. pCsetInfo->cpiWindows == CP_ISO2022JPSIO)
  1545. {
  1546. hr = S_OK;
  1547. goto exit;
  1548. }
  1549. // Is Windows Code Page DBCS ?
  1550. hr = (IsDBCSCodePage(pCsetInfo->cpiWindows) == TRUE) ? S_OK : S_FALSE;
  1551. exit:
  1552. // Done
  1553. return hr;
  1554. }
  1555. // --------------------------------------------------------------------------------
  1556. // CMimeInternational::HrEncodeProperty
  1557. // --------------------------------------------------------------------------------
  1558. HRESULT CMimeInternational::HrEncodeProperty(LPVARIANTCONVERT pConvert, LPMIMEVARIANT pSource,
  1559. LPMIMEVARIANT pDest)
  1560. {
  1561. // Locals
  1562. HRESULT hr=S_OK;
  1563. RFC1522INFO rRfc1522Info;
  1564. MIMEVARIANT rSource;
  1565. // Invalid Arg
  1566. Assert(pConvert && pConvert->pSymbol && pConvert->pCharset && pConvert->pOptions && pSource && pDest);
  1567. Assert(ISFLAGSET(pConvert->pSymbol->dwFlags, MPF_INETCSET));
  1568. Assert(pConvert->ietSource == IET_ENCODED || pConvert->ietSource == IET_DECODED);
  1569. // Init
  1570. ZeroMemory(&rSource, sizeof(MIMEVARIANT));
  1571. // Setup Rfc1522 Info
  1572. ZeroMemory(&rRfc1522Info, sizeof(RFC1522INFO));
  1573. rRfc1522Info.fRfc1522Allowed = ISFLAGSET(pConvert->pSymbol->dwFlags, MPF_RFC1522);
  1574. rRfc1522Info.fAllow8bit = (SAVE_RFC1521 == pConvert->pOptions->savetype) ? pConvert->pOptions->fAllow8bit : TRUE;
  1575. // If Property is Encoded, decode it first
  1576. if (IET_ENCODED == pConvert->ietSource)
  1577. {
  1578. // Set rSource.type
  1579. rSource.type = pDest->type;
  1580. // Decode It
  1581. hr = HrDecodeHeader(pConvert->pCharset, &rRfc1522Info, pSource, &rSource);
  1582. if (FAILED(hr))
  1583. goto exit;
  1584. }
  1585. // Otherwise, use pSource as rSource
  1586. else
  1587. {
  1588. // Setup Source
  1589. CopyMemory(&rSource, pSource, sizeof(MIMEVARIANT));
  1590. rSource.fCopy = TRUE;
  1591. }
  1592. // HrEncodeHeader
  1593. hr = HrEncodeHeader(pConvert->pCharset, &rRfc1522Info, &rSource, pDest);
  1594. if (FAILED(hr))
  1595. goto exit;
  1596. // Set PRSTATE_RFC1511
  1597. if (rRfc1522Info.fRfc1522Used)
  1598. FLAGSET(pConvert->dwState, PRSTATE_RFC1522);
  1599. exit:
  1600. // Cleanup
  1601. MimeVariantFree(&rSource);
  1602. // Done
  1603. return hr;
  1604. }
  1605. // --------------------------------------------------------------------------------
  1606. // CMimeInternational::HrDecodeProperty
  1607. // --------------------------------------------------------------------------------
  1608. HRESULT CMimeInternational::HrDecodeProperty(LPVARIANTCONVERT pConvert, LPMIMEVARIANT pSource,
  1609. LPMIMEVARIANT pDest)
  1610. {
  1611. // Locals
  1612. RFC1522INFO rRfc1522Info;
  1613. // Invalid Arg
  1614. Assert(pConvert && pConvert->pSymbol && pConvert->pCharset && pConvert->pOptions && pSource && pDest);
  1615. Assert(ISFLAGSET(pConvert->pSymbol->dwFlags, MPF_INETCSET) && pConvert->ietSource == IET_ENCODED);
  1616. // Setup Rfc1522 Info
  1617. ZeroMemory(&rRfc1522Info, sizeof(RFC1522INFO));
  1618. rRfc1522Info.fRfc1522Allowed = ISFLAGSET(pConvert->pSymbol->dwFlags, MPF_RFC1522);
  1619. rRfc1522Info.fAllow8bit = (SAVE_RFC1521 == pConvert->pOptions->savetype) ? pConvert->pOptions->fAllow8bit : TRUE;
  1620. // HrDecodeHeader
  1621. return HrDecodeHeader(pConvert->pCharset, &rRfc1522Info, pSource, pDest);
  1622. }
  1623. // --------------------------------------------------------------------------------
  1624. // CMimeInternational::HrWideCharToMultiByte
  1625. // --------------------------------------------------------------------------------
  1626. HRESULT CMimeInternational::HrWideCharToMultiByte(CODEPAGEID cpiCodePage, LPCPROPSTRINGW pStringW,
  1627. LPPROPSTRINGA pStringA)
  1628. {
  1629. // Locals
  1630. HRESULT hr=S_OK;
  1631. // Invalid Arg
  1632. Assert(ISVALIDSTRINGW(pStringW) && pStringA);
  1633. // Adjust cpiCodePage
  1634. if (CP_UNICODE == cpiCodePage)
  1635. cpiCodePage = CP_ACP;
  1636. // Init
  1637. pStringA->pszVal = NULL;
  1638. pStringA->cchVal = 0;
  1639. // Determine how much space is needed for translated widechar
  1640. pStringA->cchVal = ::WideCharToMultiByte(cpiCodePage, 0, pStringW->pszVal, pStringW->cchVal, NULL, 0, NULL, NULL);
  1641. if (pStringA->cchVal == 0 && pStringW->cchVal != 0)
  1642. {
  1643. DOUTL(4, "WideCharToMultiByte Failed - CodePageID = %d, GetLastError = %d\n", cpiCodePage, GetLastError());
  1644. // WideCharToMultiByte failed for some other reason than cpiCodePage being a bad codepage
  1645. if (TRUE == IsValidCodePage(cpiCodePage))
  1646. {
  1647. hr = TrapError(E_FAIL);
  1648. goto exit;
  1649. }
  1650. // Reset cpiCodePage to a valid codepage
  1651. cpiCodePage = CP_ACP;
  1652. // Use the system acp
  1653. pStringA->cchVal = ::WideCharToMultiByte(cpiCodePage, 0, pStringW->pszVal, pStringW->cchVal, NULL, 0, NULL, NULL);
  1654. if (pStringA->cchVal == 0)
  1655. {
  1656. hr = TrapError(E_FAIL);
  1657. goto exit;
  1658. }
  1659. }
  1660. // Allocate It
  1661. CHECKALLOC(pStringA->pszVal = (LPSTR)g_pMalloc->Alloc((pStringA->cchVal + 1)));
  1662. // Do the actual translation
  1663. pStringA->cchVal = ::WideCharToMultiByte(cpiCodePage, 0, pStringW->pszVal, pStringW->cchVal, pStringA->pszVal, pStringA->cchVal + 1, NULL, NULL);
  1664. if (pStringA->cchVal == 0 && pStringW->cchVal != 0)
  1665. {
  1666. DOUTL(4, "WideCharToMultiByte Failed - CodePageID = %d, GetLastError = %d\n", cpiCodePage, GetLastError());
  1667. hr = TrapError(E_FAIL);
  1668. goto exit;
  1669. }
  1670. // Insert the Null
  1671. pStringA->pszVal[pStringA->cchVal] = '\0';
  1672. exit:
  1673. // Done
  1674. return hr;
  1675. }
  1676. // --------------------------------------------------------------------------------
  1677. // CMimeInternational::HrMultiByteToWideChar
  1678. // --------------------------------------------------------------------------------
  1679. HRESULT CMimeInternational::HrMultiByteToWideChar(CODEPAGEID cpiCodePage, LPCPROPSTRINGA pStringA,
  1680. LPPROPSTRINGW pStringW)
  1681. {
  1682. // Locals
  1683. HRESULT hr=S_OK;
  1684. // Invalid Arg
  1685. // Bad codepage is okay and will be dealt with below
  1686. Assert(ISVALIDSTRINGA(pStringA) && pStringW);
  1687. // Adjust cpiCodePage
  1688. if (CP_UNICODE == cpiCodePage)
  1689. cpiCodePage = CP_ACP;
  1690. // Init
  1691. pStringW->pszVal = NULL;
  1692. pStringW->cchVal = 0;
  1693. // Determine how much space is needed for translated widechar
  1694. pStringW->cchVal = ::MultiByteToWideChar(cpiCodePage, MB_PRECOMPOSED, pStringA->pszVal, pStringA->cchVal, NULL, 0);
  1695. if (pStringW->cchVal == 0 && pStringA->cchVal != 0)
  1696. {
  1697. DOUTL(4, "MultiByteToWideChar Failed - CodePageID = %d, GetLastError = %d\n", cpiCodePage, GetLastError());
  1698. // MultiByteToWideChar failed for some other reason than cpiCodePage being a bad codepage
  1699. if (TRUE == IsValidCodePage(cpiCodePage))
  1700. {
  1701. hr = TrapError(E_FAIL);
  1702. goto exit;
  1703. }
  1704. // Reset cpiCodePage to a valid codepage
  1705. cpiCodePage = CP_ACP;
  1706. // Use the system acp
  1707. pStringW->cchVal = ::MultiByteToWideChar(cpiCodePage, MB_PRECOMPOSED, pStringA->pszVal, pStringA->cchVal, NULL, 0);
  1708. if (pStringW->cchVal == 0)
  1709. {
  1710. hr = TrapError(E_FAIL);
  1711. goto exit;
  1712. }
  1713. }
  1714. // Allocate It
  1715. CHECKALLOC(pStringW->pszVal = (LPWSTR)g_pMalloc->Alloc((pStringW->cchVal + 1) * sizeof(WCHAR)));
  1716. // Do the actual translation
  1717. pStringW->cchVal = ::MultiByteToWideChar(cpiCodePage, MB_PRECOMPOSED, pStringA->pszVal, pStringA->cchVal, pStringW->pszVal, pStringW->cchVal + 1);
  1718. if (pStringW->cchVal == 0 && pStringA->cchVal != 0)
  1719. {
  1720. DOUTL(4, "MultiByteToWideChar Failed - CodePageID = %d, GetLastError = %d\n", cpiCodePage, GetLastError());
  1721. hr = TrapError(E_FAIL);
  1722. goto exit;
  1723. }
  1724. // Insert the Null
  1725. pStringW->pszVal[pStringW->cchVal] = L'\0';
  1726. exit:
  1727. // Done
  1728. return hr;
  1729. }
  1730. // --------------------------------------------------------------------------------
  1731. void CIntlGlobals::Init()
  1732. {
  1733. mg_bInit = FALSE;
  1734. InitializeCriticalSection(&mg_cs);
  1735. mg_pDefBodyCset = NULL;
  1736. mg_pDefHeadCset = NULL;
  1737. }
  1738. void CIntlGlobals::Term()
  1739. {
  1740. DeleteCriticalSection(&mg_cs);
  1741. }
  1742. void CIntlGlobals::DoInit()
  1743. {
  1744. if (!mg_bInit)
  1745. {
  1746. EnterCriticalSection(&mg_cs);
  1747. if (!mg_bInit)
  1748. {
  1749. // Locals
  1750. CODEPAGEID cpiSystem;
  1751. // Get the system codepage
  1752. cpiSystem = GetACP();
  1753. // Get the default body charset
  1754. if (FAILED(g_pInternat->HrOpenCharset(cpiSystem, CHARSET_BODY, &mg_pDefBodyCset)))
  1755. mg_pDefBodyCset = &mg_rDefaultCharset;
  1756. // Get the Default Header Charset
  1757. if (FAILED(g_pInternat->HrOpenCharset(cpiSystem, CHARSET_HEADER, &mg_pDefHeadCset)))
  1758. mg_pDefHeadCset = mg_pDefBodyCset;
  1759. mg_bInit = TRUE;
  1760. }
  1761. LeaveCriticalSection(&mg_cs);
  1762. }
  1763. }
  1764. LPINETCSETINFO CIntlGlobals::GetDefBodyCset()
  1765. {
  1766. DoInit();
  1767. Assert(mg_pDefBodyCset);
  1768. return (mg_pDefBodyCset);
  1769. }
  1770. LPINETCSETINFO CIntlGlobals::GetDefHeadCset()
  1771. {
  1772. DoInit();
  1773. Assert(mg_pDefHeadCset);
  1774. return (mg_pDefHeadCset);
  1775. }
  1776. LPINETCSETINFO CIntlGlobals::GetDefaultCharset()
  1777. {
  1778. DoInit();
  1779. return (&mg_rDefaultCharset);
  1780. }
  1781. void CIntlGlobals::SetDefBodyCset(LPINETCSETINFO pCharset)
  1782. {
  1783. DoInit();
  1784. mg_pDefBodyCset = pCharset;
  1785. }
  1786. void CIntlGlobals::SetDefHeadCset(LPINETCSETINFO pCharset)
  1787. {
  1788. DoInit();
  1789. mg_pDefHeadCset = pCharset;
  1790. }
  1791. BOOL CIntlGlobals::mg_bInit = FALSE;
  1792. LPINETCSETINFO CIntlGlobals::mg_pDefBodyCset = NULL;
  1793. LPINETCSETINFO CIntlGlobals::mg_pDefHeadCset = NULL;
  1794. CRITICAL_SECTION CIntlGlobals::mg_cs;