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.

2230 lines
57 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. CString.cpp
  5. Abstract:
  6. A CString class, pure UNICODE internally.
  7. This code was ripped from MFC Strcore.cpp and Strex.cpp
  8. History:
  9. 05/11/2001 robkenny Added this header
  10. 05/11/2001 robkenny Fixed SplitPath.
  11. 05/11/2001 robkenny Do not Truncate(0) GetShortPathNameW,
  12. GetLongPathNameW and GetFullPathNameW if
  13. the API does not succeed.
  14. 08/14/2001 robkenny Moved code inside the ShimLib namespace.
  15. --*/
  16. #include "ShimHook.h"
  17. #include "ShimLib.h"
  18. #include "Win9xPath.h"
  19. #include <stdio.h> // for _vsnwprintf
  20. #include <stdlib.h>
  21. namespace ShimLib
  22. {
  23. typedef WCHAR _TUCHAR;
  24. struct _AFX_DOUBLE { BYTE doubleBits[sizeof(double)]; };
  25. #ifdef USE_SEH
  26. const ULONG_PTR CString::m_CStringExceptionValue = CString::eCStringExceptionValue;
  27. // Exception filter for CString __try/__except blocks
  28. // Return EXCEPTION_EXECUTE_HANDLER if this is a CString exception
  29. // otherwise return EXCEPTION_CONTINUE_SEARCH
  30. int CString::ExceptionFilter(PEXCEPTION_POINTERS pexi)
  31. {
  32. if (pexi->ExceptionRecord->ExceptionCode == CString::eCStringNoMemoryException &&
  33. pexi->ExceptionRecord->NumberParameters == 1 &&
  34. pexi->ExceptionRecord->ExceptionInformation[0] == CString::m_CStringExceptionValue
  35. )
  36. {
  37. // This is a CString exception, handle it
  38. return EXCEPTION_EXECUTE_HANDLER;
  39. }
  40. // Not our error
  41. return EXCEPTION_CONTINUE_SEARCH;
  42. }
  43. #endif
  44. // The original code was written using a memcpy that correctly handled
  45. // overlapping buffers, despite the documentation.
  46. // Replace memcpy with memmove, which correctly handles overlapping buffers
  47. #define memcpy memmove
  48. const WCHAR * wcsinc(const WCHAR * s1)
  49. {
  50. return (s1) + 1;
  51. }
  52. LPWSTR wcsinc(LPWSTR s1)
  53. {
  54. return (s1) + 1;
  55. }
  56. // WCS routines that are only available in MSVCRT
  57. wchar_t * __cdecl _wcsrev (
  58. wchar_t * string
  59. )
  60. {
  61. wchar_t *start = string;
  62. wchar_t *left = string;
  63. wchar_t ch;
  64. while (*string++) /* find end of string */
  65. ;
  66. string -= 2;
  67. while (left < string)
  68. {
  69. ch = *left;
  70. *left++ = *string;
  71. *string-- = ch;
  72. }
  73. return(start);
  74. }
  75. void __cdecl _wsplitpath (
  76. register const WCHAR *path,
  77. WCHAR *drive,
  78. WCHAR *dir,
  79. WCHAR *fname,
  80. WCHAR *ext
  81. )
  82. {
  83. register WCHAR *p;
  84. WCHAR *last_slash = NULL, *dot = NULL;
  85. unsigned len;
  86. /* we assume that the path argument has the following form, where any
  87. * or all of the components may be missing.
  88. *
  89. * <drive><dir><fname><ext>
  90. *
  91. * and each of the components has the following expected form(s)
  92. *
  93. * drive:
  94. * 0 to _MAX_DRIVE-1 characters, the last of which, if any, is a
  95. * ':'
  96. * dir:
  97. * 0 to _MAX_DIR-1 characters in the form of an absolute path
  98. * (leading '/' or '\') or relative path, the last of which, if
  99. * any, must be a '/' or '\'. E.g -
  100. * absolute path:
  101. * \top\next\last\ ; or
  102. * /top/next/last/
  103. * relative path:
  104. * top\next\last\ ; or
  105. * top/next/last/
  106. * Mixed use of '/' and '\' within a path is also tolerated
  107. * fname:
  108. * 0 to _MAX_FNAME-1 characters not including the '.' character
  109. * ext:
  110. * 0 to _MAX_EXT-1 characters where, if any, the first must be a
  111. * '.'
  112. *
  113. */
  114. /* extract drive letter and :, if any */
  115. if ((wcslen(path) >= (_MAX_DRIVE - 2)) && (*(path + _MAX_DRIVE - 2) == L':')) {
  116. if (drive) {
  117. wcsncpy(drive, path, _MAX_DRIVE - 1);
  118. *(drive + _MAX_DRIVE-1) = L'\0';
  119. }
  120. path += _MAX_DRIVE - 1;
  121. }
  122. else if (drive) {
  123. *drive = L'\0';
  124. }
  125. /* extract path string, if any. Path now points to the first character
  126. * of the path, if any, or the filename or extension, if no path was
  127. * specified. Scan ahead for the last occurence, if any, of a '/' or
  128. * '\' path separator character. If none is found, there is no path.
  129. * We will also note the last '.' character found, if any, to aid in
  130. * handling the extension.
  131. */
  132. for (last_slash = NULL, p = (WCHAR *)path; *p; p++) {
  133. if (*p == L'/' || *p == L'\\')
  134. /* point to one beyond for later copy */
  135. last_slash = p + 1;
  136. else if (*p == L'.')
  137. dot = p;
  138. }
  139. if (last_slash) {
  140. /* found a path - copy up through last_slash or max. characters
  141. * allowed, whichever is smaller
  142. */
  143. if (dir) {
  144. len = __min((unsigned)(((char *)last_slash - (char *)path) / sizeof(WCHAR)),
  145. (_MAX_DIR - 1));
  146. wcsncpy(dir, path, len);
  147. *(dir + len) = L'\0';
  148. }
  149. path = last_slash;
  150. }
  151. else if (dir) {
  152. /* no path found */
  153. *dir = L'\0';
  154. }
  155. /* extract file name and extension, if any. Path now points to the
  156. * first character of the file name, if any, or the extension if no
  157. * file name was given. Dot points to the '.' beginning the extension,
  158. * if any.
  159. */
  160. if (dot && (dot >= path)) {
  161. /* found the marker for an extension - copy the file name up to
  162. * the '.'.
  163. */
  164. if (fname) {
  165. len = __min((unsigned)(((char *)dot - (char *)path) / sizeof(WCHAR)),
  166. (_MAX_FNAME - 1));
  167. wcsncpy(fname, path, len);
  168. *(fname + len) = L'\0';
  169. }
  170. /* now we can get the extension - remember that p still points
  171. * to the terminating nul character of path.
  172. */
  173. if (ext) {
  174. len = __min((unsigned)(((char *)p - (char *)dot) / sizeof(WCHAR)),
  175. (_MAX_EXT - 1));
  176. wcsncpy(ext, dot, len);
  177. *(ext + len) = L'\0';
  178. }
  179. }
  180. else {
  181. /* found no extension, give empty extension and copy rest of
  182. * string into fname.
  183. */
  184. if (fname) {
  185. len = __min((unsigned)(((char *)p - (char *)path) / sizeof(WCHAR)),
  186. (_MAX_FNAME - 1));
  187. wcsncpy(fname, path, len);
  188. *(fname + len) = L'\0';
  189. }
  190. if (ext) {
  191. *ext = L'\0';
  192. }
  193. }
  194. }
  195. // conversion helpers
  196. int AFX_CDECL _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count);
  197. // AfxIsValidString() returns TRUE if the passed pointer
  198. // references a string of at least the given length in characters.
  199. // A length of -1 (the default parameter) means that the string
  200. // buffer's minimum length isn't known, and the function will
  201. // return TRUE no matter how long the string is. The memory
  202. // used by the string can be read-only.
  203. BOOL AFXAPI AfxIsValidString(LPCWSTR lpsz, int nLength /* = -1 */)
  204. {
  205. if (lpsz == NULL)
  206. return FALSE;
  207. return ::IsBadStringPtrW(lpsz, nLength) == 0;
  208. }
  209. // AfxIsValidAddress() returns TRUE if the passed parameter points
  210. // to at least nBytes of accessible memory. If bReadWrite is TRUE,
  211. // the memory must be writeable; if bReadWrite is FALSE, the memory
  212. // may be const.
  213. BOOL AFXAPI AfxIsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite /* = TRUE */)
  214. {
  215. // simple version using Win-32 APIs for pointer validation.
  216. return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
  217. (!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
  218. }
  219. /////////////////////////////////////////////////////////////////////////////
  220. // static class data, special inlines
  221. WCHAR CString::ChNil = L'\0';
  222. // For an empty string, m_pchData will point here
  223. // (note: avoids special case of checking for NULL m_pchData)
  224. // empty string data (and locked)
  225. int CString::_afxInitData[] = { -1, 0, 0, 0 };
  226. CStringData<WCHAR> * CString::_afxDataNil = (CStringData<WCHAR>*)&_afxInitData;
  227. const WCHAR * CString::_afxPchNil = (const WCHAR *)(((BYTE*)&_afxInitData)+sizeof(CStringData<WCHAR>));
  228. // special function to make afxEmptyString work even during initialization
  229. //const CString& AFXAPI AfxGetEmptyString()
  230. // { return *(CString*)&CString::_afxPchNil; }
  231. //////////////////////////////////////////////////////////////////////////////
  232. // Construction/Destruction
  233. CString::CString(const CString& stringSrc)
  234. {
  235. ASSERT(stringSrc.GetData()->nRefs != 0, "CString::CString(const CString& stringSrc)");
  236. if (stringSrc.GetData()->nRefs >= 0)
  237. {
  238. ASSERT(stringSrc.GetData() != _afxDataNil, "CString::CString(const CString& stringSrc)");
  239. // robkenny: increment before copy is safer
  240. InterlockedIncrement(&stringSrc.GetData()->nRefs);
  241. m_pchData = stringSrc.m_pchData;
  242. m_pchDataAnsi = NULL;
  243. }
  244. else
  245. {
  246. Init();
  247. *this = stringSrc.m_pchData;
  248. }
  249. }
  250. inline int Round4(int x)
  251. {
  252. return (x + 3) & ~3;
  253. }
  254. inline int RoundBin(int x)
  255. {
  256. return Round4(x * sizeof(WCHAR) + sizeof(CStringData<WCHAR>) );
  257. }
  258. void CString::AllocBuffer(int nLen)
  259. // always allocate one extra character for '\0' termination
  260. // assumes [optimistically] that data length will equal allocation length
  261. {
  262. ASSERT(nLen >= 0, "CString::AllocBuffer");
  263. ASSERT(nLen <= INT_MAX-1, "CString::AllocBuffer"); // max size (enough room for 1 extra)
  264. if (nLen == 0)
  265. {
  266. Init();
  267. }
  268. else
  269. {
  270. int allocGranularity = nLen + 1;
  271. if (nLen < 64)
  272. {
  273. allocGranularity = 64;
  274. }
  275. else if (nLen < 128)
  276. {
  277. allocGranularity = 128;
  278. }
  279. else if (nLen < MAX_PATH)
  280. {
  281. allocGranularity = MAX_PATH;
  282. }
  283. else if (nLen < 512)
  284. {
  285. allocGranularity = 512;
  286. }
  287. // Number of bytes necessary for the CStringData thingy.
  288. DWORD dwBufferSize = RoundBin(allocGranularity);
  289. CStringData<WCHAR>* pData = (CStringData<WCHAR>*) new BYTE[dwBufferSize];
  290. if (pData)
  291. {
  292. pData->nAllocLength = allocGranularity;
  293. pData->nRefs = 1;
  294. pData->data()[nLen] = '\0';
  295. pData->nDataLength = nLen;
  296. m_pchData = pData->data();
  297. }
  298. else
  299. {
  300. CSTRING_THROW_EXCEPTION
  301. }
  302. }
  303. }
  304. void CString::Release()
  305. {
  306. if (GetData() != _afxDataNil)
  307. {
  308. ASSERT(GetData()->nRefs != 0, "CString::Release()");
  309. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  310. FreeData(GetData());
  311. Init();
  312. }
  313. }
  314. void CString::Release(CStringData<WCHAR>* pData)
  315. {
  316. if (pData != _afxDataNil)
  317. {
  318. ASSERT(pData->nRefs != 0, "CString::Release(CStringData<WCHAR>* pData)");
  319. if (InterlockedDecrement(&pData->nRefs) <= 0)
  320. FreeData(pData);
  321. }
  322. }
  323. void CString::Empty()
  324. {
  325. if (GetData()->nDataLength == 0)
  326. return;
  327. if (GetData()->nRefs >= 0)
  328. Release();
  329. else
  330. *this = &ChNil;
  331. ASSERT(GetData()->nDataLength == 0, "CString::Empty()");
  332. ASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0, "CString::Empty()");
  333. }
  334. void CString::CopyBeforeWrite()
  335. {
  336. if (GetData()->nRefs > 1)
  337. {
  338. CStringData<WCHAR>* pData = GetData();
  339. Release();
  340. AllocBuffer(pData->nDataLength);
  341. memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(WCHAR));
  342. }
  343. ASSERT(GetData()->nRefs <= 1, "CString::CopyBeforeWrite()");
  344. }
  345. void CString::AllocBeforeWrite(int nLen)
  346. {
  347. if (GetData()->nRefs > 1 || nLen >= GetData()->nAllocLength)
  348. {
  349. Release();
  350. AllocBuffer(nLen);
  351. }
  352. ASSERT(GetData()->nRefs <= 1, "CString::AllocBeforeWrite(int nLen)");
  353. }
  354. CString::~CString()
  355. // free any attached data
  356. {
  357. if (GetData() != _afxDataNil)
  358. {
  359. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  360. FreeData(GetData());
  361. }
  362. if (m_pchDataAnsi)
  363. {
  364. free(m_pchDataAnsi);
  365. }
  366. }
  367. //////////////////////////////////////////////////////////////////////////////
  368. // Helpers for the rest of the implementation
  369. void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
  370. int nExtraLen) const
  371. {
  372. // Copy nCopyIndex to nCopyIndex+nCopyLen into dest
  373. // Make sure dest has nExtraLen chars left over in the dest string
  374. int nNewLen = nCopyLen + nExtraLen;
  375. if (nNewLen == 0)
  376. {
  377. dest.Init();
  378. }
  379. else
  380. {
  381. WCHAR * lpszDestBuffer = dest.GetBuffer(nNewLen);
  382. memcpy(lpszDestBuffer, m_pchData+nCopyIndex, nCopyLen*sizeof(WCHAR));
  383. lpszDestBuffer[nCopyLen] = '\0';
  384. dest.ReleaseBuffer(nCopyLen);
  385. }
  386. }
  387. ///////////////////////////////////////////////////////////////////////////////
  388. // CString conversion helpers (these use the current system locale)
  389. int AFX_CDECL _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  390. {
  391. if (count == 0 && wcstr != NULL)
  392. return 0;
  393. int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1,
  394. wcstr, count);
  395. ASSERT(wcstr == NULL || result <= (int)count, "CString::_mbstowcsz");
  396. if (result > 0)
  397. wcstr[result-1] = 0;
  398. return result;
  399. }
  400. //////////////////////////////////////////////////////////////////////////////
  401. // More sophisticated construction
  402. CString::CString(LPCWSTR lpsz)
  403. {
  404. Init();
  405. {
  406. int nLen = SafeStrlen(lpsz);
  407. if (nLen != 0)
  408. {
  409. AllocBuffer(nLen);
  410. memcpy(m_pchData, lpsz, nLen*sizeof(WCHAR));
  411. }
  412. }
  413. }
  414. /////////////////////////////////////////////////////////////////////////////
  415. // Special conversion constructors
  416. CString::CString(LPCSTR lpsz)
  417. {
  418. Init();
  419. int nSrcLen = lpsz != NULL ? strlenChars(lpsz) : 0;
  420. if (nSrcLen != 0)
  421. {
  422. AllocBuffer(nSrcLen);
  423. _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  424. ReleaseBuffer();
  425. }
  426. }
  427. CString::CString(LPCSTR lpsz, int nCharacters)
  428. {
  429. Init();
  430. if (nCharacters != 0)
  431. {
  432. AllocBuffer(nCharacters);
  433. _mbstowcsz(m_pchData, lpsz, nCharacters);
  434. ReleaseBuffer(nCharacters);
  435. }
  436. }
  437. //////////////////////////////////////////////////////////////////////////////
  438. // Diagnostic support
  439. #ifdef _DEBUG
  440. CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CString& string)
  441. {
  442. dc << string.m_pchData;
  443. return dc;
  444. }
  445. #endif //_DEBUG
  446. //////////////////////////////////////////////////////////////////////////////
  447. // Assignment operators
  448. // All assign a new value to the string
  449. // (a) first see if the buffer is big enough
  450. // (b) if enough room, copy on top of old buffer, set size and type
  451. // (c) otherwise free old string data, and create a new one
  452. //
  453. // All routines return the new string (but as a 'const CString&' so that
  454. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  455. //
  456. void CString::AssignCopy(int nSrcLen, LPCWSTR lpszSrcData)
  457. {
  458. AllocBeforeWrite(nSrcLen);
  459. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(WCHAR));
  460. GetData()->nDataLength = nSrcLen;
  461. m_pchData[nSrcLen] = '\0';
  462. }
  463. const CString& CString::operator=(const CString& stringSrc)
  464. {
  465. if (m_pchData != stringSrc.m_pchData)
  466. {
  467. if ((GetData()->nRefs < 0 && GetData() != _afxDataNil) ||
  468. stringSrc.GetData()->nRefs < 0)
  469. {
  470. // actual copy necessary since one of the strings is locked
  471. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  472. }
  473. else
  474. {
  475. // can just copy references around
  476. Release();
  477. ASSERT(stringSrc.GetData() != _afxDataNil, "CString::operator=(const CString& stringSrc)");
  478. // robkenny: increment before copy is safer
  479. InterlockedIncrement(&stringSrc.GetData()->nRefs);
  480. m_pchData = stringSrc.m_pchData;
  481. m_pchDataAnsi = NULL;
  482. }
  483. }
  484. return *this;
  485. }
  486. const CString& CString::operator=(LPCWSTR lpsz)
  487. {
  488. ASSERT(lpsz == NULL || AfxIsValidString(lpsz), "CString::operator=(LPCWSTR lpsz)");
  489. AssignCopy(SafeStrlen(lpsz), lpsz);
  490. return *this;
  491. }
  492. /////////////////////////////////////////////////////////////////////////////
  493. // Special conversion assignment
  494. const CString& CString::operator=(LPCSTR lpsz)
  495. {
  496. int nSrcLen = lpsz != NULL ? strlenChars(lpsz) : 0;
  497. AllocBeforeWrite(nSrcLen);
  498. _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  499. ReleaseBuffer();
  500. return *this;
  501. }
  502. //////////////////////////////////////////////////////////////////////////////
  503. // concatenation
  504. // NOTE: "operator+" is done as friend functions for simplicity
  505. // There are three variants:
  506. // CString + CString
  507. // and for ? = WCHAR, LPCWSTR
  508. // CString + ?
  509. // ? + CString
  510. void CString::ConcatCopy(int nSrc1Len, LPCWSTR lpszSrc1Data,
  511. int nSrc2Len, LPCWSTR lpszSrc2Data)
  512. {
  513. // -- master concatenation routine
  514. // Concatenate two sources
  515. // -- assume that 'this' is a new CString object
  516. int nNewLen = nSrc1Len + nSrc2Len;
  517. if (nNewLen != 0)
  518. {
  519. AllocBuffer(nNewLen);
  520. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(WCHAR));
  521. memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(WCHAR));
  522. }
  523. }
  524. CString AFXAPI operator+(const CString& string1, const CString& string2)
  525. {
  526. CString s;
  527. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
  528. string2.GetData()->nDataLength, string2.m_pchData);
  529. return s;
  530. }
  531. CString AFXAPI operator+(const CString& string, LPCWSTR lpsz)
  532. {
  533. ASSERT(lpsz == NULL || AfxIsValidString(lpsz), "CString::operator+(const CString& string, LPCWSTR lpsz)");
  534. CString s;
  535. s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
  536. CString::SafeStrlen(lpsz), lpsz);
  537. return s;
  538. }
  539. CString AFXAPI operator+(LPCWSTR lpsz, const CString& string)
  540. {
  541. ASSERT(lpsz == NULL || AfxIsValidString(lpsz), "CString::operator+(LPCWSTR lpsz, const CString& string)");
  542. CString s;
  543. s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
  544. string.m_pchData);
  545. return s;
  546. }
  547. //////////////////////////////////////////////////////////////////////////////
  548. // concatenate in place
  549. void CString::ConcatInPlace(int nSrcLen, LPCWSTR lpszSrcData)
  550. {
  551. // -- the main routine for += operators
  552. // concatenating an empty string is a no-op!
  553. if (nSrcLen == 0)
  554. return;
  555. // if the buffer is too small, or we have a width mis-match, just
  556. // allocate a new buffer (slow but sure)
  557. if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen + 1 > GetData()->nAllocLength)
  558. {
  559. // we have to grow the buffer, use the ConcatCopy routine
  560. CStringData<WCHAR>* pOldData = GetData();
  561. ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
  562. ASSERT(pOldData != NULL, "CString::ConcatInPlace");
  563. CString::Release(pOldData);
  564. }
  565. else
  566. {
  567. // fast concatenation when buffer big enough
  568. memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(WCHAR));
  569. GetData()->nDataLength += nSrcLen;
  570. ASSERT(GetData()->nDataLength <= GetData()->nAllocLength, "CString::ConcatInPlace");
  571. m_pchData[GetData()->nDataLength] = '\0';
  572. }
  573. }
  574. const CString& CString::operator+=(LPCWSTR lpsz)
  575. {
  576. ASSERT(lpsz == NULL || AfxIsValidString(lpsz), "CString::operator+=(LPCWSTR lpsz)");
  577. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  578. return *this;
  579. }
  580. const CString& CString::operator+=(WCHAR ch)
  581. {
  582. ConcatInPlace(1, &ch);
  583. return *this;
  584. }
  585. const CString& CString::operator+=(const CString& string)
  586. {
  587. ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  588. return *this;
  589. }
  590. ///////////////////////////////////////////////////////////////////////////////
  591. // Advanced direct buffer access
  592. LPWSTR CString::GetBuffer(int nMinBufLength)
  593. {
  594. ASSERT(nMinBufLength >= 0, "CString::GetBuffer");
  595. if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  596. {
  597. #ifdef _DEBUG
  598. // give a warning in case locked string becomes unlocked
  599. if (GetData() != _afxDataNil && GetData()->nRefs < 0)
  600. TRACE0("Warning: GetBuffer on locked CString creates unlocked CString!\n");
  601. #endif
  602. // we have to grow the buffer
  603. CStringData<WCHAR>* pOldData = GetData();
  604. int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
  605. if (nMinBufLength < nOldLen)
  606. nMinBufLength = nOldLen;
  607. AllocBuffer(nMinBufLength);
  608. memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(WCHAR));
  609. GetData()->nDataLength = nOldLen;
  610. CString::Release(pOldData);
  611. }
  612. ASSERT(GetData()->nRefs <= 1, "CString::GetBuffer");
  613. // return a pointer to the character storage for this string
  614. ASSERT(m_pchData != NULL, "CString::GetBuffer");
  615. return m_pchData;
  616. }
  617. void CString::ReleaseBuffer(int nNewLength)
  618. {
  619. CopyBeforeWrite(); // just in case GetBuffer was not called
  620. if (nNewLength == -1)
  621. nNewLength = wcslen(m_pchData); // zero terminated
  622. ASSERT(nNewLength <= GetData()->nAllocLength, "CString::ReleaseBuffer");
  623. GetData()->nDataLength = nNewLength;
  624. m_pchData[nNewLength] = '\0';
  625. }
  626. LPWSTR CString::GetBufferSetLength(int nNewLength)
  627. {
  628. ASSERT(nNewLength >= 0, "CString::GetBufferSetLength");
  629. GetBuffer(nNewLength);
  630. GetData()->nDataLength = nNewLength;
  631. m_pchData[nNewLength] = '\0';
  632. return m_pchData;
  633. }
  634. void CString::FreeExtra()
  635. {
  636. ASSERT(GetData()->nDataLength <= GetData()->nAllocLength, "CString::FreeExtra");
  637. if (GetData()->nDataLength != GetData()->nAllocLength)
  638. {
  639. CStringData<WCHAR>* pOldData = GetData();
  640. AllocBuffer(GetData()->nDataLength);
  641. memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(WCHAR));
  642. ASSERT(m_pchData[GetData()->nDataLength] == '\0', "CString::FreeExtra");
  643. CString::Release(pOldData);
  644. }
  645. ASSERT(GetData() != NULL, "CString::FreeExtra");
  646. }
  647. LPWSTR CString::LockBuffer()
  648. {
  649. LPWSTR lpsz = GetBuffer(0);
  650. GetData()->nRefs = -1;
  651. return lpsz;
  652. }
  653. void CString::UnlockBuffer()
  654. {
  655. ASSERT(GetData()->nRefs == -1, "CString::UnlockBuffer");
  656. if (GetData() != _afxDataNil)
  657. GetData()->nRefs = 1;
  658. }
  659. ///////////////////////////////////////////////////////////////////////////////
  660. // Commonly used routines (rarely used routines in STREX.CPP)
  661. int CString::Find(WCHAR ch) const
  662. {
  663. return Find(ch, 0);
  664. }
  665. int CString::Find(WCHAR ch, int nStart) const
  666. {
  667. int nLength = GetData()->nDataLength;
  668. if (nStart >= nLength)
  669. return -1;
  670. // find first single character
  671. LPWSTR lpsz = wcschr(m_pchData + nStart, (_TUCHAR)ch);
  672. // return -1 if not found and index otherwise
  673. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  674. }
  675. int CString::FindOneOf(LPCWSTR lpszCharSet) const
  676. {
  677. return FindOneOf(lpszCharSet, 0);
  678. }
  679. int CString::FindOneOf(LPCWSTR lpszCharSet, int nCount) const
  680. {
  681. ASSERT(AfxIsValidString(lpszCharSet), "CString::FindOneOf");
  682. LPCWSTR lpsz = wcspbrk(m_pchData + nCount, lpszCharSet);
  683. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  684. }
  685. int CString::FindOneNotOf(const WCHAR * lpszCharSet, int nCount) const
  686. {
  687. ASSERT(AfxIsValidString(lpszCharSet), "CString::FindOneNotOf");
  688. while (wcschr(lpszCharSet, m_pchData[nCount]))
  689. {
  690. nCount += 1;
  691. }
  692. if (nCount >= GetLength())
  693. {
  694. // entire string contains lpszCharSet
  695. return -1;
  696. }
  697. return nCount;
  698. }
  699. void CString::MakeUpper()
  700. {
  701. CopyBeforeWrite();
  702. _wcsupr(m_pchData);
  703. }
  704. void CString::MakeLower()
  705. {
  706. CopyBeforeWrite();
  707. _wcslwr(m_pchData);
  708. }
  709. void CString::MakeReverse()
  710. {
  711. CopyBeforeWrite();
  712. _wcsrev(m_pchData);
  713. }
  714. void CString::SetAt(int nIndex, WCHAR ch)
  715. {
  716. ASSERT(nIndex >= 0, "CString::SetAt");
  717. ASSERT(nIndex < GetData()->nDataLength, "CString::SetAt");
  718. CopyBeforeWrite();
  719. m_pchData[nIndex] = ch;
  720. }
  721. ///////////////////////////////////////////////////////////////////////////////
  722. // More sophisticated construction
  723. CString::CString(WCHAR ch, int nLength)
  724. {
  725. Init();
  726. if (nLength >= 1)
  727. {
  728. AllocBuffer(nLength);
  729. for (int i = 0; i < nLength; i++)
  730. m_pchData[i] = ch;
  731. }
  732. }
  733. CString::CString(int nLength)
  734. {
  735. Init();
  736. if (nLength >= 1)
  737. {
  738. AllocBuffer(nLength);
  739. GetData()->nDataLength = 0;
  740. }
  741. }
  742. CString::CString(LPCWSTR lpch, int nLength)
  743. {
  744. Init();
  745. if (nLength != 0)
  746. {
  747. ASSERT(AfxIsValidAddress(lpch, nLength, FALSE), "CString::CString(LPCWSTR lpch, int nLength)");
  748. AllocBuffer(nLength);
  749. memcpy(m_pchData, lpch, nLength*sizeof(WCHAR));
  750. }
  751. }
  752. /////////////////////////////////////////////////////////////////////////////
  753. // Special conversion constructors
  754. //////////////////////////////////////////////////////////////////////////////
  755. // Assignment operators
  756. const CString& CString::operator=(WCHAR ch)
  757. {
  758. AssignCopy(1, &ch);
  759. return *this;
  760. }
  761. //////////////////////////////////////////////////////////////////////////////
  762. // less common string expressions
  763. CString AFXAPI operator+(const CString& string1, WCHAR ch)
  764. {
  765. CString s;
  766. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  767. return s;
  768. }
  769. CString AFXAPI operator+(WCHAR ch, const CString& string)
  770. {
  771. CString s;
  772. s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  773. return s;
  774. }
  775. //////////////////////////////////////////////////////////////////////////////
  776. // Advanced manipulation
  777. int CString::Delete(int nIndex, int nCount /* = 1 */)
  778. {
  779. if (nIndex < 0)
  780. nIndex = 0;
  781. int nNewLength = GetData()->nDataLength;
  782. if (nCount > 0 && nIndex < nNewLength)
  783. {
  784. CopyBeforeWrite();
  785. int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
  786. memcpy(m_pchData + nIndex,
  787. m_pchData + nIndex + nCount, nBytesToCopy * sizeof(WCHAR));
  788. GetData()->nDataLength = nNewLength - nCount;
  789. }
  790. return nNewLength;
  791. }
  792. int CString::Insert(int nIndex, WCHAR ch)
  793. {
  794. CopyBeforeWrite();
  795. if (nIndex < 0)
  796. nIndex = 0;
  797. int nNewLength = GetData()->nDataLength;
  798. if (nIndex > nNewLength)
  799. nIndex = nNewLength;
  800. nNewLength++;
  801. if (GetData()->nAllocLength < nNewLength)
  802. {
  803. CStringData<WCHAR>* pOldData = GetData();
  804. LPWSTR pstr = m_pchData;
  805. AllocBuffer(nNewLength);
  806. memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(WCHAR));
  807. CString::Release(pOldData);
  808. }
  809. // move existing bytes down
  810. memcpy(m_pchData + nIndex + 1,
  811. m_pchData + nIndex, (nNewLength-nIndex)*sizeof(WCHAR));
  812. m_pchData[nIndex] = ch;
  813. GetData()->nDataLength = nNewLength;
  814. return nNewLength;
  815. }
  816. int CString::Insert(int nIndex, LPCWSTR pstr)
  817. {
  818. if (nIndex < 0)
  819. nIndex = 0;
  820. int nInsertLength = SafeStrlen(pstr);
  821. int nNewLength = GetData()->nDataLength;
  822. if (nInsertLength > 0)
  823. {
  824. CopyBeforeWrite();
  825. if (nIndex > nNewLength)
  826. nIndex = nNewLength;
  827. nNewLength += nInsertLength;
  828. if (GetData()->nAllocLength < nNewLength)
  829. {
  830. CStringData<WCHAR>* pOldData = GetData();
  831. LPWSTR lpwsz = m_pchData;
  832. AllocBuffer(nNewLength);
  833. memcpy(m_pchData, lpwsz, (pOldData->nDataLength+1)*sizeof(WCHAR));
  834. CString::Release(pOldData);
  835. }
  836. // move existing bytes down
  837. memcpy(m_pchData + nIndex + nInsertLength,
  838. m_pchData + nIndex,
  839. (nNewLength-nIndex-nInsertLength+1)*sizeof(WCHAR));
  840. memcpy(m_pchData + nIndex,
  841. pstr, nInsertLength*sizeof(WCHAR));
  842. GetData()->nDataLength = nNewLength;
  843. }
  844. return nNewLength;
  845. }
  846. int CString::Replace(WCHAR chOld, WCHAR chNew)
  847. {
  848. int nCount = 0;
  849. // short-circuit the nop case
  850. if (chOld != chNew)
  851. {
  852. // otherwise modify each character that matches in the string
  853. CopyBeforeWrite();
  854. LPWSTR psz = m_pchData;
  855. LPWSTR pszEnd = psz + GetData()->nDataLength;
  856. while (psz < pszEnd)
  857. {
  858. // replace instances of the specified character only
  859. if (*psz == chOld)
  860. {
  861. *psz = chNew;
  862. nCount++;
  863. }
  864. psz = wcsinc(psz);
  865. }
  866. }
  867. return nCount;
  868. }
  869. int CString::Replace(LPCWSTR lpszOld, LPCWSTR lpszNew)
  870. {
  871. return ReplaceRoutine(lpszOld, lpszNew, wcsstr);
  872. }
  873. int CString::ReplaceI(LPCWSTR lpszOld, LPCWSTR lpszNew)
  874. {
  875. return ReplaceRoutine(lpszOld, lpszNew, wcsistr);
  876. }
  877. int CString::ReplaceRoutine(LPCWSTR lpszOld, LPCWSTR lpszNew, _pfn_wcsstr tcsstr)
  878. {
  879. // can't have empty or NULL lpszOld
  880. int nSourceLen = SafeStrlen(lpszOld);
  881. if (nSourceLen == 0)
  882. return 0;
  883. int nReplacementLen = SafeStrlen(lpszNew);
  884. // loop once to figure out the size of the result string
  885. int nCount = 0;
  886. LPWSTR lpszStart = m_pchData;
  887. LPWSTR lpszEnd = m_pchData + GetData()->nDataLength;
  888. LPWSTR lpszTarget;
  889. while (lpszStart < lpszEnd)
  890. {
  891. while ((lpszTarget = tcsstr(lpszStart, lpszOld)) != NULL)
  892. {
  893. nCount++;
  894. lpszStart = lpszTarget + nSourceLen;
  895. }
  896. lpszStart += wcslen(lpszStart) + 1;
  897. }
  898. // if any changes were made, make them
  899. if (nCount > 0)
  900. {
  901. CopyBeforeWrite();
  902. // if the buffer is too small, just
  903. // allocate a new buffer (slow but sure)
  904. int nOldLength = GetData()->nDataLength;
  905. int nNewLength = nOldLength + (nReplacementLen-nSourceLen)*nCount;
  906. if (GetData()->nAllocLength < nNewLength + 1 || GetData()->nRefs > 1)
  907. {
  908. CStringData<WCHAR>* pOldData = GetData();
  909. LPWSTR pstr = m_pchData;
  910. AllocBuffer(nNewLength);
  911. memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(WCHAR));
  912. CString::Release(pOldData);
  913. }
  914. // else, we just do it in-place
  915. lpszStart = m_pchData;
  916. lpszEnd = m_pchData + GetData()->nDataLength;
  917. // loop again to actually do the work
  918. while (lpszStart < lpszEnd)
  919. {
  920. while ( (lpszTarget = wcsstr(lpszStart, lpszOld)) != NULL)
  921. {
  922. int nBalance = nOldLength - ((int)(lpszTarget - m_pchData) + nSourceLen);
  923. memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen,
  924. nBalance * sizeof(WCHAR));
  925. memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(WCHAR));
  926. lpszStart = lpszTarget + nReplacementLen;
  927. lpszStart[nBalance] = '\0';
  928. nOldLength += (nReplacementLen - nSourceLen);
  929. }
  930. lpszStart += wcslen(lpszStart) + 1;
  931. }
  932. ASSERT(m_pchData[nNewLength] == '\0', "CString::ReplaceRoutine");
  933. GetData()->nDataLength = nNewLength;
  934. }
  935. return nCount;
  936. }
  937. int CString::Remove(WCHAR chRemove)
  938. {
  939. CopyBeforeWrite();
  940. LPWSTR pstrSource = m_pchData;
  941. LPWSTR pstrDest = m_pchData;
  942. LPWSTR pstrEnd = m_pchData + GetData()->nDataLength;
  943. while (pstrSource < pstrEnd)
  944. {
  945. if (*pstrSource != chRemove)
  946. {
  947. *pstrDest = *pstrSource;
  948. pstrDest = wcsinc(pstrDest);
  949. }
  950. pstrSource = wcsinc(pstrSource);
  951. }
  952. *pstrDest = '\0';
  953. int nCount = (int)(pstrSource - pstrDest);
  954. GetData()->nDataLength -= nCount;
  955. return nCount;
  956. }
  957. //////////////////////////////////////////////////////////////////////////////
  958. // Very simple sub-string extraction
  959. CString CString::Mid(int nFirst) const
  960. {
  961. return Mid(nFirst, GetData()->nDataLength - nFirst);
  962. }
  963. CString CString::Mid(int nFirst, int nCount) const
  964. {
  965. CString dest;
  966. Mid(nFirst, nCount, dest);
  967. return dest;
  968. }
  969. CString CString::Right(int nCount) const
  970. {
  971. CString dest;
  972. Right(nCount, dest);
  973. return dest;
  974. }
  975. CString CString::Left(int nCount) const
  976. {
  977. CString dest;
  978. Left(nCount, dest);
  979. return dest;
  980. }
  981. // strspn equivalent
  982. CString CString::SpanIncluding(LPCWSTR lpszCharSet) const
  983. {
  984. ASSERT(AfxIsValidString(lpszCharSet), "CString::SpanIncluding");
  985. return Left(wcsspn(m_pchData, lpszCharSet));
  986. }
  987. // strcspn equivalent
  988. CString CString::SpanExcluding(LPCWSTR lpszCharSet) const
  989. {
  990. ASSERT(AfxIsValidString(lpszCharSet), "CString::SpanIncluding");
  991. return Left(wcscspn(m_pchData, lpszCharSet));
  992. }
  993. void CString::Mid(int nFirst, CString & csMid) const
  994. {
  995. Mid(nFirst, GetData()->nDataLength - nFirst, csMid);
  996. }
  997. void CString::Mid(int nFirst, int nCount, CString & csMid) const
  998. {
  999. // out-of-bounds requests return sensible things
  1000. if (nFirst < 0)
  1001. nFirst = 0;
  1002. if (nCount < 0)
  1003. nCount = 0;
  1004. if (nFirst + nCount > GetData()->nDataLength)
  1005. nCount = GetData()->nDataLength - nFirst;
  1006. if (nFirst > GetData()->nDataLength)
  1007. nCount = 0;
  1008. ASSERT(nFirst >= 0, "CString::Mid(int nFirst, int nCount)");
  1009. ASSERT(nFirst + nCount <= GetData()->nDataLength, "CString::Mid(int nFirst, int nCount)");
  1010. // optimize case of returning entire string
  1011. if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
  1012. {
  1013. csMid = *this;
  1014. return;
  1015. }
  1016. AllocCopy(csMid, nCount, nFirst, 0);
  1017. }
  1018. void CString::Right(int nCount, CString & csRight) const
  1019. {
  1020. if (nCount < 0)
  1021. nCount = 0;
  1022. if (nCount >= GetData()->nDataLength)
  1023. return;
  1024. AllocCopy(csRight, nCount, GetData()->nDataLength-nCount, 0);
  1025. }
  1026. void CString::Left(int nCount, CString & csLeft) const
  1027. {
  1028. if (nCount < 0)
  1029. nCount = 0;
  1030. if (nCount >= GetData()->nDataLength)
  1031. return;
  1032. AllocCopy(csLeft, nCount, 0, 0);
  1033. }
  1034. void CString::SpanIncluding(const WCHAR * lpszCharSet, CString & csSpanInc) const
  1035. {
  1036. ASSERT(AfxIsValidString(lpszCharSet), "CString::SpanIncluding");
  1037. return Left(wcsspn(m_pchData, lpszCharSet), csSpanInc);
  1038. }
  1039. void CString::SpanExcluding(const WCHAR * lpszCharSet, CString & csSpanExc) const
  1040. {
  1041. ASSERT(AfxIsValidString(lpszCharSet), "CString::SpanIncluding");
  1042. return Left(wcscspn(m_pchData, lpszCharSet), csSpanExc);
  1043. }
  1044. //////////////////////////////////////////////////////////////////////////////
  1045. // Finding
  1046. int CString::ReverseFind(WCHAR ch) const
  1047. {
  1048. // find last single character
  1049. LPCWSTR lpsz = wcsrchr(m_pchData, (_TUCHAR) ch);
  1050. // return -1 if not found, distance from beginning otherwise
  1051. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1052. }
  1053. // find a sub-string (like strstr)
  1054. int CString::Find(LPCWSTR lpszSub) const
  1055. {
  1056. return Find(lpszSub, 0);
  1057. }
  1058. int CString::Find(LPCWSTR lpszSub, int nStart) const
  1059. {
  1060. ASSERT(AfxIsValidString(lpszSub), "CString::Find");
  1061. int nLength = GetData()->nDataLength;
  1062. if (nStart > nLength)
  1063. return -1;
  1064. // find first matching substring
  1065. LPWSTR lpsz = wcsstr(m_pchData + nStart, lpszSub);
  1066. // return -1 for not found, distance from beginning otherwise
  1067. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1068. }
  1069. /////////////////////////////////////////////////////////////////////////////
  1070. // CString formatting
  1071. #define TCHAR_ARG WCHAR
  1072. #define WCHAR_ARG WCHAR
  1073. #define CHAR_ARG WCHAR
  1074. #ifdef _X86_
  1075. #define DOUBLE_ARG _AFX_DOUBLE
  1076. #else
  1077. #define DOUBLE_ARG double
  1078. #endif
  1079. #define FORCE_ANSI 0x10000
  1080. #define FORCE_UNICODE 0x20000
  1081. #define FORCE_INT64 0x40000
  1082. void CString::FormatV(LPCWSTR lpszFormat, va_list argList)
  1083. {
  1084. ASSERT(AfxIsValidString(lpszFormat), "CString::FormatV");
  1085. va_list argListSave = argList;
  1086. // make a guess at the maximum length of the resulting string
  1087. int nMaxLen = 0;
  1088. for (LPCWSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = wcsinc(lpsz))
  1089. {
  1090. // handle '%' character, but watch out for '%%'
  1091. if (*lpsz != '%' || *(lpsz = wcsinc(lpsz)) == '%')
  1092. {
  1093. nMaxLen += 1;
  1094. continue;
  1095. }
  1096. int nItemLen = 0;
  1097. // handle '%' character with format
  1098. int nWidth = 0;
  1099. for (; *lpsz != '\0'; lpsz = wcsinc(lpsz))
  1100. {
  1101. // check for valid flags
  1102. if (*lpsz == '#')
  1103. nMaxLen += 2; // for '0x'
  1104. else if (*lpsz == '*')
  1105. nWidth = va_arg(argList, int);
  1106. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  1107. *lpsz == ' ')
  1108. ;
  1109. else // hit non-flag character
  1110. break;
  1111. }
  1112. // get width and skip it
  1113. if (nWidth == 0)
  1114. {
  1115. // width indicated by
  1116. nWidth = _wtoi(lpsz);
  1117. for (; *lpsz != '\0' && iswdigit(*lpsz); lpsz = wcsinc(lpsz))
  1118. ;
  1119. }
  1120. ASSERT(nWidth >= 0, "CString::FormatV");
  1121. int nPrecision = 0;
  1122. if (*lpsz == '.')
  1123. {
  1124. // skip past '.' separator (width.precision)
  1125. lpsz = wcsinc(lpsz);
  1126. // get precision and skip it
  1127. if (*lpsz == '*')
  1128. {
  1129. nPrecision = va_arg(argList, int);
  1130. lpsz = wcsinc(lpsz);
  1131. }
  1132. else
  1133. {
  1134. nPrecision = _wtoi(lpsz);
  1135. for (; *lpsz != '\0' && iswdigit(*lpsz); lpsz = wcsinc(lpsz))
  1136. ;
  1137. }
  1138. ASSERT(nPrecision >= 0, "CString::FormatV");
  1139. }
  1140. // should be on type modifier or specifier
  1141. int nModifier = 0;
  1142. if (wcsncmp(lpsz, L"I64", 3) == 0)
  1143. {
  1144. lpsz += 3;
  1145. nModifier = FORCE_INT64;
  1146. #if !defined(_X86_) && !defined(_ALPHA_)
  1147. // __int64 is only available on X86 and ALPHA platforms
  1148. ASSERT(FALSE, "CString::FormatV");
  1149. #endif
  1150. }
  1151. else
  1152. {
  1153. switch (*lpsz)
  1154. {
  1155. // modifiers that affect size
  1156. case 'h':
  1157. nModifier = FORCE_ANSI;
  1158. lpsz = wcsinc(lpsz);
  1159. break;
  1160. case 'l':
  1161. nModifier = FORCE_UNICODE;
  1162. lpsz = wcsinc(lpsz);
  1163. break;
  1164. // modifiers that do not affect size
  1165. case 'F':
  1166. case 'N':
  1167. case 'L':
  1168. lpsz = wcsinc(lpsz);
  1169. break;
  1170. }
  1171. }
  1172. // now should be on specifier
  1173. switch (*lpsz | nModifier)
  1174. {
  1175. // single characters
  1176. case 'c':
  1177. case 'C':
  1178. nItemLen = 2;
  1179. va_arg(argList, TCHAR_ARG);
  1180. break;
  1181. case 'c'|FORCE_ANSI:
  1182. case 'C'|FORCE_ANSI:
  1183. nItemLen = 2;
  1184. va_arg(argList, CHAR_ARG);
  1185. break;
  1186. case 'c'|FORCE_UNICODE:
  1187. case 'C'|FORCE_UNICODE:
  1188. nItemLen = 2;
  1189. va_arg(argList, WCHAR_ARG);
  1190. break;
  1191. // strings
  1192. case 's':
  1193. {
  1194. LPCWSTR pstrNextArg = va_arg(argList, LPCWSTR);
  1195. if (pstrNextArg == NULL)
  1196. nItemLen = 6; // "(null)"
  1197. else
  1198. {
  1199. nItemLen = wcslen(pstrNextArg);
  1200. nItemLen = max(1, nItemLen);
  1201. }
  1202. }
  1203. break;
  1204. case 'S':
  1205. {
  1206. #ifndef _UNICODE
  1207. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  1208. if (pstrNextArg == NULL)
  1209. nItemLen = 6; // "(null)"
  1210. else
  1211. {
  1212. nItemLen = wcslen(pstrNextArg);
  1213. nItemLen = max(1, nItemLen);
  1214. }
  1215. #else
  1216. LPCWSTR pstrNextArg = va_arg(argList, LPCWSTR);
  1217. if (pstrNextArg == NULL)
  1218. nItemLen = 6; // "(null)"
  1219. else
  1220. {
  1221. nItemLen = wcslenChars(pstrNextArg);
  1222. nItemLen = max(1, nItemLen);
  1223. }
  1224. #endif
  1225. }
  1226. break;
  1227. case 's'|FORCE_ANSI:
  1228. case 'S'|FORCE_ANSI:
  1229. {
  1230. LPCWSTR pstrNextArg = va_arg(argList, LPCWSTR);
  1231. if (pstrNextArg == NULL)
  1232. nItemLen = 6; // "(null)"
  1233. else
  1234. {
  1235. nItemLen = wcslen(pstrNextArg);
  1236. nItemLen = max(1, nItemLen);
  1237. }
  1238. }
  1239. break;
  1240. case 's'|FORCE_UNICODE:
  1241. case 'S'|FORCE_UNICODE:
  1242. {
  1243. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  1244. if (pstrNextArg == NULL)
  1245. nItemLen = 6; // "(null)"
  1246. else
  1247. {
  1248. nItemLen = wcslen(pstrNextArg);
  1249. nItemLen = max(1, nItemLen);
  1250. }
  1251. }
  1252. break;
  1253. }
  1254. // adjust nItemLen for strings
  1255. if (nItemLen != 0)
  1256. {
  1257. if (nPrecision != 0)
  1258. nItemLen = min(nItemLen, nPrecision);
  1259. nItemLen = max(nItemLen, nWidth);
  1260. }
  1261. else
  1262. {
  1263. switch (*lpsz)
  1264. {
  1265. // integers
  1266. case 'd':
  1267. case 'i':
  1268. case 'u':
  1269. case 'x':
  1270. case 'X':
  1271. case 'o':
  1272. if (nModifier & FORCE_INT64)
  1273. va_arg(argList, __int64);
  1274. else
  1275. va_arg(argList, int);
  1276. nItemLen = 32;
  1277. nItemLen = max(nItemLen, nWidth+nPrecision);
  1278. break;
  1279. case 'e':
  1280. case 'g':
  1281. case 'G':
  1282. va_arg(argList, DOUBLE_ARG);
  1283. nItemLen = 128;
  1284. nItemLen = max(nItemLen, nWidth+nPrecision);
  1285. break;
  1286. case 'f':
  1287. va_arg(argList, DOUBLE_ARG);
  1288. nItemLen = 128; // width isn't truncated
  1289. // 312 == strlen("-1+(309 zeroes).")
  1290. // 309 zeroes == max precision of a double
  1291. nItemLen = max(nItemLen, 312+nPrecision);
  1292. break;
  1293. case 'p':
  1294. va_arg(argList, void*);
  1295. nItemLen = 32;
  1296. nItemLen = max(nItemLen, nWidth+nPrecision);
  1297. break;
  1298. // no output
  1299. case 'n':
  1300. va_arg(argList, int*);
  1301. break;
  1302. default:
  1303. ASSERT(FALSE, "CString::FormatV"); // unknown formatting option
  1304. }
  1305. }
  1306. // adjust nMaxLen for output nItemLen
  1307. nMaxLen += nItemLen;
  1308. }
  1309. GetBuffer(nMaxLen);
  1310. int nChars = _vsnwprintf(m_pchData, nMaxLen, lpszFormat, argListSave);
  1311. ASSERT(nChars <= GetAllocLength(), "CString::FormatV");
  1312. ReleaseBuffer();
  1313. va_end(argListSave);
  1314. }
  1315. // formatting (using wsprintf style formatting)
  1316. void AFX_CDECL CString::Format(LPCWSTR lpszFormat, ...)
  1317. {
  1318. ASSERT(AfxIsValidString(lpszFormat), "CString::Format");
  1319. va_list argList;
  1320. va_start(argList, lpszFormat);
  1321. FormatV(lpszFormat, argList);
  1322. va_end(argList);
  1323. }
  1324. // formatting (using FormatMessage style formatting)
  1325. void AFX_CDECL CString::FormatMessage(LPCWSTR lpszFormat, ...)
  1326. {
  1327. // format message into temporary buffer lpszTemp
  1328. va_list argList;
  1329. va_start(argList, lpszFormat);
  1330. LPWSTR lpszTemp;
  1331. if (::FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1332. lpszFormat, 0, 0, (LPWSTR)&lpszTemp, 0, &argList) == 0 ||
  1333. lpszTemp == NULL)
  1334. {
  1335. CSTRING_THROW_EXCEPTION
  1336. }
  1337. else
  1338. {
  1339. // assign lpszTemp into the resulting string and free the temporary
  1340. *this = lpszTemp;
  1341. LocalFree(lpszTemp);
  1342. va_end(argList);
  1343. }
  1344. }
  1345. void CString::TrimRight(LPCWSTR lpszTargetList)
  1346. {
  1347. // find beginning of trailing matches
  1348. // by starting at beginning (DBCS aware)
  1349. CopyBeforeWrite();
  1350. LPWSTR lpsz = m_pchData;
  1351. LPWSTR lpszLast = NULL;
  1352. while (*lpsz != '\0')
  1353. {
  1354. if (wcschr(lpszTargetList, *lpsz) != NULL)
  1355. {
  1356. if (lpszLast == NULL)
  1357. lpszLast = lpsz;
  1358. }
  1359. else
  1360. lpszLast = NULL;
  1361. lpsz = wcsinc(lpsz);
  1362. }
  1363. if (lpszLast != NULL)
  1364. {
  1365. // truncate at left-most matching character
  1366. *lpszLast = '\0';
  1367. GetData()->nDataLength = (int)(lpszLast - m_pchData);
  1368. }
  1369. }
  1370. void CString::TrimRight(WCHAR chTarget)
  1371. {
  1372. // find beginning of trailing matches
  1373. // by starting at beginning (DBCS aware)
  1374. CopyBeforeWrite();
  1375. LPWSTR lpsz = m_pchData;
  1376. LPWSTR lpszLast = NULL;
  1377. while (*lpsz != '\0')
  1378. {
  1379. if (*lpsz == chTarget)
  1380. {
  1381. if (lpszLast == NULL)
  1382. lpszLast = lpsz;
  1383. }
  1384. else
  1385. lpszLast = NULL;
  1386. lpsz = wcsinc(lpsz);
  1387. }
  1388. if (lpszLast != NULL)
  1389. {
  1390. // truncate at left-most matching character
  1391. *lpszLast = '\0';
  1392. GetData()->nDataLength = (int)(lpszLast - m_pchData);
  1393. }
  1394. }
  1395. void CString::TrimRight()
  1396. {
  1397. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  1398. CopyBeforeWrite();
  1399. LPWSTR lpsz = m_pchData;
  1400. LPWSTR lpszLast = NULL;
  1401. while (*lpsz != '\0')
  1402. {
  1403. if (iswspace(*lpsz))
  1404. {
  1405. if (lpszLast == NULL)
  1406. lpszLast = lpsz;
  1407. }
  1408. else
  1409. lpszLast = NULL;
  1410. lpsz = wcsinc(lpsz);
  1411. }
  1412. if (lpszLast != NULL)
  1413. {
  1414. // truncate at trailing space start
  1415. *lpszLast = '\0';
  1416. GetData()->nDataLength = (int)(lpszLast - m_pchData);
  1417. }
  1418. }
  1419. void CString::TrimLeft(LPCWSTR lpszTargets)
  1420. {
  1421. // if we're not trimming anything, we're not doing any work
  1422. if (SafeStrlen(lpszTargets) == 0)
  1423. return;
  1424. CopyBeforeWrite();
  1425. LPCWSTR lpsz = m_pchData;
  1426. while (*lpsz != '\0')
  1427. {
  1428. if (wcschr(lpszTargets, *lpsz) == NULL)
  1429. break;
  1430. lpsz = wcsinc(lpsz);
  1431. }
  1432. if (lpsz != m_pchData)
  1433. {
  1434. // fix up data and length
  1435. int nDataLength = GetData()->nDataLength - (int)(lpsz - m_pchData);
  1436. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(WCHAR));
  1437. GetData()->nDataLength = nDataLength;
  1438. }
  1439. }
  1440. void CString::TrimLeft(WCHAR chTarget)
  1441. {
  1442. // find first non-matching character
  1443. CopyBeforeWrite();
  1444. LPCWSTR lpsz = m_pchData;
  1445. while (chTarget == *lpsz)
  1446. lpsz = wcsinc(lpsz);
  1447. if (lpsz != m_pchData)
  1448. {
  1449. // fix up data and length
  1450. int nDataLength = GetData()->nDataLength - (int)(lpsz - m_pchData);
  1451. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(WCHAR));
  1452. GetData()->nDataLength = nDataLength;
  1453. }
  1454. }
  1455. void CString::TrimLeft()
  1456. {
  1457. // find first non-space character
  1458. CopyBeforeWrite();
  1459. LPCWSTR lpsz = m_pchData;
  1460. while (iswspace(*lpsz))
  1461. lpsz = wcsinc(lpsz);
  1462. if (lpsz != m_pchData)
  1463. {
  1464. // fix up data and length
  1465. int nDataLength = GetData()->nDataLength - (int)(lpsz - m_pchData);
  1466. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(WCHAR));
  1467. GetData()->nDataLength = nDataLength;
  1468. }
  1469. }
  1470. void CString::SplitPath(
  1471. CString * csDrive,
  1472. CString * csDir,
  1473. CString * csName,
  1474. CString * csExt) const
  1475. {
  1476. WCHAR * drive = NULL;
  1477. WCHAR * dir = NULL;
  1478. WCHAR * name = NULL;
  1479. WCHAR * ext = NULL;
  1480. if (csDrive)
  1481. {
  1482. drive = csDrive->GetBuffer(_MAX_DRIVE);
  1483. }
  1484. if (csDir)
  1485. {
  1486. dir = csDir->GetBuffer(_MAX_DIR);
  1487. }
  1488. if (csName)
  1489. {
  1490. name = csName->GetBuffer(_MAX_FNAME);
  1491. }
  1492. if (csExt)
  1493. {
  1494. ext = csExt->GetBuffer(_MAX_EXT);
  1495. }
  1496. _wsplitpath(Get(), drive, dir, name, ext);
  1497. if (csDrive)
  1498. {
  1499. csDrive->ReleaseBuffer(-1);
  1500. }
  1501. if (csDir)
  1502. {
  1503. csDir->ReleaseBuffer(-1);
  1504. }
  1505. if (csName)
  1506. {
  1507. csName->ReleaseBuffer(-1);
  1508. }
  1509. if (csExt)
  1510. {
  1511. csExt->ReleaseBuffer(-1);
  1512. }
  1513. }
  1514. void CString::MakePath(
  1515. const CString * csDrive,
  1516. const CString * csDir,
  1517. const CString * csName,
  1518. const CString * csExt)
  1519. {
  1520. Truncate(0);
  1521. if (csDrive && !csDrive->IsEmpty())
  1522. {
  1523. ConcatInPlace(SafeStrlen(csDrive->Get()), csDrive->Get());
  1524. }
  1525. if (csDir && !csDir->IsEmpty())
  1526. {
  1527. ConcatInPlace(SafeStrlen(csDir->Get()), csDir->Get());
  1528. }
  1529. if (csName && !csName->IsEmpty())
  1530. {
  1531. // Make sure there is a \ between the two
  1532. if (!IsEmpty() && !IsPathSep(GetLength()) && !csName->IsPathSep(0) )
  1533. {
  1534. ConcatInPlace(1, L"\\");
  1535. }
  1536. ConcatInPlace(SafeStrlen(csName->Get()), csName->Get());
  1537. }
  1538. if (csExt && !csExt->IsEmpty())
  1539. {
  1540. // Make sure the extension has a dot
  1541. if (csExt->GetAt(0) != L'.')
  1542. {
  1543. ConcatInPlace(1, L".");
  1544. }
  1545. ConcatInPlace(SafeStrlen(csExt->Get()), csExt->Get());
  1546. }
  1547. }
  1548. void CString::AppendPath(const WCHAR * lpszPath)
  1549. {
  1550. int nLen = GetLength();
  1551. BOOL bThisHasSep = (nLen > 0) ? IsPathSep(nLen - 1) : FALSE;
  1552. BOOL bThatHasSep = ShimLib::IsPathSep(*lpszPath);
  1553. if (lpszPath == NULL || *lpszPath == 0)
  1554. {
  1555. return;
  1556. }
  1557. else if (nLen == 0)
  1558. {
  1559. // No path seperator is necessary
  1560. }
  1561. else if ((nLen == 2) && (GetAt(1) == L':') && !bThatHasSep )
  1562. {
  1563. // We must place a path seperator between the two
  1564. ConcatInPlace(1, L"\\");
  1565. }
  1566. else if (!bThisHasSep && !bThatHasSep )
  1567. {
  1568. // We must place a path seperator between the two
  1569. ConcatInPlace(1, L"\\");
  1570. }
  1571. else if (bThisHasSep && bThatHasSep )
  1572. {
  1573. // Both have seperators, remove one
  1574. do
  1575. {
  1576. lpszPath += 1;
  1577. }
  1578. while (ShimLib::IsPathSep(*lpszPath));
  1579. }
  1580. ConcatInPlace(SafeStrlen(lpszPath), lpszPath);
  1581. }
  1582. // Find the trailing path component
  1583. // Return index of the last path seperator or -1 if none found
  1584. int CString::FindLastPathComponent() const
  1585. {
  1586. for (int nLen = GetLength() - 1; nLen >= 0; --nLen)
  1587. {
  1588. if (IsPathSep(nLen))
  1589. {
  1590. return nLen;
  1591. }
  1592. }
  1593. return -1;
  1594. }
  1595. // Remove the trailing path component from the string
  1596. void CString::StripPath()
  1597. {
  1598. int nLastPathComponent = FindLastPathComponent();
  1599. if (nLastPathComponent != -1)
  1600. {
  1601. Truncate(nLastPathComponent);
  1602. }
  1603. else
  1604. {
  1605. Truncate(0);
  1606. }
  1607. }
  1608. char * CString::GetAnsi() const
  1609. {
  1610. // Since we don't know if the original (WCHAR) data has changed
  1611. // we need to update the ansi string each time.
  1612. if (m_pchDataAnsi)
  1613. {
  1614. free(m_pchDataAnsi);
  1615. m_pchDataAnsi = NULL;
  1616. }
  1617. // Get the number of bytes necessary for the WCHAR string
  1618. int nBytes = WideCharToMultiByte(CP_ACP, 0, m_pchData, -1, NULL, 0, NULL, NULL);
  1619. m_pchDataAnsi = (char *) malloc(nBytes);
  1620. if (m_pchDataAnsi)
  1621. {
  1622. WideCharToMultiByte(CP_ACP, 0, m_pchData, -1, m_pchDataAnsi, nBytes, NULL, NULL);
  1623. }
  1624. else
  1625. {
  1626. CSTRING_THROW_EXCEPTION
  1627. }
  1628. return m_pchDataAnsi;
  1629. }
  1630. void CString::GetLastPathComponent(CString & pathComponent) const
  1631. {
  1632. int nPath = FindLastPathComponent();
  1633. if (nPath < 0)
  1634. {
  1635. pathComponent = *this;
  1636. }
  1637. else
  1638. {
  1639. Mid(nPath+1, pathComponent);
  1640. }
  1641. }
  1642. // Get what's not the "file" portion of this path
  1643. void CString::GetNotLastPathComponent(CString & pathComponent) const
  1644. {
  1645. int nPath = FindLastPathComponent();
  1646. if (nPath < 1)
  1647. {
  1648. pathComponent.Truncate(0);
  1649. }
  1650. else
  1651. {
  1652. Left(nPath, pathComponent);
  1653. }
  1654. }
  1655. // Get the Drive portion of this path,
  1656. // Either C: or \\server\disk format.
  1657. void CString::GetDrivePortion(CString & csDrivePortion) const
  1658. {
  1659. const WCHAR * lpwszPath = Get();
  1660. const WCHAR * lpwszNonDrivePortion = ShimLib::GetDrivePortion(lpwszPath);
  1661. if (lpwszPath == lpwszNonDrivePortion)
  1662. {
  1663. csDrivePortion.Truncate(0);
  1664. }
  1665. else
  1666. {
  1667. Left((int)(lpwszNonDrivePortion - lpwszPath), csDrivePortion);
  1668. }
  1669. }
  1670. DWORD CString::GetModuleFileNameW(
  1671. HMODULE hModule // handle to module
  1672. )
  1673. {
  1674. // Force the size to MAX_PATH because there is no way to determine necessary buffer size.
  1675. WCHAR * lpsz = GetBuffer(MAX_PATH);
  1676. DWORD dwChars = ::GetModuleFileNameW(hModule, lpsz, MAX_PATH);
  1677. ReleaseBuffer(dwChars);
  1678. return dwChars;
  1679. }
  1680. DWORD CString::GetSystemDirectoryW(void)
  1681. {
  1682. UINT dwChars = ::GetSystemDirectoryW(NULL, 0);
  1683. if (dwChars)
  1684. {
  1685. dwChars += 1; // One for the NULL
  1686. // Get a pointer to the actual lpsz data
  1687. WCHAR * lpszPath = GetBuffer(dwChars);
  1688. dwChars = ::GetSystemDirectoryW(lpszPath, dwChars);
  1689. ReleaseBuffer(dwChars);
  1690. }
  1691. else
  1692. {
  1693. Truncate(0);
  1694. }
  1695. return dwChars;
  1696. }
  1697. UINT CString::GetSystemWindowsDirectoryW(void)
  1698. {
  1699. UINT dwChars = ::GetSystemWindowsDirectoryW(NULL, 0);
  1700. if (dwChars)
  1701. {
  1702. dwChars += 1; // One for the NULL
  1703. // Get a pointer to the actual lpsz data
  1704. WCHAR * lpszPath = GetBuffer(dwChars);
  1705. dwChars = ::GetSystemWindowsDirectoryW(lpszPath, dwChars);
  1706. ReleaseBuffer(dwChars);
  1707. }
  1708. else
  1709. {
  1710. Truncate(0);
  1711. }
  1712. return dwChars;
  1713. }
  1714. DWORD CString::GetWindowsDirectoryW(void)
  1715. {
  1716. UINT dwChars = ::GetWindowsDirectoryW(NULL, 0);
  1717. if (dwChars)
  1718. {
  1719. dwChars += 1; // One for the NULL
  1720. // Get a pointer to the actual lpsz data
  1721. WCHAR * lpszPath = GetBuffer(dwChars);
  1722. dwChars = ::GetWindowsDirectoryW(lpszPath, dwChars);
  1723. ReleaseBuffer(dwChars);
  1724. }
  1725. else
  1726. {
  1727. Truncate(0);
  1728. }
  1729. return dwChars;
  1730. }
  1731. DWORD CString::GetShortPathNameW(void)
  1732. {
  1733. DWORD dwChars = ::GetShortPathNameW(Get(), NULL, 0);
  1734. if (dwChars)
  1735. {
  1736. dwChars += 1; // One for the NULL
  1737. CString csCopy(*this);
  1738. // Get a pointer to the actual lpsz data
  1739. WCHAR * lpszPath = GetBuffer(dwChars);
  1740. dwChars = ::GetShortPathNameW(csCopy, lpszPath, dwChars);
  1741. ReleaseBuffer(dwChars);
  1742. }
  1743. return dwChars;
  1744. }
  1745. DWORD CString::GetLongPathNameW(void)
  1746. {
  1747. DWORD dwChars = ::GetLongPathNameW(Get(), NULL, 0);
  1748. if (dwChars)
  1749. {
  1750. dwChars += 1; // One for the NULL
  1751. CString csCopy(*this);
  1752. // Get a pointer to the actual lpsz data
  1753. WCHAR * lpszPath = GetBuffer(dwChars);
  1754. dwChars = ::GetLongPathNameW(csCopy, lpszPath, dwChars);
  1755. ReleaseBuffer(dwChars);
  1756. }
  1757. return dwChars;
  1758. }
  1759. DWORD CString::GetFullPathNameW(void)
  1760. {
  1761. DWORD dwChars = ::GetFullPathNameW(Get(), 0, NULL, NULL);
  1762. if (dwChars)
  1763. {
  1764. dwChars += 1; // One for the NULL
  1765. CString csCopy(*this);
  1766. // Get a pointer to the actual lpsz data
  1767. WCHAR * lpszPath = GetBuffer(dwChars);
  1768. dwChars = ::GetFullPathNameW(csCopy, dwChars, lpszPath, NULL);
  1769. ReleaseBuffer(dwChars);
  1770. }
  1771. return dwChars;
  1772. }
  1773. DWORD CString::GetTempPathW(void)
  1774. {
  1775. DWORD dwChars = ::GetTempPathW(0, NULL);
  1776. if (dwChars)
  1777. {
  1778. dwChars += 1; // One for the NULL
  1779. // Get a pointer to the actual lpsz data
  1780. WCHAR * lpszPath = GetBuffer(dwChars);
  1781. dwChars = ::GetTempPathW(dwChars, lpszPath);
  1782. ReleaseBuffer(dwChars);
  1783. }
  1784. else
  1785. {
  1786. Truncate(0);
  1787. }
  1788. return dwChars;
  1789. }
  1790. UINT CString::GetTempFileNameW(
  1791. LPCWSTR lpPathName, // directory name
  1792. LPCWSTR lpPrefixString, // file name prefix
  1793. UINT uUnique // integer
  1794. )
  1795. {
  1796. WCHAR * lpsz = GetBuffer(MAX_PATH);
  1797. DWORD dwChars = ::GetTempFileNameW(lpPathName, lpPrefixString, uUnique, lpsz);
  1798. ReleaseBuffer(dwChars);
  1799. return dwChars;
  1800. }
  1801. DWORD CString::GetCurrentDirectoryW(void)
  1802. {
  1803. DWORD dwChars = ::GetCurrentDirectory(0, NULL);
  1804. if (dwChars)
  1805. {
  1806. dwChars += 1; // One for the NULL
  1807. // Get a pointer to the actual lpsz data
  1808. WCHAR * lpsz = GetBuffer(dwChars);
  1809. dwChars = ::GetCurrentDirectoryW(dwChars, lpsz);
  1810. ReleaseBuffer(dwChars);
  1811. }
  1812. else
  1813. {
  1814. Truncate(0);
  1815. }
  1816. return dwChars;
  1817. }
  1818. DWORD CString::ExpandEnvironmentStringsW( )
  1819. {
  1820. DWORD dwChars = ::ExpandEnvironmentStringsW(Get(), NULL, 0);
  1821. if (dwChars)
  1822. {
  1823. dwChars += 1; // One for the NULL
  1824. CString csCopy(*this);
  1825. // Get a pointer to the actual lpsz data
  1826. WCHAR * lpszPath = GetBuffer(dwChars);
  1827. dwChars = ::ExpandEnvironmentStringsW(csCopy, lpszPath, dwChars);
  1828. ReleaseBuffer(dwChars-1);
  1829. }
  1830. return dwChars;
  1831. }
  1832. // delete all characters to the right of nIndex
  1833. void CString::Truncate(int nIndex)
  1834. {
  1835. ASSERT(nIndex >= 0, "CString::Truncate");
  1836. if (nIndex < GetLength())
  1837. {
  1838. SetAt(nIndex, L'\0');
  1839. GetData()->nDataLength = nIndex;
  1840. }
  1841. }
  1842. // Copy the ansi version of this string into the specified buffer,
  1843. // If the buffer is not large enough, no data is copied.
  1844. //
  1845. // Returns the number of BYTES necessary for the buffer
  1846. //
  1847. DWORD CString::CopyAnsiBytes(char * lpszBuffer, DWORD nBytes)
  1848. {
  1849. const char * lpszAnsi = GetAnsi();
  1850. // Length of cstring, in bytes, not including terminator.
  1851. int nDataBytes = strlen(lpszAnsi);
  1852. // Length of buffer (no terminator)
  1853. int nBufBytes = nBytes - 1;
  1854. // Only copy the data if the buffer is large enough
  1855. if (nDataBytes <= nBufBytes)
  1856. {
  1857. // Copy the data into the buffer
  1858. strcpy(lpszBuffer, lpszAnsi);
  1859. }
  1860. // return the actual size of string
  1861. return nDataBytes;
  1862. }
  1863. // Copy the ansi version of this string into the specified buffer,
  1864. // If the buffer is not large enough, no data is copied.
  1865. //
  1866. // Returns the number of CHARS necessary for the buffer
  1867. //
  1868. DWORD CString::CopyAnsiChars(char * lpszBuffer, DWORD nChars)
  1869. {
  1870. const char * lpszAnsi = GetAnsi();
  1871. // Length of cstring, in bytes, not including terminator.
  1872. int nDataChars = GetLength();
  1873. // Length of buffer (no terminator)
  1874. int nBufChars = nChars - 1;
  1875. // Only copy the data if the buffer is large enough
  1876. if (nDataChars <= nBufChars)
  1877. {
  1878. // Copy the data into the buffer
  1879. strcpy(lpszBuffer, lpszAnsi);
  1880. }
  1881. // return the actual size of string
  1882. return nDataChars;
  1883. }
  1884. BOOL CString::PatternMatch(const WCHAR * lpszPattern) const
  1885. {
  1886. return PatternMatchW(lpszPattern, Get());
  1887. }
  1888. }; // end of namespace ShimLib