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

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