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.

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