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.

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