Source code of Windows XP (NT5)
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.

2410 lines
68 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: misc
  6. File: util.cpp
  7. Owner: AndrewS
  8. This file contains random useful utility functions
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "MemChk.h"
  13. #include "locale.h"
  14. #include <malloc.h>
  15. #include <mbstring.h>
  16. #include <mbctype.h>
  17. extern CPINFO g_SystemCPInfo; // global System CodePage default info.
  18. // ***************************************************************************
  19. // M I S C
  20. // ***************************************************************************
  21. /*===================================================================
  22. Server_ValSize
  23. Server_FindKey
  24. This helper function assists in the implementation of the
  25. SERVER_GET macro
  26. Parameters:
  27. PIReq pointer to CIsapiReqInfo
  28. szBuffer Buffer to write to
  29. pdwBufLen On entry: size of the buffer
  30. On Exit, actual size of the buffer
  31. (required size if buffer was too small)
  32. szKey Key to search for
  33. Returns:
  34. TRUE - it succeeded, string in szBuffer
  35. FALSE - buffer was too small, *pdwBufLen has required size
  36. ===================================================================*/
  37. BOOL Server_FindKey
  38. (
  39. CIsapiReqInfo *PIReq,
  40. char *szBuffer,
  41. DWORD *pdwBufLen,
  42. const char *szKey
  43. )
  44. {
  45. // If no buffer, then just calculate the size (old behavior)
  46. Assert (szBuffer != NULL);
  47. if (PIReq && PIReq->GetServerVariableA(const_cast<char *>(szKey), szBuffer, pdwBufLen))
  48. return TRUE;
  49. szBuffer[0] = '\0';
  50. // Bug 965: If malicious request comes, do not _alloca, and pretend like we
  51. // didn't get anything. This is OK - the rest of Denali will just assume
  52. // there were no cookies, request parameters or client headers.
  53. //
  54. if (!PIReq || GetLastError() == ERROR_INVALID_INDEX || *pdwBufLen > REQUEST_ALLOC_MAX)
  55. {
  56. *pdwBufLen = 1;
  57. return TRUE;
  58. }
  59. return FALSE;
  60. }
  61. /*===================================================================
  62. * F i n d A p p l i c a t i o n P a t h
  63. *
  64. * Get application path from CIsapiReqInfo. It gets the metabase key and
  65. * strips it of prefix.
  66. *
  67. * Parameters:
  68. * PIReq - CIsapiReqInfo
  69. * pszPath - [out] the application path (URL)
  70. *
  71. * Returns:
  72. * HRESULT
  73. *
  74. * Allocates pszPath using malloc()
  75. ===================================================================*/
  76. HRESULT FindApplicationPath
  77. (
  78. CIsapiReqInfo *PIReq,
  79. TCHAR *szPath,
  80. int cbPath
  81. )
  82. {
  83. if (!PIReq)
  84. return E_FAIL;
  85. // Extract virtual path from the metabase path
  86. TCHAR *pch = NULL;
  87. int cch = 0;
  88. // Get the metabase path
  89. TCHAR *szMDPath = PIReq->QueryPszApplnMDPath();
  90. if (szMDPath)
  91. {
  92. Assert(szMDPath[0] == _T('/'));
  93. pch = szMDPath;
  94. // find 4th '/' in "/LM/w3svc/X/root/vroot" after starting '/'
  95. for (int i = 0; i < 4 && pch != NULL; i++)
  96. pch = _tcschr(pch+1, _T('/'));
  97. if (pch)
  98. cch = _tcslen(pch);
  99. else
  100. cch = 1; // special case of default app -- assume /
  101. }
  102. else
  103. {
  104. // assume /
  105. pch = NULL;
  106. cch = 1;
  107. }
  108. if (cch >= (int)(cbPath/sizeof(TCHAR)))
  109. return E_FAIL;
  110. _tcscpy(szPath, pch ? pch : _T("/"));
  111. // remove trailing / if any
  112. if (cch > 1)
  113. {
  114. pch = &szPath[cch - 1];
  115. if (*pch == _T('/'))
  116. *pch = _T('\0');
  117. }
  118. return S_OK;
  119. }
  120. /*===================================================================
  121. VariantResolveDispatch
  122. Convert an IDispatch VARIANT to a (non-Dispatch) VARIANT by
  123. invoking its default property until the object that remains
  124. is not an IDispatch. If the original VARIANT is not an IDispatch
  125. then the behavior is identical to VariantCopyInd(), with the
  126. exception that arrays are copied.
  127. Parameters:
  128. pVarOut - if successful, the return value is placed here
  129. pVarIn - the variant to copy
  130. GUID *iidObj - the calling interface (for error reporting)
  131. nObjID - the Object's name from the resource file
  132. pVarOut need not be initialized. Since pVarOut is a new
  133. variant, the caller must VariantClear this object.
  134. Returns:
  135. The result of calling IDispatch::Invoke. (either S_OK or
  136. the error resulting from the call to Invoke) may also return
  137. E_OUTOFMEMORY if an allocation fails
  138. This function always calls Exception() if an error occurs -
  139. this is because we need to call Exception() if an IDispatch
  140. method raises an exception. Instead of having the client
  141. worry about whether we called Exception() on its behalf or
  142. not, we always raise the exception.
  143. ===================================================================*/
  144. HRESULT VariantResolveDispatch(VARIANT *pVarOut, VARIANT *pVarIn, const GUID &iidObj, int nObjID)
  145. {
  146. VARIANT varResolved; // value of IDispatch::Invoke
  147. DISPPARAMS dispParamsNoArgs = {NULL, NULL, 0, 0};
  148. EXCEPINFO ExcepInfo;
  149. HRESULT hrCopy;
  150. Assert (pVarIn != NULL && pVarOut != NULL);
  151. VariantInit(pVarOut);
  152. if (V_VT(pVarIn) & VT_BYREF)
  153. hrCopy = VariantCopyInd(pVarOut, pVarIn);
  154. else
  155. hrCopy = VariantCopy(pVarOut, pVarIn);
  156. if (FAILED(hrCopy))
  157. {
  158. ExceptionId(iidObj, nObjID, (hrCopy == E_OUTOFMEMORY)? IDE_OOM : IDE_UNEXPECTED);
  159. return hrCopy;
  160. }
  161. // follow the IDispatch chain.
  162. //
  163. while (V_VT(pVarOut) == VT_DISPATCH)
  164. {
  165. HRESULT hrInvoke = S_OK;
  166. // If the variant is equal to Nothing, then it can be argued
  167. // with certainty that it does not have a default property!
  168. // hence we return DISP_E_MEMBERNOTFOUND for this case.
  169. //
  170. if (V_DISPATCH(pVarOut) == NULL)
  171. hrInvoke = DISP_E_MEMBERNOTFOUND;
  172. else
  173. {
  174. VariantInit(&varResolved);
  175. hrInvoke = V_DISPATCH(pVarOut)->Invoke(
  176. DISPID_VALUE,
  177. IID_NULL,
  178. LOCALE_SYSTEM_DEFAULT,
  179. DISPATCH_PROPERTYGET | DISPATCH_METHOD,
  180. &dispParamsNoArgs,
  181. &varResolved,
  182. &ExcepInfo,
  183. NULL);
  184. }
  185. if (FAILED(hrInvoke))
  186. {
  187. if (hrInvoke == DISP_E_EXCEPTION)
  188. {
  189. //
  190. // forward the ExcepInfo from Invoke to caller's ExcepInfo
  191. //
  192. Exception(iidObj, ExcepInfo.bstrSource, ExcepInfo.bstrDescription);
  193. SysFreeString(ExcepInfo.bstrHelpFile);
  194. }
  195. else
  196. ExceptionId(iidObj, nObjID, IDE_UTIL_NO_VALUE);
  197. VariantClear(pVarOut);
  198. return hrInvoke;
  199. }
  200. // The correct code to restart the loop is:
  201. //
  202. // VariantClear(pVar)
  203. // VariantCopy(pVar, &varResolved);
  204. // VariantClear(&varResolved);
  205. //
  206. // however, the same affect can be achieved by:
  207. //
  208. // VariantClear(pVar)
  209. // *pVar = varResolved;
  210. // VariantInit(&varResolved)
  211. //
  212. // this avoids a copy. The equivalence rests in the fact that
  213. // *pVar will contain the pointers of varResolved, after we
  214. // trash varResolved (WITHOUT releasing strings or dispatch
  215. // pointers), so the net ref count is unchanged. For strings,
  216. // there is still only one pointer to the string.
  217. //
  218. // NOTE: the next interation of the loop will do the VariantInit.
  219. //
  220. VariantClear(pVarOut);
  221. *pVarOut = varResolved;
  222. }
  223. return S_OK;
  224. }
  225. /*===================================================================
  226. VariantGetBSTR
  227. Gets BSTR from the variant (does one possible indirection)
  228. Parameters:
  229. var - VARIANT
  230. Returns:
  231. BSTR or NULL if none
  232. ===================================================================*/
  233. BSTR VariantGetBSTR(const VARIANT *pvar)
  234. {
  235. if (V_VT(pvar) == VT_BSTR) // straight BSTR
  236. return V_BSTR(pvar);
  237. if (V_VT(pvar) == (VT_BYREF|VT_VARIANT))
  238. {
  239. VARIANT *pvarRef = V_VARIANTREF(pvar); // Variant by ref
  240. if (pvarRef && V_VT(pvarRef) == VT_BSTR)
  241. return V_BSTR(pvarRef);
  242. }
  243. return NULL;
  244. }
  245. /*===================================================================
  246. Normalize
  247. Converts a filename IN PLACE to a normalized form so that we don't
  248. cache identical files with different names (i.e. Foo, foo,
  249. .\foo, etc)
  250. Algorithm:
  251. The file is translated to uppercase and forward slash (/)
  252. characters are converted to backward slash (\)
  253. Return Value:
  254. cch of normalized string
  255. Note: This function is used for PathInfo only, and using system ANSI codepage.
  256. ===================================================================*/
  257. int Normalize
  258. (
  259. char* szSrc // source string
  260. )
  261. {
  262. char *szDest = szSrc;
  263. CPINFO CpInfo;
  264. BOOL fReturn;
  265. Assert(szSrc != NULL);
  266. fReturn = GetCPInfo(CP_ACP, (LPCPINFO)&CpInfo);
  267. Assert(fReturn == TRUE);
  268. // CONSIDER reinstate LCMapString
  269. // NOTE LCMapString should return string length but it returns 0? - could avoid call to lstrlen
  270. int cchRet = lstrlen(szSrc);
  271. /* bug 1236: CONSIDER reinstate LCMapString
  272. if(FIsWinNT())
  273. {
  274. LCMapString(
  275. LOCALE_SYSTEM_DEFAULT, // LCID locale identifier
  276. LCMAP_UPPERCASE, // DWORD mapping transformation type
  277. szSrc, // LPCTSTR address of source string
  278. -1, // int number of characters in source string
  279. szDest, // LPTSTR address of destination buffer
  280. cchRet // int size of destination buffer
  281. );
  282. }
  283. else
  284. */
  285. {
  286. if (szDest == szSrc)
  287. { //convert source string IN PLACE
  288. while(*szDest)
  289. {
  290. if (CpInfo.MaxCharSize == 2 && IsDBCSLeadByte((BYTE)*szDest))
  291. {
  292. szDest += 2;
  293. continue;
  294. }
  295. *szDest = (char)toupper(*szDest);
  296. szDest++;
  297. }
  298. szDest = szSrc;
  299. }
  300. else
  301. {
  302. CHAR *szDestT;
  303. CHAR *szSrcT;
  304. szDestT = szDest;
  305. szSrcT = szSrc;
  306. while(*szSrcT)
  307. {
  308. if (CpInfo.MaxCharSize == 2 && IsDBCSLeadByte((BYTE)*szSrcT))
  309. {
  310. *szDestT++ = *szSrcT++;
  311. *szDestT++ = *szSrcT++;
  312. continue;
  313. }
  314. *szDestT = (CHAR)toupper(*szSrcT);
  315. szSrcT++;
  316. szDestT++;
  317. }
  318. }
  319. }
  320. szDest[cchRet] = '\0';
  321. char *szTemp = szDest;
  322. while (*szTemp)
  323. {
  324. if (CpInfo.MaxCharSize == 2 && IsDBCSLeadByte((BYTE)*szTemp))
  325. {
  326. szTemp += 2;
  327. continue;
  328. }
  329. // DBCSLeadByte can not be any printable char
  330. if (*szTemp == '/')
  331. *szTemp = '\\';
  332. ++szTemp;
  333. }
  334. return cchRet;
  335. }
  336. #ifdef DBG
  337. BOOLB IsNormalized(const char *_sz)
  338. {
  339. CPINFO CpInfo;
  340. BOOL fReturn;
  341. fReturn = GetCPInfo(CP_ACP, (LPCPINFO)&CpInfo);
  342. Assert(fReturn == TRUE);
  343. const unsigned char *sz = reinterpret_cast<const unsigned char *>(_sz);
  344. while (*sz)
  345. {
  346. if (CpInfo.MaxCharSize == 2 &&IsDBCSLeadByte((BYTE)*sz))
  347. {
  348. sz += 2;
  349. continue;
  350. }
  351. if (*sz != toupper(*sz) || *sz == '/')
  352. return FALSE;
  353. ++sz;
  354. }
  355. return TRUE;
  356. }
  357. #endif // DBG
  358. /*===================================================================
  359. HTMLEncodeLen
  360. HTML Encode len returns an int representing the string size
  361. required to HTMLEncode a string.
  362. Note: This returned value might be exceeds the actually string size needed to
  363. HTMLEncode a string.(since we are going to drop the leading zeros in &#00257;
  364. case.,
  365. the returned value includes the 2 chars for the leading zeros)
  366. Parameters:
  367. szSrc - Pointer to the source buffer
  368. fEncodeExtCharOnly - FALSE, Normal encoding
  369. TRUE, encodes extended chars, does not encode '<', '>', '&',
  370. and '"'.
  371. uCodePage - system code page
  372. Returns:
  373. int storage required to encode string.
  374. ===================================================================*/
  375. int HTMLEncodeLen(const char *szSrc, UINT uCodePage, BSTR bstrIn, BOOL fEncodeExtCharOnly)
  376. {
  377. int nstrlen = 1; // Add NUL space now
  378. int i = 0;
  379. // Bug 97049 return 0 on NULL instead of crashing
  380. if (!szSrc)
  381. return 0;
  382. while (*szSrc)
  383. {
  384. // The original condition is unsuitable for DBCS.
  385. // It is possible that new one allows to encode extended character
  386. // even if running system is DBCS.
  387. //
  388. // if bstrIn == NULL, chech DBCS
  389. // if bstrIn != NULL and Unicode is latin-1 area(<0x100), check DBCS
  390. // else skip to check DBCS
  391. if (!(bstrIn && bstrIn[i] < 0x100) && ::IsDBCSLeadByteEx(uCodePage, (BYTE)*szSrc))
  392. {
  393. // this is a DBCS code page do not encode the data copy 2 bytes
  394. // no incremnt because of using CharNextExA at the end of the loop
  395. nstrlen += 2;
  396. }
  397. // Japanese only.
  398. // Do not encode if character is half-width katakana character.
  399. // We should use GetStringTypeA to detect half-width katakana char instead of _ismbbkana()???
  400. // (I used _ismbbkana at this time for performance reason...)
  401. //
  402. else if ((uCodePage == 932 || uCodePage == CP_ACP && ::GetACP() == 932 ) && _ismbbkana(*szSrc))
  403. {
  404. nstrlen++;
  405. }
  406. // Special case character encoding
  407. //
  408. else if (*szSrc == '<')
  409. if (fEncodeExtCharOnly)
  410. nstrlen++;
  411. else
  412. nstrlen += 4;
  413. else if (*szSrc == '>')
  414. if (fEncodeExtCharOnly)
  415. nstrlen++;
  416. else
  417. nstrlen += 4;
  418. else if (*szSrc == '&')
  419. if (fEncodeExtCharOnly)
  420. nstrlen++;
  421. else
  422. nstrlen += 5;
  423. else if (*szSrc == '"')
  424. if (fEncodeExtCharOnly)
  425. nstrlen++;
  426. else
  427. nstrlen += 6;
  428. // According RFC, if character code is greater than equal 0xa0, encode it.
  429. //
  430. // Note: For &#00257;, we might drop the leading zeros, therefore, we are not
  431. // going to use all 8 chars. We will need only 6 digits in this case.(&#257;).
  432. // We need at most 8 chars.
  433. else if ( bstrIn && (bstrIn[i] >= 0xa0) )
  434. {
  435. nstrlen += 8;
  436. }
  437. else if ((unsigned char)*szSrc >= 0xa0 )
  438. {
  439. nstrlen += 6;
  440. }
  441. else
  442. {
  443. nstrlen++;
  444. }
  445. // increment szSrc and i (they must be kept in sync)
  446. szSrc = AspCharNextA(WORD(uCodePage), szSrc);
  447. i++;
  448. }
  449. return nstrlen;
  450. }
  451. /*===================================================================
  452. HTMLEncode
  453. HTML Encode a string containing the following characters
  454. less than < &lt;
  455. greater than > &gt;
  456. ampersand & &amp;
  457. quote " &quot;
  458. any Ascii ? &#xxx (where xxx is the ascii char val)
  459. Parameters:
  460. szDest - Pointer to the buffer to store the HTMLEncoded string
  461. szSrc - Pointer to the source buffer
  462. fEncodeExtCharOnly - FALSE, Normal encoding
  463. TRUE, encodes extended chars, does not encode '<', '>', '&',
  464. and '"'.
  465. uCodePage - system code page
  466. Returns:
  467. A pointer to the NUL terminated string.
  468. ===================================================================*/
  469. char *HTMLEncode(char *szDest, const char *szSrc, UINT uCodePage, BSTR bstrIn, BOOL fEncodeExtCharOnly)
  470. {
  471. char *pszDest = szDest;
  472. int i = 0;
  473. // Bug 97049 return on NULL instead of crashing
  474. if (!szDest)
  475. return NULL;
  476. if (!szSrc)
  477. {
  478. *szDest = '\0';
  479. return pszDest;
  480. }
  481. while (*szSrc)
  482. {
  483. //
  484. // The original condition is unsuitable for DBCS.
  485. // It is possible that new one allows to encode extended character
  486. // even if running system is DBCS.
  487. //
  488. // if Unicode is latin-1 area(<0x100), skip to check DBCS
  489. // bstrIn == NULL to handle the case were HTMLEncode is called internally
  490. // and bstrIn is NULL
  491. //
  492. // if bstrIn == NULL, chech DBCS
  493. // if bstrIn != NULL and Unicode is latin-1 area(<0x100), check DBCS
  494. // else skip to check DBCS
  495. if (!(bstrIn && bstrIn[i] < 0x100) && ::IsDBCSLeadByteEx(uCodePage, (BYTE)*szSrc))
  496. {
  497. // this is a DBCS code page do not encode the data copy 2 bytes
  498. // no incremnt because of using CharNextExA at the end of the loop
  499. *szDest++ = *szSrc;
  500. *szDest++ = *(szSrc + 1);
  501. }
  502. //
  503. // Japanese only.
  504. // Do not encode if character is half-width katakana character.
  505. //
  506. else if ( (uCodePage == 932 || uCodePage == CP_ACP && ::GetACP() == 932) && _ismbbkana(*szSrc))
  507. {
  508. *szDest++ = *szSrc;
  509. }
  510. // Special case character encoding
  511. else if (*szSrc == '<')
  512. if (fEncodeExtCharOnly)
  513. *szDest++ = *szSrc;
  514. else
  515. szDest = strcpyExA(szDest, "&lt;");
  516. else if (*szSrc == '>')
  517. if (fEncodeExtCharOnly)
  518. *szDest++ = *szSrc;
  519. else
  520. szDest = strcpyExA(szDest, "&gt;");
  521. else if (*szSrc == '&')
  522. if (fEncodeExtCharOnly)
  523. *szDest++ = *szSrc;
  524. else
  525. szDest = strcpyExA(szDest, "&amp;");
  526. else if (*szSrc == '"')
  527. if (fEncodeExtCharOnly)
  528. *szDest++ = *szSrc;
  529. else
  530. szDest = strcpyExA(szDest, "&quot;");
  531. // According RFC, if character code is greater than equal 0xa0, encode it.
  532. //
  533. // BUG 153089 - WideCharToMultiByte would incorrectly convert some
  534. // characters above the range of 0xA0 so we now use the BSTR as our source
  535. // to check for characters that should be encoded.
  536. //
  537. else if ( bstrIn && (bstrIn[i] >= 0xa0))
  538. {
  539. BOOL fSurrogate = FALSE;
  540. WORD count = 1;
  541. // Check if the bstrIn currently points to a surrogate Pair
  542. // Surrogate pairs would account for 2 bytes in the BSTR.
  543. // High Surrogate = U+D800 <==> U+DBFF
  544. // Low Surrogate = U+DC00 <==> U+DFFF
  545. if ((bstrIn[i] >= 0xd800 && bstrIn[i] <= 0xdfff) // Check the higher byte.
  546. && (bstrIn[i+1] >= 0xd800 && bstrIn[i+1] <= 0xdfff)) // Check the lower byte too.
  547. {
  548. // Surrogate Pair exists so iterate through the code twice.
  549. fSurrogate = TRUE;
  550. count++;
  551. }
  552. for (WORD iter = 0; iter < count ; iter ++)
  553. {
  554. WORD wTemp = *(bstrIn+i+iter);
  555. INT iTemp;
  556. BOOL fLeadZero = TRUE;
  557. *szDest++ = '&';
  558. *szDest++ = '#';
  559. for (WORD Index = 10000; Index > 0; Index /= 10)
  560. {
  561. iTemp = ((unsigned char) (wTemp / Index));
  562. if (fLeadZero == TRUE)
  563. {
  564. if (iTemp == 0 && Index > 100)
  565. {
  566. continue;
  567. }
  568. else
  569. {
  570. fLeadZero = FALSE;
  571. }
  572. }
  573. *szDest++ = iTemp + '0';
  574. wTemp = wTemp % Index;
  575. }
  576. *szDest++ = ';';
  577. }
  578. if (fSurrogate)
  579. i++; // Increment bstrIn index as surrogatepair was detected.
  580. }
  581. else if ((unsigned char)*szSrc >= 0xa0)
  582. {
  583. // Since this is unsigned char casting, the value of WORD wTemp
  584. // is not going to exceed 0xff(255). So, 3 digit is sufficient here.
  585. WORD wTemp = (unsigned char)*szSrc;
  586. *szDest++ = '&';
  587. *szDest++ = '#';
  588. for (WORD Index = 100; Index > 0; Index /= 10)
  589. {
  590. *szDest++ = ((unsigned char) (wTemp / Index)) + '0';
  591. wTemp = wTemp % Index;
  592. }
  593. *szDest++ = ';';
  594. }
  595. else
  596. *szDest++ = *szSrc;
  597. // increment szSrc and i (they must be kept in sync)
  598. szSrc = AspCharNextA(WORD(uCodePage), szSrc);
  599. i++; // Regular increment of the bstrIn index.
  600. }
  601. *szDest = '\0';
  602. return pszDest;
  603. }
  604. /*===================================================================
  605. strcpyExA
  606. Copy one string to another, returning a pointer to the NUL character
  607. in the destination
  608. Parameters:
  609. szDest - pointer to the destination string
  610. szSrc - pointer to the source string
  611. Returns:
  612. A pointer to the NUL terminator is returned.
  613. ===================================================================*/
  614. char *strcpyExA(char *szDest, const char *szSrc)
  615. {
  616. while (*szDest++ = *szSrc++)
  617. ;
  618. return szDest - 1;
  619. }
  620. /*===================================================================
  621. strcpyExW
  622. Copy one wide string to another, returning a pointer to the NUL character
  623. in the destination
  624. Parameters:
  625. wszDest - pointer to the destination string
  626. wszSrc - pointer to the source string
  627. Returns:
  628. A pointer to the NUL terminator is returned.
  629. ===================================================================*/
  630. wchar_t *strcpyExW(wchar_t *wszDest, const wchar_t *wszSrc)
  631. {
  632. while (*wszDest++ = *wszSrc++)
  633. ;
  634. return wszDest - 1;
  635. }
  636. /*===================================================================
  637. URLEncodeLen
  638. Return the storage requirements for a URL-Encoded string
  639. Parameters:
  640. szSrc - Pointer to the string to URL Encode
  641. Returns:
  642. the number of bytes required to encode the string
  643. ===================================================================*/
  644. int URLEncodeLen(const char *szSrc)
  645. {
  646. int cbURL = 1; // add terminator now
  647. // Bug 97049 return 0 on NULL instead of crashing
  648. if (!szSrc)
  649. return 0;
  650. while (*szSrc)
  651. {
  652. if (*szSrc & 0x80) // encode foreign characters
  653. cbURL += 3;
  654. else if (*szSrc == ' ') // encoded space requires only one character
  655. ++cbURL;
  656. else if (!isalnum((UCHAR)(*szSrc))) // encode non-alphabetic characters
  657. cbURL += 3;
  658. else
  659. ++cbURL;
  660. ++szSrc;
  661. }
  662. return cbURL;
  663. }
  664. /*===================================================================
  665. URLEncode
  666. URL Encode a string by changing space characters to '+' and escaping
  667. non-alphanumeric characters in hex.
  668. Parameters:
  669. szDest - Pointer to the buffer to store the URLEncoded string
  670. szSrc - Pointer to the source buffer
  671. Returns:
  672. A pointer to the NUL terminator is returned.
  673. ===================================================================*/
  674. char *URLEncode(char *szDest, const char *szSrc)
  675. {
  676. char hex[] = "0123456789ABCDEF";
  677. // Bug 97049 return on NULL instead of crashing
  678. if (!szDest)
  679. return NULL;
  680. if (!szSrc)
  681. {
  682. *szDest = '\0';
  683. return szDest;
  684. }
  685. while (*szSrc)
  686. {
  687. if (*szSrc == ' ')
  688. {
  689. *szDest++ = '+';
  690. ++szSrc;
  691. }
  692. else if ( (*szSrc & 0x80) || !isalnum((UCHAR)(*szSrc)) )
  693. {
  694. *szDest++ = '%';
  695. *szDest++ = hex[BYTE(*szSrc) >> 4];
  696. *szDest++ = hex[*szSrc++ & 0x0F];
  697. }
  698. else
  699. *szDest++ = *szSrc++;
  700. }
  701. *szDest = '\0';
  702. return szDest;
  703. }
  704. /*===================================================================
  705. DBCSEncodeLen
  706. Return the storage requirements for a DBCS encoded string
  707. (url-encoding of characters with the upper bit set ONLY)
  708. Parameters:
  709. szSrc - Pointer to the string to URL Encode
  710. Returns:
  711. the number of bytes required to encode the string
  712. ===================================================================*/
  713. int DBCSEncodeLen(const char *szSrc)
  714. {
  715. int cbURL = 1; // add terminator now
  716. // Bug 97049 return 0 on NULL instead of crashing
  717. if (!szSrc)
  718. return 0;
  719. while (*szSrc)
  720. {
  721. cbURL += ((*szSrc & 0x80) || (!isalnum((UCHAR)(*szSrc)) && !strchr("/$-_.+!*'(),", *szSrc)))? 3 : 1;
  722. ++szSrc;
  723. }
  724. return cbURL;
  725. }
  726. /*===================================================================
  727. DBCSEncode
  728. DBCS Encode a string by escaping characters with the upper bit
  729. set - Basically used to convert 8 bit data to 7 bit in contexts
  730. where full encoding is not needed.
  731. Parameters:
  732. szDest - Pointer to the buffer to store the URLEncoded string
  733. szSrc - Pointer to the source buffer
  734. Returns:
  735. A pointer to the NUL terminator is returned.
  736. ===================================================================*/
  737. char *DBCSEncode(char *szDest, const char *szSrc)
  738. {
  739. char hex[] = "0123456789ABCDEF";
  740. // Bug 97049 return on NULL instead of crashing
  741. if (!szDest)
  742. return NULL;
  743. if (!szSrc)
  744. {
  745. *szDest = '\0';
  746. return szDest;
  747. }
  748. while (*szSrc)
  749. {
  750. if ((*szSrc & 0x80) || (!isalnum((UCHAR)(*szSrc)) && !strchr("/$-_.+!*'(),", *szSrc)))
  751. {
  752. *szDest++ = '%';
  753. *szDest++ = hex[BYTE(*szSrc) >> 4];
  754. *szDest++ = hex[*szSrc++ & 0x0F];
  755. }
  756. else
  757. *szDest++ = *szSrc++;
  758. }
  759. *szDest = '\0';
  760. return szDest;
  761. }
  762. /*===================================================================
  763. URLPathEncodeLen
  764. Return the storage requirements for a URLPath-Encoded string
  765. Parameters:
  766. szSrc - Pointer to the string to URL Path Encode
  767. Returns:
  768. the number of bytes required to encode the string
  769. ===================================================================*/
  770. int URLPathEncodeLen(const char *szSrc)
  771. {
  772. int cbURL = 1; // count terminator now
  773. // Bug 97049 return 0 on NULL instead of crashing
  774. if (!szSrc)
  775. return 0;
  776. while ((*szSrc) && (*szSrc != '?'))
  777. {
  778. switch (*szSrc)
  779. {
  780. // Ignore safe characters
  781. case '$' : case '_' : case '-' :
  782. case '+' : case '.' : case '&' :
  783. // Ignore URL syntax elements
  784. case '/' : case ':' : case '@' :
  785. case '#' : case '*' : case '!' :
  786. ++cbURL;
  787. break;
  788. default:
  789. if (!isalnum((UCHAR)(*szSrc)) || // encode non-alphabetic characters
  790. (*szSrc & 0x80)) // encode foreign characters
  791. cbURL += 3;
  792. else
  793. ++cbURL;
  794. }
  795. ++szSrc;
  796. }
  797. if (*szSrc == '?')
  798. {
  799. while (*szSrc)
  800. {
  801. ++cbURL;
  802. ++szSrc;
  803. }
  804. }
  805. return cbURL;
  806. }
  807. /*===================================================================
  808. URLPathEncode
  809. Encodes the path portion of a URL. All characters up to the first
  810. '?' are encoded with the following rules:
  811. o Charcters that are needed to parse the URL are left alone:
  812. '/' '.' ':' '@' '#' '*' '!'
  813. o Non-foreign alphanumberic characters are left alone
  814. o Anything else is escape encoded
  815. Everything after the '?' is ignored.
  816. Parameters:
  817. szDest - Pointer to the buffer to store the URLPathEncoded string
  818. szSrc - Pointer to the source buffer
  819. Returns:
  820. A pointer to the NUL terminator is returned.
  821. ===================================================================*/
  822. char *URLPathEncode(char *szDest, const char *szSrc)
  823. {
  824. char hex[] = "0123456789ABCDEF";
  825. // Bug 97049 return on NULL instead of crashing
  826. if (!szDest)
  827. return NULL;
  828. if (!szSrc)
  829. {
  830. *szDest = '\0';
  831. return szDest;
  832. }
  833. while ((*szSrc) && (*szSrc != '?'))
  834. {
  835. switch (*szSrc)
  836. {
  837. // Ignore safe characters
  838. case '$' : case '_' : case '-' :
  839. case '+' : case '.' : case '~' :
  840. case '&' :
  841. // Ignore URL syntax elements
  842. case '/' : case ':' : case '@' :
  843. case '#' : case '*' : case '!' :
  844. *szDest++ = *szSrc++;
  845. break;
  846. default:
  847. if (!isalnum((UCHAR)(*szSrc)) || (*szSrc & 0x80))
  848. {
  849. *szDest++ = '%';
  850. *szDest++ = hex[BYTE(*szSrc) >> 4];
  851. *szDest++ = hex[*szSrc++ & 0x0F];
  852. }
  853. else
  854. *szDest++ = *szSrc++;
  855. }
  856. }
  857. if (*szSrc == '?')
  858. {
  859. while (*szSrc)
  860. {
  861. *szDest++ = *szSrc++;
  862. }
  863. }
  864. *szDest = '\0';
  865. return szDest;
  866. }
  867. // ***************************************************************************
  868. // T I M E C O N V E R S I O N S U P P O R T
  869. // ***************************************************************************
  870. /*===================================================================
  871. CTimeToVariantDate
  872. Converts a time_t structure to a Variant Date structure
  873. Parameters:
  874. ptNow - date & time to convert
  875. pdtResult - DATE output of this function
  876. Returns:
  877. E_FAIL if things go wrong.
  878. ===================================================================*/
  879. HRESULT CTimeToVariantDate(const time_t *ptNow, DATE *pdtResult)
  880. {
  881. struct tm *ptmNow = localtime(ptNow);
  882. if (ptmNow == NULL)
  883. return E_FAIL;
  884. return
  885. DosDateTimeToVariantTime(
  886. ptmNow->tm_mday | ((ptmNow->tm_mon + 1) << 5) | ((ptmNow->tm_year - 80) << 9),
  887. (unsigned(ptmNow->tm_sec) >> 1) | (ptmNow->tm_min << 5) | (ptmNow->tm_hour << 11),
  888. pdtResult);
  889. }
  890. /*===================================================================
  891. VariantDateToCTime
  892. Converts a variant date to a time_t structure used by the "C"
  893. language
  894. Parameters:
  895. dt - date to convert to "time_t"
  896. ptResult - pointer to result which has the value
  897. Returns:
  898. E_FAIL if things go wrong.
  899. ===================================================================*/
  900. HRESULT VariantDateToCTime(DATE dt, time_t *ptResult)
  901. {
  902. // Convert the variant time to a documented time format
  903. //
  904. unsigned short wDOSDate, wDOSTime;
  905. if (! VariantTimeToDosDateTime(dt, &wDOSDate, &wDOSTime))
  906. return E_FAIL;
  907. // populate a "tm" struct
  908. //
  909. struct tm tmConverted;
  910. tmConverted.tm_sec = (wDOSTime & 0x1F) << 1;
  911. tmConverted.tm_min = (wDOSTime >> 5) & 0x3F;
  912. tmConverted.tm_hour = wDOSTime >> 11;
  913. tmConverted.tm_mday = wDOSDate & 0x1F;
  914. tmConverted.tm_mon = ((wDOSDate >> 5) & 0x0F) - 1;
  915. tmConverted.tm_year = (wDOSDate >> 9) + 80; // adjust for offset from 1980
  916. tmConverted.tm_isdst = -1;
  917. // convert the "tm" struct to the number of seconds since Jan 1, 1980
  918. //
  919. *ptResult = mktime(&tmConverted);
  920. return (*ptResult == -1)? E_FAIL : S_OK;
  921. }
  922. /*===================================================================
  923. CTimeToStringGMT
  924. Converts a C language time_t to a string of the form:
  925. "Wed, 09-Nov-1999 23:12:40 GMT"
  926. Parameters:
  927. ptNow - the time to convert
  928. szBuffer - pointer to the destination buffer
  929. Returns:
  930. E_FAIL if something goes wrong
  931. Notes:
  932. The longest day of the week (in terms of spelling) is "Wednesday";
  933. the other fields are fixed length. This means that we can
  934. guarantee the maximum length of szBuffer - there is no need
  935. for client code to dynamically allocate a buffer.
  936. ===================================================================*/
  937. HRESULT CTimeToStringGMT(const time_t *ptNow, char szBuffer[DATE_STRING_SIZE], BOOL fFunkyCookieFormat)
  938. {
  939. // The internet standard explicitly says that
  940. // month and weekday names are in english.
  941. const char rgstrDOW[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  942. const char rgstrMonth[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  943. // convert time to GMT
  944. struct tm *ptmGMT = gmtime(ptNow);
  945. if (ptmGMT == NULL)
  946. {
  947. return E_FAIL;
  948. }
  949. // send output in internet format
  950. const char *szDateFormat = fFunkyCookieFormat?
  951. "%s, %02d-%s-%d %02d:%02d:%02d GMT"
  952. : "%s, %02d %s %d %02d:%02d:%02d GMT";
  953. sprintf(szBuffer, szDateFormat, rgstrDOW[ptmGMT->tm_wday], ptmGMT->tm_mday,
  954. rgstrMonth[ptmGMT->tm_mon], ptmGMT->tm_year+1900,
  955. ptmGMT->tm_hour, ptmGMT->tm_min, ptmGMT->tm_sec);
  956. return S_OK;
  957. }
  958. /*
  959. // there is a bug in the C-runtime function strftime that will cause
  960. // an AV on the ALPHA on multi-threaded stress the function has been
  961. // re-written to work around this problem
  962. //
  963. HRESULT CTimeToStringGMT(const time_t *ptNow, char szBuffer[DATE_STRING_SIZE], BOOL fFunkyCookieFormat)
  964. {
  965. // convert time to GMT
  966. //
  967. struct tm *ptmGMT = gmtime(ptNow);
  968. if (ptmGMT == NULL)
  969. return E_FAIL;
  970. // Set locale to "C" locale. The internet standard explicitly says that
  971. // month and weekday names are in english.
  972. //
  973. char *lcTimeCurrent = setlocale(LC_TIME, "C");
  974. if (lcTimeCurrent == NULL)
  975. return E_FAIL;
  976. // send output in internet format
  977. //
  978. const char *szDateFormat = fFunkyCookieFormat?
  979. "%a, %d-%b-%Y %H:%M:%S GMT"
  980. : "%a, %d %b %Y %H:%M:%S GMT";
  981. strftime(szBuffer, DATE_STRING_SIZE, szDateFormat, ptmGMT);
  982. // Restore locale
  983. //
  984. if (! setlocale(LC_TIME, lcTimeCurrent))
  985. return E_FAIL;
  986. // done
  987. return S_OK;
  988. }
  989. */
  990. // ***************************************************************************
  991. // W I D E C H A R A C T E R S U P P O R T
  992. // ***************************************************************************
  993. /*============================================================================
  994. WstrToMBstrEx
  995. Copies a wide character string into an ansi string.
  996. Parameters:
  997. LPSTR dest - The string to copy into
  998. LPWSTR src - the input BSTR
  999. cchBuffer - the number of CHARs allocated for the destination string.
  1000. lCodePage - the codepage used in conversion, default to CP_ACP
  1001. ============================================================================*/
  1002. UINT WstrToMBstrEx(LPSTR dest, INT cchDest, LPCWSTR src, int cchSrc, UINT lCodePage)
  1003. {
  1004. UINT cch;
  1005. DBG_ASSERT(cchDest > 0);
  1006. // if the src length was specified, then reserve room for the NULL terminator.
  1007. // This is necessary because WideCharToMultiByte doesn't add or account for
  1008. // the NULL terminator if a source is specified.
  1009. if (cchSrc != -1)
  1010. cchDest--;
  1011. cch = WideCharToMultiByte(lCodePage, 0, src, cchSrc, dest, cchDest, NULL, NULL);
  1012. if (cch == 0)
  1013. {
  1014. dest[0] = '\0';
  1015. if(ERROR_INSUFFICIENT_BUFFER == GetLastError())
  1016. {
  1017. cch = WideCharToMultiByte(lCodePage, 0, src, cchSrc, dest, 0, NULL, NULL);
  1018. // if a src length was specified, then WideCharToMultiByte does not include
  1019. // it in it's resulting length. Bump the count so that the caller does
  1020. // account for the NULL.
  1021. if (cchSrc != -1)
  1022. cch++;
  1023. }
  1024. else
  1025. {
  1026. DBG_ASSERT(FALSE);
  1027. DBGERROR((DBG_CONTEXT, "Last error is %d\n", GetLastError()));
  1028. cch = 1;
  1029. }
  1030. }
  1031. else if (cchSrc != -1)
  1032. {
  1033. // if a src length was specified, then WideCharToMultiByte does not include
  1034. // it in it's resulting length nor does it add the NULL terminator. So add
  1035. // it and bump the count.
  1036. dest[cch++] = '\0';
  1037. }
  1038. DBG_ASSERT(cch != 0);
  1039. return cch;
  1040. }
  1041. /*============================================================================
  1042. MBstrToWstrEx
  1043. Copies a ansi string into an wide character string.
  1044. Parameters:
  1045. LPWSTR dest - The string to copy into
  1046. LPSTR src - the input ANSI string
  1047. cchDest - the number of Wide CHARs allocated for the destination string.
  1048. cchSrc - the length of the source ANSI string
  1049. lCodePage - the codepage used in conversion, default to CP_ACP
  1050. ============================================================================*/
  1051. UINT MBstrToWstrEx(LPWSTR dest, INT cchDest, LPCSTR src, int cchSrc, UINT lCodePage)
  1052. {
  1053. UINT cch;
  1054. DBG_ASSERT(cchDest > 0);
  1055. // if the src length was specified, then reserve room for the NULL terminator.
  1056. // This is necessary because WideCharToMultiByte doesn't add or account for
  1057. // the NULL terminator if a source is specified.
  1058. if (cchSrc != -1)
  1059. cchDest--;
  1060. cch = MultiByteToWideChar(lCodePage, 0, src, cchSrc, dest, cchDest);
  1061. if (cch == 0)
  1062. {
  1063. dest[0] = '\0';
  1064. if(ERROR_INSUFFICIENT_BUFFER == GetLastError())
  1065. {
  1066. cch = MultiByteToWideChar(lCodePage, 0, src, cchSrc, dest, 0);
  1067. // if a src length was specified, then WideCharToMultiByte does not include
  1068. // it in it's resulting length. Bump the count so that the caller does
  1069. // account for the NULL.
  1070. if (cchSrc != -1)
  1071. cch++;
  1072. }
  1073. else
  1074. {
  1075. DBG_ASSERT(FALSE);
  1076. DBGERROR((DBG_CONTEXT, "Last error is %d\n", GetLastError()));
  1077. cch = 1;
  1078. }
  1079. }
  1080. else if (cchSrc != -1)
  1081. {
  1082. // if a src length was specified, then WideCharToMultiByte does not include
  1083. // it in it's resulting length nor does it add the NULL terminator. So add
  1084. // it and bump the count.
  1085. dest[cch++] = '\0';
  1086. }
  1087. DBG_ASSERT(cch != 0);
  1088. return cch;
  1089. }
  1090. /*============================================================================
  1091. SysAllocStringFromSz
  1092. Allocate a System BSTR and copy the given ANSI string into it.
  1093. Parameters:
  1094. sz - The string to copy (Note: this IS an "sz", we will stop at the first NULL)
  1095. cch - the number of ANSI characters in szT. If 0, will calculate size.
  1096. BSTR *pbstrRet - the returned BSTR
  1097. lCodePage - the codepage for conversion
  1098. Returns:
  1099. Allocated BSTR in return value
  1100. S_OK on success, E_OUTOFMEMORY on OOM
  1101. Side effects:
  1102. Allocates memory. Caller must deallocate
  1103. ============================================================================*/
  1104. HRESULT SysAllocStringFromSz
  1105. (
  1106. CHAR *sz,
  1107. DWORD cch,
  1108. BSTR *pbstrRet,
  1109. UINT lCodePage
  1110. )
  1111. {
  1112. BSTR bstrRet;
  1113. Assert(pbstrRet != NULL);
  1114. if (sz == NULL)
  1115. {
  1116. *pbstrRet = NULL;
  1117. return(S_OK);
  1118. }
  1119. // initialize this because callers look at this to see if the routine was
  1120. // successful
  1121. *pbstrRet = NULL;
  1122. // If they passed 0, then determine string length
  1123. if (cch == 0)
  1124. cch = strlen(sz);
  1125. // Allocate a string of the desired length
  1126. // SysAllocStringLen allocates enough room for unicode characters plus a null
  1127. // Given a NULL string it will just allocate the space
  1128. bstrRet = SysAllocStringLen(NULL, cch);
  1129. if (bstrRet == NULL)
  1130. return(E_OUTOFMEMORY);
  1131. // If we were given "", we will have cch=0. return the empty bstr
  1132. // otherwise, really copy/convert the string
  1133. // NOTE we pass -1 as 4th parameter of MulitByteToWideChar for DBCS support
  1134. if (cch != 0)
  1135. {
  1136. UINT cchTemp = 0;
  1137. if (MultiByteToWideChar(lCodePage, 0, sz, -1, bstrRet, cch+1) == 0)
  1138. return(HRESULT_FROM_WIN32(GetLastError()));
  1139. // If there are some DBCS characters in the sz(Input), then, the character count of BSTR(DWORD) is
  1140. // already set to cch(strlen(sz)) in SysAllocStringLen(NULL, cch), we cannot change the count,
  1141. // and later call of SysStringLen(bstr) always returns the number of characters specified in the
  1142. // cch parameter at allocation time. Bad, because one DBCS character(2 bytes) will convert
  1143. // to one UNICODE character(2 bytes), not 2 UNICODE characters(4 bytes).
  1144. // Example: For input sz contains only one DBCS character, we want to see SysStringLen(bstr)
  1145. // = 1, not 2.
  1146. bstrRet[cch] = 0;
  1147. cchTemp = wcslen(bstrRet);
  1148. if (cchTemp < cch)
  1149. {
  1150. BSTR bstrTemp = SysAllocString(bstrRet);
  1151. if (bstrTemp == NULL)
  1152. return(E_OUTOFMEMORY);
  1153. SysFreeString(bstrRet);
  1154. bstrRet = bstrTemp;
  1155. cch = cchTemp;
  1156. }
  1157. }
  1158. bstrRet[cch] = 0;
  1159. *pbstrRet = bstrRet;
  1160. return(S_OK);
  1161. }
  1162. /*============================================================================
  1163. StringDupA
  1164. Duplicate a string. An empty string will only be duplicated if the fDupEmpty
  1165. flag is set, else a NULL is returned.
  1166. Parameter
  1167. CHAR *pszStrIn string to duplicate
  1168. Returns:
  1169. NULL if failed.
  1170. Otherwise, the duplicated string.
  1171. Side Effects:
  1172. ***ALLOCATES MEMORY -- CALLER MUST FREE***
  1173. ============================================================================*/
  1174. CHAR *StringDupA
  1175. (
  1176. CHAR *pszStrIn,
  1177. BOOL fDupEmpty
  1178. )
  1179. {
  1180. CHAR *pszStrOut;
  1181. INT cch, cBytes;
  1182. if (NULL == pszStrIn)
  1183. return NULL;
  1184. cch = strlen(pszStrIn);
  1185. if ((0 == cch) && !fDupEmpty)
  1186. return NULL;
  1187. cBytes = sizeof(CHAR) * (cch+1);
  1188. pszStrOut = (CHAR *)malloc(cBytes);
  1189. if (NULL == pszStrOut)
  1190. return NULL;
  1191. memcpy(pszStrOut, pszStrIn, cBytes);
  1192. return pszStrOut;
  1193. }
  1194. /*============================================================================
  1195. StringDupW
  1196. Same as StrDup but for WCHAR strings
  1197. Parameter
  1198. WCHAR *pwszStrIn string to duplicate
  1199. Returns:
  1200. NULL if failed.
  1201. Otherwise, the duplicated string.
  1202. Side Effects:
  1203. ***ALLOCATES MEMORY -- CALLER MUST FREE***
  1204. ============================================================================*/
  1205. WCHAR *StringDupW
  1206. (
  1207. WCHAR *pwszStrIn,
  1208. BOOL fDupEmpty
  1209. )
  1210. {
  1211. WCHAR *pwszStrOut;
  1212. INT cch, cBytes;
  1213. if (NULL == pwszStrIn)
  1214. return NULL;
  1215. cch = wcslen(pwszStrIn);
  1216. if ((0 == cch) && !fDupEmpty)
  1217. return NULL;
  1218. cBytes = sizeof(WCHAR) * (cch+1);
  1219. pwszStrOut = (WCHAR *)malloc(cBytes);
  1220. if (NULL == pwszStrOut)
  1221. return NULL;
  1222. memcpy(pwszStrOut, pwszStrIn, cBytes);
  1223. return pwszStrOut;
  1224. }
  1225. /*============================================================================
  1226. StringDupUTF8
  1227. Same as StrDup but for WCHAR strings that need to be Dup'd to UTF8
  1228. Parameter
  1229. WCHAR *pwszStrIn string to duplicate
  1230. Returns:
  1231. NULL if failed.
  1232. Otherwise, the duplicated UTF8 string.
  1233. Side Effects:
  1234. ***ALLOCATES MEMORY -- CALLER MUST FREE***
  1235. ============================================================================*/
  1236. CHAR *StringDupUTF8
  1237. (
  1238. WCHAR *pwszStrIn,
  1239. BOOL fDupEmpty
  1240. )
  1241. {
  1242. CWCharToMBCS convStr;
  1243. if ((pwszStrIn == NULL) || (*pwszStrIn == L'\0')) {
  1244. goto returnEmpty;
  1245. }
  1246. if (FAILED(convStr.Init(pwszStrIn))) {
  1247. goto returnEmpty;
  1248. }
  1249. else {
  1250. CHAR *pRetStr = convStr.GetString(TRUE);
  1251. if (!pRetStr)
  1252. goto returnEmpty;
  1253. return pRetStr;
  1254. }
  1255. returnEmpty:
  1256. if (fDupEmpty)
  1257. return StringDupA(NULL, TRUE);
  1258. else
  1259. return NULL;
  1260. }
  1261. /*===================================================================
  1262. CbWStr
  1263. Get byte length of WCHAR string (needed to manipulate hash keys)
  1264. Parameter
  1265. LPWSTR pwszString WCHAR string
  1266. Returns
  1267. length in bytes
  1268. ===================================================================*/
  1269. DWORD CbWStr
  1270. (
  1271. WCHAR *pwszString
  1272. )
  1273. {
  1274. return (pwszString ? (sizeof(WCHAR) * wcslen(pwszString)) : 0);
  1275. }
  1276. /*===================================================================
  1277. DotPathToPath
  1278. This function offers support for parent path translation. for example
  1279. szFileSpec = "../foo/bar.asp"
  1280. szParentDirectory = "/scripts/more/stuff"
  1281. result = "/scripts/more/foo/bar.asp"
  1282. Parameter
  1283. char *szDest - destination string
  1284. const char *szFileSpec - input path mask
  1285. const char *szParentDirectory - path to map from
  1286. Notes
  1287. No more than "MAX_PATH" bytes are written into szDest.
  1288. Returns FALSE when this happens.
  1289. Returns
  1290. int TRUE/FALSE
  1291. ===================================================================*/
  1292. BOOL
  1293. DotPathToPath
  1294. (
  1295. TCHAR *szDest,
  1296. const TCHAR *szFileSpec,
  1297. const TCHAR *szParentDirectory
  1298. )
  1299. {
  1300. STACK_BUFFER( tempFileSpec, MAX_PATH );
  1301. if (szFileSpec[0] == _T('\0')) {
  1302. _tcscpy(szDest, szParentDirectory);
  1303. return TRUE;
  1304. }
  1305. if (szFileSpec[0] == _T('/') || szFileSpec[0] == _T('\\'))
  1306. return FALSE;
  1307. // Make a copy of the FileSpec to allow for
  1308. // a. szDest == szFileSpec (inplace) should work
  1309. // b. Algorithm below works if szFileSpec ends with a '/' (or '\\')
  1310. //
  1311. if (!tempFileSpec.Resize((_tcslen(szFileSpec) + 2)*sizeof(TCHAR))) {
  1312. return FALSE;
  1313. }
  1314. TCHAR *szFileSpecT = (TCHAR *)(tempFileSpec.QueryPtr());
  1315. TCHAR *szT = strcpyEx(szFileSpecT, szFileSpec);
  1316. szT = CharPrev(szFileSpecT, szT);
  1317. if( *szT != _T('/') && *szT != _T('\\')) {
  1318. szT = CharNext(szT);
  1319. *szT++ = _T('/');
  1320. *szT = _T('\0');
  1321. }
  1322. // Initialize "cchDest" - count of characters in destination
  1323. int cchDest = _tcslen(szParentDirectory) + 1;
  1324. if (cchDest > MAX_PATH)
  1325. return FALSE;
  1326. // OK if szParentDirectory is rewritten in place
  1327. TCHAR *pchDestEnd;
  1328. if (szDest == szParentDirectory)
  1329. pchDestEnd = const_cast<TCHAR *>(&szParentDirectory[_tcslen(szParentDirectory)]);
  1330. else
  1331. pchDestEnd = strcpyEx(szDest, szParentDirectory);
  1332. // Loop through each component in "szFileSpec", then do the following:
  1333. // for ".", do nothing
  1334. // for "..", delete rightmost dir from szDest
  1335. // otherwise, append the component.
  1336. //
  1337. const TCHAR *pchBegin = szFileSpecT;
  1338. while (*pchBegin != _T('\0')) {
  1339. // Calculate end of this segment
  1340. const TCHAR *pchEnd = _tcspbrk(pchBegin,_T("\\/"));
  1341. // check for parent path
  1342. if ((_tcsncmp(pchBegin, _T(".."), 2) == 0)
  1343. && ((pchBegin[2] == _T('/')) || (pchBegin[2] == _T('\\')))) {
  1344. // Delete rightmost path in dest
  1345. while ((pchDestEnd > szDest)
  1346. && (*pchDestEnd != _T('/'))
  1347. && (*pchDestEnd != _T('\\'))) {
  1348. pchDestEnd = CharPrev(szDest, pchDestEnd);
  1349. }
  1350. if (pchDestEnd == szDest) // we ".."'ed too many levels
  1351. return FALSE;
  1352. *pchDestEnd = _T('\0');
  1353. }
  1354. // Make sure this is not ".". If it is not, append the path
  1355. else if (! (pchBegin[0] == _T('.') && (pchBegin[1] == _T('/') || pchBegin[1] == _T('\\')))) {
  1356. cchDest += 1 + (int)(pchEnd - pchBegin);
  1357. if (cchDest > MAX_PATH)
  1358. return FALSE;
  1359. *pchDestEnd++ = _T('/');
  1360. _tcsncpy(pchDestEnd, pchBegin, pchEnd - pchBegin);
  1361. pchDestEnd += (pchEnd - pchBegin);
  1362. *pchDestEnd = _T('\0');
  1363. }
  1364. // Prepare for next iteration
  1365. pchBegin = pchEnd + 1;
  1366. }
  1367. // It's possible that if the relative path is something like "..", and parent path is a single path
  1368. // (either "/" or "C:/", then the root directory is indicator is missing - szDest is either the
  1369. // empty string or something like "C:"
  1370. //
  1371. #if UNICODE
  1372. if (szDest[0] == '\0'
  1373. || ((szDest[1] == L':') && (szDest[2] == L'\0'))) {
  1374. szDest[2] = L'/';
  1375. szDest[3] = L'\0';
  1376. }
  1377. #else
  1378. if (szDest[0] == '\0' ||
  1379. (!IsDBCSLeadByte(szDest[0]) && szDest[1] == ':' && szDest[2] == '\0') ||
  1380. (IsDBCSLeadByte(szDest[0]) && szDest[2] == ':' && szDest[3] == '\0')) {
  1381. strcat(szDest, "/");
  1382. }
  1383. #endif
  1384. return TRUE;
  1385. }
  1386. /*===================================================================
  1387. FIsGlobalAsa
  1388. Check if the given path points to GLOBAL.ASA
  1389. Parameter
  1390. szPath the path to check
  1391. Returns
  1392. TRUE/FALSE
  1393. ===================================================================*/
  1394. BOOL FIsGlobalAsa
  1395. (
  1396. const TCHAR *szPath,
  1397. DWORD cchPath
  1398. )
  1399. {
  1400. if (cchPath == 0)
  1401. cchPath = _tcslen(szPath);
  1402. return (cchPath >= CCH_GLOBAL_ASA &&
  1403. !_tcsicmp(szPath+(cchPath-CCH_GLOBAL_ASA), SZ_GLOBAL_ASA));
  1404. }
  1405. /*===================================================================
  1406. EncodeSessionIdCookie
  1407. Convert 3 DWORDs into a SessionID cookie string
  1408. Parameters
  1409. dw1, dw2, dw3 DWORDs
  1410. pszCookie cookie to fill in
  1411. Returns
  1412. HRESULT
  1413. ===================================================================*/
  1414. HRESULT EncodeSessionIdCookie
  1415. (
  1416. DWORD dw1, DWORD dw2, DWORD dw3,
  1417. char *pszCookie
  1418. )
  1419. {
  1420. DWORD dw = dw1;
  1421. for (int idw = 0; idw < 3; idw++)
  1422. {
  1423. for (int i = 0; i < 8; i++)
  1424. {
  1425. *(pszCookie++) = (char)('A' + (dw & 0xf));
  1426. dw >>= 4;
  1427. }
  1428. dw = (idw == 0) ? dw2 : dw3;
  1429. }
  1430. *pszCookie = '\0';
  1431. return S_OK;
  1432. }
  1433. /*===================================================================
  1434. DecodeSessionIdCookie
  1435. Convert SessionID cookie string into 3 DWORDs
  1436. Parameters
  1437. pszCookie cookie string
  1438. pdw1, pdw2, pdw3 [out] DWORDs
  1439. Returns
  1440. HRESULT
  1441. ===================================================================*/
  1442. HRESULT DecodeSessionIdCookie
  1443. (
  1444. const char *pszCookie,
  1445. DWORD *pdw1, DWORD *pdw2, DWORD *pdw3
  1446. )
  1447. {
  1448. if (strlen(pszCookie) != SESSIONID_LEN)
  1449. return E_FAIL;
  1450. DWORD *pdw = pdw1;
  1451. for (int idw = 0; idw < 3; idw++)
  1452. {
  1453. *pdw = 0;
  1454. for (int i = 0; i < 8; i++)
  1455. {
  1456. int ch = pszCookie[idw*8+7-i];
  1457. if (ch < 'A' || ch > ('A'+0xf))
  1458. return E_FAIL;
  1459. *pdw <<= 4;
  1460. *pdw |= (ch - 'A');
  1461. }
  1462. pdw = (idw == 0) ? pdw2 : pdw3;
  1463. }
  1464. return S_OK;
  1465. }
  1466. /*===================================================================
  1467. GetTypelibFilenameFromRegistry
  1468. Find a typelib filename (path) from the registry using GUID, version,
  1469. and LCID. The algorithm taken from VBA. Does some tricky matching.
  1470. Parameters
  1471. szUUID GUID
  1472. szVersion Version
  1473. lcid LCID
  1474. szName [out] TYPELIB Path
  1475. cbName buffer length of szName
  1476. Returns
  1477. HRESULT
  1478. ===================================================================*/
  1479. HRESULT GetTypelibFilenameFromRegistry
  1480. (
  1481. const char *szUUID,
  1482. const char *szVersion,
  1483. LCID lcid,
  1484. char *szName,
  1485. DWORD cbName
  1486. )
  1487. {
  1488. szName[0] = '\0';
  1489. LONG iRet;
  1490. HKEY hkeyTLib = NULL;
  1491. HKEY hkeyGuid = NULL;
  1492. // Open up the typelib section of the registry.
  1493. iRet = RegOpenKeyExA(HKEY_CLASSES_ROOT, "TypeLib", 0, KEY_READ, &hkeyTLib);
  1494. if (iRet != ERROR_SUCCESS)
  1495. return E_FAIL;
  1496. // Now open up the guid, if it is registered.
  1497. iRet = RegOpenKeyExA(hkeyTLib, szUUID, 0, KEY_READ, &hkeyGuid);
  1498. if (iRet != ERROR_SUCCESS)
  1499. {
  1500. RegCloseKey(hkeyTLib);
  1501. return E_FAIL;
  1502. }
  1503. // Iterate through the versions trying to find the exact match
  1504. // or get the latest (max version number)
  1505. char szMaxVersion[16];
  1506. DWORD dwMaxVersion = 0; // to calculate max version number
  1507. BOOL fLookForExactMatch = (szVersion && *szVersion);
  1508. int iVer = 0;
  1509. szMaxVersion[0] = '\0';
  1510. while (1)
  1511. {
  1512. char szEnumVer[16];
  1513. iRet = RegEnumKeyA(hkeyGuid, iVer++, szEnumVer, sizeof(szEnumVer));
  1514. if (iRet != ERROR_SUCCESS)
  1515. break;
  1516. // check for the exact match first
  1517. if (fLookForExactMatch && strcmp(szEnumVer, szVersion))
  1518. {
  1519. strcpy(szMaxVersion, szEnumVer);
  1520. break;
  1521. }
  1522. // calc the version number
  1523. char *pchDot = strchr(szEnumVer, '.');
  1524. if (!pchDot) // ignore if not #.#
  1525. continue;
  1526. DWORD dwVer = (strtoul(szEnumVer, NULL, 16) << 16) |
  1527. strtoul(pchDot+1, NULL, 16);
  1528. if (dwVer && szMaxVersion[0] == '\0' || dwVer > dwMaxVersion)
  1529. {
  1530. strcpy(szMaxVersion, szEnumVer);
  1531. dwMaxVersion = dwVer;
  1532. }
  1533. }
  1534. // szMaxVersion (if not empty now has the desired version number)
  1535. if (szMaxVersion[0])
  1536. {
  1537. HKEY hkeyVer = NULL;
  1538. iRet = RegOpenKeyExA(hkeyGuid, szMaxVersion, 0, KEY_READ, &hkeyVer);
  1539. if (iRet == ERROR_SUCCESS)
  1540. {
  1541. HKEY hkeyWin32 = NULL; // "win32" under LCID is for TYPELIB name
  1542. BOOL fLcidFound = FALSE;
  1543. // Now there's a version key.
  1544. // We need to find the best matching lcid
  1545. for (int iTry = 1; !fLcidFound && iTry <= 3; iTry++)
  1546. {
  1547. char szLcid[10];
  1548. switch (iTry)
  1549. {
  1550. case 1:
  1551. // if the passed lcid is not 0, try it
  1552. if (!lcid)
  1553. continue;
  1554. _ultoa(lcid, szLcid, 16);
  1555. break;
  1556. case 2:
  1557. // passed lcid stripped to primary language
  1558. if (!lcid)
  1559. continue;
  1560. _ultoa(PRIMARYLANGID(lcid), szLcid, 16);
  1561. break;
  1562. case 3:
  1563. // "0"
  1564. szLcid[0] = '0';
  1565. szLcid[1] = '\0';
  1566. break;
  1567. }
  1568. HKEY hkeyLcid = NULL;
  1569. iRet = RegOpenKeyExA(hkeyVer, szLcid, 0, KEY_READ, &hkeyLcid);
  1570. if (iRet == ERROR_SUCCESS)
  1571. {
  1572. iRet = RegOpenKeyExA(hkeyLcid, "win32", 0, KEY_READ, &hkeyWin32);
  1573. if (iRet == ERROR_SUCCESS)
  1574. fLcidFound = TRUE;
  1575. RegCloseKey(hkeyLcid);
  1576. }
  1577. }
  1578. if (fLcidFound)
  1579. {
  1580. // LCID has been found - get the TYPELIB name
  1581. Assert(hkeyWin32);
  1582. LONG lName = cbName;
  1583. iRet = RegQueryValueA(hkeyWin32, NULL, szName, &lName);
  1584. if (iRet != ERROR_SUCCESS)
  1585. szName[0] = '\0';
  1586. RegCloseKey(hkeyWin32);
  1587. }
  1588. RegCloseKey(hkeyVer);
  1589. }
  1590. }
  1591. RegCloseKey(hkeyGuid);
  1592. RegCloseKey(hkeyTLib);
  1593. return (szName[0] == '\0') ? E_FAIL : S_OK;
  1594. }
  1595. /*============================================================================
  1596. GetSecDescriptor
  1597. Get a file's Security Descriptor
  1598. Parameters:
  1599. LPCSTR lpFileName - file name
  1600. PSECURITY_DESCRIPTOR &pSecurityDescriptor - security descriptor
  1601. DWORD &nLength - size of security descriptor
  1602. Returns:
  1603. 0 = No error
  1604. or this will return the GetLastError results.
  1605. Allocates memory. Caller must deallocate (pSecurityDescriptor)
  1606. ============================================================================*/
  1607. DWORD GetSecDescriptor(LPCTSTR lpFileName, PSECURITY_DESCRIPTOR *ppSecurityDescriptor, DWORD *pnLength)
  1608. {
  1609. if (!FIsWinNT())
  1610. return 0;
  1611. // this should always be NULL
  1612. Assert(*ppSecurityDescriptor == NULL);
  1613. const SECURITY_INFORMATION RequestedInformation =
  1614. OWNER_SECURITY_INFORMATION // security info struct
  1615. | GROUP_SECURITY_INFORMATION
  1616. | DACL_SECURITY_INFORMATION;
  1617. DWORD nLastError = 0;
  1618. int fDidItWork = TRUE;
  1619. DWORD nLengthNeeded = 0;
  1620. *ppSecurityDescriptor = (PSECURITY_DESCRIPTOR) malloc( *pnLength );
  1621. if (*ppSecurityDescriptor == NULL) {
  1622. return E_OUTOFMEMORY;
  1623. }
  1624. while(TRUE)
  1625. {
  1626. fDidItWork = GetFileSecurity
  1627. (lpFileName, // address of string for file name
  1628. RequestedInformation, // requested information
  1629. *ppSecurityDescriptor, // address of security descriptor
  1630. *pnLength, // size of security descriptor buffer
  1631. &nLengthNeeded // address of required size of buffer
  1632. );
  1633. if(!fDidItWork)
  1634. {
  1635. nLastError = GetLastError();
  1636. if (ERROR_INSUFFICIENT_BUFFER == nLastError)
  1637. {
  1638. *ppSecurityDescriptor = (PSECURITY_DESCRIPTOR) realloc(*ppSecurityDescriptor, nLengthNeeded );
  1639. *pnLength = nLengthNeeded;
  1640. nLastError = 0;
  1641. }
  1642. else
  1643. {
  1644. break;
  1645. }
  1646. }
  1647. else
  1648. {
  1649. *pnLength = GetSecurityDescriptorLength( *ppSecurityDescriptor );
  1650. break;
  1651. }
  1652. }
  1653. // deal with errors and free the SD if needed
  1654. //
  1655. if (nLastError != 0)
  1656. {
  1657. if(*ppSecurityDescriptor)
  1658. {
  1659. free(*ppSecurityDescriptor);
  1660. *ppSecurityDescriptor = NULL;
  1661. }
  1662. }
  1663. return nLastError;
  1664. }
  1665. /*============================================================================
  1666. AspGetFileAttributes
  1667. Wraps GetFileAttributes() and GetFileAttributesEx()
  1668. Parameters:
  1669. pfad -- optional WIN32_FILE_ATTRIBUTE_DATA structure
  1670. Returns:
  1671. S_OK or E_FAIL
  1672. ============================================================================*/
  1673. HRESULT AspGetFileAttributes
  1674. (
  1675. LPCTSTR szFileName,
  1676. WIN32_FILE_ATTRIBUTE_DATA *pfad
  1677. )
  1678. {
  1679. // Take care of NT first (GetFileAttributesEx exists)
  1680. if (Glob(fWinNT))
  1681. {
  1682. WIN32_FILE_ATTRIBUTE_DATA fad;
  1683. BOOL fRet = GetFileAttributesEx
  1684. (
  1685. szFileName,
  1686. GetFileExInfoStandard,
  1687. pfad ? pfad : &fad
  1688. );
  1689. return fRet ? S_OK : E_FAIL;
  1690. }
  1691. // Win9x case
  1692. DWORD dwAttributes = GetFileAttributes(szFileName);
  1693. if (dwAttributes == 0xffffffff)
  1694. return E_FAIL;
  1695. // simulate the return of FAD if requested
  1696. if (pfad)
  1697. {
  1698. memset(pfad, 0, sizeof(WIN32_FILE_ATTRIBUTE_DATA));
  1699. pfad->dwFileAttributes = dwAttributes;
  1700. }
  1701. return S_OK;
  1702. }
  1703. /*============================================================================
  1704. AspCharNextA
  1705. UTF-8 aware CharNext()
  1706. ============================================================================*/
  1707. char *AspCharNextA(WORD wCodePage, const char *sz)
  1708. {
  1709. if (wCodePage != CP_UTF8)
  1710. return CharNextExA(wCodePage, sz, 0);
  1711. else
  1712. {
  1713. // CharNextExA won't work correctly in UTF-8.
  1714. // Add support for UTF-8 encoding for Surrogate pairs
  1715. // 110110wwwwzzzzyyyyyyxxxxxx gets encoded as 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
  1716. // where uuuuu = wwww + 1 (to account for addition of 10000(b16) )
  1717. // For further information refer : Page A-7 of "The Unicode Standard 2.0" ISBN-0-201-48345-9
  1718. if ((*sz & 0xf8) == 0xF0)
  1719. return const_cast<char *>(sz + 4);
  1720. //zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
  1721. if ((*sz & 0xF0) == 0xE0)
  1722. return const_cast<char *>(sz + 3);
  1723. //00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
  1724. else if ((*sz & 0xE0) == 0xC0)
  1725. return const_cast<char *>(sz + 2);
  1726. //000000000xxxxxxx = 0xxxxxxx
  1727. else
  1728. return const_cast<char *>(sz + 1);
  1729. }
  1730. }
  1731. /*============================================================================
  1732. CWCharToMBCS::~CWCharToMBCS
  1733. The destructor has to be in the source file to ensure that it gets the right
  1734. memory allocation routines defined.
  1735. ============================================================================*/
  1736. CWCharToMBCS::~CWCharToMBCS()
  1737. {
  1738. if(m_pszResult && (m_pszResult != m_resMemory))
  1739. free(m_pszResult);
  1740. }
  1741. /*============================================================================
  1742. CWCharToMBCS::Init
  1743. Converts the passed in WideChar string to MultiByte in the code page
  1744. specified. Uses memory declared in the object if it can, else allocates
  1745. from the heap.
  1746. ============================================================================*/
  1747. HRESULT CWCharToMBCS::Init(LPCWSTR pWSrc, UINT lCodePage /* = CP_ACP */, int cchWSrc /* = -1 */)
  1748. {
  1749. INT cbRequired;
  1750. // don't even try to convert if we get a NULL pointer to the source. This
  1751. // condition could be handled by setting by just initing an empty string.
  1752. if (pWSrc == NULL) {
  1753. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1754. }
  1755. // The init method can be called multiple times on the same object. Check
  1756. // to see if memory was allocated the last time it was called. If so,
  1757. // free it and restore the result pointer to the object memory. Note that
  1758. // an allocation failure could have occurred in a previous call. The result
  1759. // would be a NULL m_pszResult.
  1760. if (m_pszResult != m_resMemory) {
  1761. if (m_pszResult)
  1762. free(m_pszResult);
  1763. m_pszResult = m_resMemory;
  1764. m_cbResult = 0;
  1765. }
  1766. // set the first byte of the result string to NULL char. This should help
  1767. // to ensure that nothing wacky happens if this function fails.
  1768. *m_pszResult = '\0';
  1769. // attempt translation into object memory.
  1770. cbRequired = WstrToMBstrEx(m_pszResult, sizeof(m_resMemory), pWSrc, cchWSrc, lCodePage);
  1771. // if the conversion fit, then we're done. Note the final result size and
  1772. // return.
  1773. if (cbRequired <= sizeof(m_resMemory)) {
  1774. m_cbResult = cbRequired;
  1775. return NO_ERROR;
  1776. }
  1777. // if it didn't fit, allocate memory. Return E_OUTOFMEMORY if it fails.
  1778. m_pszResult = (LPSTR)malloc(cbRequired);
  1779. if (m_pszResult == NULL) {
  1780. return E_OUTOFMEMORY;
  1781. }
  1782. // try the convert again. It should work.
  1783. cbRequired = WstrToMBstrEx(m_pszResult, cbRequired, pWSrc, cchWSrc, lCodePage);
  1784. // store the final char count in the object.
  1785. m_cbResult = cbRequired;
  1786. return NO_ERROR;
  1787. }
  1788. /*============================================================================
  1789. CWCharToMBCS::GetString
  1790. Returns a pointer to the converted string.
  1791. If the fTakeOwnerShip parameter is FALSE, then the pointer in the object is
  1792. simply returned to the caller.
  1793. If the fTakeOwnerShip parameter is TRUE, then the caller is expecting to be
  1794. returned a pointer to heap memory that they have to manage. If the converted
  1795. string is in the object's memory, then the string is duplicated into the heap.
  1796. If it's already heap memory, then the pointer is handed off to the caller.
  1797. NOTE - Taking ownership essentially destroys the current contents of the
  1798. object. GetString cannot be called on the object again to get the same value.
  1799. The result will be a pointer to a empty string.
  1800. ============================================================================*/
  1801. LPSTR CWCharToMBCS::GetString(BOOL fTakeOwnerShip)
  1802. {
  1803. LPSTR retSz;
  1804. // return the pointer stored in m_psz_Result if not being
  1805. // requested to give up ownership on the memory or the
  1806. // current value is NULL.
  1807. if ((fTakeOwnerShip == FALSE) || (m_pszResult == NULL)) {
  1808. retSz = m_pszResult;
  1809. }
  1810. // ownership is being requested and the pointer is non-NULL.
  1811. // if the pointer is pointing to the object's memory, dup
  1812. // the string and return that.
  1813. else if (m_pszResult == m_resMemory) {
  1814. retSz = StringDupA(m_pszResult, TRUE);
  1815. }
  1816. // if not pointing to the object's memory, then this is allocated
  1817. // memory and we can relinquish it to the caller. However, re-establish
  1818. // the object's memory as the value for m_pszResult.
  1819. else {
  1820. retSz = m_pszResult;
  1821. m_pszResult = m_resMemory;
  1822. *m_pszResult = '\0';
  1823. m_cbResult = 0;
  1824. }
  1825. return(retSz);
  1826. }
  1827. /*============================================================================
  1828. CMBCSToWChar::~CMBCSToWChar
  1829. The destructor has to be in the source file to ensure that it gets the right
  1830. memory allocation routines defined.
  1831. ============================================================================*/
  1832. CMBCSToWChar::~CMBCSToWChar()
  1833. {
  1834. if(m_pszResult && (m_pszResult != m_resMemory))
  1835. free(m_pszResult);
  1836. }
  1837. /*============================================================================
  1838. CMBCSToWChar::Init
  1839. Converts the passed in MultiByte string to UNICODE in the code page
  1840. specified. Uses memory declared in the object if it can, else allocates
  1841. from the heap.
  1842. ============================================================================*/
  1843. HRESULT CMBCSToWChar::Init(LPCSTR pASrc, UINT lCodePage /* = CP_ACP */, int cchASrc /* = -1 */)
  1844. {
  1845. INT cchRequired;
  1846. // don't even try to convert if we get a NULL pointer to the source. This
  1847. // condition could be handled by setting by just initing an empty string.
  1848. if (pASrc == NULL) {
  1849. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1850. }
  1851. // The init method can be called multiple times on the same object. Check
  1852. // to see if memory was allocated the last time it was called. If so,
  1853. // free it and restore the result pointer to the object memory. Note that
  1854. // an allocation failure could have occurred in a previous call. The result
  1855. // would be a NULL m_pszResult.
  1856. if (m_pszResult != m_resMemory) {
  1857. if (m_pszResult)
  1858. free(m_pszResult);
  1859. m_pszResult = m_resMemory;
  1860. m_cchResult = 0;
  1861. }
  1862. // set the first byte of the result string to NULL char. This should help
  1863. // to ensure that nothing wacky happens if this function fails.
  1864. *m_pszResult = '\0';
  1865. // attempt translation into object memory. NOTE - MBstrToWstrEx returns the
  1866. // count of characters, not bytes.
  1867. cchRequired = MBstrToWstrEx(m_pszResult, sizeof(m_resMemory)/sizeof(WCHAR), pASrc, cchASrc, lCodePage);
  1868. // if the conversion fit, then we're done. Note the final result size and
  1869. // return.
  1870. if (cchRequired <= (sizeof(m_resMemory)/sizeof(WCHAR))) {
  1871. m_cchResult = cchRequired;
  1872. return NO_ERROR;
  1873. }
  1874. // if it didn't fit, allocate memory. Return E_OUTOFMEMORY if it fails.
  1875. m_pszResult = (LPWSTR)malloc(cchRequired*sizeof(WCHAR));
  1876. if (m_pszResult == NULL) {
  1877. return E_OUTOFMEMORY;
  1878. }
  1879. // try the convert again. It should work.
  1880. cchRequired = MBstrToWstrEx(m_pszResult, cchRequired, pASrc, cchASrc, lCodePage);
  1881. // store the final char count in the object.
  1882. m_cchResult = cchRequired;
  1883. return NO_ERROR;
  1884. }
  1885. /*============================================================================
  1886. CMBCSToWChar::GetString
  1887. Returns a pointer to the converted string.
  1888. If the fTakeOwnerShip parameter is FALSE, then the pointer in the object is
  1889. simply returned to the caller.
  1890. If the fTakeOwnerShip parameter is TRUE, then the caller is expecting to be
  1891. returned a pointer to heap memory that they have to manage. If the converted
  1892. string is in the object's memory, then the string is duplicated into the heap.
  1893. If it's already heap memory, then the pointer is handed off to the caller.
  1894. NOTE - Taking ownership essentially destroys the current contents of the
  1895. object. GetString cannot be called on the object again to get the same value.
  1896. The result will be a pointer to a empty string.
  1897. ============================================================================*/
  1898. LPWSTR CMBCSToWChar::GetString(BOOL fTakeOwnerShip)
  1899. {
  1900. LPWSTR retSz;
  1901. // return the pointer stored in m_psz_Result if not being
  1902. // requested to give up ownership on the memory or the
  1903. // current value is NULL.
  1904. if ((fTakeOwnerShip == FALSE) || (m_pszResult == NULL)) {
  1905. retSz = m_pszResult;
  1906. }
  1907. // ownership is being requested and the pointer is non-NULL.
  1908. // if the pointer is pointing to the object's memory, dup
  1909. // the string and return that.
  1910. else if (m_pszResult == m_resMemory) {
  1911. retSz = StringDupW(m_pszResult, TRUE);
  1912. }
  1913. // if not pointing to the object's memory, then this is allocated
  1914. // memory and we can relinquish it to the caller. However, re-establish
  1915. // the object's memory as the value for m_pszResult.
  1916. else {
  1917. retSz = m_pszResult;
  1918. m_pszResult = m_resMemory;
  1919. *m_pszResult = '\0';
  1920. m_cchResult = 0;
  1921. }
  1922. return(retSz);
  1923. }