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.

1058 lines
32 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: N C S T R I N G . C P P
  7. //
  8. // Contents: Common string routines.
  9. //
  10. // Notes:
  11. //
  12. // Author: shaunco 24 Mar 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.h>
  16. #pragma hdrstop
  17. #include "ncdebug.h"
  18. #include "ncstring.h"
  19. //+---------------------------------------------------------------------------
  20. //
  21. // Function: CbOfSzSafe, CbOfSzaSafe,
  22. // CbOfSzAndTermSafe, CbOfSzaAndTermSafe
  23. //
  24. // Purpose: Count the bytes required to hold a string. The string
  25. // may be NULL in which case zero is returned.
  26. //
  27. // Arguments:
  28. // psz [in] String to return count of bytes for.
  29. //
  30. // Returns: Count of bytes required to store string.
  31. //
  32. // Author: shaunco 24 Mar 1997
  33. //
  34. // Notes: 'AndTerm' variants includes space for the null-terminator.
  35. //
  36. ULONG
  37. CbOfSzSafe (
  38. IN PCWSTR psz)
  39. {
  40. return (psz) ? CbOfSz(psz) : 0;
  41. }
  42. ULONG
  43. CbOfSzaSafe (
  44. IN PCSTR psza)
  45. {
  46. return (psza) ? CbOfSza(psza) : 0;
  47. }
  48. ULONG
  49. CbOfSzAndTermSafe (
  50. IN PCWSTR psz)
  51. {
  52. return (psz) ? CbOfSzAndTerm(psz) : 0;
  53. }
  54. ULONG
  55. CbOfSzaAndTermSafe (
  56. IN PCSTR psza)
  57. {
  58. return (psza) ? CbOfSzaAndTerm(psza) : 0;
  59. }
  60. ULONG
  61. CchOfSzSafe (
  62. IN PCWSTR psz)
  63. {
  64. return (psz) ? wcslen(psz) : 0;
  65. }
  66. //+---------------------------------------------------------------------------
  67. //
  68. // Function: DwFormatString
  69. //
  70. // Purpose: Uses FormatMessage to format a string from variable arguments.
  71. // The string is formatted into a fixed-size buffer the caller
  72. // provides.
  73. // See the description of FormatMessage in the Win32 API.
  74. //
  75. // Arguments:
  76. // pszFmt [in] pointer to format string
  77. // pszBuf [out] pointer to formatted output
  78. // cchBuf [in] count of characters in pszBuf
  79. // ... [in] replaceable string parameters
  80. //
  81. // Returns: the return value of FormatMessage
  82. //
  83. // Author: shaunco 15 Apr 1997
  84. //
  85. // Notes: The variable arguments must be strings otherwise
  86. // FormatMessage will barf.
  87. //
  88. DWORD
  89. WINAPIV
  90. DwFormatString (
  91. IN PCWSTR pszFmt,
  92. OUT PWSTR pszBuf,
  93. IN DWORD cchBuf,
  94. IN ...)
  95. {
  96. Assert (pszFmt);
  97. va_list val;
  98. va_start(val, cchBuf);
  99. DWORD dwRet = FormatMessage (FORMAT_MESSAGE_FROM_STRING,
  100. pszFmt, 0, 0, pszBuf, cchBuf, &val);
  101. va_end(val);
  102. return dwRet;
  103. }
  104. //+---------------------------------------------------------------------------
  105. //
  106. // Function: DwFormatStringWithLocalAlloc
  107. //
  108. // Purpose: Uses FormatMessage to format a string from variable arguments.
  109. // The string is allocated by FormatMessage using LocalAlloc.
  110. // See the description of FormatMessage in the Win32 API.
  111. //
  112. // Arguments:
  113. // pszFmt [in] pointer to format string
  114. // ppszBuf [out] the returned formatted string
  115. // ... [in] replaceable string parameters
  116. //
  117. // Returns: the return value of FormatMessage
  118. //
  119. // Author: shaunco 3 May 1997
  120. //
  121. // Notes: The variable arguments must be strings otherwise
  122. // FormatMessage will barf.
  123. //
  124. DWORD
  125. WINAPIV
  126. DwFormatStringWithLocalAlloc (
  127. IN PCWSTR pszFmt,
  128. OUT PWSTR* ppszBuf,
  129. IN ...)
  130. {
  131. Assert (pszFmt);
  132. va_list val;
  133. va_start(val, ppszBuf);
  134. DWORD dwRet = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
  135. FORMAT_MESSAGE_FROM_STRING,
  136. pszFmt, 0, 0,
  137. (PWSTR)ppszBuf,
  138. 0, &val);
  139. va_end(val);
  140. return dwRet;
  141. }
  142. //+--------------------------------------------------------------------------
  143. //
  144. // Function: FFindStringInCommaSeparatedList
  145. //
  146. // Purpose: Given a comma separated list, pszList, and a search string,
  147. // pszSubString, this routine will try to locate pszSubString
  148. // in the list,
  149. //
  150. // Arguments:
  151. // pszSubString [in] The string to search for
  152. // pszList [in] The list to search in
  153. // eIgnoreSpaces [in] If NC_IGNORE, skip leading and trailing spaces
  154. // when comparing.
  155. // If NC_DONT_IGNORE, don't skip leading and
  156. // trailing spaces.
  157. // dwPosition [out] Optional. If found, the position of the first
  158. // occurrence of the substring in the list. The first
  159. // position is 0.
  160. //
  161. // Returns: BOOL. TRUE if pszSubString is in pszList, FALSE otherwise
  162. //
  163. // Author: billbe 09 Sep 1997
  164. //
  165. // Notes:
  166. //
  167. BOOL
  168. FFindStringInCommaSeparatedList (
  169. IN PCWSTR pszSubString,
  170. IN PCWSTR pszList,
  171. IN NC_IGNORE_SPACES eIgnoreSpaces,
  172. OUT DWORD* pdwPosition)
  173. {
  174. Assert(pszSubString);
  175. Assert(pszList);
  176. int cchSubString = lstrlenW (pszSubString);
  177. int cchList = lstrlenW (pszList);
  178. BOOL fFound = FALSE;
  179. PCWSTR pszTemp = pszList;
  180. int nIndex;
  181. const WCHAR c_chDelim = L',';
  182. // Initialize out param if specified.
  183. if (pdwPosition)
  184. {
  185. *pdwPosition = 0;
  186. }
  187. // This routine searches the list for a substring matching pszSubString
  188. // If found, checks are made to ensure the substring is not part of
  189. // a larger substring. We continue until we find the substring or we
  190. // have searched through the entire list.
  191. //
  192. while (!fFound)
  193. {
  194. // Search for the next occurence of the substring.
  195. if (pszTemp = wcsstr (pszTemp, pszSubString))
  196. {
  197. // we found an occurrence, so now we make sure it is not part of
  198. // a larger string.
  199. //
  200. fFound = TRUE;
  201. nIndex = (int)(pszTemp - pszList);
  202. // If the substring was not found at the beginning of the list
  203. // we check the previous character to ensure it is the delimiter.
  204. if (nIndex > 0)
  205. {
  206. int cchSubtract = 1;
  207. // If we are to ignore leading spaces, find the first
  208. // non-space character if there is one.
  209. //
  210. if (NC_IGNORE == eIgnoreSpaces)
  211. {
  212. // Keep skipping leading spaces until we either find a
  213. // non-space or pass the beginning of the list.
  214. while ((L' ' == *(pszTemp - cchSubtract)) &&
  215. cchSubtract <= nIndex)
  216. {
  217. cchSubtract--;
  218. }
  219. }
  220. // If we haven't passed the beginning of the list, compare the
  221. // character.
  222. if (cchSubtract <= nIndex)
  223. {
  224. fFound = (*(pszTemp - cchSubtract) == c_chDelim);
  225. }
  226. }
  227. // If the end of the substring is not the end of the list
  228. // we check the character after the substring to ensure
  229. // it is a delimiter.
  230. if (fFound && ((nIndex + cchSubString) < cchList))
  231. {
  232. int cchAdd = cchSubString;
  233. // If we are ignoring white spaces, we have to check the next
  234. // available non-space character
  235. //
  236. if (NC_IGNORE == eIgnoreSpaces)
  237. {
  238. // Search for a non-space until we find one or pass
  239. // the end of the list
  240. while ((L' ' == *(pszTemp + cchAdd)) &&
  241. (cchAdd + nIndex) < cchList)
  242. {
  243. cchAdd++;
  244. }
  245. }
  246. // If we haven't passed the end of the list, check the
  247. // character
  248. if (nIndex + cchAdd < cchList)
  249. {
  250. fFound = (*(pszTemp + cchSubString) == c_chDelim);
  251. }
  252. if (NC_IGNORE == eIgnoreSpaces)
  253. {
  254. // advance pointer the number of white spaces we skipped
  255. // so we won't check those characters on the next pass
  256. Assert(cchAdd >= cchSubString);
  257. pszTemp += (cchAdd - cchSubString);
  258. }
  259. }
  260. // At this point, if the checks worked out, we found our string
  261. // and will be exiting the loop
  262. //
  263. // Advance the temp pointer the length of the sub string we are
  264. // searching for so we can search the rest of the list
  265. // if we need to
  266. pszTemp += cchSubString;
  267. }
  268. else
  269. {
  270. // Search string wasn't found
  271. break;
  272. }
  273. }
  274. // If we found the string and the out param exists,
  275. // then we need to return the strings position in the list.
  276. //
  277. if (fFound && pdwPosition)
  278. {
  279. // We will use the number of delimters found before the string
  280. // as an indicator of the strings position.
  281. //
  282. // Start at the beginning
  283. pszTemp = pszList;
  284. PWSTR pszDelim;
  285. // The string is nIndex characters in the list so lets get
  286. // its correct address.
  287. PCWSTR pszFoundString = pszList + nIndex;
  288. // As long as we keep finding a delimiter in the list...
  289. while (pszDelim = wcschr(pszTemp, c_chDelim))
  290. {
  291. // If the delimiter we just found is before our string...
  292. if (pszDelim < pszFoundString)
  293. {
  294. // Increase our position indicator
  295. ++(*pdwPosition);
  296. // Move the temp pointer to the next string
  297. pszTemp = pszDelim + 1;
  298. continue;
  299. }
  300. // The delimiter we just found is located after our
  301. // found string so get out of the loop.
  302. break;
  303. }
  304. }
  305. return fFound;
  306. }
  307. //+---------------------------------------------------------------------------
  308. //
  309. // Function: FIsSubstr
  310. //
  311. // Purpose: Case *insensitive* substring search.
  312. //
  313. // Arguments:
  314. // pszSubString [in] Substring to look for.
  315. // pszString [in] String to search in.
  316. //
  317. // Returns: TRUE if substring was found, FALSE otherwise.
  318. //
  319. // Author: danielwe 25 Feb 1997
  320. //
  321. // Notes: Allocates temp buffers on stack so they do not need to be
  322. // freed.
  323. //
  324. BOOL
  325. FIsSubstr (
  326. IN PCWSTR pszSubString,
  327. IN PCWSTR pszString)
  328. {
  329. PWSTR pszStringUpper;
  330. PWSTR pszSubStringUpper;
  331. Assert(pszString);
  332. Assert(pszSubString);
  333. #ifndef STACK_ALLOC_DOESNT_WORK
  334. pszStringUpper = (PWSTR)
  335. (PvAllocOnStack (CbOfSzAndTerm(pszString)));
  336. pszSubStringUpper = (PWSTR)
  337. (PvAllocOnStack (CbOfSzAndTerm(pszSubString)));
  338. #else
  339. pszStringUpper = MemAlloc(CbOfSzAndTerm(pszString));
  340. pszSubStringUpper = MemAlloc(CbOfSzAndTerm(pszSubString));
  341. #endif
  342. lstrcpyW (pszStringUpper, pszString);
  343. lstrcpyW (pszSubStringUpper, pszSubString);
  344. // Convert both strings to uppercase before calling strstr
  345. CharUpper (pszStringUpper);
  346. CharUpper (pszSubStringUpper);
  347. #ifndef STACK_ALLOC_DOESNT_WORK
  348. return NULL != wcsstr(pszStringUpper, pszSubStringUpper);
  349. #else
  350. BOOL fRet = (NULL != wcsstr (pszStringUpper, pszSubStringUpper));
  351. MemFree(pszStringUpper);
  352. MemFree(pszSubStringUpper);
  353. return fRet;
  354. #endif
  355. }
  356. //+---------------------------------------------------------------------------
  357. //
  358. // Function: HrRegAddStringToDelimitedSz
  359. //
  360. // Purpose: Add a string into a REG_MULTI_SZ registry value.
  361. //
  362. // Arguments:
  363. // pszAddString [in] The string to add to the delimited psz.
  364. // pszIn [in] The delimited psz list.
  365. // chDelimiter [in] The character to be used to delimit the
  366. // values. Most multi-valued REG_SZ strings are
  367. // delimited with either ',' or ' '. This will
  368. // be used to delimit the value that we add,
  369. // as well.
  370. // dwFlags [in] Can contain one or more of the following
  371. // values:
  372. //
  373. // STRING_FLAG_ALLOW_DUPLICATES
  374. // Don't remove duplicate values when adding
  375. // the string to the list. Default is to
  376. // remove all other instance of this string.
  377. // STRING_FLAG_ENSURE_AT_FRONT
  378. // Insert the string as the first element of
  379. // the list.
  380. // STRING_FLAG_ENSURE_AT_END
  381. // Insert the string as the last
  382. // element of the list. This can not be used
  383. // with STRING_FLAG_ENSURE_AT_FRONT.
  384. // STRING_FLAG_ENSURE_AT_INDEX
  385. // Ensure that the string is at dwStringIndex
  386. // in the psz. If the index specified
  387. // is greater than the number of strings
  388. // in the psz, the string will be
  389. // placed at the end.
  390. // dwStringIndex [in] If STRING_FLAG_ENSURE_AT_INDEX is specified,
  391. // this is the index for the string position.
  392. // Otherwise, this value is ignored.
  393. // pmszOut [out] The new delimited psz.
  394. //
  395. //
  396. // Returns: S_OK or an HRESULT_FROM_WIN32 error code.
  397. //
  398. // Author: jeffspr 27 Mar 1997
  399. //
  400. // Modified: BillBe 9 Nov 1998
  401. // (Extracted from HrRegAddStringToSz and modified)
  402. //
  403. //
  404. // Note:
  405. // Might want to allow for the removal of leading/trailing spaces
  406. //
  407. HRESULT
  408. HrAddStringToDelimitedSz (
  409. IN PCWSTR pszAddString,
  410. IN PCWSTR pszIn,
  411. IN WCHAR chDelimiter,
  412. IN DWORD dwFlags,
  413. IN DWORD dwStringIndex,
  414. OUT PWSTR* ppszOut)
  415. {
  416. Assert(pszAddString);
  417. Assert(ppszOut);
  418. HRESULT hr = S_OK;
  419. // Don't continue if the pointers are NULL
  420. if (!pszAddString || !ppszOut)
  421. {
  422. hr = E_POINTER;
  423. }
  424. if (S_OK == hr)
  425. {
  426. // Initialize out param
  427. *ppszOut = NULL;
  428. }
  429. BOOL fEnsureAtFront = dwFlags & STRING_FLAG_ENSURE_AT_FRONT;
  430. BOOL fEnsureAtEnd = dwFlags & STRING_FLAG_ENSURE_AT_END;
  431. BOOL fEnsureAtIndex = dwFlags & STRING_FLAG_ENSURE_AT_INDEX;
  432. // Can't specify more than one of these flags
  433. if ((fEnsureAtFront && fEnsureAtEnd) ||
  434. (fEnsureAtFront && fEnsureAtIndex) ||
  435. (fEnsureAtEnd && fEnsureAtIndex))
  436. {
  437. AssertSz(FALSE, "Invalid flags in HrAddStringToSz");
  438. hr = E_INVALIDARG;
  439. }
  440. // Have to specify at least one of these
  441. if (!fEnsureAtFront && !fEnsureAtEnd && !fEnsureAtIndex)
  442. {
  443. AssertSz(FALSE, "Must specify a STRING_FLAG_ENSURE flag");
  444. hr = E_INVALIDARG;
  445. }
  446. if (S_OK == hr)
  447. {
  448. // Alloc the new blob, including enough space for the trailing comma
  449. //
  450. *ppszOut = (PWSTR) MemAlloc (CbOfSzAndTermSafe(pszIn) +
  451. CbOfSzSafe(pszAddString) + sizeof(WCHAR));
  452. if (!*ppszOut)
  453. {
  454. hr = E_OUTOFMEMORY;
  455. }
  456. }
  457. if (S_OK == hr)
  458. {
  459. DWORD dwCurrentIndex = 0; // Current index in the new buffer
  460. // Prime the new string
  461. //
  462. (*ppszOut)[0] = L'\0';
  463. // If we have the "ensure at front" flag, do so with the passed in
  464. // value. We also do this if we have the ensure at index flag
  465. // set with index of 0 or if the ensure at index is set but
  466. // the input string is null or empty
  467. //
  468. if (fEnsureAtFront || (fEnsureAtIndex && (0 == dwStringIndex)) ||
  469. (fEnsureAtIndex && (!pszIn || !*pszIn)))
  470. {
  471. lstrcpyW (*ppszOut, pszAddString);
  472. ++dwCurrentIndex;
  473. }
  474. // If there was a previous value, walk through it and copy as needed.
  475. // If not, then we're done.
  476. if (pszIn && *pszIn)
  477. {
  478. PCWSTR pszCurrent = pszIn;
  479. // Loop through the old buffer, and copy all of the strings that
  480. // are not identical to our insertion string.
  481. //
  482. // Find the first string's end (at the delimiter).
  483. PCWSTR pszEnd = wcschr (pszCurrent, chDelimiter);
  484. while (*pszCurrent)
  485. {
  486. // If the delimiter didn't exist, set the end to the end of the
  487. // entire string
  488. //
  489. if (!pszEnd)
  490. {
  491. pszEnd = pszCurrent + lstrlenW (pszCurrent);
  492. }
  493. LONG lLength = lstrlenW (*ppszOut);
  494. if (fEnsureAtIndex && (dwCurrentIndex == dwStringIndex))
  495. {
  496. // We know we are not at the first item since
  497. // this would mean dwStringIndex is 0 and we would
  498. // have copied the string before this point
  499. //
  500. (*ppszOut)[lLength++] = chDelimiter;
  501. (*ppszOut)[lLength++] = L'\0';
  502. // Append the string.
  503. lstrcatW (*ppszOut, pszAddString);
  504. ++dwCurrentIndex;
  505. }
  506. else
  507. {
  508. DWORD cch = (DWORD)(pszEnd - pszCurrent);
  509. // If we are allowing duplicates or the current string
  510. // doesn't match the string we want to add, then we will
  511. // copy it.
  512. //
  513. if ((dwFlags & STRING_FLAG_ALLOW_DUPLICATES) ||
  514. (_wcsnicmp (pszCurrent, pszAddString, cch) != 0))
  515. {
  516. // If we're not the first item, then add the delimiter.
  517. //
  518. if (lLength > 0)
  519. {
  520. (*ppszOut)[lLength++] = chDelimiter;
  521. (*ppszOut)[lLength++] = L'\0';
  522. }
  523. // Append the string.
  524. wcsncat (*ppszOut, pszCurrent, cch);
  525. ++dwCurrentIndex;
  526. }
  527. // Advance the pointer to one past the end of the current
  528. // string unless, the end is not the delimiter but NULL.
  529. // In that case, set the current point to equal the end
  530. // pointer
  531. //
  532. pszCurrent = pszEnd + (*pszEnd ? 1 : 0);
  533. // If the current pointer is not at the end of the input
  534. // string, then find the next delimiter
  535. //
  536. if (*pszCurrent)
  537. {
  538. pszEnd = wcschr (pszCurrent, chDelimiter);
  539. }
  540. }
  541. }
  542. }
  543. // If we don't have the "insert at front" flag, then we should insert
  544. // at the end (this is the same as having the
  545. // STRING_FLAG_ENSURE_AT_END flag set)
  546. //
  547. if (fEnsureAtEnd ||
  548. (fEnsureAtIndex && (dwCurrentIndex <= dwStringIndex)))
  549. {
  550. LONG lLength = lstrlenW (*ppszOut);
  551. // If we're not the first item, add the delimiter.
  552. //
  553. if (lstrlenW (*ppszOut) > 0)
  554. {
  555. (*ppszOut)[lLength++] = chDelimiter;
  556. (*ppszOut)[lLength++] = L'\0';
  557. }
  558. // Append the string.
  559. //
  560. lstrcatW (*ppszOut, pszAddString);
  561. }
  562. }
  563. TraceError ("HrAddStringToDelimitedSz", hr);
  564. return hr;
  565. }
  566. //+---------------------------------------------------------------------------
  567. //
  568. // Function: HrRegRemoveStringFromDelimitedSz
  569. //
  570. // Purpose: Removes a string from a delimited string value
  571. //
  572. // Arguments:
  573. // pszRemove [in] The string to be removed from the multi-sz
  574. // pszIn [in] The delimited list to scan for pszRemove
  575. // cDelimiter [in] The character to be used to delimit the
  576. // values. Most multi-valued REG_SZ strings are
  577. // delimited with either ',' or ' '.
  578. // dwFlags [in] Can contain one or more of the following
  579. // values:
  580. //
  581. // STRING_FLAG_REMOVE_SINGLE
  582. // Don't remove more than one value, if
  583. // multiple are present.
  584. // STRING_FLAG_REMOVE_ALL
  585. // If multiple matching values are present,
  586. // remove them all.
  587. // ppszOut [out] The string with pszRemove removed. Note
  588. // that the output parameter is always set even
  589. // if pszRemove did not exist in the list.
  590. //
  591. // Returns: S_OK or an HRESULT_FROM_WIN32 error code.
  592. //
  593. // Author: jeffspr 27 Mar 1997
  594. //
  595. // Modified: BillBe 10 Nov 1998
  596. // (Extracted from HrRegAddStringToSz and modified)
  597. //
  598. //
  599. //
  600. // Note:
  601. // Might want to allow for the removal of leading/trailing spaces
  602. //
  603. HRESULT
  604. HrRemoveStringFromDelimitedSz(
  605. IN PCWSTR pszRemove,
  606. IN PCWSTR pszIn,
  607. IN WCHAR chDelimiter,
  608. IN DWORD dwFlags,
  609. OUT PWSTR* ppszOut)
  610. {
  611. Assert(pszIn && *pszIn);
  612. Assert(ppszOut);
  613. HRESULT hr = S_OK;
  614. // If the out param is not specified, get out
  615. if (!ppszOut)
  616. {
  617. return E_INVALIDARG;
  618. }
  619. // Alloc the new blob
  620. //
  621. hr = E_OUTOFMEMORY;
  622. *ppszOut = (PWSTR) MemAlloc (CbOfSzAndTermSafe (pszIn));
  623. if (*ppszOut)
  624. {
  625. hr = S_OK;
  626. // Prime the new string
  627. //
  628. (*ppszOut)[0] = L'\0';
  629. // If there was a previous value, walk through it and copy as needed.
  630. // If not, then we're done
  631. //
  632. if (pszIn)
  633. {
  634. // Loop through the old buffer, and copy all of the strings that
  635. // are not identical to our insertion string.
  636. //
  637. PCWSTR pszCurrent = pszIn;
  638. // Loop through the old buffer, and copy all of the strings that
  639. // are not identical to our insertion string.
  640. //
  641. // Find the first string's end (at the delimiter).
  642. PCWSTR pszEnd = wcschr (pszCurrent, chDelimiter);
  643. // Keep track of how many instances have been removed.
  644. DWORD dwNumRemoved = 0;
  645. while (*pszCurrent)
  646. {
  647. // If the delimiter didn't exist, set the end to the end of
  648. // the entire string.
  649. //
  650. if (!pszEnd)
  651. {
  652. pszEnd = pszCurrent + lstrlenW (pszCurrent);
  653. }
  654. DWORD cch = (DWORD)(pszEnd - pszCurrent);
  655. INT iCompare;
  656. // If we have a match, and we want to remove it (meaning that
  657. // if we have the remove-single set, that we haven't removed
  658. // one already).
  659. iCompare = _wcsnicmp (pszCurrent, pszRemove, cch);
  660. if ((iCompare) ||
  661. ((dwFlags & STRING_FLAG_REMOVE_SINGLE) &&
  662. (dwNumRemoved > 0)))
  663. {
  664. LONG lLength = lstrlenW (*ppszOut);
  665. // If we're not the first item, then add the delimiter.
  666. //
  667. if (lLength > 0)
  668. {
  669. (*ppszOut)[lLength++] = chDelimiter;
  670. (*ppszOut)[lLength++] = L'\0';
  671. }
  672. // Append the string.
  673. wcsncat (*ppszOut, pszCurrent, cch);
  674. }
  675. else
  676. {
  677. dwNumRemoved++;
  678. }
  679. // Advance the pointer to one past the end of the current
  680. // string unless, the end is not the delimiter but NULL.
  681. // In that case, set the current point to equal the end
  682. // pointer
  683. //
  684. pszCurrent = pszEnd + (*pszEnd ? 1 : 0);
  685. // If the current pointer is not at the end of the input
  686. // string, then find the next delimiter
  687. //
  688. if (*pszCurrent)
  689. {
  690. pszEnd = wcschr (pszCurrent, chDelimiter);
  691. }
  692. }
  693. }
  694. }
  695. TraceError("HrRemoveStringFromDelimitedSz", hr);
  696. return hr;
  697. }
  698. PWSTR
  699. PszAllocateAndCopyPsz (
  700. IN PCWSTR pszSrc)
  701. {
  702. if (!pszSrc)
  703. {
  704. return NULL;
  705. }
  706. ULONG cb = (wcslen (pszSrc) + 1) * sizeof(WCHAR);
  707. PWSTR psz = (PWSTR)MemAlloc (cb);
  708. if (psz)
  709. {
  710. CopyMemory (psz, pszSrc, cb);
  711. }
  712. return psz;
  713. }
  714. //+---------------------------------------------------------------------------
  715. //
  716. // Function: SzLoadStringPcch
  717. //
  718. // Purpose: Load a resource string. (This function will never return NULL.)
  719. //
  720. // Arguments:
  721. // hinst [in] Instance handle of module with the string resource.
  722. // unId [in] Resource ID of the string to load.
  723. // pcch [out] Pointer to returned character length.
  724. //
  725. // Returns: Pointer to the constant string.
  726. //
  727. // Author: shaunco 24 Mar 1997
  728. //
  729. // Notes: The loaded string is pointer directly into the read-only
  730. // resource section. Any attempt to write through this pointer
  731. // will generate an access violation.
  732. //
  733. // The implementations is referenced from "Win32 Binary Resource
  734. // Formats" (MSDN) 4.8 String Table Resources
  735. //
  736. // User must have RCOPTIONS = -N turned on in your sources file.
  737. //
  738. PCWSTR
  739. SzLoadStringPcch (
  740. IN HINSTANCE hinst,
  741. IN UINT unId,
  742. OUT int* pcch)
  743. {
  744. Assert(hinst);
  745. Assert(unId);
  746. Assert(pcch);
  747. static const WCHAR c_szSpace[] = L" ";
  748. PCWSTR psz = c_szSpace;
  749. int cch = 1;
  750. // String Tables are broken up into 16 string segments. Find the segment
  751. // containing the string we are interested in.
  752. HRSRC hrsrcInfo = FindResource (hinst,
  753. (PWSTR)ULongToPtr( ((LONG)(((USHORT)unId >> 4) + 1)) ),
  754. RT_STRING);
  755. if (hrsrcInfo)
  756. {
  757. // Page the resource segment into memory.
  758. HGLOBAL hglbSeg = LoadResource (hinst, hrsrcInfo);
  759. if (hglbSeg)
  760. {
  761. // Lock the resource.
  762. psz = (PCWSTR)LockResource(hglbSeg);
  763. if (psz)
  764. {
  765. // Move past the other strings in this segment.
  766. // (16 strings in a segment -> & 0x0F)
  767. unId &= 0x0F;
  768. cch = 0;
  769. do
  770. {
  771. psz += cch; // Step to start of next string
  772. cch = *((WCHAR*)psz++); // PASCAL like string count
  773. }
  774. while (unId--);
  775. // If we have a non-zero count, it includes the
  776. // null-terminiator. Subtract this off for the return value.
  777. //
  778. if (cch)
  779. {
  780. cch--;
  781. }
  782. else
  783. {
  784. AssertSz(0, "String resource not found");
  785. psz = c_szSpace;
  786. cch = 1;
  787. }
  788. }
  789. else
  790. {
  791. psz = c_szSpace;
  792. cch = 1;
  793. TraceLastWin32Error("SzLoadStringPcch: LockResource failed.");
  794. }
  795. }
  796. else
  797. TraceLastWin32Error("SzLoadStringPcch: LoadResource failed.");
  798. }
  799. else
  800. TraceLastWin32Error("SzLoadStringPcch: FindResource failed.");
  801. *pcch = cch;
  802. Assert(*pcch);
  803. Assert(psz);
  804. return psz;
  805. }
  806. //+---------------------------------------------------------------------------
  807. //
  808. // Function: SzaDupSza
  809. //
  810. // Purpose: Duplicates a string
  811. //
  812. // Arguments:
  813. // pszaSrc [in] string to be duplicated
  814. //
  815. // Returns: Pointer to the new copy of the string
  816. //
  817. // Author: CWill 25 Mar 1997
  818. //
  819. // Notes: The string return must be freed (MemFree).
  820. //
  821. PSTR
  822. SzaDupSza (
  823. PCSTR pszaSrc)
  824. {
  825. AssertSz(pszaSrc, "Invalid source string");
  826. PSTR pszaDst;
  827. pszaDst = (PSTR) MemAlloc (CbOfSzaAndTerm(pszaSrc));
  828. if(pszaDst) lstrcpyA(pszaDst, pszaSrc);
  829. return pszaDst;
  830. }
  831. //+---------------------------------------------------------------------------
  832. //
  833. // Function: SzDupSz
  834. //
  835. // Purpose: Duplicates a string
  836. //
  837. // Arguments:
  838. // pszSrc [in] string to be duplicated
  839. //
  840. // Returns: Pointer to the new copy of the string
  841. //
  842. // Author: CWill 25 Mar 1997
  843. //
  844. // Notes: The string return must be freed.
  845. //
  846. PWSTR
  847. SzDupSz (
  848. IN PCWSTR pszSrc)
  849. {
  850. AssertSz(pszSrc, "Invalid source string");
  851. PWSTR pszDst;
  852. pszDst = (PWSTR) MemAlloc (CbOfSzAndTerm(pszSrc));
  853. if(pszDst) lstrcpyW (pszDst, pszSrc);
  854. return pszDst;
  855. }
  856. BOOL
  857. FSubstringMatch (
  858. PCTSTR pStr1,
  859. PCTSTR pStr2,
  860. const WCHAR** ppStart,
  861. ULONG* pcch)
  862. {
  863. const WCHAR* p1Start;
  864. const WCHAR* p1End;
  865. const WCHAR* p2Start;
  866. const WCHAR* p2End;
  867. ULONG cch1;
  868. ULONG cch2;
  869. if (ppStart)
  870. {
  871. *ppStart = NULL;
  872. }
  873. if (pcch)
  874. {
  875. *pcch = NULL;
  876. }
  877. p1End = pStr1;
  878. while (1)
  879. {
  880. GetNextCommaSeparatedToken(p1Start, p1End, cch1);
  881. if (!cch1)
  882. {
  883. break;
  884. }
  885. p2End = pStr2;
  886. while (1)
  887. {
  888. GetNextCommaSeparatedToken(p2Start, p2End, cch2);
  889. if (!cch2)
  890. {
  891. break;
  892. }
  893. if (cch1 == cch2)
  894. {
  895. if (0 == memcmp(p1Start, p2Start, cch1 * sizeof(WCHAR)))
  896. {
  897. if (ppStart)
  898. {
  899. *ppStart = p1Start;
  900. }
  901. if (pcch)
  902. {
  903. *pcch = cch1;
  904. }
  905. return TRUE;
  906. }
  907. }
  908. }
  909. }
  910. return FALSE;
  911. }
  912. VOID
  913. DeleteColString (
  914. list<tstring*>* pcolstr)
  915. {
  916. Assert( pcolstr );
  917. list<tstring*>::const_iterator iter;
  918. tstring* pstr;
  919. for (iter = pcolstr->begin(); iter != pcolstr->end(); iter++)
  920. {
  921. pstr = *iter;
  922. delete pstr;
  923. }
  924. pcolstr->erase( pcolstr->begin(), pcolstr->end() );
  925. }
  926. VOID
  927. DeleteColString (
  928. vector<tstring*>* pcolstr)
  929. {
  930. Assert( pcolstr );
  931. vector<tstring*>::const_iterator iter;
  932. tstring* pstr;
  933. for (iter = pcolstr->begin(); iter != pcolstr->end(); iter++)
  934. {
  935. pstr = *iter;
  936. delete pstr;
  937. }
  938. pcolstr->erase( pcolstr->begin(), pcolstr->end() );
  939. }