Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1212 lines
31 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. #include "ncmsz.h"
  20. //+---------------------------------------------------------------------------
  21. //
  22. // Function: CbOfSzSafe, CbOfSzaSafe,
  23. // CbOfSzAndTermSafe, CbOfSzaAndTermSafe
  24. //
  25. // Purpose: Count the bytes required to hold a string. The string
  26. // may be NULL in which case zero is returned.
  27. //
  28. // Arguments:
  29. // psz [in] String to return count of bytes for.
  30. //
  31. // Returns: Count of bytes required to store string.
  32. //
  33. // Author: shaunco 24 Mar 1997
  34. //
  35. // Notes: 'AndTerm' variants includes space for the null-terminator.
  36. //
  37. ULONG
  38. CbOfSzSafe (
  39. IN PCWSTR psz)
  40. {
  41. return (psz) ? CbOfSz(psz) : 0;
  42. }
  43. ULONG
  44. CbOfSzaSafe (
  45. IN PCSTR psza)
  46. {
  47. return (psza) ? CbOfSza(psza) : 0;
  48. }
  49. ULONG
  50. CbOfTSzSafe (
  51. IN PCTSTR psza)
  52. {
  53. return (psza) ? CbOfTSz(psza) : 0;
  54. }
  55. ULONG
  56. CbOfSzAndTermSafe (
  57. IN PCWSTR psz)
  58. {
  59. return (psz) ? CbOfSzAndTerm(psz) : 0;
  60. }
  61. ULONG
  62. CbOfSzaAndTermSafe (
  63. IN PCSTR psza)
  64. {
  65. return (psza) ? CbOfSzaAndTerm(psza) : 0;
  66. }
  67. ULONG
  68. CbOfTSzAndTermSafe (
  69. IN PCTSTR psza)
  70. {
  71. return (psza) ? CbOfTSzAndTerm(psza) : 0;
  72. }
  73. ULONG
  74. CchOfSzSafe (
  75. IN PCTSTR psz)
  76. {
  77. return (psz) ? _tcslen(psz) : 0;
  78. }
  79. //+---------------------------------------------------------------------------
  80. //
  81. // Function: DwFormatString
  82. //
  83. // Purpose: Uses FormatMessage to format a string from variable arguments.
  84. // The string is formatted into a fixed-size buffer the caller
  85. // provides.
  86. // See the description of FormatMessage in the Win32 API.
  87. //
  88. // Arguments:
  89. // pszFmt [in] pointer to format string
  90. // pszBuf [out] pointer to formatted output
  91. // cchBuf [in] count of characters in pszBuf
  92. // ... [in] replaceable string parameters
  93. //
  94. // Returns: the return value of FormatMessage
  95. //
  96. // Author: shaunco 15 Apr 1997
  97. //
  98. // Notes: The variable arguments must be strings otherwise
  99. // FormatMessage will barf.
  100. //
  101. DWORD
  102. WINAPIV
  103. DwFormatString (
  104. IN PCWSTR pszFmt,
  105. OUT PWSTR pszBuf,
  106. IN DWORD cchBuf,
  107. IN ...)
  108. {
  109. Assert (pszFmt);
  110. va_list val;
  111. va_start(val, cchBuf);
  112. DWORD dwRet = FormatMessageW (FORMAT_MESSAGE_FROM_STRING,
  113. pszFmt, 0, 0, pszBuf, cchBuf, &val);
  114. va_end(val);
  115. return dwRet;
  116. }
  117. //+---------------------------------------------------------------------------
  118. //
  119. // Function: DwFormatStringWithLocalAlloc
  120. //
  121. // Purpose: Uses FormatMessage to format a string from variable arguments.
  122. // The string is allocated by FormatMessage using LocalAlloc.
  123. // See the description of FormatMessage in the Win32 API.
  124. //
  125. // Arguments:
  126. // pszFmt [in] pointer to format string
  127. // ppszBuf [out] the returned formatted string
  128. // ... [in] replaceable string parameters
  129. //
  130. // Returns: the return value of FormatMessage
  131. //
  132. // Author: shaunco 3 May 1997
  133. //
  134. // Notes: The variable arguments must be strings otherwise
  135. // FormatMessage will barf.
  136. //
  137. DWORD
  138. WINAPIV
  139. DwFormatStringWithLocalAlloc (
  140. IN PCWSTR pszFmt,
  141. OUT PWSTR* ppszBuf,
  142. IN ...)
  143. {
  144. Assert (pszFmt);
  145. va_list val;
  146. va_start(val, ppszBuf);
  147. DWORD dwRet = FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
  148. FORMAT_MESSAGE_FROM_STRING,
  149. pszFmt, 0, 0,
  150. (PWSTR)ppszBuf,
  151. 0, &val);
  152. va_end(val);
  153. return dwRet;
  154. }
  155. PWSTR
  156. WszAllocateAndCopyWsz (
  157. IN PCWSTR pszSrc)
  158. {
  159. if (!pszSrc)
  160. {
  161. return NULL;
  162. }
  163. ULONG cb = (wcslen (pszSrc) + 1) * sizeof(WCHAR);
  164. PWSTR psz = (PWSTR)MemAlloc (cb);
  165. if (psz)
  166. {
  167. CopyMemory (psz, pszSrc, cb);
  168. }
  169. return psz;
  170. }
  171. //+---------------------------------------------------------------------------
  172. //
  173. // Function: WszLoadStringPcch
  174. //
  175. // Purpose: Load a resource string. (This function will never return NULL.)
  176. //
  177. // Arguments:
  178. // hinst [in] Instance handle of module with the string resource.
  179. // unId [in] Resource ID of the string to load.
  180. // pcch [out] Pointer to returned character length.
  181. //
  182. // Returns: Pointer to the constant string.
  183. //
  184. // Author: shaunco 24 Mar 1997
  185. //
  186. // Notes: The loaded string is pointer directly into the read-only
  187. // resource section. Any attempt to write through this pointer
  188. // will generate an access violation.
  189. //
  190. // The implementations is referenced from "Win32 Binary Resource
  191. // Formats" (MSDN) 4.8 String Table Resources
  192. //
  193. // User must have RCOPTIONS = -N turned on in your sources file.
  194. //
  195. PCWSTR
  196. WszLoadStringPcch (
  197. IN HINSTANCE hinst,
  198. IN UINT unId,
  199. OUT int* pcch)
  200. {
  201. Assert(hinst);
  202. Assert(unId);
  203. Assert(pcch);
  204. static const WCHAR c_szSpace[] = L" ";
  205. PCWSTR psz = c_szSpace;
  206. int cch = 1;
  207. // String Tables are broken up into 16 string segments. Find the segment
  208. // containing the string we are interested in.
  209. // See KB ID: Q20011 for a half-explanation of the second argument below.
  210. HRSRC hrsrcInfo = FindResource (hinst,
  211. (PTSTR)ULongToPtr( ((LONG)(((USHORT)unId >> 4) + 1)) ),
  212. RT_STRING);
  213. if (hrsrcInfo)
  214. {
  215. // Page the resource segment into memory.
  216. HGLOBAL hglbSeg = LoadResource (hinst, hrsrcInfo);
  217. if (hglbSeg)
  218. {
  219. // Lock the resource.
  220. psz = (PCWSTR)LockResource(hglbSeg);
  221. if (psz)
  222. {
  223. // Move past the other strings in this segment.
  224. // (16 strings in a segment -> & 0x0F)
  225. unId &= 0x0F;
  226. cch = 0;
  227. do
  228. {
  229. psz += cch; // Step to start of next string
  230. cch = *((WCHAR*)psz++); // PASCAL like string count
  231. }
  232. while (unId--);
  233. // If we have a non-zero count, it includes the
  234. // null-terminiator. Subtract this off for the return value.
  235. //
  236. if (cch)
  237. {
  238. cch--;
  239. }
  240. else
  241. {
  242. AssertSz(0, "String resource not found");
  243. psz = c_szSpace;
  244. cch = 1;
  245. }
  246. }
  247. else
  248. {
  249. psz = c_szSpace;
  250. cch = 1;
  251. TraceLastWin32Error("SzLoadStringPcch: LockResource failed.");
  252. }
  253. }
  254. else
  255. TraceLastWin32Error("SzLoadStringPcch: LoadResource failed.");
  256. }
  257. else
  258. TraceLastWin32Error("SzLoadStringPcch: FindResource failed.");
  259. *pcch = cch;
  260. Assert(*pcch);
  261. Assert(psz);
  262. return psz;
  263. }
  264. //+---------------------------------------------------------------------------
  265. //
  266. // Function: SzaDupSza
  267. //
  268. // Purpose: Duplicates a string
  269. //
  270. // Arguments:
  271. // pszaSrc [in] string to be duplicated
  272. //
  273. // Returns: Pointer to the new copy of the string
  274. //
  275. // Author: CWill 25 Mar 1997
  276. //
  277. // Notes: The string return must be freed (MemFree).
  278. //
  279. PSTR
  280. SzaDupSza (
  281. PCSTR pszaSrc)
  282. {
  283. AssertSz(pszaSrc, "Invalid source string");
  284. PSTR pszaDst;
  285. pszaDst = (PSTR) MemAlloc (CbOfSzaAndTerm(pszaSrc));
  286. if (pszaDst)
  287. {
  288. strcpy(pszaDst, pszaSrc);
  289. }
  290. return pszaDst;
  291. }
  292. //+---------------------------------------------------------------------------
  293. //
  294. // Function: TszDupTsz
  295. //
  296. // Purpose: Duplicates a string
  297. //
  298. // Arguments:
  299. // pszSrc [in] string to be duplicated
  300. //
  301. // Returns: Pointer to the new copy of the string
  302. //
  303. // Notes: The string return must be freed.
  304. //
  305. PTSTR
  306. TszDupTsz (
  307. IN PCTSTR pszSrc)
  308. {
  309. AssertSz(pszSrc, "Invalid source string");
  310. PTSTR pszDst;
  311. pszDst = (PTSTR) MemAlloc (CbOfTSzAndTermSafe(pszSrc));
  312. if (pszDst)
  313. {
  314. _tcscpy(pszDst, pszSrc);
  315. }
  316. return pszDst;
  317. }
  318. //+---------------------------------------------------------------------------
  319. //
  320. // Function: WszDupWsz
  321. //
  322. // Purpose: Duplicates a wide string
  323. //
  324. // Arguments:
  325. // szOld [in] String to duplicate
  326. //
  327. // Returns: Newly allocated copy
  328. //
  329. // Author: danielwe 4 Aug 2000
  330. //
  331. // Notes: Caller must free result with delete []
  332. //
  333. LPWSTR WszDupWsz(LPCWSTR szOld)
  334. {
  335. LPWSTR szNew;
  336. szNew = new WCHAR[lstrlen(szOld) + 1];
  337. if (szNew)
  338. {
  339. lstrcpy(szNew, szOld);
  340. }
  341. return szNew;
  342. }
  343. LPWSTR WszFromSz(LPCSTR szAnsi)
  344. {
  345. Assert(szAnsi);
  346. LPWSTR pszResult;
  347. LPWSTR pszWide;
  348. INT cchWide;
  349. INT result;
  350. pszResult = NULL;
  351. if (!szAnsi)
  352. {
  353. goto Cleanup;
  354. }
  355. result = ::MultiByteToWideChar(CP_ACP,
  356. 0,
  357. szAnsi,
  358. -1,
  359. NULL,
  360. 0);
  361. if (!result)
  362. {
  363. TraceLastWin32Error("WszFromSz: MultiByteToWideChar #1");
  364. goto Cleanup;
  365. }
  366. cchWide = result;
  367. pszWide = new WCHAR [ cchWide ];
  368. if (!pszWide)
  369. {
  370. TraceError("WszFromSz: new", E_OUTOFMEMORY);
  371. goto Cleanup;
  372. }
  373. result = ::MultiByteToWideChar(CP_ACP,
  374. 0,
  375. szAnsi,
  376. -1,
  377. pszWide,
  378. cchWide);
  379. if (!result)
  380. {
  381. TraceLastWin32Error("WszFromSz: MultiByteToWideChar #2");
  382. delete [] pszWide;
  383. goto Cleanup;
  384. }
  385. pszResult = pszWide;
  386. Cleanup:
  387. return pszResult;
  388. }
  389. LPWSTR WszFromUtf8(LPCSTR szUtf8)
  390. {
  391. Assert(szUtf8);
  392. LPWSTR pszResult;
  393. LPWSTR pszWide;
  394. INT cchWide;
  395. INT result;
  396. pszResult = NULL;
  397. if (!szUtf8)
  398. {
  399. goto Cleanup;
  400. }
  401. result = ::MultiByteToWideChar(CP_UTF8,
  402. 0,
  403. szUtf8,
  404. -1,
  405. NULL,
  406. 0);
  407. if (!result)
  408. {
  409. TraceLastWin32Error("WszFromUtf8: MultiByteToWideChar #1");
  410. goto Cleanup;
  411. }
  412. cchWide = result;
  413. pszWide = new WCHAR [ cchWide ];
  414. if (!pszWide)
  415. {
  416. TraceError("WszFromUtf8: new", E_OUTOFMEMORY);
  417. goto Cleanup;
  418. }
  419. result = ::MultiByteToWideChar(CP_UTF8,
  420. 0,
  421. szUtf8,
  422. -1,
  423. pszWide,
  424. cchWide);
  425. if (!result)
  426. {
  427. TraceLastWin32Error("WszFromUtf8: MultiByteToWideChar #2");
  428. delete [] pszWide;
  429. goto Cleanup;
  430. }
  431. pszResult = pszWide;
  432. Cleanup:
  433. return pszResult;
  434. }
  435. LPSTR SzFromWsz(LPCWSTR szWide)
  436. {
  437. Assert(szWide);
  438. LPSTR pszResult;
  439. LPSTR pszAnsi;
  440. INT cbAnsi;
  441. INT result;
  442. pszResult = NULL;
  443. if (!szWide)
  444. {
  445. goto Cleanup;
  446. }
  447. result = ::WideCharToMultiByte(CP_ACP,
  448. 0,
  449. szWide,
  450. -1,
  451. NULL,
  452. 0,
  453. NULL,
  454. NULL);
  455. if (!result)
  456. {
  457. TraceLastWin32Error("SzFromWsz: WideCharToMultiByte #1");
  458. goto Cleanup;
  459. }
  460. cbAnsi = result;
  461. pszAnsi = (CHAR *)MemAlloc(cbAnsi);
  462. if (!pszAnsi)
  463. {
  464. TraceError("SzFromWsz: MemAlloc", E_OUTOFMEMORY);
  465. goto Cleanup;
  466. }
  467. result = ::WideCharToMultiByte(CP_ACP,
  468. 0,
  469. szWide,
  470. -1,
  471. pszAnsi,
  472. cbAnsi,
  473. NULL,
  474. NULL);
  475. if (!result)
  476. {
  477. TraceLastWin32Error("SzFromWsz: WideCharToMultiByte #2");
  478. MemFree(pszAnsi);
  479. goto Cleanup;
  480. }
  481. pszResult = pszAnsi;
  482. Cleanup:
  483. return pszResult;
  484. }
  485. LPSTR Utf8FromWsz(LPCWSTR szWide)
  486. {
  487. Assert(szWide);
  488. LPSTR pszResult;
  489. LPSTR pszUtf8;
  490. INT cbUtf8;
  491. INT result;
  492. pszResult = NULL;
  493. if (!szWide)
  494. {
  495. goto Cleanup;
  496. }
  497. result = ::WideCharToMultiByte(CP_UTF8,
  498. 0,
  499. szWide,
  500. -1,
  501. NULL,
  502. 0,
  503. NULL,
  504. NULL);
  505. if (!result)
  506. {
  507. TraceLastWin32Error("Utf8FromWsz: WideCharToMultiByte #1");
  508. goto Cleanup;
  509. }
  510. cbUtf8 = result;
  511. pszUtf8 = (CHAR *)MemAlloc(cbUtf8);
  512. if (!pszUtf8)
  513. {
  514. TraceError("SzFromWsz: MemAlloc", E_OUTOFMEMORY);
  515. goto Cleanup;
  516. }
  517. result = ::WideCharToMultiByte(CP_UTF8,
  518. 0,
  519. szWide,
  520. -1,
  521. pszUtf8,
  522. cbUtf8,
  523. NULL,
  524. NULL);
  525. if (!result)
  526. {
  527. TraceLastWin32Error("Utf8FromWsz: WideCharToMultiByte #2");
  528. MemFree(pszUtf8);
  529. goto Cleanup;
  530. }
  531. pszResult = pszUtf8;
  532. Cleanup:
  533. return pszResult;
  534. }
  535. LPWSTR WszFromTsz(LPCTSTR pszInputString)
  536. {
  537. #ifdef _UNICODE
  538. return WszAllocateAndCopyWsz(pszInputString);
  539. #else // not unicode
  540. return WszFromSz(pszInputString);
  541. #endif // _UNICODE
  542. }
  543. LPTSTR TszFromWsz(LPCWSTR pszInputString)
  544. {
  545. #ifdef _UNICODE
  546. return WszAllocateAndCopyWsz(pszInputString);
  547. #else // not unicode
  548. return SzFromWsz(pszInputString);
  549. #endif // _UNICODE
  550. }
  551. LPTSTR TszFromSz(LPCSTR szAnsi)
  552. {
  553. #ifdef _UNICODE
  554. return WszFromSz(szAnsi);
  555. #else
  556. return SzaDupSza(szAnsi);
  557. #endif
  558. }
  559. LPSTR SzFromTsz(LPCTSTR pszInputString)
  560. {
  561. #ifdef _UNICODE
  562. return SzFromWsz(pszInputString);
  563. #else
  564. return SzaDupSza(pszInputString);
  565. #endif
  566. }
  567. //+---------------------------------------------------------------------------
  568. //
  569. // Function: HrRegAddStringToDelimitedSz
  570. //
  571. // Purpose: Add a string into a REG_MULTI_SZ registry value.
  572. //
  573. // Arguments:
  574. // pszAddString [in] The string to add to the delimited psz.
  575. // pszIn [in] The delimited psz list.
  576. // chDelimiter [in] The character to be used to delimit the
  577. // values. Most multi-valued REG_SZ strings are
  578. // delimited with either ',' or ' '. This will
  579. // be used to delimit the value that we add,
  580. // as well.
  581. // dwFlags [in] Can contain one or more of the following
  582. // values:
  583. //
  584. // STRING_FLAG_ALLOW_DUPLICATES
  585. // Don't remove duplicate values when adding
  586. // the string to the list. Default is to
  587. // remove all other instance of this string.
  588. // STRING_FLAG_ENSURE_AT_FRONT
  589. // Insert the string as the first element of
  590. // the list.
  591. // STRING_FLAG_ENSURE_AT_END
  592. // Insert the string as the last
  593. // element of the list. This can not be used
  594. // with STRING_FLAG_ENSURE_AT_FRONT.
  595. // STRING_FLAG_ENSURE_AT_INDEX
  596. // Ensure that the string is at dwStringIndex
  597. // in the psz. If the index specified
  598. // is greater than the number of strings
  599. // in the psz, the string will be
  600. // placed at the end.
  601. // dwStringIndex [in] If STRING_FLAG_ENSURE_AT_INDEX is specified,
  602. // this is the index for the string position.
  603. // Otherwise, this value is ignored.
  604. // pmszOut [out] The new delimited psz.
  605. //
  606. //
  607. // Returns: S_OK or an HRESULT_FROM_WIN32 error code.
  608. //
  609. // Author: jeffspr 27 Mar 1997
  610. //
  611. // Modified: BillBe 9 Nov 1998
  612. // (Extracted from HrRegAddStringToSz and modified)
  613. //
  614. //
  615. // Note:
  616. // Might want to allow for the removal of leading/trailing spaces
  617. //
  618. HRESULT
  619. HrAddStringToDelimitedSz (
  620. IN PCTSTR pszAddString,
  621. IN PCTSTR pszIn,
  622. IN TCHAR chDelimiter,
  623. IN DWORD dwFlags,
  624. IN DWORD dwStringIndex,
  625. OUT PTSTR* ppszOut)
  626. {
  627. Assert(pszAddString);
  628. Assert(ppszOut);
  629. HRESULT hr = S_OK;
  630. // Don't continue if the pointers are NULL
  631. if (!pszAddString || !ppszOut)
  632. {
  633. hr = E_POINTER;
  634. }
  635. if (S_OK == hr)
  636. {
  637. // Initialize out param
  638. *ppszOut = NULL;
  639. }
  640. BOOL fEnsureAtFront = dwFlags & STRING_FLAG_ENSURE_AT_FRONT;
  641. BOOL fEnsureAtEnd = dwFlags & STRING_FLAG_ENSURE_AT_END;
  642. BOOL fEnsureAtIndex = dwFlags & STRING_FLAG_ENSURE_AT_INDEX;
  643. // Can't specify more than one of these flags
  644. if ((fEnsureAtFront && fEnsureAtEnd) ||
  645. (fEnsureAtFront && fEnsureAtIndex) ||
  646. (fEnsureAtEnd && fEnsureAtIndex))
  647. {
  648. AssertSz(FALSE, "Invalid flags in HrAddStringToSz");
  649. hr = E_INVALIDARG;
  650. }
  651. // Have to specify at least one of these
  652. if (!fEnsureAtFront && !fEnsureAtEnd && !fEnsureAtIndex)
  653. {
  654. AssertSz(FALSE, "Must specify a STRING_FLAG_ENSURE flag");
  655. hr = E_INVALIDARG;
  656. }
  657. if (S_OK == hr)
  658. {
  659. // Alloc the new blob, including enough space for the trailing comma
  660. //
  661. *ppszOut = (PTSTR) MemAlloc (CbOfTSzAndTermSafe(pszIn) +
  662. CbOfTSzSafe(pszAddString) + sizeof(TCHAR));
  663. if (!*ppszOut)
  664. {
  665. hr = E_OUTOFMEMORY;
  666. }
  667. }
  668. if (S_OK == hr)
  669. {
  670. DWORD dwCurrentIndex = 0; // Current index in the new buffer
  671. // Prime the new string
  672. //
  673. (*ppszOut)[0] = L'\0';
  674. // If we have the "ensure at front" flag, do so with the passed in
  675. // value. We also do this if we have the ensure at index flag
  676. // set with index of 0 or if the ensure at index is set but
  677. // the input string is null or empty
  678. //
  679. if (fEnsureAtFront || (fEnsureAtIndex && (0 == dwStringIndex)) ||
  680. (fEnsureAtIndex && (!pszIn || !*pszIn)))
  681. {
  682. _tcscpy (*ppszOut, pszAddString);
  683. ++dwCurrentIndex;
  684. }
  685. // If there was a previous value, walk through it and copy as needed.
  686. // If not, then we're done.
  687. if (pszIn && *pszIn)
  688. {
  689. PCTSTR pszCurrent = pszIn;
  690. // Loop through the old buffer, and copy all of the strings that
  691. // are not identical to our insertion string.
  692. //
  693. // Find the first string's end (at the delimiter).
  694. PCTSTR pszEnd = _tcschr (pszCurrent, chDelimiter);
  695. while (*pszCurrent)
  696. {
  697. // If the delimiter didn't exist, set the end to the end of the
  698. // entire string
  699. //
  700. if (!pszEnd)
  701. {
  702. pszEnd = pszCurrent + _tcslen (pszCurrent);
  703. }
  704. LONG lLength = _tcslen (*ppszOut);
  705. if (fEnsureAtIndex && (dwCurrentIndex == dwStringIndex))
  706. {
  707. // We know we are not at the first item since
  708. // this would mean dwStringIndex is 0 and we would
  709. // have copied the string before this point
  710. //
  711. (*ppszOut)[lLength++] = chDelimiter;
  712. (*ppszOut)[lLength++] = L'\0';
  713. // Append the string.
  714. _tcscat (*ppszOut, pszAddString);
  715. ++dwCurrentIndex;
  716. }
  717. else
  718. {
  719. DWORD_PTR cch = pszEnd - pszCurrent;
  720. // If we are allowing duplicates or the current string
  721. // doesn't match the string we want to add, then we will
  722. // copy it.
  723. //
  724. if ((dwFlags & STRING_FLAG_ALLOW_DUPLICATES) ||
  725. (_tcsnicmp (pszCurrent, pszAddString, cch) != 0))
  726. {
  727. // If we're not the first item, then add the delimiter.
  728. //
  729. if (lLength > 0)
  730. {
  731. (*ppszOut)[lLength++] = chDelimiter;
  732. (*ppszOut)[lLength++] = L'\0';
  733. }
  734. // Append the string.
  735. _tcsncat (*ppszOut, pszCurrent, cch);
  736. ++dwCurrentIndex;
  737. }
  738. // Advance the pointer to one past the end of the current
  739. // string unless, the end is not the delimiter but NULL.
  740. // In that case, set the current point to equal the end
  741. // pointer
  742. //
  743. pszCurrent = pszEnd + (*pszEnd ? 1 : 0);
  744. // If the current pointer is not at the end of the input
  745. // string, then find the next delimiter
  746. //
  747. if (*pszCurrent)
  748. {
  749. pszEnd = _tcschr (pszCurrent, chDelimiter);
  750. }
  751. }
  752. }
  753. }
  754. // If we don't have the "insert at front" flag, then we should insert
  755. // at the end (this is the same as having the
  756. // STRING_FLAG_ENSURE_AT_END flag set)
  757. //
  758. if (fEnsureAtEnd ||
  759. (fEnsureAtIndex && (dwCurrentIndex <= dwStringIndex)))
  760. {
  761. LONG lLength = _tcslen (*ppszOut);
  762. // If we're not the first item, add the delimiter.
  763. //
  764. if (_tcslen (*ppszOut) > 0)
  765. {
  766. (*ppszOut)[lLength++] = chDelimiter;
  767. (*ppszOut)[lLength++] = L'\0';
  768. }
  769. // Append the string.
  770. //
  771. _tcscat (*ppszOut, pszAddString);
  772. }
  773. }
  774. TraceError ("HrAddStringToDelimitedSz", hr);
  775. return hr;
  776. }
  777. //+---------------------------------------------------------------------------
  778. //
  779. // Function: HrRegRemoveStringFromDelimitedSz
  780. //
  781. // Purpose: Removes a string from a delimited string value
  782. //
  783. // Arguments:
  784. // pszRemove [in] The string to be removed from the multi-sz
  785. // pszIn [in] The delimited list to scan for pszRemove
  786. // cDelimiter [in] The character to be used to delimit the
  787. // values. Most multi-valued REG_SZ strings are
  788. // delimited with either ',' or ' '.
  789. // dwFlags [in] Can contain one or more of the following
  790. // values:
  791. //
  792. // STRING_FLAG_REMOVE_SINGLE
  793. // Don't remove more than one value, if
  794. // multiple are present.
  795. // STRING_FLAG_REMOVE_ALL
  796. // If multiple matching values are present,
  797. // remove them all.
  798. // ppszOut [out] The string with pszRemove removed. Note
  799. // that the output parameter is always set even
  800. // if pszRemove did not exist in the list.
  801. //
  802. // Returns: S_OK or an HRESULT_FROM_WIN32 error code.
  803. //
  804. // Author: jeffspr 27 Mar 1997
  805. //
  806. // Modified: BillBe 10 Nov 1998
  807. // (Extracted from HrRegAddStringToSz and modified)
  808. //
  809. //
  810. //
  811. // Note:
  812. // Might want to allow for the removal of leading/trailing spaces
  813. //
  814. HRESULT
  815. HrRemoveStringFromDelimitedSz(
  816. IN PCTSTR pszRemove,
  817. IN PCTSTR pszIn,
  818. IN TCHAR chDelimiter,
  819. IN DWORD dwFlags,
  820. OUT PTSTR* ppszOut)
  821. {
  822. Assert(pszIn && *pszIn);
  823. Assert(ppszOut);
  824. HRESULT hr = S_OK;
  825. // If the out param is not specified, get out
  826. if (!ppszOut)
  827. {
  828. return E_INVALIDARG;
  829. }
  830. // Alloc the new blob
  831. //
  832. hr = E_OUTOFMEMORY;
  833. *ppszOut = (PTSTR) MemAlloc (CbOfTSzAndTermSafe (pszIn));
  834. if (*ppszOut)
  835. {
  836. hr = S_OK;
  837. // Prime the new string
  838. //
  839. (*ppszOut)[0] = L'\0';
  840. // If there was a previous value, walk through it and copy as needed.
  841. // If not, then we're done
  842. //
  843. if (pszIn)
  844. {
  845. // Loop through the old buffer, and copy all of the strings that
  846. // are not identical to our insertion string.
  847. //
  848. PCTSTR pszCurrent = pszIn;
  849. // Loop through the old buffer, and copy all of the strings that
  850. // are not identical to our insertion string.
  851. //
  852. // Find the first string's end (at the delimiter).
  853. PCTSTR pszEnd = _tcschr (pszCurrent, chDelimiter);
  854. // Keep track of how many instances have been removed.
  855. DWORD dwNumRemoved = 0;
  856. while (*pszCurrent)
  857. {
  858. // If the delimiter didn't exist, set the end to the end of
  859. // the entire string.
  860. //
  861. if (!pszEnd)
  862. {
  863. pszEnd = pszCurrent + _tcslen (pszCurrent);
  864. }
  865. DWORD_PTR cch = pszEnd - pszCurrent;
  866. INT iCompare;
  867. // If we have a match, and we want to remove it (meaning that
  868. // if we have the remove-single set, that we haven't removed
  869. // one already).
  870. iCompare = _tcsnicmp (pszCurrent, pszRemove, cch);
  871. if ((iCompare) ||
  872. ((dwFlags & STRING_FLAG_REMOVE_SINGLE) &&
  873. (dwNumRemoved > 0)))
  874. {
  875. LONG lLength = _tcslen (*ppszOut);
  876. // If we're not the first item, then add the delimiter.
  877. //
  878. if (lLength > 0)
  879. {
  880. (*ppszOut)[lLength++] = chDelimiter;
  881. (*ppszOut)[lLength++] = L'\0';
  882. }
  883. // Append the string.
  884. _tcsncat (*ppszOut, pszCurrent, cch);
  885. }
  886. else
  887. {
  888. dwNumRemoved++;
  889. }
  890. // Advance the pointer to one past the end of the current
  891. // string unless, the end is not the delimiter but NULL.
  892. // In that case, set the current point to equal the end
  893. // pointer
  894. //
  895. pszCurrent = pszEnd + (*pszEnd ? 1 : 0);
  896. // If the current pointer is not at the end of the input
  897. // string, then find the next delimiter
  898. //
  899. if (*pszCurrent)
  900. {
  901. pszEnd = _tcschr (pszCurrent, chDelimiter);
  902. }
  903. }
  904. }
  905. }
  906. TraceError("HrRemoveStringFromDelimitedSz", hr);
  907. return hr;
  908. }
  909. //+---------------------------------------------------------------------------
  910. //
  911. // Function: HrReallocAndCopyString
  912. //
  913. // Purpose: Copies a given string into a string pointer that might
  914. // already contain an alloc()ed string. If the destination
  915. // pointer contains a string (e.g. is non-null), that string
  916. // is freed before the copy occurs.
  917. //
  918. // Arguments:
  919. // pszSrc The string to copy. This may be NULL.
  920. // ppszDest The address of the pointer which will contain the copied
  921. // string. If *ppszDest is non-NULL when the function is
  922. // called, its value will be freed before the string is
  923. // copied. On return, it will contain a copy of pszSrc,
  924. // or be set to NULL (if pszSrc is NULL).
  925. //
  926. // Returns: TRUE if the *ppszDest was set
  927. // E_OUTOFMEMORY if the new string could not be allocated
  928. //
  929. // Notes:
  930. //
  931. HRESULT
  932. HrReallocAndCopyString(/* IN */ LPCWSTR pszSrc, /* INOUT */ LPWSTR * ppszDest)
  933. {
  934. Assert(ppszDest);
  935. HRESULT hr;
  936. LPWSTR pszTemp;
  937. hr = S_OK;
  938. pszTemp = NULL;
  939. if (pszSrc)
  940. {
  941. // copy the string into pszTemp
  942. pszTemp = WszAllocateAndCopyWsz(pszSrc);
  943. if (!pszTemp)
  944. {
  945. hr = E_OUTOFMEMORY;
  946. goto Cleanup;
  947. }
  948. }
  949. if (*ppszDest)
  950. {
  951. delete [] *ppszDest;
  952. }
  953. *ppszDest = pszTemp;
  954. Cleanup:
  955. TraceError("HrReallocAndCopyString", hr);
  956. return hr;
  957. }
  958. //+---------------------------------------------------------------------------
  959. //
  960. // Function: HrCopyString
  961. //
  962. // Purpose: Copies a string using new
  963. //
  964. // Arguments:
  965. // szSrc [in] String to be copied
  966. // pszDest [out] Copy
  967. //
  968. // Returns:
  969. //
  970. // Author: mbend 12 Nov 2000
  971. //
  972. // Notes:
  973. //
  974. HRESULT HrCopyString(const char * szSrc, char ** pszDest)
  975. {
  976. HRESULT hr = S_OK;
  977. if(szSrc)
  978. {
  979. *pszDest = new char[lstrlenA(szSrc) + 1];
  980. if(!*pszDest)
  981. {
  982. hr = E_OUTOFMEMORY;
  983. }
  984. if(SUCCEEDED(hr))
  985. {
  986. lstrcpyA(*pszDest, szSrc);
  987. }
  988. }
  989. else
  990. {
  991. hr = E_POINTER;
  992. }
  993. TraceHr(ttidError, FAL, hr, (hr == E_POINTER), "HrCopyString");
  994. return hr;
  995. }
  996. //+---------------------------------------------------------------------------
  997. //
  998. // Function: HrCopyString
  999. //
  1000. // Purpose: Copies a string using new
  1001. //
  1002. // Arguments:
  1003. // szSrc [in] String to be copied
  1004. // pszDest [out] Copy
  1005. //
  1006. // Returns:
  1007. //
  1008. // Author: mbend 12 Nov 2000
  1009. //
  1010. // Notes:
  1011. //
  1012. HRESULT HrCopyString(const wchar_t * szSrc, wchar_t ** pszDest)
  1013. {
  1014. HRESULT hr = S_OK;
  1015. if(szSrc)
  1016. {
  1017. *pszDest = new wchar_t[lstrlen(szSrc) + 1];
  1018. if(!*pszDest)
  1019. {
  1020. hr = E_OUTOFMEMORY;
  1021. }
  1022. if(SUCCEEDED(hr))
  1023. {
  1024. lstrcpy(*pszDest, szSrc);
  1025. }
  1026. }
  1027. else
  1028. {
  1029. hr = E_POINTER;
  1030. }
  1031. TraceHr(ttidError, FAL, hr, (hr == E_POINTER), "HrCopyString");
  1032. return hr;
  1033. }
  1034. //
  1035. // Stol.. er. "borrowed" from \\index2\ntsrc\enduser\windows.com\wuv3\wuv3\string.cpp
  1036. //
  1037. char *stristr(const char *string1, const char *string2)
  1038. {
  1039. char *pSave = (char *)string1;
  1040. char *ps1 = (char *)string1;
  1041. char *ps2 = (char *)string2;
  1042. if ( !*ps1 || !ps2 || !ps1 )
  1043. return NULL;
  1044. if ( !*ps2 )
  1045. return ps1;
  1046. while( *ps1 )
  1047. {
  1048. while( *ps2 && (toupper(*ps2) == toupper(*ps1)) )
  1049. {
  1050. ps2++;
  1051. ps1++;
  1052. }
  1053. if ( !*ps2 )
  1054. return pSave;
  1055. if ( ps2 == string2 )
  1056. {
  1057. ps1++;
  1058. pSave = ps1;
  1059. }
  1060. else
  1061. ps2 = (char *)string2;
  1062. }
  1063. return NULL;
  1064. }