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.

1993 lines
50 KiB

  1. // Local BSTR derived from WTL3.1 CString Class
  2. #ifndef __LOCAL_BSTR__
  3. #define __LOCAL_BSTR__
  4. #pragma once
  5. #ifndef __cplusplus
  6. #error ATL requires C++ compilation (use a .cpp suffix)
  7. #endif
  8. #ifndef __ATLAPP_H__
  9. #error atlmisc.h requires atlapp.h to be included first
  10. #endif
  11. // We're ripping out non-Unicode support to remove potential buffer overrun problems in the ansi implementation
  12. #ifdef _UNICODE
  13. namespace LBSTR
  14. {
  15. /////////////////////////////////////////////////////////////////////////////
  16. // Forward declarations
  17. #ifndef _WTL_NO_LOCAL_BSTR
  18. class CString;
  19. #endif //!_WTL_NO_CSTRING
  20. /////////////////////////////////////////////////////////////////////////////
  21. // CString - String class
  22. #ifdef DEBUG
  23. #define VERIFY_LOCAL_BSTR
  24. #endif
  25. #ifdef VERIFY_LOCAL_BSTR
  26. #ifdef DEBUG
  27. #define VERIFY_ASSERT(expr) ASSERT(expr)
  28. #else
  29. #if _MSC_VER >= 1300 && !defined(_CRT_PORTABLE)
  30. #define _CrtRetailBreak() __debugbreak()
  31. #elif defined(_M_IX86) && !defined(_CRT_PORTABLE)
  32. #define _CrtRetailBreak() __asm { int 3 }
  33. #elif defined(_M_ALPHA) && !defined(_CRT_PORTABLE)
  34. void _BPT();
  35. #pragma intrinsic(_BPT)
  36. #define _CrtRetailBreak() _BPT()
  37. #elif defined(_M_IA64) && !defined(_CRT_PORTABLE)
  38. void __break(int);
  39. #pragma intrinsic (__break)
  40. #define _CrtRetailBreak() __break(0x80016)
  41. #else
  42. _CRTIMP void __cdecl _CrtRetailBreak(
  43. void
  44. );
  45. #endif
  46. #if _MSC_VER >= 1300 || !defined(_M_IX86) || defined(_CRT_PORTABLE)
  47. #define _RETAIL_ASSERT_BASE(expr) \
  48. (void) ((expr) || \
  49. (_CrtRetailBreak(), 0))
  50. #else
  51. #define _RETAIL_ASSERT_BASE(expr) \
  52. do { if (!(expr)) \
  53. _CrtRetailBreak(); } while (0)
  54. #endif
  55. #define VERIFY_ASSERT(expr) _RETAIL_ASSERT_BASE(expr)
  56. #endif // DEBUG
  57. #endif // VERIFY_LOCAL_BSTR
  58. #ifndef _WTL_NO_LOCAL_BSTR
  59. class CStringData
  60. {
  61. public:
  62. #ifdef VERIFY_LOCAL_BSTR
  63. int nStartTag;
  64. #endif
  65. long nRefs; // reference count
  66. int nDataLength;
  67. int nAllocLength;
  68. #ifdef VERIFY_LOCAL_BSTR
  69. int nMiddleTag;
  70. #endif
  71. ULONG cbDataLength;
  72. void SetDataLength( int p_nDataLength )
  73. {
  74. ASSERT( p_nDataLength >= 0 );
  75. nDataLength = p_nDataLength;
  76. cbDataLength = p_nDataLength * sizeof(TCHAR);
  77. }
  78. // TCHAR data[nAllocLength]
  79. TCHAR* data()
  80. { return (TCHAR*)(this + 1); }
  81. #ifdef VERIFY_LOCAL_BSTR
  82. BYTE * GetTagPtr(void)
  83. {
  84. TCHAR * pzEndTag;
  85. pzEndTag = data() + ( nAllocLength + 1 );
  86. return (BYTE *) pzEndTag;
  87. }
  88. int GetEndTag(void)
  89. {
  90. int nEnd;
  91. memcpy( &nEnd, GetTagPtr(), sizeof(int) );
  92. return nEnd;
  93. }
  94. void SetEndTag( int nEnd )
  95. {
  96. memcpy( GetTagPtr(), &nEnd, sizeof(int) );
  97. }
  98. #endif
  99. };
  100. // Globals
  101. // For an empty string, m_pchData will point here
  102. // (note: avoids special case of checking for NULL m_pchData)
  103. // empty string data (and locked)
  104. #ifdef VERIFY_LOCAL_BSTR
  105. const int START_TAG = 0x01234567;
  106. const int MIDDLE_TAG = 0x89abcdef;
  107. const int END_TAG = 0xfedcba98;
  108. _declspec(selectany) int rgInitData[] = { START_TAG, -1, 0, 0, MIDDLE_TAG, 0, 0, END_TAG };
  109. #else
  110. _declspec(selectany) int rgInitData[] = { -1, 0, 0, 0, 0 };
  111. #endif
  112. _declspec(selectany) CStringData* _atltmpDataNil = (CStringData*)&rgInitData;
  113. _declspec(selectany) LPCTSTR _atltmpPchNil = (LPCTSTR)(((BYTE*)&rgInitData) + sizeof(CStringData));
  114. class CString
  115. {
  116. public:
  117. // Constructors
  118. CString();
  119. CString(const CString& stringSrc);
  120. CString(TCHAR ch, int nRepeat = 1);
  121. CString(LPCSTR lpsz);
  122. CString(LPCWSTR lpsz);
  123. CString(LPCTSTR lpch, int nLength);
  124. CString(const unsigned char* psz);
  125. #ifdef VERIFY_LOCAL_BSTR
  126. void VerifyInitData( void )
  127. {
  128. VerifyBlankData();
  129. CStringData * pData = GetData();
  130. VerifyTagData( pData );
  131. }
  132. #endif
  133. // Attributes & Operations
  134. // as an array of characters
  135. int GetLength() const;
  136. BOOL IsEmpty() const;
  137. void Empty(); // free up the data
  138. TCHAR GetAt(int nIndex) const; // 0 based
  139. TCHAR operator[](int nIndex) const; // same as GetAt
  140. void SetAt(int nIndex, TCHAR ch);
  141. operator LPCTSTR() const; // as a C string
  142. operator BSTR() const; // as a BSTR string
  143. // overloaded assignment
  144. const CString& operator=(const CString& stringSrc);
  145. const CString& operator=(TCHAR ch);
  146. const CString& operator=(char ch);
  147. const CString& operator=(LPCSTR lpsz);
  148. const CString& operator=(LPCWSTR lpsz);
  149. const CString& operator=(const unsigned char* psz);
  150. // string concatenation
  151. const CString& operator+=(const CString& string);
  152. const CString& operator+=(TCHAR ch);
  153. const CString& operator+=(char ch);
  154. const CString& operator+=(LPCTSTR lpsz);
  155. friend CString __stdcall operator+(const CString& string1, const CString& string2);
  156. friend CString __stdcall operator+(const CString& string, TCHAR ch);
  157. friend CString __stdcall operator+(TCHAR ch, const CString& string);
  158. friend CString __stdcall operator+(const CString& string, char ch);
  159. friend CString __stdcall operator+(char ch, const CString& string);
  160. friend CString __stdcall operator+(const CString& string, LPCTSTR lpsz);
  161. friend CString __stdcall operator+(LPCTSTR lpsz, const CString& string);
  162. // string comparison
  163. int Compare(LPCTSTR lpsz) const; // straight character
  164. int CompareNoCase(LPCTSTR lpsz) const; // ignore case
  165. int Collate(LPCTSTR lpsz) const; // NLS aware
  166. // simple sub-string extraction
  167. CString Mid(int nFirst, int nCount) const;
  168. CString Mid(int nFirst) const;
  169. CString Left(int nCount) const;
  170. CString Right(int nCount) const;
  171. CString SpanIncluding(LPCTSTR lpszCharSet) const;
  172. CString SpanExcluding(LPCTSTR lpszCharSet) const;
  173. // upper/lower/reverse conversion
  174. void MakeUpper();
  175. void MakeLower();
  176. void MakeReverse();
  177. // trimming whitespace (either side)
  178. void TrimRight();
  179. void TrimLeft();
  180. // advanced manipulation
  181. // replace occurrences of chOld with chNew
  182. int Replace(TCHAR chOld, TCHAR chNew);
  183. // replace occurrences of substring lpszOld with lpszNew;
  184. // empty lpszNew removes instances of lpszOld
  185. int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew);
  186. // remove occurrences of chRemove
  187. int Remove(TCHAR chRemove);
  188. // insert character at zero-based index; concatenates
  189. // if index is past end of string
  190. int Insert(int nIndex, TCHAR ch);
  191. // insert substring at zero-based index; concatenates
  192. // if index is past end of string
  193. int Insert(int nIndex, LPCTSTR pstr);
  194. // delete nCount characters starting at zero-based index
  195. int Delete(int nIndex, int nCount = 1);
  196. // searching (return starting index, or -1 if not found)
  197. // look for a single character match
  198. int Find(TCHAR ch) const; // like "C" strchr
  199. int ReverseFind(TCHAR ch) const;
  200. int FindOneOf(LPCTSTR lpszCharSet) const;
  201. // look for a specific sub-string
  202. int Find(LPCTSTR lpszSub) const; // like "C" strstr
  203. // Concatentation for non strings
  204. const CString& Append(int n)
  205. {
  206. TCHAR szBuffer[10];
  207. wsprintf(szBuffer,_T("%d"),n);
  208. ConcatInPlace(SafeStrlen(szBuffer), szBuffer);
  209. return *this;
  210. }
  211. // simple formatting
  212. void __cdecl Format(LPCTSTR lpszFormat, ...);
  213. void __cdecl Format(UINT nFormatID, ...);
  214. // formatting for localization (uses FormatMessage API)
  215. BOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...);
  216. BOOL __cdecl FormatMessage(UINT nFormatID, ...);
  217. // Windows support
  218. BOOL LoadString(UINT nID); // load from string resource
  219. // 255 chars max
  220. #ifndef _ATL_NO_COM
  221. // OLE BSTR support (use for OLE automation)
  222. BSTR AllocSysString() const;
  223. BSTR SetSysString(BSTR* pbstr) const;
  224. #endif //!_ATL_NO_COM
  225. // Access to string implementation buffer as "C" character array
  226. LPTSTR GetBuffer(int nMinBufLength);
  227. void ReleaseBuffer(int nNewLength = -1);
  228. LPTSTR GetBufferSetLength(int nNewLength);
  229. void FreeExtra();
  230. // Use LockBuffer/UnlockBuffer to turn refcounting off
  231. LPTSTR LockBuffer();
  232. void UnlockBuffer();
  233. // Implementation
  234. public:
  235. ~CString();
  236. int GetAllocLength() const;
  237. static BOOL __stdcall _IsValidString(LPCWSTR lpsz, int nLength)
  238. {
  239. if(lpsz == NULL)
  240. return FALSE;
  241. return !::IsBadStringPtrW(lpsz, nLength);
  242. }
  243. static BOOL __stdcall _IsValidString(LPCSTR lpsz, int nLength)
  244. {
  245. if(lpsz == NULL)
  246. return FALSE;
  247. return !::IsBadStringPtrA(lpsz, nLength);
  248. }
  249. protected:
  250. LPTSTR m_pchData; // pointer to ref counted string data
  251. // implementation helpers
  252. CStringData* GetData() const;
  253. void Init();
  254. void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const;
  255. BOOL AllocBuffer(int nLen);
  256. void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
  257. BOOL ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data);
  258. void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData);
  259. void FormatV(LPCTSTR lpszFormat, va_list argList);
  260. void CopyBeforeWrite();
  261. BOOL AllocBeforeWrite(int nLen);
  262. void Release();
  263. static void PASCAL Release(CStringData* pData);
  264. static int PASCAL SafeStrlen(LPCTSTR lpsz);
  265. static int __stdcall _LoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)
  266. {
  267. #ifdef _DEBUG
  268. // LoadString without annoying warning from the Debug kernel if the
  269. // segment containing the string is not present
  270. if (::FindResource(_Module.GetResourceInstance(), MAKEINTRESOURCE((nID>>4) + 1), RT_STRING) == NULL)
  271. {
  272. lpszBuf[0] = '\0';
  273. return 0; // not found
  274. }
  275. #endif //_DEBUG
  276. int nLen = ::LoadString(_Module.GetResourceInstance(), nID, lpszBuf, nMaxBuf);
  277. if (nLen == 0)
  278. lpszBuf[0] = '\0';
  279. return nLen;
  280. }
  281. #ifdef VERIFY_LOCAL_BSTR
  282. static void VerifyBlankData( void )
  283. {
  284. VERIFY_ASSERT( rgInitData[0] == START_TAG );
  285. VERIFY_ASSERT( rgInitData[1] == -1 );
  286. VERIFY_ASSERT( rgInitData[2] == 0 );
  287. VERIFY_ASSERT( rgInitData[3] == 0 );
  288. VERIFY_ASSERT( rgInitData[4] == MIDDLE_TAG );
  289. VERIFY_ASSERT( rgInitData[5] == 0 );
  290. VERIFY_ASSERT( rgInitData[6] == 0 );
  291. VERIFY_ASSERT( rgInitData[7] == END_TAG );
  292. }
  293. static void VerifyTagData( CStringData * pData )
  294. {
  295. if ( pData && pData != _atltmpDataNil )
  296. {
  297. VERIFY_ASSERT( pData->nStartTag == START_TAG );
  298. VERIFY_ASSERT( pData->nMiddleTag == MIDDLE_TAG );
  299. VERIFY_ASSERT( pData->GetEndTag() == END_TAG );
  300. }
  301. }
  302. #endif
  303. static const CString& __stdcall _GetEmptyString()
  304. {
  305. #ifdef VERIFY_LOCAL_BSTR
  306. VerifyBlankData();
  307. #endif
  308. return *(CString*)&_atltmpPchNil;
  309. }
  310. // CString conversion helpers
  311. static int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  312. {
  313. if (count == 0 && mbstr != NULL)
  314. return 0;
  315. int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1, mbstr, (int)count, NULL, NULL);
  316. ATLASSERT(mbstr == NULL || result <= (int)count);
  317. if (result > 0)
  318. mbstr[result - 1] = 0;
  319. return result;
  320. }
  321. static int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  322. {
  323. if (count == 0 && wcstr != NULL)
  324. return 0;
  325. int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1, wcstr, (int)count);
  326. ATLASSERT(wcstr == NULL || result <= (int)count);
  327. if (result > 0)
  328. wcstr[result - 1] = 0;
  329. return result;
  330. }
  331. // Helpers to avoid CRT startup code
  332. static TCHAR* _cstrchr(const TCHAR* p, TCHAR ch)
  333. {
  334. //strchr for '\0' should succeed
  335. while (*p != 0)
  336. {
  337. if (*p == ch)
  338. break;
  339. p = ::CharNext(p);
  340. }
  341. return (TCHAR*)((*p == ch) ? p : NULL);
  342. }
  343. static TCHAR* _cstrchr_db(const TCHAR* p, TCHAR ch1, TCHAR ch2)
  344. {
  345. const TCHAR* lpsz = NULL;
  346. while (*p != 0)
  347. {
  348. if (*p == ch1 && *(p + 1) == ch2)
  349. {
  350. lpsz = p;
  351. break;
  352. }
  353. p = ::CharNext(p);
  354. }
  355. return (TCHAR*)lpsz;
  356. }
  357. static TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch)
  358. {
  359. const TCHAR* lpsz = NULL;
  360. while (*p != 0)
  361. {
  362. if (*p == ch)
  363. lpsz = p;
  364. p = ::CharNext(p);
  365. }
  366. return (TCHAR*)lpsz;
  367. }
  368. static TCHAR* _cstrrev(TCHAR* pStr)
  369. {
  370. // Optimize NULL, zero-length, and single-char case.
  371. if ((pStr == NULL) || (pStr[0] == '\0') || (pStr[1] == '\0'))
  372. return pStr;
  373. TCHAR* p = pStr;
  374. while (p[1] != 0)
  375. {
  376. TCHAR* pNext = ::CharNext(p);
  377. if(pNext > p + 1)
  378. {
  379. char p1 = *(char*)p;
  380. *(char*)p = *(char*)(p + 1);
  381. *(char*)(p + 1) = p1;
  382. }
  383. p = pNext;
  384. }
  385. TCHAR* q = pStr;
  386. while (q < p)
  387. {
  388. TCHAR t = *q;
  389. *q = *p;
  390. *p = t;
  391. q++;
  392. p--;
  393. }
  394. return (TCHAR*)pStr;
  395. }
  396. static TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet)
  397. {
  398. int nLen = lstrlen(pCharSet);
  399. if (nLen == 0)
  400. return (TCHAR*)pStr;
  401. const TCHAR* pRet = NULL;
  402. const TCHAR* pCur = pStr;
  403. while((pStr = _cstrchr(pCur, *pCharSet)) != NULL)
  404. {
  405. if(memcmp(pCur, pCharSet, nLen * sizeof(TCHAR)) == 0)
  406. {
  407. pRet = pCur;
  408. break;
  409. }
  410. pCur = ::CharNext(pCur);
  411. }
  412. return (TCHAR*) pRet;
  413. }
  414. static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet)
  415. {
  416. int nRet = 0;
  417. TCHAR* p = (TCHAR*)pStr;
  418. while (*p != 0)
  419. {
  420. TCHAR* pNext = ::CharNext(p);
  421. if(pNext > p + 1)
  422. {
  423. if(_cstrchr_db(pCharSet, *p, *(p + 1)) == NULL)
  424. break;
  425. nRet += 2;
  426. }
  427. else
  428. {
  429. if(_cstrchr(pCharSet, *p) == NULL)
  430. break;
  431. nRet++;
  432. }
  433. p = pNext;
  434. }
  435. return nRet;
  436. }
  437. static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet)
  438. {
  439. int nRet = 0;
  440. TCHAR* p = (TCHAR*)pStr;
  441. while (*p != 0)
  442. {
  443. TCHAR* pNext = ::CharNext(p);
  444. if(pNext > p + 1)
  445. {
  446. if(_cstrchr_db(pCharSet, *p, *(p + 1)) != NULL)
  447. break;
  448. nRet += 2;
  449. }
  450. else
  451. {
  452. if(_cstrchr(pCharSet, *p) != NULL)
  453. break;
  454. nRet++;
  455. }
  456. p = pNext;
  457. }
  458. return nRet;
  459. }
  460. static TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet)
  461. {
  462. while (*p != 0)
  463. {
  464. if (_cstrchr(lpszCharSet, *p) != NULL)
  465. {
  466. return (TCHAR*)p;
  467. break;
  468. }
  469. p = ::CharNext(p);
  470. }
  471. return NULL;
  472. }
  473. static int _cstrisdigit(TCHAR ch)
  474. {
  475. WORD type;
  476. GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
  477. return (type & C1_DIGIT) == C1_DIGIT;
  478. }
  479. static int _cstrisspace(TCHAR ch)
  480. {
  481. WORD type;
  482. GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
  483. return (type & C1_SPACE) == C1_SPACE;
  484. }
  485. static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther)
  486. {
  487. return lstrcmp(pstrOne, pstrOther);
  488. }
  489. static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther)
  490. {
  491. return lstrcmpi(pstrOne, pstrOther);
  492. }
  493. static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther)
  494. {
  495. int nRet = CompareString(GetThreadLocale(), 0, pstrOne, -1, pstrOther, -1);
  496. ATLASSERT(nRet != 0);
  497. return nRet - 2; // Convert to strcmp convention. This really is documented.
  498. }
  499. static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther)
  500. {
  501. int nRet = CompareString(GetThreadLocale(), NORM_IGNORECASE, pstrOne, -1, pstrOther, -1);
  502. ATLASSERT(nRet != 0);
  503. return nRet - 2; // Convert to strcmp convention. This really is documented.
  504. }
  505. };
  506. // Compare helpers
  507. bool __stdcall operator==(const CString& s1, const CString& s2);
  508. bool __stdcall operator==(const CString& s1, LPCTSTR s2);
  509. bool __stdcall operator==(LPCTSTR s1, const CString& s2);
  510. bool __stdcall operator!=(const CString& s1, const CString& s2);
  511. bool __stdcall operator!=(const CString& s1, LPCTSTR s2);
  512. bool __stdcall operator!=(LPCTSTR s1, const CString& s2);
  513. bool __stdcall operator<(const CString& s1, const CString& s2);
  514. bool __stdcall operator<(const CString& s1, LPCTSTR s2);
  515. bool __stdcall operator<(LPCTSTR s1, const CString& s2);
  516. bool __stdcall operator>(const CString& s1, const CString& s2);
  517. bool __stdcall operator>(const CString& s1, LPCTSTR s2);
  518. bool __stdcall operator>(LPCTSTR s1, const CString& s2);
  519. bool __stdcall operator<=(const CString& s1, const CString& s2);
  520. bool __stdcall operator<=(const CString& s1, LPCTSTR s2);
  521. bool __stdcall operator<=(LPCTSTR s1, const CString& s2);
  522. bool __stdcall operator>=(const CString& s1, const CString& s2);
  523. bool __stdcall operator>=(const CString& s1, LPCTSTR s2);
  524. bool __stdcall operator>=(LPCTSTR s1, const CString& s2);
  525. /////////////////////////////////////////////////////////////////////////////
  526. // CString Implementation
  527. inline CStringData* CString::GetData() const
  528. { ATLASSERT(m_pchData != NULL); return ((CStringData*)m_pchData) - 1; }
  529. inline void CString::Init()
  530. { m_pchData = _GetEmptyString().m_pchData; }
  531. inline CString::CString(const unsigned char* lpsz)
  532. { Init(); *this = (LPCSTR)lpsz; }
  533. inline const CString& CString::operator=(const unsigned char* lpsz)
  534. { *this = (LPCSTR)lpsz; return *this; }
  535. inline const CString& CString::operator+=(char ch)
  536. { *this += (TCHAR)ch; return *this; }
  537. inline const CString& CString::operator=(char ch)
  538. { *this = (TCHAR)ch; return *this; }
  539. inline CString __stdcall operator+(const CString& string, char ch)
  540. { return string + (TCHAR)ch; }
  541. inline CString __stdcall operator+(char ch, const CString& string)
  542. { return (TCHAR)ch + string; }
  543. inline int CString::GetLength() const
  544. { return GetData()->nDataLength; }
  545. inline int CString::GetAllocLength() const
  546. { return GetData()->nAllocLength; }
  547. inline BOOL CString::IsEmpty() const
  548. { return GetData()->nDataLength == 0; }
  549. inline CString::operator LPCTSTR() const
  550. { return m_pchData; }
  551. inline CString::operator BSTR() const
  552. { return (BSTR) m_pchData; }
  553. inline int PASCAL CString::SafeStrlen(LPCTSTR lpsz)
  554. { return (lpsz == NULL) ? 0 : lstrlen(lpsz); }
  555. // CString support (windows specific)
  556. inline int CString::Compare(LPCTSTR lpsz) const
  557. { return _cstrcmp(m_pchData, lpsz); } // MBCS/Unicode aware
  558. inline int CString::CompareNoCase(LPCTSTR lpsz) const
  559. { return _cstrcmpi(m_pchData, lpsz); } // MBCS/Unicode aware
  560. // CString::Collate is often slower than Compare but is MBSC/Unicode
  561. // aware as well as locale-sensitive with respect to sort order.
  562. inline int CString::Collate(LPCTSTR lpsz) const
  563. { return _cstrcoll(m_pchData, lpsz); } // locale sensitive
  564. inline TCHAR CString::GetAt(int nIndex) const
  565. {
  566. ATLASSERT(nIndex >= 0);
  567. ATLASSERT(nIndex < GetData()->nDataLength);
  568. return m_pchData[nIndex];
  569. }
  570. inline TCHAR CString::operator[](int nIndex) const
  571. {
  572. // same as GetAt
  573. ATLASSERT(nIndex >= 0);
  574. ATLASSERT(nIndex < GetData()->nDataLength);
  575. return m_pchData[nIndex];
  576. }
  577. inline bool __stdcall operator==(const CString& s1, const CString& s2)
  578. { return s1.Compare(s2) == 0; }
  579. inline bool __stdcall operator==(const CString& s1, LPCTSTR s2)
  580. { return s1.Compare(s2) == 0; }
  581. inline bool __stdcall operator==(LPCTSTR s1, const CString& s2)
  582. { return s2.Compare(s1) == 0; }
  583. inline bool __stdcall operator!=(const CString& s1, const CString& s2)
  584. { return s1.Compare(s2) != 0; }
  585. inline bool __stdcall operator!=(const CString& s1, LPCTSTR s2)
  586. { return s1.Compare(s2) != 0; }
  587. inline bool __stdcall operator!=(LPCTSTR s1, const CString& s2)
  588. { return s2.Compare(s1) != 0; }
  589. inline bool __stdcall operator<(const CString& s1, const CString& s2)
  590. { return s1.Compare(s2) < 0; }
  591. inline bool __stdcall operator<(const CString& s1, LPCTSTR s2)
  592. { return s1.Compare(s2) < 0; }
  593. inline bool __stdcall operator<(LPCTSTR s1, const CString& s2)
  594. { return s2.Compare(s1) > 0; }
  595. inline bool __stdcall operator>(const CString& s1, const CString& s2)
  596. { return s1.Compare(s2) > 0; }
  597. inline bool __stdcall operator>(const CString& s1, LPCTSTR s2)
  598. { return s1.Compare(s2) > 0; }
  599. inline bool __stdcall operator>(LPCTSTR s1, const CString& s2)
  600. { return s2.Compare(s1) < 0; }
  601. inline bool __stdcall operator<=(const CString& s1, const CString& s2)
  602. { return s1.Compare(s2) <= 0; }
  603. inline bool __stdcall operator<=(const CString& s1, LPCTSTR s2)
  604. { return s1.Compare(s2) <= 0; }
  605. inline bool __stdcall operator<=(LPCTSTR s1, const CString& s2)
  606. { return s2.Compare(s1) >= 0; }
  607. inline bool __stdcall operator>=(const CString& s1, const CString& s2)
  608. { return s1.Compare(s2) >= 0; }
  609. inline bool __stdcall operator>=(const CString& s1, LPCTSTR s2)
  610. { return s1.Compare(s2) >= 0; }
  611. inline bool __stdcall operator>=(LPCTSTR s1, const CString& s2)
  612. { return s2.Compare(s1) <= 0; }
  613. inline CString::CString()
  614. {
  615. Init();
  616. }
  617. inline CString::CString(const CString& stringSrc)
  618. {
  619. ATLASSERT(stringSrc.GetData()->nRefs != 0);
  620. if (stringSrc.GetData()->nRefs >= 0)
  621. {
  622. ATLASSERT(stringSrc.GetData() != _atltmpDataNil);
  623. m_pchData = stringSrc.m_pchData;
  624. InterlockedIncrement(&GetData()->nRefs);
  625. }
  626. else
  627. {
  628. Init();
  629. *this = stringSrc.m_pchData;
  630. }
  631. }
  632. inline BOOL CString::AllocBuffer(int nLen)
  633. // always allocate one extra character for '\0' termination
  634. // assumes [optimistically] that data length will equal allocation length
  635. {
  636. ATLASSERT(nLen >= 0);
  637. ATLASSERT(nLen <= INT_MAX - 1); // max size (enough room for 1 extra)
  638. #ifdef VERIFY_LOCAL_BSTR
  639. VerifyInitData();
  640. #endif
  641. if (nLen == 0)
  642. {
  643. Init();
  644. }
  645. else
  646. {
  647. CStringData* pData = NULL;
  648. int cbBufLen = sizeof(CStringData) + (nLen + 1) * sizeof(TCHAR);
  649. #ifdef VERIFY_LOCAL_BSTR
  650. cbBufLen += sizeof(int); // End Tag
  651. #endif
  652. ATLTRY(pData = (CStringData*)new BYTE[ cbBufLen ]);
  653. if(pData == NULL)
  654. return FALSE;
  655. pData->nRefs = 1;
  656. pData->data()[nLen] = '\0';
  657. pData->SetDataLength( nLen );
  658. pData->nAllocLength = nLen;
  659. m_pchData = pData->data();
  660. #ifdef VERIFY_LOCAL_BSTR
  661. pData->nStartTag = START_TAG;
  662. pData->nMiddleTag = MIDDLE_TAG;
  663. pData->SetEndTag( END_TAG );
  664. #endif
  665. }
  666. return TRUE;
  667. }
  668. inline void CString::Release()
  669. {
  670. #ifdef VERIFY_LOCAL_BSTR
  671. VerifyInitData();
  672. #endif
  673. if (GetData() != _atltmpDataNil)
  674. {
  675. ASSERT( 0 != GetData()->nRefs );
  676. if (InterlockedDecrement(&GetData()->nRefs) == 0)
  677. {
  678. delete[] (BYTE*)GetData();
  679. }
  680. Init();
  681. }
  682. }
  683. inline void PASCAL CString::Release(CStringData* pData)
  684. {
  685. #ifdef VERIFY_LOCAL_BSTR
  686. VerifyBlankData();
  687. VerifyTagData( pData );
  688. #endif
  689. if (pData != _atltmpDataNil)
  690. {
  691. ASSERT( 0 != pData->nRefs );
  692. if (InterlockedDecrement(&pData->nRefs) == 0)
  693. {
  694. delete[] (BYTE*)pData;
  695. }
  696. }
  697. }
  698. inline void CString::Empty()
  699. {
  700. if (GetData()->nDataLength == 0)
  701. return;
  702. if (GetData()->nRefs >= 0)
  703. Release();
  704. else
  705. *this = _T("");
  706. ATLASSERT(GetData()->nDataLength == 0);
  707. ATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
  708. #ifdef VERIFY_LOCAL_BSTR
  709. VerifyInitData();
  710. #endif
  711. }
  712. inline void CString::CopyBeforeWrite()
  713. {
  714. if (GetData()->nRefs > 1)
  715. {
  716. CStringData* pData = GetData();
  717. Release();
  718. if(AllocBuffer(pData->nDataLength))
  719. {
  720. memcpy(m_pchData, pData->data(), (pData->nDataLength + 1) * sizeof(TCHAR));
  721. }
  722. }
  723. ATLASSERT(GetData()->nRefs <= 1);
  724. }
  725. inline BOOL CString::AllocBeforeWrite(int nLen)
  726. {
  727. BOOL bRet = TRUE;
  728. if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
  729. {
  730. Release();
  731. bRet = AllocBuffer(nLen);
  732. }
  733. ATLASSERT(GetData()->nRefs <= 1);
  734. return bRet;
  735. }
  736. inline CString::~CString()
  737. // free any attached data
  738. {
  739. #ifdef VERIFY_LOCAL_BSTR
  740. VerifyInitData();
  741. #endif
  742. if (GetData() != _atltmpDataNil)
  743. {
  744. ASSERT( 0 != GetData()->nRefs );
  745. if (InterlockedDecrement(&GetData()->nRefs) == 0)
  746. {
  747. delete[] (BYTE*)GetData();
  748. }
  749. }
  750. }
  751. inline void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
  752. int nExtraLen) const
  753. {
  754. // will clone the data attached to this string
  755. // allocating 'nExtraLen' characters
  756. // Places results in uninitialized string 'dest'
  757. // Will copy the part or all of original data to start of new string
  758. int nNewLen = nCopyLen + nExtraLen;
  759. if (nNewLen == 0)
  760. {
  761. dest.Init();
  762. }
  763. else
  764. {
  765. if(dest.AllocBuffer(nNewLen))
  766. memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen * sizeof(TCHAR));
  767. }
  768. }
  769. inline CString::CString(LPCTSTR lpsz)
  770. {
  771. Init();
  772. if (lpsz != NULL && HIWORD(lpsz) == NULL)
  773. {
  774. UINT nID = LOWORD((DWORD_PTR)lpsz);
  775. if (!LoadString(nID))
  776. ATLTRACE2(atlTraceUI, 0, _T("Warning: implicit LoadString(%u) in CString failed\n"), nID);
  777. }
  778. else
  779. {
  780. int nLen = SafeStrlen(lpsz);
  781. if (nLen != 0)
  782. {
  783. if(AllocBuffer(nLen))
  784. memcpy(m_pchData, lpsz, nLen * sizeof(TCHAR));
  785. }
  786. }
  787. }
  788. inline CString::CString(LPCSTR lpsz)
  789. {
  790. Init();
  791. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  792. if (nSrcLen != 0)
  793. {
  794. if(AllocBuffer(nSrcLen))
  795. {
  796. _mbstowcsz(m_pchData, lpsz, nSrcLen + 1);
  797. ReleaseBuffer();
  798. }
  799. }
  800. }
  801. // Assignment operators
  802. // All assign a new value to the string
  803. // (a) first see if the buffer is big enough
  804. // (b) if enough room, copy on top of old buffer, set size and type
  805. // (c) otherwise free old string data, and create a new one
  806. //
  807. // All routines return the new string (but as a 'const CString&' so that
  808. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  809. //
  810. inline void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  811. {
  812. if(AllocBeforeWrite(nSrcLen))
  813. {
  814. memcpy(m_pchData, lpszSrcData, nSrcLen * sizeof(TCHAR));
  815. GetData()->SetDataLength( nSrcLen );
  816. m_pchData[nSrcLen] = '\0';
  817. }
  818. }
  819. inline const CString& CString::operator=(const CString& stringSrc)
  820. {
  821. if (m_pchData != stringSrc.m_pchData)
  822. {
  823. if ((GetData()->nRefs < 0 && GetData() != _atltmpDataNil) || stringSrc.GetData()->nRefs < 0)
  824. {
  825. // actual copy necessary since one of the strings is locked
  826. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  827. }
  828. else
  829. {
  830. // can just copy references around
  831. Release();
  832. ATLASSERT(stringSrc.GetData() != _atltmpDataNil);
  833. m_pchData = stringSrc.m_pchData;
  834. InterlockedIncrement(&GetData()->nRefs);
  835. }
  836. }
  837. return *this;
  838. }
  839. inline const CString& CString::operator=(LPCTSTR lpsz)
  840. {
  841. ATLASSERT(lpsz == NULL || _IsValidString(lpsz, FALSE));
  842. AssignCopy(SafeStrlen(lpsz), lpsz);
  843. return *this;
  844. }
  845. inline const CString& CString::operator=(LPCSTR lpsz)
  846. {
  847. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  848. if(AllocBeforeWrite(nSrcLen))
  849. {
  850. _mbstowcsz(m_pchData, lpsz, nSrcLen + 1);
  851. ReleaseBuffer();
  852. }
  853. return *this;
  854. }
  855. // Concatenation
  856. // NOTE: "operator+" is done as friend functions for simplicity
  857. // There are three variants:
  858. // CString + CString
  859. // and for ? = TCHAR, LPCTSTR
  860. // CString + ?
  861. // ? + CString
  862. inline BOOL CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  863. int nSrc2Len, LPCTSTR lpszSrc2Data)
  864. {
  865. // -- master concatenation routine
  866. // Concatenate two sources
  867. // -- assume that 'this' is a new CString object
  868. BOOL bRet = TRUE;
  869. int nNewLen = nSrc1Len + nSrc2Len;
  870. if (nNewLen != 0)
  871. {
  872. bRet = AllocBuffer(nNewLen);
  873. if (bRet)
  874. {
  875. memcpy(m_pchData, lpszSrc1Data, nSrc1Len * sizeof(TCHAR));
  876. memcpy(m_pchData + nSrc1Len, lpszSrc2Data, nSrc2Len * sizeof(TCHAR));
  877. }
  878. }
  879. return bRet;
  880. }
  881. inline CString __stdcall operator+(const CString& string1, const CString& string2)
  882. {
  883. CString s;
  884. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, string2.GetData()->nDataLength, string2.m_pchData);
  885. return s;
  886. }
  887. inline CString __stdcall operator+(const CString& string, LPCTSTR lpsz)
  888. {
  889. ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz, FALSE));
  890. CString s;
  891. s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, CString::SafeStrlen(lpsz), lpsz);
  892. return s;
  893. }
  894. inline CString __stdcall operator+(LPCTSTR lpsz, const CString& string)
  895. {
  896. ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz, FALSE));
  897. CString s;
  898. s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength, string.m_pchData);
  899. return s;
  900. }
  901. inline void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  902. {
  903. // -- the main routine for += operators
  904. // concatenating an empty string is a no-op!
  905. if (nSrcLen == 0)
  906. return;
  907. // if the buffer is too small, or we have a width mis-match, just
  908. // allocate a new buffer (slow but sure)
  909. if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
  910. {
  911. // we have to grow the buffer, use the ConcatCopy routine
  912. CStringData* pOldData = GetData();
  913. if (ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData))
  914. {
  915. ATLASSERT(pOldData != NULL);
  916. CString::Release(pOldData);
  917. }
  918. }
  919. else
  920. {
  921. // fast concatenation when buffer big enough
  922. memcpy(m_pchData + GetData()->nDataLength, lpszSrcData, nSrcLen * sizeof(TCHAR));
  923. GetData()->SetDataLength( GetData()->nDataLength + nSrcLen );
  924. ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  925. m_pchData[GetData()->nDataLength] = '\0';
  926. }
  927. }
  928. inline const CString& CString::operator+=(LPCTSTR lpsz)
  929. {
  930. ATLASSERT(lpsz == NULL || _IsValidString(lpsz, FALSE));
  931. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  932. return *this;
  933. }
  934. inline const CString& CString::operator+=(TCHAR ch)
  935. {
  936. ConcatInPlace(1, &ch);
  937. return *this;
  938. }
  939. inline const CString& CString::operator+=(const CString& string)
  940. {
  941. ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  942. return *this;
  943. }
  944. inline LPTSTR CString::GetBuffer(int nMinBufLength)
  945. {
  946. ATLASSERT(nMinBufLength >= 0);
  947. if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  948. {
  949. // we have to grow the buffer
  950. CStringData* pOldData = GetData();
  951. int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
  952. if (nMinBufLength < nOldLen)
  953. nMinBufLength = nOldLen;
  954. if(AllocBuffer(nMinBufLength))
  955. {
  956. memcpy(m_pchData, pOldData->data(), (nOldLen + 1) * sizeof(TCHAR));
  957. GetData()->SetDataLength( nOldLen );
  958. CString::Release(pOldData);
  959. }
  960. }
  961. ATLASSERT(GetData()->nRefs <= 1);
  962. #ifdef VERIFY_LOCAL_BSTR
  963. VerifyInitData();
  964. #endif
  965. // return a pointer to the character storage for this string
  966. ATLASSERT(m_pchData != NULL);
  967. return m_pchData;
  968. }
  969. inline void CString::ReleaseBuffer(int nNewLength)
  970. {
  971. CopyBeforeWrite(); // just in case GetBuffer was not called
  972. if (nNewLength == -1)
  973. nNewLength = lstrlen(m_pchData); // zero terminated
  974. ATLASSERT(nNewLength <= GetData()->nAllocLength);
  975. GetData()->SetDataLength( nNewLength );
  976. m_pchData[nNewLength] = '\0';
  977. #ifdef VERIFY_LOCAL_BSTR
  978. VerifyInitData();
  979. #endif
  980. }
  981. inline LPTSTR CString::GetBufferSetLength(int nNewLength)
  982. {
  983. ATLASSERT(nNewLength >= 0);
  984. GetBuffer(nNewLength);
  985. if ( GetAllocLength() >= nNewLength )
  986. {
  987. GetData()->SetDataLength( nNewLength );
  988. m_pchData[nNewLength] = '\0';
  989. }
  990. #ifdef VERIFY_LOCAL_BSTR
  991. VerifyInitData();
  992. #endif
  993. return m_pchData;
  994. }
  995. inline void CString::FreeExtra()
  996. {
  997. ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  998. if (GetData()->nDataLength != GetData()->nAllocLength)
  999. {
  1000. CStringData* pOldData = GetData();
  1001. if(AllocBuffer(GetData()->nDataLength))
  1002. {
  1003. memcpy(m_pchData, pOldData->data(), pOldData->nDataLength * sizeof(TCHAR));
  1004. ATLASSERT(m_pchData[GetData()->nDataLength] == '\0');
  1005. CString::Release(pOldData);
  1006. }
  1007. }
  1008. ATLASSERT(GetData() != NULL);
  1009. }
  1010. inline LPTSTR CString::LockBuffer()
  1011. {
  1012. LPTSTR lpsz = GetBuffer(0);
  1013. GetData()->nRefs = -1;
  1014. return lpsz;
  1015. }
  1016. inline void CString::UnlockBuffer()
  1017. {
  1018. ATLASSERT(GetData()->nRefs == -1);
  1019. if (GetData() != _atltmpDataNil)
  1020. GetData()->nRefs = 1;
  1021. }
  1022. inline int CString::Find(TCHAR ch) const
  1023. {
  1024. // find first single character
  1025. LPTSTR lpsz = _cstrchr(m_pchData, (_TUCHAR)ch);
  1026. // return -1 if not found and index otherwise
  1027. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1028. }
  1029. inline int CString::FindOneOf(LPCTSTR lpszCharSet) const
  1030. {
  1031. ATLASSERT(_IsValidString(lpszCharSet, FALSE));
  1032. LPTSTR lpsz = _cstrpbrk(m_pchData, lpszCharSet);
  1033. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1034. }
  1035. inline void CString::MakeUpper()
  1036. {
  1037. CopyBeforeWrite();
  1038. CharUpper(m_pchData);
  1039. }
  1040. inline void CString::MakeLower()
  1041. {
  1042. CopyBeforeWrite();
  1043. CharLower(m_pchData);
  1044. }
  1045. inline void CString::MakeReverse()
  1046. {
  1047. CopyBeforeWrite();
  1048. _cstrrev(m_pchData);
  1049. }
  1050. inline void CString::SetAt(int nIndex, TCHAR ch)
  1051. {
  1052. ATLASSERT(nIndex >= 0);
  1053. ATLASSERT(nIndex < GetData()->nDataLength);
  1054. CopyBeforeWrite();
  1055. m_pchData[nIndex] = ch;
  1056. }
  1057. inline CString::CString(TCHAR ch, int nLength)
  1058. {
  1059. ATLASSERT(!_istlead(ch)); // can't create a lead byte string
  1060. Init();
  1061. if (nLength >= 1)
  1062. {
  1063. if(AllocBuffer(nLength))
  1064. {
  1065. for (int i = 0; i < nLength; i++)
  1066. m_pchData[i] = ch;
  1067. }
  1068. }
  1069. }
  1070. inline CString::CString(LPCTSTR lpch, int nLength)
  1071. {
  1072. Init();
  1073. if (nLength != 0)
  1074. {
  1075. if(AllocBuffer(nLength))
  1076. memcpy(m_pchData, lpch, nLength * sizeof(TCHAR));
  1077. }
  1078. }
  1079. inline const CString& CString::operator=(TCHAR ch)
  1080. {
  1081. ATLASSERT(!_istlead(ch)); // can't set single lead byte
  1082. AssignCopy(1, &ch);
  1083. return *this;
  1084. }
  1085. inline CString __stdcall operator+(const CString& string1, TCHAR ch)
  1086. {
  1087. CString s;
  1088. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  1089. return s;
  1090. }
  1091. inline CString __stdcall operator+(TCHAR ch, const CString& string)
  1092. {
  1093. CString s;
  1094. s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  1095. return s;
  1096. }
  1097. inline CString CString::Mid(int nFirst) const
  1098. {
  1099. return Mid(nFirst, GetData()->nDataLength - nFirst);
  1100. }
  1101. inline CString CString::Mid(int nFirst, int nCount) const
  1102. {
  1103. // out-of-bounds requests return sensible things
  1104. if (nFirst < 0)
  1105. nFirst = 0;
  1106. if (nCount < 0)
  1107. nCount = 0;
  1108. if (nFirst + nCount > GetData()->nDataLength)
  1109. nCount = GetData()->nDataLength - nFirst;
  1110. if (nFirst > GetData()->nDataLength)
  1111. nCount = 0;
  1112. CString dest;
  1113. AllocCopy(dest, nCount, nFirst, 0);
  1114. return dest;
  1115. }
  1116. inline CString CString::Right(int nCount) const
  1117. {
  1118. if (nCount < 0)
  1119. nCount = 0;
  1120. else if (nCount > GetData()->nDataLength)
  1121. nCount = GetData()->nDataLength;
  1122. CString dest;
  1123. AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  1124. return dest;
  1125. }
  1126. inline CString CString::Left(int nCount) const
  1127. {
  1128. if (nCount < 0)
  1129. nCount = 0;
  1130. else if (nCount > GetData()->nDataLength)
  1131. nCount = GetData()->nDataLength;
  1132. CString dest;
  1133. AllocCopy(dest, nCount, 0, 0);
  1134. return dest;
  1135. }
  1136. // strspn equivalent
  1137. inline CString CString::SpanIncluding(LPCTSTR lpszCharSet) const
  1138. {
  1139. ATLASSERT(_IsValidString(lpszCharSet, FALSE));
  1140. return Left(_cstrspn(m_pchData, lpszCharSet));
  1141. }
  1142. // strcspn equivalent
  1143. inline CString CString::SpanExcluding(LPCTSTR lpszCharSet) const
  1144. {
  1145. ATLASSERT(_IsValidString(lpszCharSet, FALSE));
  1146. return Left(_cstrcspn(m_pchData, lpszCharSet));
  1147. }
  1148. inline int CString::ReverseFind(TCHAR ch) const
  1149. {
  1150. // find last single character
  1151. LPTSTR lpsz = _cstrrchr(m_pchData, (_TUCHAR)ch);
  1152. // return -1 if not found, distance from beginning otherwise
  1153. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1154. }
  1155. // find a sub-string (like strstr)
  1156. inline int CString::Find(LPCTSTR lpszSub) const
  1157. {
  1158. ATLASSERT(_IsValidString(lpszSub, FALSE));
  1159. // find first matching substring
  1160. LPTSTR lpsz = _cstrstr(m_pchData, lpszSub);
  1161. // return -1 for not found, distance from beginning otherwise
  1162. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1163. }
  1164. inline void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  1165. {
  1166. ATLASSERT(_IsValidString(lpszFormat, FALSE));
  1167. enum _FormatModifiers
  1168. {
  1169. FORCE_ANSI = 0x10000,
  1170. FORCE_UNICODE = 0x20000,
  1171. FORCE_INT64 = 0x40000
  1172. };
  1173. va_list argListSave = argList;
  1174. // make a guess at the maximum length of the resulting string
  1175. int nMaxLen = 0;
  1176. for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = ::CharNext(lpsz))
  1177. {
  1178. // handle '%' character, but watch out for '%%'
  1179. if (*lpsz != '%' || *(lpsz = ::CharNext(lpsz)) == '%')
  1180. {
  1181. nMaxLen += (int)lstrlen(lpsz);
  1182. continue;
  1183. }
  1184. int nItemLen = 0;
  1185. // handle '%' character with format
  1186. int nWidth = 0;
  1187. for (; *lpsz != '\0'; lpsz = ::CharNext(lpsz))
  1188. {
  1189. // check for valid flags
  1190. if (*lpsz == '#')
  1191. nMaxLen += 2; // for '0x'
  1192. else if (*lpsz == '*')
  1193. nWidth = va_arg(argList, int);
  1194. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' || *lpsz == ' ')
  1195. ;
  1196. else // hit non-flag character
  1197. break;
  1198. }
  1199. // get width and skip it
  1200. if (nWidth == 0)
  1201. {
  1202. // width indicated by
  1203. nWidth = _ttoi(lpsz);
  1204. for (; *lpsz != '\0' && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))
  1205. ;
  1206. }
  1207. ATLASSERT(nWidth >= 0);
  1208. int nPrecision = 0;
  1209. if (*lpsz == '.')
  1210. {
  1211. // skip past '.' separator (width.precision)
  1212. lpsz = ::CharNext(lpsz);
  1213. // get precision and skip it
  1214. if (*lpsz == '*')
  1215. {
  1216. nPrecision = va_arg(argList, int);
  1217. lpsz = ::CharNext(lpsz);
  1218. }
  1219. else
  1220. {
  1221. nPrecision = _ttoi(lpsz);
  1222. for (; *lpsz != '\0' && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))
  1223. ;
  1224. }
  1225. ATLASSERT(nPrecision >= 0);
  1226. }
  1227. // should be on type modifier or specifier
  1228. int nModifier = 0;
  1229. if(lpsz[0] == _T('I') && lpsz[1] == _T('6') && lpsz[2] == _T('4'))
  1230. {
  1231. lpsz += 3;
  1232. nModifier = FORCE_INT64;
  1233. }
  1234. else
  1235. {
  1236. switch (*lpsz)
  1237. {
  1238. // modifiers that affect size
  1239. case 'h':
  1240. nModifier = FORCE_ANSI;
  1241. lpsz = ::CharNext(lpsz);
  1242. break;
  1243. case 'l':
  1244. nModifier = FORCE_UNICODE;
  1245. lpsz = ::CharNext(lpsz);
  1246. break;
  1247. // modifiers that do not affect size
  1248. case 'F':
  1249. case 'N':
  1250. case 'L':
  1251. lpsz = ::CharNext(lpsz);
  1252. break;
  1253. }
  1254. }
  1255. // now should be on specifier
  1256. switch (*lpsz | nModifier)
  1257. {
  1258. // single characters
  1259. case 'c':
  1260. case 'C':
  1261. nItemLen = 2;
  1262. va_arg(argList, TCHAR);
  1263. break;
  1264. case 'c' | FORCE_ANSI:
  1265. case 'C' | FORCE_ANSI:
  1266. nItemLen = 2;
  1267. va_arg(argList, char);
  1268. break;
  1269. case 'c' | FORCE_UNICODE:
  1270. case 'C' | FORCE_UNICODE:
  1271. nItemLen = 2;
  1272. va_arg(argList, WCHAR);
  1273. break;
  1274. // strings
  1275. case 's':
  1276. {
  1277. LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  1278. if (pstrNextArg == NULL)
  1279. {
  1280. nItemLen = 6; // "(null)"
  1281. }
  1282. else
  1283. {
  1284. nItemLen = lstrlen(pstrNextArg);
  1285. nItemLen = max(1, nItemLen);
  1286. }
  1287. break;
  1288. }
  1289. case 'S':
  1290. {
  1291. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  1292. if (pstrNextArg == NULL)
  1293. {
  1294. nItemLen = 6; // "(null)"
  1295. }
  1296. else
  1297. {
  1298. nItemLen = lstrlenA(pstrNextArg);
  1299. nItemLen = max(1, nItemLen);
  1300. }
  1301. break;
  1302. }
  1303. case 's' | FORCE_ANSI:
  1304. case 'S' | FORCE_ANSI:
  1305. {
  1306. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  1307. if (pstrNextArg == NULL)
  1308. {
  1309. nItemLen = 6; // "(null)"
  1310. }
  1311. else
  1312. {
  1313. nItemLen = lstrlenA(pstrNextArg);
  1314. nItemLen = max(1, nItemLen);
  1315. }
  1316. break;
  1317. }
  1318. case 's' | FORCE_UNICODE:
  1319. case 'S' | FORCE_UNICODE:
  1320. {
  1321. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  1322. if (pstrNextArg == NULL)
  1323. {
  1324. nItemLen = 6; // "(null)"
  1325. }
  1326. else
  1327. {
  1328. nItemLen = (int)wcslen(pstrNextArg);
  1329. nItemLen = max(1, nItemLen);
  1330. }
  1331. break;
  1332. }
  1333. }
  1334. // adjust nItemLen for strings
  1335. if (nItemLen != 0)
  1336. {
  1337. nItemLen = max(nItemLen, nWidth);
  1338. if (nPrecision != 0)
  1339. nItemLen = min(nItemLen, nPrecision);
  1340. }
  1341. else
  1342. {
  1343. switch (*lpsz)
  1344. {
  1345. // integers
  1346. case 'd':
  1347. case 'i':
  1348. case 'u':
  1349. case 'x':
  1350. case 'X':
  1351. case 'o':
  1352. if (nModifier & FORCE_INT64)
  1353. va_arg(argList, __int64);
  1354. else
  1355. va_arg(argList, int);
  1356. nItemLen = 32;
  1357. nItemLen = max(nItemLen, nWidth + nPrecision);
  1358. break;
  1359. #ifndef _ATL_USE_CSTRING_FLOAT
  1360. case 'e':
  1361. case 'f':
  1362. case 'g':
  1363. case 'G':
  1364. ATLASSERT(!"Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class.");
  1365. #ifndef _DEBUG
  1366. ::OutputDebugString(_T("Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class."));
  1367. ::DebugBreak();
  1368. #endif //!_DEBUG
  1369. break;
  1370. #else //_ATL_USE_CSTRING_FLOAT
  1371. case 'e':
  1372. case 'g':
  1373. case 'G':
  1374. va_arg(argList, double);
  1375. nItemLen = 128;
  1376. nItemLen = max(nItemLen, nWidth + nPrecision);
  1377. break;
  1378. case 'f':
  1379. {
  1380. double f;
  1381. LPTSTR pszTemp;
  1382. // 312 == strlen("-1+(309 zeroes).")
  1383. // 309 zeroes == max precision of a double
  1384. // 6 == adjustment in case precision is not specified,
  1385. // which means that the precision defaults to 6
  1386. pszTemp = (LPTSTR)_alloca(max(nWidth, 312 + nPrecision + 6));
  1387. f = va_arg(argList, double);
  1388. _stprintf(pszTemp, _T( "%*.*f" ), nWidth, nPrecision + 6, f);
  1389. nItemLen = _tcslen(pszTemp);
  1390. }
  1391. break;
  1392. #endif //_ATL_USE_CSTRING_FLOAT
  1393. case 'p':
  1394. va_arg(argList, void*);
  1395. nItemLen = 32;
  1396. nItemLen = max(nItemLen, nWidth + nPrecision);
  1397. break;
  1398. // no output
  1399. case 'n':
  1400. va_arg(argList, int*);
  1401. break;
  1402. default:
  1403. ATLASSERT(FALSE); // unknown formatting option
  1404. }
  1405. }
  1406. // adjust nMaxLen for output nItemLen
  1407. nMaxLen += nItemLen;
  1408. }
  1409. GetBuffer(nMaxLen);
  1410. #ifndef _ATL_USE_CSTRING_FLOAT
  1411. int nRet = wvsprintf(m_pchData, lpszFormat, argListSave);
  1412. #else //_ATL_USE_CSTRING_FLOAT
  1413. int nRet = _vstprintf(m_pchData, lpszFormat, argListSave);
  1414. #endif //_ATL_USE_CSTRING_FLOAT
  1415. nRet; // ref
  1416. ATLASSERT(nRet <= GetAllocLength());
  1417. ReleaseBuffer();
  1418. va_end(argListSave);
  1419. }
  1420. // formatting (using wsprintf style formatting)
  1421. inline void __cdecl CString::Format(LPCTSTR lpszFormat, ...)
  1422. {
  1423. ATLASSERT(_IsValidString(lpszFormat, FALSE));
  1424. va_list argList;
  1425. va_start(argList, lpszFormat);
  1426. FormatV(lpszFormat, argList);
  1427. va_end(argList);
  1428. }
  1429. inline void __cdecl CString::Format(UINT nFormatID, ...)
  1430. {
  1431. CString strFormat;
  1432. BOOL bRet = strFormat.LoadString(nFormatID);
  1433. bRet; // ref
  1434. ATLASSERT(bRet != 0);
  1435. va_list argList;
  1436. va_start(argList, nFormatID);
  1437. FormatV(strFormat, argList);
  1438. va_end(argList);
  1439. }
  1440. // formatting (using FormatMessage style formatting)
  1441. inline BOOL __cdecl CString::FormatMessage(LPCTSTR lpszFormat, ...)
  1442. {
  1443. // format message into temporary buffer lpszTemp
  1444. va_list argList;
  1445. va_start(argList, lpszFormat);
  1446. LPTSTR lpszTemp;
  1447. BOOL bRet = TRUE;
  1448. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1449. lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL)
  1450. bRet = FALSE;
  1451. // assign lpszTemp into the resulting string and free the temporary
  1452. *this = lpszTemp;
  1453. LocalFree(lpszTemp);
  1454. va_end(argList);
  1455. return bRet;
  1456. }
  1457. inline BOOL __cdecl CString::FormatMessage(UINT nFormatID, ...)
  1458. {
  1459. // get format string from string table
  1460. CString strFormat;
  1461. BOOL bRetTmp = strFormat.LoadString(nFormatID);
  1462. bRetTmp; // ref
  1463. ATLASSERT(bRetTmp != 0);
  1464. // format message into temporary buffer lpszTemp
  1465. va_list argList;
  1466. va_start(argList, nFormatID);
  1467. LPTSTR lpszTemp;
  1468. BOOL bRet = TRUE;
  1469. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1470. (LPCTSTR)strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL)
  1471. bRet = FALSE;
  1472. // assign lpszTemp into the resulting string and free lpszTemp
  1473. *this = lpszTemp;
  1474. LocalFree(lpszTemp);
  1475. va_end(argList);
  1476. return bRet;
  1477. }
  1478. inline void CString::TrimRight()
  1479. {
  1480. CopyBeforeWrite();
  1481. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  1482. LPTSTR lpsz = m_pchData;
  1483. LPTSTR lpszLast = NULL;
  1484. while (*lpsz != '\0')
  1485. {
  1486. if (_cstrisspace(*lpsz))
  1487. {
  1488. if (lpszLast == NULL)
  1489. lpszLast = lpsz;
  1490. }
  1491. else
  1492. {
  1493. lpszLast = NULL;
  1494. }
  1495. lpsz = ::CharNext(lpsz);
  1496. }
  1497. if (lpszLast != NULL)
  1498. {
  1499. // truncate at trailing space start
  1500. *lpszLast = '\0';
  1501. GetData()->SetDataLength( (int)(DWORD_PTR)(lpszLast - m_pchData) );
  1502. }
  1503. }
  1504. inline void CString::TrimLeft()
  1505. {
  1506. CopyBeforeWrite();
  1507. // find first non-space character
  1508. LPCTSTR lpsz = m_pchData;
  1509. while (_cstrisspace(*lpsz))
  1510. lpsz = ::CharNext(lpsz);
  1511. // fix up data and length
  1512. int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);
  1513. memmove(m_pchData, lpsz, (nDataLength + 1) * sizeof(TCHAR));
  1514. GetData()->SetDataLength( nDataLength );
  1515. }
  1516. inline int CString::Delete(int nIndex, int nCount /* = 1 */)
  1517. {
  1518. if (nIndex < 0)
  1519. nIndex = 0;
  1520. int nNewLength = GetData()->nDataLength;
  1521. if (nCount > 0 && nIndex < nNewLength)
  1522. {
  1523. CopyBeforeWrite();
  1524. int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
  1525. memmove(m_pchData + nIndex, m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
  1526. GetData()->SetDataLength( nNewLength - nCount );
  1527. }
  1528. return nNewLength;
  1529. }
  1530. inline int CString::Insert(int nIndex, TCHAR ch)
  1531. {
  1532. CopyBeforeWrite();
  1533. if (nIndex < 0)
  1534. nIndex = 0;
  1535. int nNewLength = GetData()->nDataLength;
  1536. if (nIndex > nNewLength)
  1537. nIndex = nNewLength;
  1538. nNewLength++;
  1539. if (GetData()->nAllocLength < nNewLength)
  1540. {
  1541. CStringData* pOldData = GetData();
  1542. LPTSTR pstr = m_pchData;
  1543. if(!AllocBuffer(nNewLength))
  1544. return -1;
  1545. memcpy(m_pchData, pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
  1546. CString::Release(pOldData);
  1547. }
  1548. // move existing bytes down
  1549. memmove(m_pchData + nIndex + 1, m_pchData + nIndex, (nNewLength - nIndex) * sizeof(TCHAR));
  1550. m_pchData[nIndex] = ch;
  1551. GetData()->SetDataLength( nNewLength );
  1552. return nNewLength;
  1553. }
  1554. inline int CString::Insert(int nIndex, LPCTSTR pstr)
  1555. {
  1556. if (nIndex < 0)
  1557. nIndex = 0;
  1558. int nInsertLength = SafeStrlen(pstr);
  1559. int nNewLength = GetData()->nDataLength;
  1560. if (nInsertLength > 0)
  1561. {
  1562. CopyBeforeWrite();
  1563. if (nIndex > nNewLength)
  1564. nIndex = nNewLength;
  1565. nNewLength += nInsertLength;
  1566. if (GetData()->nAllocLength < nNewLength)
  1567. {
  1568. CStringData* pOldData = GetData();
  1569. LPTSTR pstr = m_pchData;
  1570. if(!AllocBuffer(nNewLength))
  1571. return -1;
  1572. memcpy(m_pchData, pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
  1573. CString::Release(pOldData);
  1574. }
  1575. // move existing bytes down
  1576. memmove(m_pchData + nIndex + nInsertLength, m_pchData + nIndex, (nNewLength - nIndex - nInsertLength + 1) * sizeof(TCHAR));
  1577. memcpy(m_pchData + nIndex, pstr, nInsertLength * sizeof(TCHAR));
  1578. GetData()->SetDataLength( nNewLength );
  1579. }
  1580. return nNewLength;
  1581. }
  1582. inline int CString::Replace(TCHAR chOld, TCHAR chNew)
  1583. {
  1584. int nCount = 0;
  1585. // short-circuit the nop case
  1586. if (chOld != chNew)
  1587. {
  1588. // otherwise modify each character that matches in the string
  1589. CopyBeforeWrite();
  1590. LPTSTR psz = m_pchData;
  1591. LPTSTR pszEnd = psz + GetData()->nDataLength;
  1592. while (psz < pszEnd)
  1593. {
  1594. // replace instances of the specified character only
  1595. if (*psz == chOld)
  1596. {
  1597. *psz = chNew;
  1598. nCount++;
  1599. }
  1600. psz = ::CharNext(psz);
  1601. }
  1602. }
  1603. return nCount;
  1604. }
  1605. inline int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
  1606. {
  1607. // can't have empty or NULL lpszOld
  1608. int nSourceLen = SafeStrlen(lpszOld);
  1609. if (nSourceLen == 0)
  1610. return 0;
  1611. int nReplacementLen = SafeStrlen(lpszNew);
  1612. // loop once to figure out the size of the result string
  1613. int nCount = 0;
  1614. LPTSTR lpszStart = m_pchData;
  1615. LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
  1616. LPTSTR lpszTarget;
  1617. while (lpszStart < lpszEnd)
  1618. {
  1619. while ((lpszTarget = _cstrstr(lpszStart, lpszOld)) != NULL)
  1620. {
  1621. nCount++;
  1622. lpszStart = lpszTarget + nSourceLen;
  1623. }
  1624. lpszStart += lstrlen(lpszStart) + 1;
  1625. }
  1626. // if any changes were made, make them
  1627. if (nCount > 0)
  1628. {
  1629. CopyBeforeWrite();
  1630. // if the buffer is too small, just
  1631. // allocate a new buffer (slow but sure)
  1632. int nOldLength = GetData()->nDataLength;
  1633. int nNewLength = nOldLength + (nReplacementLen - nSourceLen) * nCount;
  1634. if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
  1635. {
  1636. CStringData* pOldData = GetData();
  1637. LPTSTR pstr = m_pchData;
  1638. if(!AllocBuffer(nNewLength))
  1639. return -1;
  1640. memcpy(m_pchData, pstr, pOldData->nDataLength * sizeof(TCHAR));
  1641. CString::Release(pOldData);
  1642. }
  1643. // else, we just do it in-place
  1644. lpszStart = m_pchData;
  1645. lpszEnd = m_pchData + GetData()->nDataLength;
  1646. // loop again to actually do the work
  1647. while (lpszStart < lpszEnd)
  1648. {
  1649. while ( (lpszTarget = _cstrstr(lpszStart, lpszOld)) != NULL)
  1650. {
  1651. int nBalance = nOldLength - ((int)(DWORD_PTR)(lpszTarget - m_pchData) + nSourceLen);
  1652. memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen, nBalance * sizeof(TCHAR));
  1653. memcpy(lpszTarget, lpszNew, nReplacementLen * sizeof(TCHAR));
  1654. lpszStart = lpszTarget + nReplacementLen;
  1655. lpszStart[nBalance] = '\0';
  1656. nOldLength += (nReplacementLen - nSourceLen);
  1657. }
  1658. lpszStart += lstrlen(lpszStart) + 1;
  1659. }
  1660. ATLASSERT(m_pchData[nNewLength] == '\0');
  1661. GetData()->SetDataLength( nNewLength );
  1662. }
  1663. return nCount;
  1664. }
  1665. inline int CString::Remove(TCHAR chRemove)
  1666. {
  1667. CopyBeforeWrite();
  1668. LPTSTR pstrSource = m_pchData;
  1669. LPTSTR pstrDest = m_pchData;
  1670. LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;
  1671. while (pstrSource < pstrEnd)
  1672. {
  1673. if (*pstrSource != chRemove)
  1674. {
  1675. *pstrDest = *pstrSource;
  1676. pstrDest = ::CharNext(pstrDest);
  1677. }
  1678. pstrSource = ::CharNext(pstrSource);
  1679. }
  1680. *pstrDest = '\0';
  1681. int nCount = (int)(DWORD_PTR)(pstrSource - pstrDest);
  1682. GetData()->SetDataLength( GetData()->nDataLength - nCount );
  1683. return nCount;
  1684. }
  1685. #define CHAR_FUDGE 1 // one TCHAR unused is good enough
  1686. inline BOOL CString::LoadString(UINT nID)
  1687. {
  1688. // try fixed buffer first (to avoid wasting space in the heap)
  1689. TCHAR szTemp[256];
  1690. int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
  1691. int nLen = _LoadString(nID, szTemp, nCount);
  1692. if (nCount - nLen > CHAR_FUDGE)
  1693. {
  1694. *this = szTemp;
  1695. return nLen > 0;
  1696. }
  1697. // try buffer size of 512, then larger size until entire string is retrieved
  1698. int nSize = 256;
  1699. do
  1700. {
  1701. nSize += 256;
  1702. nLen = _LoadString(nID, GetBuffer(nSize - 1), nSize);
  1703. } while (nSize - nLen <= CHAR_FUDGE);
  1704. ReleaseBuffer();
  1705. return nLen > 0;
  1706. }
  1707. #ifndef _ATL_NO_COM
  1708. inline BSTR CString::AllocSysString() const
  1709. {
  1710. BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);
  1711. return bstr;
  1712. }
  1713. inline BSTR CString::SetSysString(BSTR* pbstr) const
  1714. {
  1715. ::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength);
  1716. ATLASSERT(*pbstr != NULL);
  1717. return *pbstr;
  1718. }
  1719. #endif //!_ATL_NO_COM
  1720. #endif //!_WTL_NO_CSTRING
  1721. }; //namespace LBSTR
  1722. #endif // _UNICODE
  1723. #endif // __LOCAL_BSTR__