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.

1835 lines
62 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. fusionbuffer.h
  5. Abstract:
  6. Author:
  7. Revision History:
  8. --*/
  9. #if !defined(FUSION_INC_FUSIONBUFFER_H_INCLUDED_)
  10. #define FUSION_INC_FUSIONBUFFER_H_INCLUDED_
  11. #pragma once
  12. #include <stdio.h>
  13. #include <limits.h>
  14. #include "arrayhelp.h"
  15. #include "smartref.h"
  16. #include "returnstrategy.h"
  17. #include "fusionstring.h"
  18. #include "fusiontrace.h"
  19. #include "fusionchartraits.h"
  20. // avoid circular reference to Util.h
  21. BOOL FusionpIsPathSeparator(WCHAR ch);
  22. BOOL FusionpIsDriveLetter(WCHAR ch);
  23. //
  24. // This header file defines the Fusion character string buffer class.
  25. // The purpose of this class is to encapsulate common activities that
  26. // callers want to do with character string buffers and handle it in
  27. // a generic fashion. A principle tenet of this class is that it is
  28. // not a string class, although one could consider building a string
  29. // class upon it.
  30. //
  31. // The buffer maintains a certain amount of storage within the buffer
  32. // object itself, and if more storage is required, a buffer is
  33. // dynamically allocated from a heap.
  34. //
  35. //
  36. // Like the STL string class, we use a helper class called a "character
  37. // traits" class to provide the actual code to manipulate character string
  38. // buffers with a specific encoding.
  39. //
  40. // All the members are inline static and with normal optimization turned
  41. // on, the C++ compiler generates code that fully meets expectations.
  42. //
  43. //
  44. // We provide two implementations: one for Unicode strings, and another
  45. // template class for MBCS strings. The code page of the string is a
  46. // template parameter for the MBCS string, so without any extra storage
  47. // wasted per-instance, code can separately handle MBCS strings which
  48. // are expected to be in the thread-default windows code page (CP_THREAD_ACP),
  49. // process-default windows code page (CP_ACP) or even a particular code
  50. // page (e.g. CP_UTF8).
  51. //
  52. //
  53. // This template class uses a number of non-type template parameters to
  54. // control things like growth algorithms etc. As a result there are
  55. // many comparisons of template parameters against well-known constant
  56. // values, for which the compiler generates warning C4127. We'll turn that
  57. // warning off.
  58. //
  59. #pragma warning(disable:4127)
  60. #pragma warning(disable:4284)
  61. #if !defined(FUSION_DEFAULT_STRINGBUFFER_CHARS)
  62. #define FUSION_DEFAULT_STRINGBUFFER_CHARS (MAX_PATH)
  63. #endif
  64. #if !defined(FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS)
  65. #define FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS (8)
  66. #endif
  67. #if !defined(FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS)
  68. #define FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS (64)
  69. #endif
  70. #if !defined(FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS)
  71. #define FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS (128)
  72. #endif
  73. enum EIfNoExtension
  74. {
  75. eAddIfNoExtension,
  76. eDoNothingIfNoExtension,
  77. eErrorIfNoExtension
  78. };
  79. enum ECaseConversionDirection
  80. {
  81. eConvertToUpperCase,
  82. eConvertToLowerCase
  83. };
  84. enum EPreserveContents
  85. {
  86. ePreserveBufferContents,
  87. eDoNotPreserveBufferContents
  88. };
  89. template <typename TCharTraits> class CGenericStringBufferAccessor;
  90. template <typename TCharTraits> class CGenericBaseStringBuffer
  91. {
  92. friend TCharTraits;
  93. friend CGenericStringBufferAccessor<TCharTraits>;
  94. //
  95. // These two are to induce build breaks on people doing sb1 = sb2
  96. //
  97. CGenericBaseStringBuffer& operator=(PCWSTR OtherString);
  98. CGenericBaseStringBuffer& operator=(CGenericBaseStringBuffer &rOtherString);
  99. public:
  100. typedef typename TCharTraits::TChar TChar;
  101. typedef typename TCharTraits::TMutableString TMutableString;
  102. typedef typename TCharTraits::TConstantString TConstantString;
  103. typedef CGenericStringBufferAccessor<TCharTraits> TAccessor;
  104. inline static TChar NullCharacter() { return TCharTraits::NullCharacter(); }
  105. inline static bool IsNullCharacter(TChar ch) { return TCharTraits::IsNullCharacter(ch); }
  106. inline static TChar PreferredPathSeparator() { return TCharTraits::PreferredPathSeparator(); }
  107. inline static TConstantString PreferredPathSeparatorString() { return TCharTraits::PreferredPathSeparatorString(); }
  108. inline static TConstantString PathSeparators() { return TCharTraits::PathSeparators(); }
  109. inline static bool IsPathSeparator(TChar ch) { return TCharTraits::IsPathSeparator(ch); }
  110. inline static TConstantString DotString() { return TCharTraits::DotString(); }
  111. inline static SIZE_T DotStringCch() { return TCharTraits::DotStringCch(); }
  112. inline static TChar DotChar() { return TCharTraits::DotChar(); }
  113. protected:
  114. // You may not instantiate an instance of this class directly; you need to provide a derived
  115. // class which adds allocation/deallocation particulars.
  116. CGenericBaseStringBuffer() : m_prgchBuffer(NULL), m_cchBuffer(0), m_cAttachedAccessors(0), m_cch(0)
  117. {
  118. }
  119. //
  120. // Note that somewhat counter-intuitively, there is neither an assignment operator,
  121. // copy constructor or constructor taking a TConstantString. This is necessary
  122. // because such a constructor would need to perform a dynamic allocation
  123. // if the path passed in were longer than nInlineChars which could fail and
  124. // since we do not throw exceptions, constructors may not fail. Instead the caller
  125. // must just perform the default construction and then use the Assign() member
  126. // function, remembering of course to check its return status.
  127. //
  128. ~CGenericBaseStringBuffer()
  129. {
  130. ASSERT_NTC(m_cAttachedAccessors == 0);
  131. }
  132. inline void IntegrityCheck() const
  133. {
  134. #if DBG
  135. ASSERT_NTC(m_cch < m_cchBuffer);
  136. #endif // DBG
  137. }
  138. // Derived constructors should call this to get the initial buffer pointers set up.
  139. inline void InitializeInlineBuffer()
  140. {
  141. ASSERT_NTC(m_prgchBuffer == NULL);
  142. ASSERT_NTC(m_cchBuffer == 0);
  143. m_prgchBuffer = this->GetInlineBuffer();
  144. m_cchBuffer = this->GetInlineBufferCch();
  145. }
  146. VOID AttachAccessor(TAccessor *)
  147. {
  148. ::InterlockedIncrement(&m_cAttachedAccessors);
  149. }
  150. VOID DetachAccessor(TAccessor *)
  151. {
  152. ::InterlockedDecrement(&m_cAttachedAccessors);
  153. }
  154. virtual BOOL Win32AllocateBuffer(SIZE_T cch, TMutableString &rpsz) const = 0;
  155. virtual VOID DeallocateBuffer(TMutableString sz) const = 0;
  156. virtual TMutableString GetInlineBuffer() const = 0;
  157. virtual SIZE_T GetInlineBufferCch() const = 0;
  158. public:
  159. BOOL Win32Assign(PCWSTR psz, SIZE_T cchIn)
  160. {
  161. FN_PROLOG_WIN32
  162. ASSERT(static_cast<SSIZE_T>(cchIn) >= 0);
  163. this->IntegrityCheck();
  164. SIZE_T cchIncludingTrailingNull;
  165. // it would seem innocuous to allow assigns that don't resize the buffer to not
  166. // invalidate accessors, but that makes finding such bugs subject to even more
  167. // strenuous coverage problems than this simple error. The simple rule is that
  168. // you should not have an accessor attached to a string buffer when you use
  169. // any of member functions that may mutate the value.
  170. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  171. IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(psz, cchIn, cchIncludingTrailingNull));
  172. // Only force the buffer to be dynamically grown if the new contents do not
  173. // fit in the old buffer.
  174. if (cchIncludingTrailingNull > m_cchBuffer)
  175. IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(cchIncludingTrailingNull));
  176. IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(m_prgchBuffer, m_cchBuffer, psz, cchIn));
  177. ASSERT(cchIncludingTrailingNull <= m_cchBuffer);
  178. ASSERT((cchIncludingTrailingNull == 0) || this->IsNullCharacter(m_prgchBuffer[cchIncludingTrailingNull - 1]));
  179. // cch was the buffer size we needed (including the trailing null); we don't need the trailing
  180. // null any more...
  181. m_cch = cchIncludingTrailingNull - 1;
  182. FN_EPILOG
  183. }
  184. BOOL Win32Assign(PCSTR psz, SIZE_T cchIn)
  185. {
  186. FN_PROLOG_WIN32
  187. ASSERT(static_cast<SSIZE_T>(cchIn) >= 0);
  188. this->IntegrityCheck();
  189. SIZE_T cchIncludingTrailingNull;
  190. // it would seem innocuous to allow assigns that don't resize the buffer to not
  191. // invalidate accessors, but that makes finding such bugs subject to even more
  192. // strenuous coverage problems than this simple error. The simple rule is that
  193. // you should not have an accessor attached to a string buffer when you use
  194. // any of member functions that may mutate the value.
  195. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  196. IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(psz, cchIn, cchIncludingTrailingNull));
  197. // Only force the buffer to be dynamically grown if the new contents do not
  198. // fit in the old buffer.
  199. if (cchIncludingTrailingNull > m_cchBuffer)
  200. IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(cchIncludingTrailingNull));
  201. IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(m_prgchBuffer, m_cchBuffer, psz, cchIn));
  202. ASSERT(cchIncludingTrailingNull <= m_cchBuffer);
  203. ASSERT((cchIncludingTrailingNull == 0) || this->IsNullCharacter(m_prgchBuffer[cchIncludingTrailingNull - 1]));
  204. // cch was the buffer size we needed (including the trailing null); we don't need the trailing
  205. // null any more...
  206. m_cch = cchIncludingTrailingNull - 1;
  207. FN_EPILOG
  208. }
  209. BOOL Win32Assign(const UNICODE_STRING* NtString)
  210. {
  211. return Win32Assign(NtString->Buffer, RTL_STRING_GET_LENGTH_CHARS(NtString));
  212. }
  213. BOOL Win32Assign(const ANSI_STRING* NtString)
  214. {
  215. return Win32Assign(NtString->Buffer, RTL_STRING_GET_LENGTH_CHARS(NtString));
  216. }
  217. BOOL Win32Append(const UNICODE_STRING* NtString)
  218. { return this->Win32Append(NtString->Buffer, RTL_STRING_GET_LENGTH_CHARS(NtString)); }
  219. BOOL Win32AppendPathElement(const UNICODE_STRING* NtString)
  220. { return this->Win32AppendPathElement(NtString->Buffer, RTL_STRING_GET_LENGTH_CHARS(NtString)); }
  221. BOOL Win32Assign(const CGenericBaseStringBuffer &r) { return this->Win32Assign(r, r.Cch()); }
  222. BOOL Win32AssignWVa(SIZE_T cStrings, va_list ap)
  223. {
  224. this->IntegrityCheck();
  225. BOOL fSuccess = FALSE;
  226. FN_TRACE_WIN32(fSuccess);
  227. TMutableString pszCursor;
  228. SIZE_T cchIncludingTrailingNull = 1; // leave space for trailing null...
  229. SIZE_T cchTemp = 0;
  230. SIZE_T i = 0;
  231. va_list ap2 = ap;
  232. // it would seem innocuous to allow assigns that don't resize the buffer to not
  233. // invalidate accessors, but that makes finding such bugs subject to even more
  234. // strenuous coverage problems than this simple error. The simple rule is that
  235. // you should not have an accessor attached to a string buffer when you use
  236. // any of member functions that may mutate the value.
  237. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  238. for (i=0; i<cStrings; i++)
  239. {
  240. PCWSTR psz = va_arg(ap, PCWSTR);
  241. INT cchArg = va_arg(ap, INT);
  242. SIZE_T cchThis = (cchArg < 0) ? ((psz != NULL) ? ::wcslen(psz) : 0) : static_cast<SIZE_T>(cchArg);
  243. SIZE_T cchRequired;
  244. IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(psz, cchThis, cchRequired));
  245. ASSERT((cchRequired != 0) || (cchThis == 0));
  246. cchIncludingTrailingNull += (cchRequired - 1);
  247. }
  248. IFW32FALSE_EXIT(this->Win32ResizeBuffer(cchIncludingTrailingNull, eDoNotPreserveBufferContents));
  249. pszCursor = m_prgchBuffer;
  250. cchTemp = cchIncludingTrailingNull;
  251. for (i=0; i<cStrings; i++)
  252. {
  253. PCWSTR psz = va_arg(ap2, PCWSTR);
  254. INT cchArg = va_arg(ap2, INT);
  255. SIZE_T cchThis = (cchArg < 0) ? ((psz != NULL) ? ::wcslen(psz) : 0) : static_cast<SIZE_T>(cchArg);
  256. IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBufferAndAdvanceCursor(pszCursor, cchTemp, psz, cchThis));
  257. }
  258. *pszCursor++ = this->NullCharacter();
  259. ASSERT(cchTemp == 1);
  260. ASSERT(static_cast<SIZE_T>(pszCursor - m_prgchBuffer) == cchIncludingTrailingNull);
  261. m_cch = (cchIncludingTrailingNull - 1);
  262. FN_EPILOG
  263. }
  264. BOOL Win32AssignW(ULONG cStrings, ...)
  265. {
  266. this->IntegrityCheck();
  267. BOOL fSuccess = FALSE;
  268. FN_TRACE_WIN32(fSuccess);
  269. va_list ap;
  270. va_start(ap, cStrings);
  271. IFW32FALSE_EXIT(this->Win32AssignWVa(cStrings, ap));
  272. fSuccess = TRUE;
  273. Exit:
  274. va_end(ap);
  275. return fSuccess;
  276. }
  277. BOOL Win32AssignFill(TChar ch, SIZE_T cch)
  278. {
  279. FN_PROLOG_WIN32
  280. TMutableString Cursor;
  281. ASSERT(static_cast<SSIZE_T>(cch) >= 0);
  282. IFW32FALSE_EXIT(this->Win32ResizeBuffer(cch + 1, eDoNotPreserveBufferContents));
  283. Cursor = m_prgchBuffer;
  284. while (cch > 0)
  285. {
  286. *Cursor++ = ch;
  287. cch--;
  288. }
  289. *Cursor = NullCharacter();
  290. m_cch = (Cursor - m_prgchBuffer);
  291. FN_EPILOG
  292. }
  293. BOOL Win32Append(PCWSTR sz, SIZE_T cchIn)
  294. {
  295. this->IntegrityCheck();
  296. BOOL fSuccess = FALSE;
  297. ASSERT_NTC(static_cast<SSIZE_T>(cchIn) >= 0);
  298. SIZE_T cchIncludingTrailingNull; // note that cch will include space for a tailing null character
  299. // it would seem innocuous to allow assigns that don't resize the buffer to not
  300. // invalidate accessors, but that makes finding such bugs subject to even more
  301. // strenuous coverage problems than this simple error. The simple rule is that
  302. // you should not have an accessor attached to a string buffer when you use
  303. // any of member functions that may mutate the value.
  304. ASSERT_NTC(m_cAttachedAccessors == 0);
  305. if (!TCharTraits::Win32DetermineRequiredCharacters(sz, cchIn, cchIncludingTrailingNull))
  306. goto Exit;
  307. // Bypass all this junk if the string to append is empty.
  308. if (cchIncludingTrailingNull > 1)
  309. {
  310. if (!this->Win32ResizeBufferPreserveContentsInternal(m_cch + cchIncludingTrailingNull))
  311. goto Exit;
  312. if (!TCharTraits::Win32CopyIntoBuffer(&m_prgchBuffer[m_cch], m_cchBuffer - m_cch, sz, cchIn))
  313. goto Exit;
  314. m_cch += (cchIncludingTrailingNull - 1);
  315. }
  316. fSuccess = TRUE;
  317. Exit:
  318. return fSuccess;
  319. }
  320. BOOL Win32Append(PCSTR sz, SIZE_T cchIn)
  321. {
  322. this->IntegrityCheck();
  323. BOOL fSuccess = FALSE;
  324. FN_TRACE_WIN32(fSuccess);
  325. ASSERT(static_cast<SSIZE_T>(cchIn) >= 0);
  326. SIZE_T cchIncludingTrailingNull;
  327. // it would seem innocuous to allow assigns that don't resize the buffer to not
  328. // invalidate accessors, but that makes finding such bugs subject to even more
  329. // strenuous coverage problems than this simple error. The simple rule is that
  330. // you should not have an accessor attached to a string buffer when you use
  331. // any of member functions that may mutate the value.
  332. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  333. IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(sz, cchIn, cchIncludingTrailingNull));
  334. // Bypass all this junk if the string to append is empty.
  335. if (cchIncludingTrailingNull > 1)
  336. {
  337. IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + cchIncludingTrailingNull));
  338. IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(&m_prgchBuffer[m_cch], m_cchBuffer - m_cch, sz, cchIn));
  339. m_cch += (cchIncludingTrailingNull - 1);
  340. this->IntegrityCheck();
  341. }
  342. FN_EPILOG
  343. }
  344. BOOL Win32Append(const CGenericBaseStringBuffer &r) { return this->Win32Append(r, r.Cch()); }
  345. BOOL Win32Append(WCHAR wch) { WCHAR rgwch[1] = { wch }; return this->Win32Append(rgwch, 1); }
  346. BOOL Win32AppendFill(TChar ch, SIZE_T cch)
  347. {
  348. FN_PROLOG_WIN32
  349. ASSERT(static_cast<SSIZE_T>(cch) >= 0);
  350. TMutableString Cursor;
  351. IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + cch + 1));
  352. Cursor = m_prgchBuffer + m_cch;
  353. while (cch > 0)
  354. {
  355. *Cursor++ = ch;
  356. cch--;
  357. }
  358. *Cursor = NullCharacter();
  359. m_cch = Cursor - m_prgchBuffer;
  360. FN_EPILOG
  361. }
  362. BOOL Win32Prepend(const CGenericBaseStringBuffer& other ) { return this->Win32Prepend(other, other.Cch()); }
  363. BOOL Win32Prepend(TConstantString sz, SIZE_T cchIn)
  364. {
  365. this->IntegrityCheck();
  366. BOOL fSuccess = FALSE;
  367. FN_TRACE_WIN32(fSuccess);
  368. ASSERT(static_cast<SSIZE_T>(cchIn) >= 0);
  369. SIZE_T cchIncludingTrailingNull; // note that cch will include space for a tailing null character
  370. // it would seem innocuous to allow assigns that don't resize the buffer to not
  371. // invalidate accessors, but that makes finding such bugs subject to even more
  372. // strenuous coverage problems than this simple error. The simple rule is that
  373. // you should not have an accessor attached to a string buffer when you use
  374. // any of member functions that may mutate the value.
  375. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  376. if ( m_cch == 0 )
  377. {
  378. IFW32FALSE_EXIT(this->Win32Assign(sz, cchIn));
  379. }
  380. else
  381. {
  382. //
  383. // Enlarge the buffer, move the current data to past where the new data will need
  384. // to go, copy in the new data, and place the trailing null.
  385. //
  386. TChar SavedChar = m_prgchBuffer[0];
  387. IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(sz, cchIn, cchIncludingTrailingNull));
  388. IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + cchIncludingTrailingNull));
  389. // Move current buffer "up"
  390. MoveMemory(m_prgchBuffer + ( cchIncludingTrailingNull - 1), m_prgchBuffer, (m_cch + 1) * sizeof(TChar));
  391. // Copy from the source string into the buffer.
  392. IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(
  393. this->m_prgchBuffer,
  394. this->m_cchBuffer,
  395. sz,
  396. cchIn));
  397. m_prgchBuffer[cchIncludingTrailingNull - 1] = SavedChar;
  398. m_cch += cchIncludingTrailingNull - 1;
  399. }
  400. FN_EPILOG
  401. }
  402. BOOL Win32Prepend(TChar ch)
  403. {
  404. FN_PROLOG_WIN32
  405. IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + 1 + 1));
  406. // move buffer ahead, including null
  407. MoveMemory(m_prgchBuffer + 1, m_prgchBuffer, (m_cch + 1) * sizeof(TChar));
  408. m_prgchBuffer[0] = ch;
  409. m_cch++;
  410. FN_EPILOG
  411. }
  412. operator TConstantString() const { this->IntegrityCheck(); return m_prgchBuffer; }
  413. inline VOID Clear(bool fFreeStorage = false)
  414. {
  415. FN_TRACE();
  416. this->IntegrityCheck();
  417. // You can't free the storage if there's an attached accessor
  418. ASSERT(!fFreeStorage || m_cAttachedAccessors == 0);
  419. if (fFreeStorage && (m_cAttachedAccessors == 0))
  420. {
  421. if (m_prgchBuffer != NULL)
  422. {
  423. const TMutableString pszInlineBuffer = this->GetInlineBuffer();
  424. if (m_prgchBuffer != pszInlineBuffer)
  425. {
  426. this->DeallocateBuffer(m_prgchBuffer);
  427. m_prgchBuffer = pszInlineBuffer;
  428. m_cchBuffer = this->GetInlineBufferCch();
  429. }
  430. }
  431. }
  432. if (m_prgchBuffer != NULL)
  433. m_prgchBuffer[0] = this->NullCharacter();
  434. m_cch = 0;
  435. }
  436. BOOL Win32ConvertCase( ECaseConversionDirection direction )
  437. {
  438. #if !FUSION_WIN
  439. return FALSE;
  440. #else
  441. FN_PROLOG_WIN32
  442. this->IntegrityCheck();
  443. // it would seem innocuous to allow assigns that don't resize the buffer to not
  444. // invalidate accessors, but that makes finding such bugs subject to even more
  445. // strenuous coverage problems than this simple error. The simple rule is that
  446. // you should not have an accessor attached to a string buffer when you use
  447. // any of member functions that may mutate the value.
  448. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  449. TMutableString Cursor = m_prgchBuffer;
  450. for ( ULONG ul = 0; ul < this->Cch(); ul++ )
  451. {
  452. if ( direction == eConvertToUpperCase )
  453. *Cursor = RtlUpcaseUnicodeChar(*Cursor);
  454. else
  455. *Cursor = RtlDowncaseUnicodeChar(*Cursor);
  456. Cursor++;
  457. }
  458. FN_EPILOG
  459. #endif
  460. }
  461. BOOL Win32Compare(TConstantString szCandidate, SIZE_T cchCandidate, StringComparisonResult &rscrOut, bool fCaseInsensitive) const
  462. {
  463. this->IntegrityCheck();
  464. BOOL fSuccess = FALSE;
  465. FN_TRACE_WIN32(fSuccess);
  466. IFW32FALSE_EXIT(TCharTraits::Win32CompareStrings(rscrOut, m_prgchBuffer, m_cch, szCandidate, cchCandidate, fCaseInsensitive));
  467. FN_EPILOG
  468. }
  469. BOOL Win32Equals(TConstantString szCandidate, SIZE_T cchCandidate, bool &rfMatches, bool fCaseInsensitive) const
  470. {
  471. this->IntegrityCheck();
  472. BOOL fSuccess = FALSE;
  473. FN_TRACE_WIN32(fSuccess);
  474. IFW32FALSE_EXIT(
  475. TCharTraits::Win32EqualStrings(
  476. rfMatches,
  477. m_prgchBuffer,
  478. m_cch,
  479. szCandidate,
  480. cchCandidate,
  481. fCaseInsensitive));
  482. FN_EPILOG
  483. }
  484. BOOL Win32Equals(const CGenericBaseStringBuffer &r, bool &rfMatches, bool fCaseInsensitive) const
  485. {
  486. return this->Win32Equals(r, r.Cch(), rfMatches, fCaseInsensitive);
  487. }
  488. SIZE_T GetBufferCch() const { this->IntegrityCheck(); return m_cchBuffer; }
  489. INT GetBufferCchAsINT() const { this->IntegrityCheck(); if (m_cchBuffer > INT_MAX) return INT_MAX; return static_cast<INT>(m_cchBuffer); }
  490. DWORD GetBufferCchAsDWORD() const { this->IntegrityCheck(); if (m_cchBuffer > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cchBuffer); }
  491. DWORD GetCchAsDWORD() const { this->IntegrityCheck(); if (m_cch > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cch); }
  492. INT GetCchAsINT() const { this->IntegrityCheck(); if (m_cch > INT_MAX) return INT_MAX; return static_cast<INT>(m_cch); }
  493. UINT GetCchAsUINT() const { this->IntegrityCheck(); if (m_cch > UINT_MAX) return UINT_MAX; return static_cast<UINT>(m_cch); }
  494. SIZE_T GetBufferCb() const { this->IntegrityCheck(); return m_cchBuffer * sizeof(TChar); }
  495. INT GetBufferCbAsINT() const { this->IntegrityCheck(); if ((m_cchBuffer * sizeof(TChar)) > INT_MAX) return INT_MAX; return static_cast<INT>(m_cchBuffer * sizeof(TChar)); }
  496. DWORD GetBufferCbAsDWORD() const { this->IntegrityCheck(); if ((m_cchBuffer * sizeof(TChar)) > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cchBuffer * sizeof(TChar)); }
  497. DWORD GetCbAsDWORD() const { this->IntegrityCheck(); if ((m_cch * sizeof(TChar)) > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cch * sizeof(TChar)); }
  498. INT GetCbAsINT() const { this->IntegrityCheck(); if ((m_cch * sizeof(TChar)) > INT_MAX) return INT_MAX; return static_cast<INT>(m_cch * sizeof(TChar)); }
  499. UINT GetCbAsUINT() const { this->IntegrityCheck(); if ((m_cch * sizeof(TChar)) > UINT_MAX) return UINT_MAX; return static_cast<UINT>(m_cch * sizeof(TChar)); }
  500. bool ContainsCharacter(WCHAR wch) const
  501. {
  502. this->IntegrityCheck();
  503. return TCharTraits::ContainsCharacter(m_prgchBuffer, m_cch, wch);
  504. }
  505. BOOL
  506. Win32ResizeBuffer(
  507. SIZE_T cch,
  508. EPreserveContents epc
  509. )
  510. {
  511. FN_PROLOG_WIN32
  512. this->IntegrityCheck();
  513. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  514. PARAMETER_CHECK((epc == ePreserveBufferContents) || (epc == eDoNotPreserveBufferContents));
  515. if (cch > m_cchBuffer)
  516. {
  517. TMutableString prgchBufferNew = NULL;
  518. IFW32FALSE_EXIT(this->Win32AllocateBuffer(cch, prgchBufferNew));
  519. if (epc == ePreserveBufferContents)
  520. {
  521. // We assume that the buffer is/was null-terminated.
  522. IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(prgchBufferNew, cch, m_prgchBuffer, m_cch));
  523. }
  524. else
  525. {
  526. m_prgchBuffer[0] = this->NullCharacter();
  527. m_cch = 0;
  528. }
  529. if ((m_prgchBuffer != NULL) && (m_prgchBuffer != this->GetInlineBuffer()))
  530. this->DeallocateBuffer(m_prgchBuffer);
  531. m_prgchBuffer = prgchBufferNew;
  532. m_cchBuffer = cch;
  533. }
  534. FN_EPILOG
  535. }
  536. BOOL Win32Format(TConstantString pszFormat, ...)
  537. {
  538. this->IntegrityCheck();
  539. va_list args;
  540. va_start(args, pszFormat);
  541. BOOL f = this->Win32FormatV(pszFormat, args);
  542. va_end(args);
  543. return f;
  544. }
  545. BOOL Win32FormatAppend(TConstantString pszFormat, ...)
  546. {
  547. this->IntegrityCheck();
  548. va_list args;
  549. va_start(args, pszFormat);
  550. BOOL f = Win32FormatAppendV(pszFormat, args);
  551. va_end(args);
  552. return f;
  553. }
  554. BOOL Win32FormatV(TConstantString pszFormat, va_list args)
  555. {
  556. BOOL fSuccess = FALSE;
  557. this->Clear();
  558. fSuccess = Win32FormatAppendV(pszFormat, args);
  559. return fSuccess;
  560. }
  561. BOOL Win32FormatAppendV(TConstantString pszFormat, va_list args)
  562. {
  563. BOOL fSuccess = FALSE;
  564. FN_TRACE_WIN32(fSuccess);
  565. SIZE_T cchRequiredBufferSize = 0;
  566. INT i = 0;
  567. this->IntegrityCheck();
  568. // it would seem innocuous to allow assigns that don't resize the buffer to not
  569. // invalidate accessors, but that makes finding such bugs subject to even more
  570. // strenuous coverage problems than this simple error. The simple rule is that
  571. // you should not have an accessor attached to a string buffer when you use
  572. // any of member functions that may mutate the value.
  573. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  574. m_prgchBuffer[m_cchBuffer - 1] = this->NullCharacter();
  575. i = TCharTraits::FormatV(m_prgchBuffer + m_cch, m_cchBuffer - 1 - m_cch, pszFormat, args);
  576. ASSERT(m_prgchBuffer[m_cchBuffer - 1] == NullCharacter());
  577. fSuccess = (i >= 0);
  578. if ( fSuccess )
  579. m_cch += i;
  580. else
  581. {
  582. //
  583. // Sprintf doesn't touch last error. The fn tracer
  584. // will fail an assertion if we return false but FusionpGetLastWin32Error()==NOERROR
  585. //
  586. ORIGINATE_WIN32_FAILURE_AND_EXIT(snwprintf_MaybeBufferTooSmall, ERROR_INVALID_PARAMETER);
  587. }
  588. Exit:
  589. return fSuccess;
  590. }
  591. SIZE_T Cch() const
  592. {
  593. this->IntegrityCheck();
  594. return this->m_cch;
  595. }
  596. BOOL IsEmpty() const
  597. {
  598. this->IntegrityCheck();
  599. const BOOL fResult = (this->m_prgchBuffer[0] == this->NullCharacter());
  600. #if DBG
  601. //
  602. // We should probably reverse how we compute the result in
  603. // retail vs. what we assert. That would be one pointer
  604. // deref instead of two in retail; not worth churn right now.
  605. // - JayKrell, June 2002.
  606. //
  607. if (fResult)
  608. {
  609. ASSERT_NTC(this->m_cch == 0);
  610. }
  611. #endif
  612. return fResult;
  613. }
  614. WCHAR GetLastCharUnsafe() const
  615. {
  616. ASSERT_NTC(!this->IsEmpty());
  617. return this->m_prgchBuffer[this->m_cch - 1];
  618. }
  619. BOOL Win32EnsureTrailingChar(WCHAR ch)
  620. {
  621. this->IntegrityCheck();
  622. BOOL fSuccess = FALSE;
  623. // it would seem innocuous to allow assigns that don't resize the buffer to not
  624. // invalidate accessors, but that makes finding such bugs subject to even more
  625. // strenuous coverage problems than this simple error. The simple rule is that
  626. // you should not have an accessor attached to a string buffer when you use
  627. // any of member functions that may mutate the value.
  628. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  629. if ((m_cch == 0) || (m_prgchBuffer[m_cch - 1] != ch))
  630. {
  631. IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + 1 + 1));
  632. m_prgchBuffer[m_cch++] = ch;
  633. m_prgchBuffer[m_cch] = this->NullCharacter();
  634. }
  635. fSuccess = TRUE;
  636. Exit:
  637. return fSuccess;
  638. }
  639. BOOL Win32EnsureTrailingPathSeparator()
  640. {
  641. this->IntegrityCheck();
  642. BOOL fSuccess = FALSE;
  643. FN_TRACE_WIN32(fSuccess);
  644. // it would seem innocuous to allow assigns that don't resize the buffer to not
  645. // invalidate accessors, but that makes finding such bugs subject to even more
  646. // strenuous coverage problems than this simple error. The simple rule is that
  647. // you should not have an accessor attached to a string buffer when you use
  648. // any of member functions that may mutate the value.
  649. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  650. if ((m_cch == 0) || !TCharTraits::IsPathSeparator(m_prgchBuffer[m_cch - 1]))
  651. {
  652. IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + 1 + 1));
  653. m_prgchBuffer[m_cch++] = this->PreferredPathSeparator();
  654. m_prgchBuffer[m_cch] = this->NullCharacter();
  655. }
  656. fSuccess = TRUE;
  657. Exit:
  658. return fSuccess;
  659. }
  660. BOOL Win32AppendPathElement(PCWSTR pathElement, SIZE_T cchPathElement)
  661. {
  662. this->IntegrityCheck();
  663. BOOL fSuccess = FALSE;
  664. FN_TRACE_WIN32(fSuccess);
  665. // it would seem innocuous to allow assigns that don't resize the buffer to not
  666. // invalidate accessors, but that makes finding such bugs subject to even more
  667. // strenuous coverage problems than this simple error. The simple rule is that
  668. // you should not have an accessor attached to a string buffer when you use
  669. // any of member functions that may mutate the value.
  670. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  671. IFW32FALSE_EXIT(this->Win32EnsureTrailingPathSeparator());
  672. IFW32FALSE_EXIT(this->Win32Append(pathElement, cchPathElement));
  673. fSuccess = TRUE;
  674. Exit:
  675. return fSuccess;
  676. }
  677. BOOL Win32AppendPathElement(const CGenericBaseStringBuffer &r) { return this->Win32AppendPathElement(r, r.Cch()); }
  678. BOOL Win32AppendPathElement(PCSTR pathElement, SIZE_T cchPathElement)
  679. {
  680. this->IntegrityCheck();
  681. BOOL fSuccess = FALSE;
  682. FN_TRACE_WIN32(fSuccess);
  683. // it would seem innocuous to allow assigns that don't resize the buffer to not
  684. // invalidate accessors, but that makes finding such bugs subject to even more
  685. // strenuous coverage problems than this simple error. The simple rule is that
  686. // you should not have an accessor attached to a string buffer when you use
  687. // any of member functions that may mutate the value.
  688. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  689. IFW32FALSE_EXIT(this->Win32EnsureTrailingPathSeparator());
  690. IFW32FALSE_EXIT(this->Win32Append(pathElement, cchPathElement));
  691. fSuccess = TRUE;
  692. Exit:
  693. return fSuccess;
  694. }
  695. BOOL Left(SIZE_T newLength)
  696. {
  697. this->IntegrityCheck();
  698. ASSERT_NTC(newLength <= m_cch);
  699. // it would seem innocuous to allow assigns that don't resize the buffer to not
  700. // invalidate accessors, but that makes finding such bugs subject to even more
  701. // strenuous coverage problems than this simple error. The simple rule is that
  702. // you should not have an accessor attached to a string buffer when you use
  703. // any of member functions that may mutate the value.
  704. // Note also that while the current implementation does not change the buffer
  705. // pointer, this is just a shortcut in the implementation; if a call to Left()
  706. // were to make the string short enough to fit in the inline buffer, we should
  707. // copy it to the inline buffer and deallocate the dynamic one.
  708. ASSERT_NTC(m_cAttachedAccessors == 0);
  709. if (m_cchBuffer > newLength)
  710. {
  711. m_prgchBuffer[newLength] = this->NullCharacter();
  712. }
  713. m_cch = newLength;
  714. this->IntegrityCheck();
  715. return TRUE;
  716. }
  717. TConstantString Begin() const
  718. {
  719. this->IntegrityCheck();
  720. return m_prgchBuffer;
  721. }
  722. TConstantString End() const
  723. {
  724. this->IntegrityCheck();
  725. return &m_prgchBuffer[m_cch];
  726. }
  727. // should factor this for reuse in CchWithoutLastPathElement
  728. SIZE_T CchWithoutTrailingPathSeparators() const
  729. {
  730. this->IntegrityCheck();
  731. // Until GetLength is constant time, optimize its use..
  732. SIZE_T length = m_cch;
  733. if (length > 0)
  734. {
  735. length -= ::StringReverseSpan(&*m_prgchBuffer, &*m_prgchBuffer + length, TCharTraits::PathSeparators());
  736. }
  737. return length;
  738. }
  739. BOOL RestoreNextPathElement()
  740. {
  741. SIZE_T index;
  742. this->IntegrityCheck();
  743. index = m_cch;
  744. m_prgchBuffer[index++] = L'\\'; // replace trailing NULL with '\'
  745. while ((index < m_cchBuffer) && (!this->IsNullCharacter(m_prgchBuffer[index])))
  746. {
  747. if (::FusionpIsPathSeparator(m_prgchBuffer[index]))
  748. {
  749. this->Left(index);
  750. return TRUE;
  751. }
  752. index++;
  753. }
  754. return FALSE;
  755. }
  756. bool HasTrailingPathSeparator() const
  757. {
  758. FN_TRACE();
  759. this->IntegrityCheck();
  760. if ((m_cch != 0) && TCharTraits::IsPathSeparator(m_prgchBuffer[m_cch - 1]))
  761. return true;
  762. return false;
  763. }
  764. BOOL Win32RemoveTrailingPathSeparators()
  765. {
  766. this->IntegrityCheck();
  767. // it would seem innocuous to allow assigns that don't resize the buffer to not
  768. // invalidate accessors, but that makes finding such bugs subject to even more
  769. // strenuous coverage problems than this simple error. The simple rule is that
  770. // you should not have an accessor attached to a string buffer when you use
  771. // any of member functions that may mutate the value.
  772. // Note also that while the current implementation does not change the buffer
  773. // pointer, this is just a shortcut in the implementation; if a call to Left()
  774. // were to make the string short enough to fit in the inline buffer, we should
  775. // copy it to the inline buffer and deallocate the dynamic one.
  776. ASSERT_NTC(m_cAttachedAccessors == 0);
  777. while ((m_cch != 0) && TCharTraits::IsPathSeparator(m_prgchBuffer[m_cch - 1]))
  778. m_cch--;
  779. m_prgchBuffer[m_cch] = this->NullCharacter();
  780. this->IntegrityCheck();
  781. return TRUE;
  782. }
  783. BOOL Right( SIZE_T cchRightCount )
  784. {
  785. this->IntegrityCheck();
  786. ASSERT_NTC(m_cAttachedAccessors == 0);
  787. ASSERT_NTC(cchRightCount <= m_cch);
  788. if (cchRightCount < m_cch)
  789. {
  790. ::MoveMemory(
  791. m_prgchBuffer,
  792. &m_prgchBuffer[m_cch - cchRightCount],
  793. (cchRightCount + 1)*sizeof(TCharTraits::TChar));
  794. m_cch = cchRightCount;
  795. }
  796. this->IntegrityCheck();
  797. return TRUE;
  798. }
  799. BOOL RemoveLeadingPathSeparators()
  800. {
  801. this->IntegrityCheck();
  802. BOOL fSuccess = this->Right(m_cch - wcsspn(m_prgchBuffer, TCharTraits::PathSeparators()));
  803. this->IntegrityCheck();
  804. return fSuccess;
  805. }
  806. BOOL Win32StripToLastPathElement()
  807. {
  808. BOOL fSuccess = FALSE;
  809. FN_TRACE_WIN32(fSuccess);
  810. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  811. this->IntegrityCheck();
  812. IFW32FALSE_EXIT(this->Right(m_cch - this->CchWithoutLastPathElement()));
  813. IFW32FALSE_EXIT(this->RemoveLeadingPathSeparators());
  814. fSuccess = TRUE;
  815. Exit:
  816. this->IntegrityCheck();
  817. return fSuccess;
  818. }
  819. BOOL Win32GetFirstPathElement( CGenericBaseStringBuffer &sbDestination, BOOL bRemoveAsWell = FALSE )
  820. {
  821. FN_PROLOG_WIN32
  822. this->IntegrityCheck();
  823. IFW32FALSE_EXIT( sbDestination.Win32Assign( m_prgchBuffer, this->CchOfFirstPathElement() ) );
  824. sbDestination.RemoveLeadingPathSeparators();
  825. if ( bRemoveAsWell )
  826. IFW32FALSE_EXIT(this->Win32RemoveFirstPathElement());
  827. this->IntegrityCheck();
  828. FN_EPILOG
  829. }
  830. BOOL Win32GetFirstPathElement( CGenericBaseStringBuffer &sbDestination ) const
  831. {
  832. BOOL bSuccess = FALSE;
  833. this->IntegrityCheck();
  834. if ( sbDestination.Win32Assign( m_prgchBuffer, CchOfFirstPathElement() ) )
  835. {
  836. sbDestination.RemoveLeadingPathSeparators();
  837. bSuccess = TRUE;
  838. }
  839. return bSuccess;
  840. }
  841. BOOL Win32StripToFirstPathElement()
  842. {
  843. BOOL fSuccess = FALSE;
  844. FN_TRACE_WIN32(fSuccess);
  845. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  846. this->IntegrityCheck();
  847. IFW32FALSE_EXIT(this->Left(this->CchOfFirstPathElement()));
  848. IFW32FALSE_EXIT(this->RemoveLeadingPathSeparators());
  849. fSuccess = TRUE;
  850. Exit:
  851. this->IntegrityCheck();
  852. return fSuccess;
  853. }
  854. BOOL Win32RemoveFirstPathElement()
  855. {
  856. BOOL fSuccess = FALSE;
  857. FN_TRACE_WIN32(fSuccess);
  858. this->IntegrityCheck();
  859. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  860. IFW32FALSE_EXIT(this->Right(this->CchWithoutFirstPathElement()));
  861. IFW32FALSE_EXIT(this->RemoveLeadingPathSeparators());
  862. fSuccess = TRUE;
  863. Exit:
  864. this->IntegrityCheck();
  865. return fSuccess;
  866. }
  867. SIZE_T CchOfFirstPathElement() const
  868. {
  869. return Cch() - CchWithoutFirstPathElement();
  870. }
  871. SIZE_T CchWithoutFirstPathElement() const
  872. {
  873. this->IntegrityCheck();
  874. SIZE_T cch = m_cch;
  875. //
  876. // We just look for the first path element, which can also be the drive
  877. // letter!
  878. //
  879. if ( cch != 0 )
  880. {
  881. cch -= wcscspn( m_prgchBuffer, PathSeparators() );
  882. }
  883. return cch;
  884. }
  885. BOOL Win32GetLastPathElement(CGenericBaseStringBuffer &sbDestination) const
  886. {
  887. BOOL bSuccess = FALSE;
  888. FN_TRACE_WIN32(bSuccess);
  889. this->IntegrityCheck();
  890. sbDestination.IntegrityCheck();
  891. IFW32FALSE_EXIT(sbDestination.Win32Assign(m_prgchBuffer, m_cch));
  892. IFW32FALSE_EXIT(sbDestination.Win32StripToLastPathElement());
  893. bSuccess = TRUE;
  894. Exit:
  895. this->IntegrityCheck();
  896. sbDestination.IntegrityCheck();
  897. return bSuccess;
  898. }
  899. SIZE_T CchWithoutLastPathElement() const
  900. {
  901. this->IntegrityCheck();
  902. // Paths are assumed to be
  903. // "\\machine\share"
  904. // or
  905. // "x:\"
  906. // Worry about alternate NTFS streams at a later date.
  907. // Worry about NT paths at a later date.
  908. // Worry about URLs at a later date.
  909. const SIZE_T length = m_cch;
  910. SIZE_T newLength = length;
  911. if (length > 0)
  912. {
  913. if ((length == 3) &&
  914. (m_prgchBuffer[1] == ':') &&
  915. ::FusionpIsPathSeparator(m_prgchBuffer[2]) &&
  916. ::FusionpIsDriveLetter(m_prgchBuffer[0]))
  917. {
  918. // c:\ => empty string
  919. newLength = 0;
  920. }
  921. else
  922. {
  923. // Remove trailing path seperators here, in the future when it is not risky.
  924. //newLength -= ::StringReverseSpan(&*m_prgchBuffer, &*m_prgchBuffer + newLength, PathSeparators());
  925. newLength -= ::StringReverseComplementSpan(&*m_prgchBuffer, &*m_prgchBuffer + newLength, PathSeparators());
  926. newLength -= ::StringReverseSpan(&*m_prgchBuffer, &*m_prgchBuffer + newLength, PathSeparators());
  927. if ((newLength == 2) && // "c:"
  928. (length >= 4) && // "c:\d"
  929. (m_prgchBuffer[1] == ':') &&
  930. ::FusionpIsPathSeparator(m_prgchBuffer[2]) &&
  931. ::FusionpIsDriveLetter(m_prgchBuffer[0]))
  932. {
  933. ++newLength; // put back the slash in "c:\"
  934. }
  935. }
  936. }
  937. return newLength;
  938. }
  939. BOOL Win32RemoveLastPathElement()
  940. {
  941. BOOL fSuccess = FALSE;
  942. FN_TRACE_WIN32( fSuccess );
  943. this->IntegrityCheck();
  944. // it would seem innocuous to allow assigns that don't resize the buffer to not
  945. // invalidate accessors, but that makes finding such bugs subject to even more
  946. // strenuous coverage problems than this simple error. The simple rule is that
  947. // you should not have an accessor attached to a string buffer when you use
  948. // any of member functions that may mutate the value.
  949. // Note also that while the current implementation does not change the buffer
  950. // pointer, this is just a shortcut in the implementation; if a call to Left()
  951. // were to make the string short enough to fit in the inline buffer, we should
  952. // copy it to the inline buffer and deallocate the dynamic one.
  953. ASSERT_NTC(m_cAttachedAccessors == 0);
  954. IFW32FALSE_EXIT(this->Left(this->CchWithoutLastPathElement()));
  955. fSuccess = TRUE;
  956. Exit:
  957. this->IntegrityCheck();
  958. return fSuccess;
  959. }
  960. BOOL Win32ClearPathExtension()
  961. {
  962. //
  963. // Replace the final '.' with a \0 to clear the path extension
  964. //
  965. BOOL fSuccess = FALSE;
  966. FN_TRACE_WIN32( fSuccess );
  967. this->IntegrityCheck();
  968. TMutableString dot = 0;
  969. const TMutableString end = End();
  970. IFW32FALSE_EXIT(TCharTraits::Win32ReverseFind(dot, m_prgchBuffer, m_cch, this->DotChar(), false));
  971. if((dot != end) && (dot != NULL))
  972. {
  973. *dot = this->NullCharacter();
  974. m_cch = (dot - m_prgchBuffer);
  975. }
  976. fSuccess = TRUE;
  977. Exit:
  978. this->IntegrityCheck();
  979. return fSuccess;
  980. }
  981. BOOL Win32GetPathExtension(CGenericBaseStringBuffer<TCharTraits> &destination) const
  982. {
  983. this->IntegrityCheck();
  984. BOOL fSuccess = FALSE;
  985. FN_TRACE_WIN32(fSuccess);
  986. SIZE_T cchExtension;
  987. const TConstantString start = Begin();
  988. const TConstantString end = End();
  989. cchExtension = ::StringReverseComplementSpan( &(*start), &(*end), L"." );
  990. IFW32FALSE_EXIT(destination.Win32Assign( static_cast<PCWSTR>(*this) + ( m_cch - cchExtension ), cchExtension));
  991. fSuccess = TRUE;
  992. Exit:
  993. return fSuccess;
  994. }
  995. // newExtension can start with a dot or not
  996. BOOL Win32ChangePathExtension(PCWSTR newExtension, SIZE_T cchExtension, EIfNoExtension e)
  997. {
  998. this->IntegrityCheck();
  999. BOOL fSuccess = FALSE;
  1000. FN_TRACE_WIN32(fSuccess);
  1001. TMutableString end = 0;
  1002. TMutableString dot = 0;
  1003. INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
  1004. PARAMETER_CHECK((e == eAddIfNoExtension) ||
  1005. (e == eDoNothingIfNoExtension) ||
  1006. (e == eErrorIfNoExtension));
  1007. if ((cchExtension != 0) && (newExtension[0] == L'.'))
  1008. {
  1009. cchExtension--;
  1010. newExtension++;
  1011. }
  1012. // the use of append when we know where the end of the string is inefficient
  1013. end = this->End();
  1014. IFW32FALSE_EXIT(TCharTraits::Win32ReverseFind(dot, m_prgchBuffer, m_cch, this->DotChar(), false));
  1015. // Found the end of the string, or Win32ReverseFind didn't find the dot anywhere...
  1016. if ((dot == end) || (dot == NULL))
  1017. {
  1018. switch (e)
  1019. {
  1020. case eAddIfNoExtension:
  1021. IFW32FALSE_EXIT(this->Win32Append(this->DotString(), 1));
  1022. IFW32FALSE_EXIT(this->Win32Append(newExtension, cchExtension));
  1023. break;
  1024. case eDoNothingIfNoExtension:
  1025. break;
  1026. case eErrorIfNoExtension:
  1027. ORIGINATE_WIN32_FAILURE_AND_EXIT(MissingExtension, ERROR_BAD_PATHNAME);
  1028. }
  1029. }
  1030. else
  1031. {
  1032. ++dot;
  1033. IFW32FALSE_EXIT(this->Left(dot - this->Begin()));
  1034. IFW32FALSE_EXIT(this->Win32Append(newExtension, cchExtension));
  1035. }
  1036. fSuccess = TRUE;
  1037. Exit:
  1038. this->IntegrityCheck();
  1039. return fSuccess;
  1040. }
  1041. BOOL Win32ChangePathExtension(const UNICODE_STRING* NtString, EIfNoExtension e)
  1042. {
  1043. return Win32ChangePathExtension(
  1044. NtString->Buffer,
  1045. RTL_STRING_GET_LENGTH_CHARS(NtString),
  1046. e);
  1047. }
  1048. BOOL Win32CopyStringOut(LPWSTR sz, ULONG *pcch) const
  1049. {
  1050. FN_PROLOG_WIN32
  1051. this->IntegrityCheck();
  1052. SIZE_T cwchRequired = 0;
  1053. PARAMETER_CHECK(pcch != NULL);
  1054. IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(m_prgchBuffer, m_cch, cwchRequired));
  1055. if ((*pcch) < cwchRequired)
  1056. {
  1057. *pcch = static_cast<DWORD>(cwchRequired);
  1058. ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
  1059. }
  1060. IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(sz, *pcch, m_prgchBuffer, m_cch));
  1061. FN_EPILOG
  1062. }
  1063. //
  1064. // This function is rather special purpose in that several design choices are not
  1065. // implemented as parameters. In particular, the pcbBytesWritten is assumed to
  1066. // accumulate a number (thus it's updated by adding the number of bytes written to
  1067. // it rather than just setting it to the count of bytes written).
  1068. //
  1069. // It also writes 0 bytes into the buffer is the string is zero length; if the string
  1070. // is not zero length, it writes the string including a trailing null.
  1071. //
  1072. inline BOOL Win32CopyIntoBuffer(
  1073. PWSTR *ppszCursor,
  1074. SIZE_T *pcbBuffer,
  1075. SIZE_T *pcbBytesWritten,
  1076. PVOID pvBase,
  1077. ULONG *pulOffset,
  1078. ULONG *pulLength
  1079. ) const
  1080. {
  1081. this->IntegrityCheck();
  1082. BOOL fSuccess = FALSE;
  1083. FN_TRACE_WIN32(fSuccess);
  1084. PWSTR pszCursor = NULL;
  1085. SSIZE_T dptr = 0;
  1086. SIZE_T cbRequired = 0;
  1087. SIZE_T cch = 0;
  1088. if (pulOffset != NULL)
  1089. *pulOffset = 0;
  1090. if (pulLength != NULL)
  1091. *pulLength = 0;
  1092. PARAMETER_CHECK(pcbBuffer != NULL);
  1093. PARAMETER_CHECK(ppszCursor != NULL);
  1094. pszCursor = *ppszCursor;
  1095. dptr = ((SSIZE_T) pszCursor) - ((SSIZE_T) pvBase);
  1096. // If they're asking for an offset or length and the cursor is too far from the base,
  1097. // fail.
  1098. PARAMETER_CHECK((pulOffset == NULL) || (dptr <= ULONG_MAX));
  1099. cch = m_cch;
  1100. cbRequired = (cch != 0) ? ((cch + 1) * sizeof(WCHAR)) : 0;
  1101. if ((*pcbBuffer) < cbRequired)
  1102. {
  1103. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  1104. goto Exit;
  1105. }
  1106. if (cbRequired > ULONG_MAX)
  1107. {
  1108. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  1109. goto Exit;
  1110. }
  1111. CopyMemory(pszCursor, static_cast<PCWSTR>(*this), cbRequired);
  1112. if (pulOffset != NULL)
  1113. {
  1114. if (cbRequired != 0)
  1115. *pulOffset = (ULONG) dptr;
  1116. }
  1117. if (pulLength != NULL)
  1118. {
  1119. if (cbRequired == 0)
  1120. *pulLength = 0;
  1121. else
  1122. {
  1123. *pulLength = (ULONG) (cbRequired - sizeof(WCHAR));
  1124. }
  1125. }
  1126. *pcbBytesWritten += cbRequired;
  1127. *pcbBuffer -= cbRequired;
  1128. *ppszCursor = (PWSTR) (((ULONG_PTR) pszCursor) + cbRequired);
  1129. fSuccess = TRUE;
  1130. Exit:
  1131. return fSuccess;
  1132. }
  1133. protected:
  1134. BOOL
  1135. __fastcall
  1136. Win32ResizeBufferPreserveContentsInternal(
  1137. SIZE_T cch
  1138. )
  1139. {
  1140. // Note: this function is performance-sensitive, so we do not use the normal
  1141. // tracing infrastucture here
  1142. if (cch > m_cchBuffer)
  1143. {
  1144. TMutableString prgchBufferNew = NULL;
  1145. if (!this->Win32AllocateBuffer(cch, prgchBufferNew))
  1146. return FALSE;
  1147. // We assume that the buffer is/was null-terminated.
  1148. if (!TCharTraits::Win32CopyIntoBuffer(prgchBufferNew, cch, m_prgchBuffer, m_cch))
  1149. {
  1150. this->DeallocateBuffer(prgchBufferNew);
  1151. return FALSE;
  1152. }
  1153. if ((m_prgchBuffer != NULL) && (m_prgchBuffer != this->GetInlineBuffer()))
  1154. this->DeallocateBuffer(m_prgchBuffer);
  1155. m_prgchBuffer = prgchBufferNew;
  1156. m_cchBuffer = cch;
  1157. }
  1158. return TRUE;
  1159. }
  1160. TMutableString Begin()
  1161. {
  1162. this->IntegrityCheck();
  1163. /* CopyBeforeWrite() */
  1164. return m_prgchBuffer;
  1165. }
  1166. TMutableString End()
  1167. {
  1168. this->IntegrityCheck();
  1169. return &m_prgchBuffer[m_cch];
  1170. }
  1171. LONG m_cAttachedAccessors;
  1172. TChar *m_prgchBuffer;
  1173. SIZE_T m_cchBuffer;
  1174. SIZE_T m_cch; // current length of string
  1175. };
  1176. template <typename TCharTraits> class CGenericStringBufferAccessor
  1177. {
  1178. public:
  1179. typedef CGenericBaseStringBuffer<TCharTraits> TBuffer;
  1180. typedef typename CGenericBaseStringBuffer<TCharTraits>::TChar TChar;
  1181. CGenericStringBufferAccessor(TBuffer* pBuffer = NULL)
  1182. : m_pBuffer(NULL),
  1183. m_pszBuffer(NULL),
  1184. m_cchBuffer(NULL)
  1185. {
  1186. if (pBuffer != NULL)
  1187. {
  1188. Attach(pBuffer);
  1189. }
  1190. }
  1191. ~CGenericStringBufferAccessor()
  1192. {
  1193. if (m_pBuffer != NULL)
  1194. {
  1195. m_pBuffer->m_cch = TCharTraits::NullTerminatedStringLength(m_pszBuffer);
  1196. m_pBuffer->DetachAccessor(this);
  1197. m_pBuffer = NULL;
  1198. m_pszBuffer = NULL;
  1199. m_cchBuffer = 0;
  1200. }
  1201. }
  1202. bool IsAttached() const
  1203. {
  1204. return (m_pBuffer != NULL);
  1205. }
  1206. static TChar NullCharacter() { return TCharTraits::NullCharacter(); }
  1207. void Attach(TBuffer *pBuffer)
  1208. {
  1209. FN_TRACE();
  1210. // NTRAID#NTBUG9 - 586534 - 2002/03/26 - xiaoyuw
  1211. // should be changed to be INTERNAL_ERROR_CHECK
  1212. //
  1213. ASSERT(!this->IsAttached());
  1214. if (!this->IsAttached())
  1215. {
  1216. pBuffer->AttachAccessor(this);
  1217. m_pBuffer = pBuffer;
  1218. m_pszBuffer = m_pBuffer->m_prgchBuffer;
  1219. m_cchBuffer = m_pBuffer->m_cchBuffer;
  1220. }
  1221. }
  1222. void Detach()
  1223. {
  1224. FN_TRACE();
  1225. // NTRAID#NTBUG9 - 586534 - 2002/03/26 - xiaoyuw
  1226. // should be changed to be INTERNAL_ERROR_CHECK
  1227. //
  1228. ASSERT (IsAttached());
  1229. if (IsAttached())
  1230. {
  1231. ASSERT(m_pszBuffer == m_pBuffer->m_prgchBuffer);
  1232. m_pBuffer->m_cch = TCharTraits::NullTerminatedStringLength(m_pszBuffer);
  1233. m_pBuffer->DetachAccessor(this);
  1234. m_pBuffer = NULL;
  1235. m_pszBuffer = NULL;
  1236. m_cchBuffer = 0;
  1237. }
  1238. else
  1239. {
  1240. ASSERT(m_pszBuffer == NULL);
  1241. ASSERT(m_cchBuffer == 0);
  1242. }
  1243. }
  1244. operator typename TCharTraits::TMutableString() const { ASSERT_NTC(this->IsAttached()); return m_pszBuffer; }
  1245. SIZE_T Cch() const { ASSERT_NTC(this->IsAttached()); return (m_pszBuffer != NULL) ? ::wcslen(m_pszBuffer) : 0; }
  1246. typename TCharTraits::TMutableString GetBufferPtr() const { ASSERT_NTC(IsAttached()); return m_pszBuffer; }
  1247. SIZE_T GetBufferCch() const { ASSERT_NTC(this->IsAttached()); return m_cchBuffer; }
  1248. INT GetBufferCchAsINT() const { ASSERT_NTC(this->IsAttached()); if (m_cchBuffer > INT_MAX) return INT_MAX; return static_cast<INT>(m_cchBuffer); }
  1249. UINT GetBufferCchAsUINT() const { ASSERT_NTC(this->IsAttached()); if (m_cchBuffer > UINT_MAX) return UINT_MAX; return static_cast<UINT>(m_cchBuffer); }
  1250. DWORD GetBufferCchAsDWORD() const { ASSERT_NTC(this->IsAttached()); if (m_cchBuffer > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cchBuffer); }
  1251. DWORD GetCchAsDWORD() const { ASSERT_NTC(this->IsAttached()); if (m_cch > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cch); }
  1252. // NTRAID#NTBUG9 - 586534 - 2002/03/26 - xiaoyuw
  1253. // (1) overflow of the result of m_cchBuffer * sizeof(TChar)
  1254. // (2) calls GetXXXAsDWORD need to check whether the return value is DWORDMAX, if so, stop;
  1255. SIZE_T GetBufferCb() const { ASSERT_NTC(this->IsAttached()); return m_cchBuffer * sizeof(*m_pszBuffer); }
  1256. INT GetBufferCbAsINT() const { ASSERT_NTC(this->IsAttached()); if ((m_cchBuffer * sizeof(TChar)) > INT_MAX) return INT_MAX; return static_cast<INT>(m_cchBuffer * sizeof(TChar)); }
  1257. DWORD GetBufferCbAsDWORD() const { ASSERT_NTC(this->IsAttached()); if ((m_cchBuffer * sizeof(TChar)) > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cchBuffer * sizeof(TChar)); }
  1258. DWORD GetCbAsDWORD() const { ASSERT_NTC(this->IsAttached()); if ((m_cch * sizeof(TChar)) > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cch * sizeof(TChar)); }
  1259. protected:
  1260. TBuffer *m_pBuffer;
  1261. typename TCharTraits::TMutableString m_pszBuffer;
  1262. SIZE_T m_cchBuffer;
  1263. };
  1264. template <SIZE_T nInlineChars, typename TCharTraits> class CGenericStringBuffer : public CGenericBaseStringBuffer<TCharTraits>
  1265. {
  1266. typedef CGenericBaseStringBuffer<TCharTraits> Base;
  1267. protected:
  1268. BOOL Win32AllocateBuffer(SIZE_T cch, TMutableString &rpsz) const
  1269. {
  1270. // You shouldn't be doing this if the required buffer size is small enough to be inline...
  1271. ASSERT_NTC(cch > nInlineChars);
  1272. rpsz = NULL;
  1273. TCharTraits::TMutableString String = NULL;
  1274. String = reinterpret_cast<TCharTraits::TMutableString>(::FusionpHeapAllocEx(
  1275. FUSION_DEFAULT_PROCESS_HEAP(),
  1276. 0,
  1277. cch * sizeof(TCharTraits::TChar),
  1278. "<string buffer>",
  1279. __FILE__,
  1280. __LINE__,
  1281. 0)); // fusion heap allocation flags
  1282. if (String == NULL)
  1283. {
  1284. ::FusionpSetLastWin32Error(FUSION_WIN32_ALLOCFAILED_ERROR);
  1285. return FALSE;
  1286. }
  1287. rpsz = String;
  1288. return TRUE;
  1289. }
  1290. VOID DeallocateBuffer(TMutableString sz) const
  1291. {
  1292. VERIFY_NTC(::FusionpHeapFree(FUSION_DEFAULT_PROCESS_HEAP(), 0, sz));
  1293. }
  1294. TMutableString GetInlineBuffer() const { return const_cast<TMutableString>(m_rgchInlineBuffer); }
  1295. SIZE_T GetInlineBufferCch() const { return nInlineChars; }
  1296. void Initialize() { m_rgchInlineBuffer[0] = this->NullCharacter(); Base::InitializeInlineBuffer(); }
  1297. void Cleanup() { if (m_prgchBuffer != m_rgchInlineBuffer) { this->DeallocateBuffer(m_prgchBuffer); } m_prgchBuffer = NULL; m_cchBuffer = 0; }
  1298. public:
  1299. void Reinitialize() { Cleanup(); Initialize(); }
  1300. CGenericStringBuffer() { Initialize(); }
  1301. ~CGenericStringBuffer() { Cleanup(); }
  1302. protected:
  1303. TChar m_rgchInlineBuffer[nInlineChars];
  1304. private:
  1305. CGenericStringBuffer(const CGenericStringBuffer &); // intentionally not implemented
  1306. void operator =(const CGenericStringBuffer &); // intentionally not implemented
  1307. };
  1308. template <SIZE_T nInlineChars, typename TCharTraits> class CGenericHeapStringBuffer : public CGenericBaseStringBuffer<TCharTraits>
  1309. {
  1310. // friend CGenericBaseStringBuffer<TCharTraits>;
  1311. typedef CGenericBaseStringBuffer<TCharTraits> Base;
  1312. protected:
  1313. BOOL Win32AllocateBuffer(SIZE_T cch, TMutableString &rpsz) const
  1314. {
  1315. // You shouldn't be doing this if the required buffer size is small enough to be inline...
  1316. ASSERT_NTC(cch > nInlineChars);
  1317. rpsz = NULL;
  1318. TCharTraits::TMutableString String = NULL;
  1319. String = reinterpret_cast<TCharTraits::TMutableString>(::FusionpHeapAllocEx(
  1320. m_hHeap,
  1321. dwDefaultWin32HeapAllocFlags,
  1322. cch * sizeof(TCharTraits::TChar),
  1323. "<string buffer>",
  1324. __FILE__,
  1325. __LINE__,
  1326. 0)) // fusion heap allocation flags
  1327. if (String == NULL)
  1328. {
  1329. ::FusionpSetLastWin32Error(FUSION_WIN32_ALLOCFAILED_ERROR);
  1330. return FALSE;
  1331. }
  1332. rpsz = String;
  1333. return TRUE;
  1334. }
  1335. VOID DeallocateBuffer(TMutableString sz) const
  1336. {
  1337. VERIFY_NTC(::FusionpHeapFree(m_hHeap, dwDefaultWin32HeapFreeFlags, sz));
  1338. }
  1339. TMutableString GetInlineBuffer() const { return m_rgchInlineBuffer; }
  1340. SIZE_T GetInlineBufferCch() const { return nInlineChars; }
  1341. public:
  1342. CGenericHeapStringBuffer(HANDLE hHeap) : m_hHeap(hHeap) { m_rgchInlineBuffer[0] = this->NullCharacter(); Base::InitializeInlineBuffer(); }
  1343. ~CGenericHeapStringBuffer() { ASSERT(m_cchBuffer == 0); ASSERT(m_prgchBuffer == NULL); }
  1344. protected:
  1345. HANDLE m_hHeap;
  1346. TChar m_rgchInlineBuffer[nInlineChars];
  1347. };
  1348. typedef CGenericStringBufferAccessor<CUnicodeCharTraits> CUnicodeStringBufferAccessor;
  1349. typedef CGenericBaseStringBuffer<CUnicodeCharTraits> CUnicodeBaseStringBuffer;
  1350. typedef CGenericStringBuffer<FUSION_DEFAULT_STRINGBUFFER_CHARS, CUnicodeCharTraits> CUnicodeStringBuffer;
  1351. typedef CGenericHeapStringBuffer<FUSION_DEFAULT_STRINGBUFFER_CHARS, CUnicodeCharTraits> CUnicodeHeapStringBuffer;
  1352. typedef CGenericStringBuffer<FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS, CUnicodeCharTraits> CTinyUnicodeStringBuffer;
  1353. typedef CGenericHeapStringBuffer<FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS, CUnicodeCharTraits> CTinyUnicodeHeapStringBuffer;
  1354. typedef CGenericStringBuffer<FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS, CUnicodeCharTraits> CSmallUnicodeStringBuffer;
  1355. typedef CGenericHeapStringBuffer<FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS, CUnicodeCharTraits> CSmallUnicodeHeapStringBuffer;
  1356. typedef CGenericStringBuffer<FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS, CUnicodeCharTraits> CMediumUnicodeStringBuffer;
  1357. typedef CGenericHeapStringBuffer<FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS, CUnicodeCharTraits> CMediumUnicodeHeapStringBuffer;
  1358. typedef CGenericStringBufferAccessor<CANSICharTraits> CANSIStringBufferAccessor;
  1359. typedef CGenericBaseStringBuffer<CANSICharTraits> CANSIBaseStringBuffer;
  1360. typedef CGenericStringBuffer<FUSION_DEFAULT_STRINGBUFFER_CHARS, CANSICharTraits> CANSIStringBuffer;
  1361. typedef CGenericHeapStringBuffer<FUSION_DEFAULT_STRINGBUFFER_CHARS, CANSICharTraits> CANSIHeapStringBuffer;
  1362. typedef CGenericStringBuffer<FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS, CANSICharTraits> CTinyANSIStringBuffer;
  1363. typedef CGenericHeapStringBuffer<FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS, CANSICharTraits> CTinyANSIHeapStringBuffer;
  1364. typedef CGenericStringBuffer<FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS, CANSICharTraits> CSmallANSIStringBuffer;
  1365. typedef CGenericHeapStringBuffer<FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS, CANSICharTraits> CSmallANSIHeapStringBuffer;
  1366. typedef CGenericStringBuffer<FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS, CANSICharTraits> CMediumANSIStringBuffer;
  1367. typedef CGenericHeapStringBuffer<FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS, CANSICharTraits> CMediumANSIHeapStringBuffer;
  1368. typedef CUnicodeBaseStringBuffer CBaseStringBuffer;
  1369. typedef CUnicodeStringBuffer CStringBuffer;
  1370. typedef CUnicodeHeapStringBuffer CHeapStringBuffer;
  1371. typedef CUnicodeStringBufferAccessor CStringBufferAccessor;
  1372. typedef CTinyUnicodeStringBuffer CTinyStringBuffer;
  1373. typedef CTinyUnicodeHeapStringBuffer CTinyHeapStringBuffer;
  1374. typedef CSmallUnicodeStringBuffer CSmallStringBuffer;
  1375. typedef CSmallUnicodeHeapStringBuffer CSmallHeapStringBuffer;
  1376. typedef CMediumUnicodeStringBuffer CMediumStringBuffer;
  1377. typedef CMediumUnicodeHeapStringBuffer CMediumHeapStringBuffer;
  1378. template <typename T1, typename T2> inline HRESULT HashTableCompareKey(T1 t1, T2 *pt2, bool &rfMatch);
  1379. template <> inline HRESULT HashTableCompareKey(PCWSTR sz, CUnicodeStringBuffer *pbuff, bool &rfMatch)
  1380. {
  1381. HRESULT hr = NOERROR;
  1382. SIZE_T cchKey = (sz != NULL) ? ::wcslen(sz) : 0;
  1383. rfMatch = false;
  1384. if (!pbuff->Win32Equals(sz, cchKey, rfMatch, false))
  1385. {
  1386. hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
  1387. goto Exit;
  1388. }
  1389. hr = NOERROR;
  1390. Exit:
  1391. return hr;
  1392. }
  1393. template <> inline HRESULT HashTableCompareKey(PCSTR sz, CANSIStringBuffer *pbuff, bool &rfMatch)
  1394. {
  1395. HRESULT hr = NOERROR;
  1396. SIZE_T cchKey = ::strlen(sz);
  1397. rfMatch = false;
  1398. if (!pbuff->Win32Equals(sz, cchKey, rfMatch, false))
  1399. {
  1400. hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
  1401. goto Exit;
  1402. }
  1403. hr = NOERROR;
  1404. Exit:
  1405. return hr;
  1406. }
  1407. //
  1408. // Support for CFusionArrays of strings
  1409. //
  1410. template<>
  1411. inline BOOL
  1412. FusionWin32CopyContents<CStringBuffer>(
  1413. CStringBuffer &rDestination,
  1414. const CStringBuffer &rSource
  1415. )
  1416. {
  1417. return rDestination.Win32Assign(rSource);
  1418. }
  1419. inline BOOL
  1420. FusionWin32CopyContents(
  1421. CStringBuffer &rDestination,
  1422. const CBaseStringBuffer &rSource
  1423. )
  1424. {
  1425. return rDestination.Win32Assign(rSource);
  1426. }
  1427. #endif