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.

3258 lines
77 KiB

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-2001 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CSTRINGT.H - Framework-independent, templateable string class
  12. #ifndef __CSTRINGT_H__
  13. #define __CSTRINGT_H__
  14. #pragma once
  15. #pragma warning(disable:4786) // avoid 255-character limit warnings
  16. #ifdef _MANAGED
  17. #include <vcclr.h> // For PtrToStringChars
  18. #endif
  19. #include <atlsimpstr.h>
  20. #include <objbase.h>
  21. #include <oleauto.h>
  22. #include <stddef.h>
  23. #ifndef _INC_NEW
  24. #include <new.h>
  25. #endif
  26. #include <stdio.h>
  27. #include <limits.h>
  28. #ifndef _ATL_NO_DEBUG_CRT
  29. #include <crtdbg.h>
  30. #endif
  31. #ifndef _ATL_MIN_CRT
  32. #include <mbstring.h>
  33. #endif
  34. #ifdef _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
  35. #define CSTRING_EXPLICIT explicit
  36. #else
  37. #define CSTRING_EXPLICIT
  38. #endif
  39. #include <atlconv.h>
  40. #include <atlmem.h>
  41. #pragma push_macro("new")
  42. #undef new
  43. /////////////////////////////////////////////////////////////////////////////
  44. // Naming conventions:
  45. // The term "length" can be confusing when dealing with ANSI, Unicode, and
  46. // MBCS character sets, so this file will use the following naming
  47. // conventions to differentiate between the different meanings of
  48. // "length":
  49. //
  50. // 'Byte Length' - Length of a buffer in bytes, regardless of character
  51. // size
  52. // 'Char Length' - Number of distinct characters in string. For wide-
  53. // character strings, this is equivalent to half the 'Byte Length'.
  54. // For ANSI strings, this is equivalent to the 'Byte Length'. For MBCS
  55. // strings, 'Char Length' counts a lead-byte/trail-byte combination
  56. // as one character.
  57. // 'Length' - When neither of the above terms is used, 'Length' refers to
  58. // length in XCHARs, which is equal to 'Byte Length'/sizeof(XCHAR).
  59. /////////////////////////////////////////////////////////////////////////////
  60. namespace ATL
  61. {
  62. /////////////////////////////////////////////////////////////////////////////
  63. // inline helpers
  64. inline int _wcstombsz(char* mbstr, const wchar_t* wcstr, ULONG count) throw()
  65. {
  66. // count is number of bytes
  67. if (count == 0 && mbstr != NULL)
  68. return 0;
  69. int result = ::WideCharToMultiByte(_AtlGetConversionACP(), 0, wcstr, -1,
  70. mbstr, count, NULL, NULL);
  71. ATLASSERT(mbstr == NULL || result <= (int)count);
  72. return result;
  73. }
  74. inline int _mbstowcsz(wchar_t* wcstr, const char* mbstr, ULONG count) throw()
  75. {
  76. // count is number of wchar_t's
  77. if (count == 0 && wcstr != NULL)
  78. return 0;
  79. int result = ::MultiByteToWideChar(_AtlGetConversionACP(), 0, mbstr, -1,
  80. wcstr, count);
  81. ATLASSERT(wcstr == NULL || result <= (int)count);
  82. if ((result > 0) && (wcstr != NULL))
  83. wcstr[result-1] = 0;
  84. return result;
  85. }
  86. #if !defined(_UNICODE) || defined(_CSTRING_ALWAYS_THUNK)
  87. // Win9x doesn't support Unicode versions of these useful string functions.
  88. // If the app was built without _UNICODE defined, we thunk at runtime to
  89. // either the real Unicode implementation (on NT), or a conversion helper
  90. // (on Win9x).
  91. inline void _AtlInstallStringThunk(void** ppThunk, void* pfnWin9x, void* pfnNT) throw()
  92. {
  93. static bool s_bWin9x = (::GetVersion()&0x80000000) != 0;
  94. void* pfn;
  95. if (s_bWin9x)
  96. pfn = pfnWin9x;
  97. else
  98. {
  99. #ifdef _CSTRING_ALWAYS_THUNK
  100. pfn = pfnWin9x;
  101. (void)pfnNT;
  102. #else
  103. pfn = pfnNT;
  104. #endif
  105. }
  106. InterlockedExchangePointer(ppThunk, pfn);
  107. }
  108. typedef int (WINAPI* ATLCOMPARESTRINGW)(LCID, DWORD, LPCWSTR, int, LPCWSTR, int);
  109. typedef BOOL (WINAPI* ATLGETSTRINGTYPEEXW)(LCID, DWORD, LPCWSTR, int, LPWORD);
  110. typedef int (WINAPI* ATLLSTRCMPIW)(LPCWSTR, LPCWSTR);
  111. typedef LPWSTR (WINAPI* ATLCHARLOWERW)(LPWSTR);
  112. typedef LPWSTR (WINAPI* ATLCHARUPPERW)(LPWSTR);
  113. typedef DWORD (WINAPI* ATLGETENVIRONMENTVARIABLEW)(LPCWSTR, LPWSTR, DWORD);
  114. struct _AtlStringThunks
  115. {
  116. ATLCOMPARESTRINGW pfnCompareStringW;
  117. ATLGETSTRINGTYPEEXW pfnGetStringTypeExW;
  118. ATLLSTRCMPIW pfnlstrcmpiW;
  119. ATLCHARLOWERW pfnCharLowerW;
  120. ATLCHARUPPERW pfnCharUpperW;
  121. ATLGETENVIRONMENTVARIABLEW pfnGetEnvironmentVariableW;
  122. };
  123. extern _AtlStringThunks _strthunks;
  124. inline DWORD WINAPI GetEnvironmentVariableWFake(LPCWSTR pszName,
  125. LPWSTR pszBuffer, DWORD nSize)
  126. {
  127. USES_CONVERSION;
  128. ULONG nSizeA;
  129. ULONG nSizeW;
  130. LPSTR pszNameA;
  131. LPSTR pszBufferA;
  132. pszNameA = W2A(pszName);
  133. nSizeA = ::GetEnvironmentVariableA(pszNameA, NULL, 0);
  134. if (nSizeA == 0)
  135. return 0;
  136. pszBufferA = LPSTR(_alloca(nSizeA*2));
  137. ::GetEnvironmentVariableA(pszNameA, pszBufferA, nSizeA);
  138. nSizeW = ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszBufferA, -1, NULL, 0);
  139. if (nSize == 0)
  140. return nSizeW;
  141. ATLASSERT(nSize >= nSizeW);
  142. ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszBufferA, -1, pszBuffer, nSizeW);
  143. return nSizeW;
  144. }
  145. inline DWORD WINAPI GetEnvironmentVariableWThunk(LPCWSTR pszName,
  146. LPWSTR pszBuffer, DWORD nSize)
  147. {
  148. _AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnGetEnvironmentVariableW),
  149. GetEnvironmentVariableWFake, ::GetEnvironmentVariableW);
  150. return _strthunks.pfnGetEnvironmentVariableW(pszName, pszBuffer, nSize);
  151. }
  152. inline int WINAPI CompareStringWFake(LCID lcid, DWORD dwFlags,
  153. LPCWSTR pszString1, int nLength1, LPCWSTR pszString2, int nLength2)
  154. {
  155. USES_CONVERSION;
  156. return ::CompareStringA(lcid, dwFlags, W2A(pszString1), nLength1, W2A(pszString2), nLength2);
  157. }
  158. inline int WINAPI CompareStringWThunk(LCID lcid, DWORD dwFlags,
  159. LPCWSTR pszString1, int nLength1, LPCWSTR pszString2, int nLength2)
  160. {
  161. _AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnCompareStringW), CompareStringWFake, ::CompareStringW);
  162. return _strthunks.pfnCompareStringW(lcid, dwFlags, pszString1, nLength1, pszString2, nLength2);
  163. }
  164. inline BOOL WINAPI GetStringTypeExWFake(LCID lcid, DWORD dwInfoType, LPCWSTR pszSrc,
  165. int nLength, LPWORD pwCharType)
  166. {
  167. int nLengthA;
  168. LPSTR pszA;
  169. nLengthA = ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0, NULL, NULL);
  170. pszA = LPSTR(_alloca(nLengthA*sizeof(char)));
  171. ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nLength, pszA, nLengthA, NULL, NULL);
  172. if (nLength == -1)
  173. nLengthA = -1;
  174. return ::GetStringTypeExA(lcid, dwInfoType, pszA, nLengthA, pwCharType);
  175. }
  176. inline BOOL WINAPI GetStringTypeExWThunk(LCID lcid, DWORD dwInfoType, LPCWSTR pszSrc,
  177. int nLength, LPWORD pwCharType)
  178. {
  179. _AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnGetStringTypeExW), GetStringTypeExWFake, ::GetStringTypeExW);
  180. return _strthunks.pfnGetStringTypeExW(lcid, dwInfoType, pszSrc, nLength, pwCharType);
  181. }
  182. inline int WINAPI lstrcmpiWFake(LPCWSTR psz1, LPCWSTR psz2)
  183. {
  184. USES_CONVERSION;
  185. return ::lstrcmpiA(W2A(psz1), W2A(psz2));
  186. }
  187. inline int WINAPI lstrcmpiWThunk(LPCWSTR psz1, LPCWSTR psz2)
  188. {
  189. _AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnlstrcmpiW), lstrcmpiWFake, ::lstrcmpiW);
  190. return _strthunks.pfnlstrcmpiW(psz1, psz2);
  191. }
  192. inline LPWSTR WINAPI CharLowerWFake(LPWSTR psz)
  193. {
  194. USES_CONVERSION;
  195. LPSTR pszA;
  196. pszA = W2A(psz);
  197. ::CharLowerA(pszA);
  198. wcscpy(psz, A2W(pszA));
  199. return psz;
  200. }
  201. inline LPWSTR WINAPI CharLowerWThunk(LPWSTR psz)
  202. {
  203. _AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnCharLowerW), CharLowerWFake, ::CharLowerW);
  204. return _strthunks.pfnCharLowerW(psz);
  205. }
  206. inline LPWSTR WINAPI CharUpperWFake(LPWSTR psz)
  207. {
  208. USES_CONVERSION;
  209. LPSTR pszA;
  210. pszA = W2A(psz);
  211. ::CharUpperA(pszA);
  212. wcscpy(psz, A2W(pszA));
  213. return psz;
  214. }
  215. inline LPWSTR WINAPI CharUpperWThunk(LPWSTR psz)
  216. {
  217. _AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnCharUpperW), CharUpperWFake, ::CharUpperW);
  218. return _strthunks.pfnCharUpperW(psz);
  219. }
  220. __declspec(selectany) _AtlStringThunks _strthunks =
  221. {
  222. CompareStringWThunk,
  223. GetStringTypeExWThunk,
  224. lstrcmpiWThunk,
  225. CharLowerWThunk,
  226. CharUpperWThunk,
  227. GetEnvironmentVariableWThunk
  228. };
  229. #endif // !_UNICODE
  230. /////////////////////////////////////////////////////////////////////////////
  231. //
  232. #ifndef _ATL_MIN_CRT
  233. template< typename _CharType = char >
  234. class ChTraitsCRT :
  235. public ChTraitsBase< _CharType >
  236. {
  237. public:
  238. static char* CharNext( const char* p ) throw()
  239. {
  240. return reinterpret_cast< char* >( _mbsinc( reinterpret_cast< const unsigned char* >( p ) ) );
  241. }
  242. static int IsDigit( char ch ) throw()
  243. {
  244. return _ismbcdigit( ch );
  245. }
  246. static int IsSpace( char ch ) throw()
  247. {
  248. return _ismbcspace( ch );
  249. }
  250. static int StringCompare( LPCSTR pszA, LPCSTR pszB ) throw()
  251. {
  252. return _mbscmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
  253. }
  254. static int StringCompareIgnore( LPCSTR pszA, LPCSTR pszB ) throw()
  255. {
  256. return _mbsicmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
  257. }
  258. static int StringCollate( LPCSTR pszA, LPCSTR pszB ) throw()
  259. {
  260. return _mbscoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
  261. }
  262. static int StringCollateIgnore( LPCSTR pszA, LPCSTR pszB ) throw()
  263. {
  264. return _mbsicoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
  265. }
  266. static LPSTR StringFindString( LPCSTR pszBlock, LPCSTR pszMatch ) throw()
  267. {
  268. return reinterpret_cast< LPSTR >( _mbsstr( reinterpret_cast< const unsigned char* >( pszBlock ),
  269. reinterpret_cast< const unsigned char* >( pszMatch ) ) );
  270. }
  271. static LPSTR StringFindChar( LPCSTR pszBlock, char chMatch ) throw()
  272. {
  273. return reinterpret_cast< LPSTR >( _mbschr( reinterpret_cast< const unsigned char* >( pszBlock ), chMatch ) );
  274. }
  275. static LPSTR StringFindCharRev( LPCSTR psz, char ch ) throw()
  276. {
  277. return reinterpret_cast< LPSTR >( _mbsrchr( reinterpret_cast< const unsigned char* >( psz ), ch ) );
  278. }
  279. static LPSTR StringScanSet( LPCSTR pszBlock, LPCSTR pszMatch ) throw()
  280. {
  281. return reinterpret_cast< LPSTR >( _mbspbrk( reinterpret_cast< const unsigned char* >( pszBlock ),
  282. reinterpret_cast< const unsigned char* >( pszMatch ) ) );
  283. }
  284. static int StringSpanIncluding( LPCSTR pszBlock, LPCSTR pszSet ) throw()
  285. {
  286. return (int)_mbsspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet ) );
  287. }
  288. static int StringSpanExcluding( LPCSTR pszBlock, LPCSTR pszSet ) throw()
  289. {
  290. return (int)_mbscspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet ) );
  291. }
  292. static LPSTR StringUppercase( LPSTR psz ) throw()
  293. {
  294. return reinterpret_cast< LPSTR >( _mbsupr( reinterpret_cast< unsigned char* >( psz ) ) );
  295. }
  296. static LPSTR StringLowercase( LPSTR psz ) throw()
  297. {
  298. return reinterpret_cast< LPSTR >( _mbslwr( reinterpret_cast< unsigned char* >( psz ) ) );
  299. }
  300. static LPSTR StringReverse( LPSTR psz ) throw()
  301. {
  302. return reinterpret_cast< LPSTR >( _mbsrev( reinterpret_cast< unsigned char* >( psz ) ) );
  303. }
  304. static int GetFormattedLength( LPCSTR pszFormat, va_list args ) throw()
  305. {
  306. return _vscprintf( pszFormat, args );
  307. }
  308. static int Format( LPSTR pszBuffer, LPCSTR pszFormat, va_list args ) throw()
  309. {
  310. return vsprintf( pszBuffer, pszFormat, args );
  311. }
  312. static int GetBaseTypeLength( LPCSTR pszSrc ) throw()
  313. {
  314. // Returns required buffer length in XCHARs
  315. return int( strlen( pszSrc ) );
  316. }
  317. static int GetBaseTypeLength( LPCSTR pszSrc, int nLength ) throw()
  318. {
  319. (void)pszSrc;
  320. // Returns required buffer length in XCHARs
  321. return nLength;
  322. }
  323. static int GetBaseTypeLength( LPCWSTR pszSource ) throw()
  324. {
  325. // Returns required buffer length in XCHARs
  326. return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL )-1;
  327. }
  328. static int GetBaseTypeLength( LPCWSTR pszSource, int nLength ) throw()
  329. {
  330. // Returns required buffer length in XCHARs
  331. return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL );
  332. }
  333. static void ConvertToBaseType( LPSTR pszDest, int nDestLength,
  334. LPCSTR pszSrc, int nSrcLength = -1 ) throw()
  335. {
  336. (void)nSrcLength;
  337. // nLen is in XCHARs
  338. memcpy( pszDest, pszSrc, nDestLength*sizeof( char ) );
  339. }
  340. static void ConvertToBaseType( LPSTR pszDest, int nDestLength,
  341. LPCWSTR pszSrc, int nSrcLength = -1 ) throw()
  342. {
  343. // nLen is in XCHARs
  344. ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL );
  345. }
  346. static void ConvertToOem( LPSTR psz ) throw()
  347. {
  348. ::AnsiToOem( psz, psz );
  349. }
  350. static void ConvertToAnsi( LPSTR psz ) throw()
  351. {
  352. ::OemToAnsi( psz, psz );
  353. }
  354. static void FloodCharacters( char ch, int nLength, char* pch ) throw()
  355. {
  356. // nLength is in XCHARs
  357. memset( pch, ch, nLength );
  358. }
  359. static BSTR AllocSysString( const char* pchData, int nDataLength ) throw()
  360. {
  361. int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength,
  362. NULL, NULL );
  363. BSTR bstr = ::SysAllocStringLen( NULL, nLen );
  364. if( bstr != NULL )
  365. {
  366. ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength,
  367. bstr, nLen );
  368. }
  369. return bstr;
  370. }
  371. static BOOL ReAllocSysString( const char* pchData, BSTR* pbstr, int nDataLength ) throw()
  372. {
  373. int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL );
  374. BOOL bSuccess = ::SysReAllocStringLen( pbstr, NULL, nLen );
  375. if( bSuccess )
  376. {
  377. ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, *pbstr, nLen );
  378. }
  379. return bSuccess;
  380. }
  381. static DWORD FormatMessage( DWORD dwFlags, LPCVOID pSource,
  382. DWORD dwMessageID, DWORD dwLanguageID, LPSTR pszBuffer,
  383. DWORD nSize, va_list* pArguments ) throw()
  384. {
  385. return ::FormatMessageA( dwFlags, pSource, dwMessageID, dwLanguageID,
  386. pszBuffer, nSize, pArguments );
  387. }
  388. static int SafeStringLen( LPCSTR psz ) throw()
  389. {
  390. // returns length in bytes
  391. return (psz != NULL) ? int( strlen( psz ) ) : 0;
  392. }
  393. static int SafeStringLen( LPCWSTR psz ) throw()
  394. {
  395. // returns length in wchar_ts
  396. return (psz != NULL) ? int( wcslen( psz ) ) : 0;
  397. }
  398. static int GetCharLen( const wchar_t* pch ) throw()
  399. {
  400. (void)pch;
  401. // returns char length
  402. return 1;
  403. }
  404. static int GetCharLen( const char* pch ) throw()
  405. {
  406. // returns char length
  407. return int( _mbclen( reinterpret_cast< const unsigned char* >( pch ) ) );
  408. }
  409. static DWORD GetEnvironmentVariable( LPCSTR pszVar,
  410. LPSTR pszBuffer, DWORD dwSize ) throw()
  411. {
  412. return ::GetEnvironmentVariableA( pszVar, pszBuffer, dwSize );
  413. }
  414. };
  415. // specialization for wchar_t
  416. template<>
  417. class ChTraitsCRT< wchar_t > :
  418. public ChTraitsBase< wchar_t >
  419. {
  420. #if defined(_UNICODE) && !defined(_CSTRING_ALWAYS_THUNK)
  421. static DWORD _GetEnvironmentVariableW( LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize ) throw()
  422. {
  423. return ::GetEnvironmentVariableW( pszName, pszBuffer, nSize );
  424. }
  425. #else // !_UNICODE
  426. static DWORD WINAPI _GetEnvironmentVariableW( LPCWSTR pszName,
  427. LPWSTR pszBuffer, DWORD nSize ) throw()
  428. {
  429. return _strthunks.pfnGetEnvironmentVariableW( pszName, pszBuffer, nSize );
  430. }
  431. #endif // !_UNICODE
  432. public:
  433. static LPWSTR CharNext( LPCWSTR psz ) throw()
  434. {
  435. return const_cast< LPWSTR >( psz+1 );
  436. }
  437. static int IsDigit( wchar_t ch ) throw()
  438. {
  439. return iswdigit( ch );
  440. }
  441. static int IsSpace( wchar_t ch ) throw()
  442. {
  443. return iswspace( ch );
  444. }
  445. static int StringCompare( LPCWSTR pszA, LPCWSTR pszB ) throw()
  446. {
  447. return wcscmp( pszA, pszB );
  448. }
  449. static int StringCompareIgnore( LPCWSTR pszA, LPCWSTR pszB ) throw()
  450. {
  451. return _wcsicmp( pszA, pszB );
  452. }
  453. static int StringCollate( LPCWSTR pszA, LPCWSTR pszB ) throw()
  454. {
  455. return wcscoll( pszA, pszB );
  456. }
  457. static int StringCollateIgnore( LPCWSTR pszA, LPCWSTR pszB ) throw()
  458. {
  459. return _wcsicoll( pszA, pszB );
  460. }
  461. static LPWSTR StringFindString( LPCWSTR pszBlock, LPCWSTR pszMatch ) throw()
  462. {
  463. return wcsstr( pszBlock, pszMatch );
  464. }
  465. static LPWSTR StringFindChar( LPCWSTR pszBlock, wchar_t chMatch ) throw()
  466. {
  467. return wcschr( pszBlock, chMatch );
  468. }
  469. static LPWSTR StringFindCharRev( LPCWSTR psz, wchar_t ch ) throw()
  470. {
  471. return wcsrchr( psz, ch );
  472. }
  473. static LPWSTR StringScanSet( LPCWSTR pszBlock, LPCWSTR pszMatch ) throw()
  474. {
  475. return wcspbrk( pszBlock, pszMatch );
  476. }
  477. static int StringSpanIncluding( LPCWSTR pszBlock, LPCWSTR pszSet ) throw()
  478. {
  479. return (int)wcsspn( pszBlock, pszSet );
  480. }
  481. static int StringSpanExcluding( LPCWSTR pszBlock, LPCWSTR pszSet ) throw()
  482. {
  483. return (int)wcscspn( pszBlock, pszSet );
  484. }
  485. static LPWSTR StringUppercase( LPWSTR psz ) throw()
  486. {
  487. return _wcsupr( psz );
  488. }
  489. static LPWSTR StringLowercase( LPWSTR psz ) throw()
  490. {
  491. return _wcslwr( psz );
  492. }
  493. static LPWSTR StringReverse( LPWSTR psz ) throw()
  494. {
  495. return _wcsrev( psz );
  496. }
  497. static int GetFormattedLength( LPCWSTR pszFormat, va_list args) throw()
  498. {
  499. return _vscwprintf( pszFormat, args );
  500. }
  501. static int Format( LPWSTR pszBuffer, LPCWSTR pszFormat, va_list args) throw()
  502. {
  503. return vswprintf( pszBuffer, pszFormat, args );
  504. }
  505. static int GetBaseTypeLength( LPCSTR pszSrc ) throw()
  506. {
  507. // Returns required buffer size in wchar_ts
  508. return ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, -1, NULL, 0 )-1;
  509. }
  510. static int GetBaseTypeLength( LPCSTR pszSrc, int nLength ) throw()
  511. {
  512. // Returns required buffer size in wchar_ts
  513. return ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0 );
  514. }
  515. static int GetBaseTypeLength( LPCWSTR pszSrc ) throw()
  516. {
  517. // Returns required buffer size in wchar_ts
  518. return (int)wcslen( pszSrc );
  519. }
  520. static int GetBaseTypeLength( LPCWSTR pszSrc, int nLength ) throw()
  521. {
  522. (void)pszSrc;
  523. // Returns required buffer size in wchar_ts
  524. return nLength;
  525. }
  526. static void ConvertToBaseType( LPWSTR pszDest, int nDestLength,
  527. LPCSTR pszSrc, int nSrcLength = -1) throw()
  528. {
  529. // nLen is in wchar_ts
  530. ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength );
  531. }
  532. static void ConvertToBaseType( LPWSTR pszDest, int nDestLength,
  533. LPCWSTR pszSrc, int nSrcLength = -1) throw()
  534. {
  535. (void)nSrcLength;
  536. // nLen is in wchar_ts
  537. memcpy( pszDest, pszSrc, nDestLength*sizeof( wchar_t ) );
  538. }
  539. static void FloodCharacters( wchar_t ch, int nLength, LPWSTR psz ) throw()
  540. {
  541. // nLength is in XCHARs
  542. for( int i = 0; i < nLength; i++ )
  543. {
  544. psz[i] = ch;
  545. }
  546. }
  547. static BSTR AllocSysString( const wchar_t* pchData, int nDataLength ) throw()
  548. {
  549. return ::SysAllocStringLen( pchData, nDataLength );
  550. }
  551. static BOOL ReAllocSysString( const wchar_t* pchData, BSTR* pbstr, int nDataLength ) throw()
  552. {
  553. return ::SysReAllocStringLen( pbstr, pchData, nDataLength );
  554. }
  555. #ifdef _UNICODE
  556. static DWORD FormatMessage( DWORD dwFlags, LPCVOID pSource,
  557. DWORD dwMessageID, DWORD dwLanguageID, LPWSTR pszBuffer,
  558. DWORD nSize, va_list* pArguments ) throw()
  559. {
  560. return ::FormatMessageW( dwFlags, pSource, dwMessageID, dwLanguageID,
  561. pszBuffer, nSize, pArguments );
  562. }
  563. #endif
  564. static int SafeStringLen( LPCSTR psz ) throw()
  565. {
  566. // returns length in bytes
  567. return (psz != NULL) ? (int)strlen( psz ) : 0;
  568. }
  569. static int SafeStringLen( LPCWSTR psz ) throw()
  570. {
  571. // returns length in wchar_ts
  572. return (psz != NULL) ? (int)wcslen( psz ) : 0;
  573. }
  574. static int GetCharLen( const wchar_t* pch ) throw()
  575. {
  576. (void)pch;
  577. // returns char length
  578. return 1;
  579. }
  580. static int GetCharLen( const char* pch ) throw()
  581. {
  582. // returns char length
  583. return (int)( _mbclen( reinterpret_cast< const unsigned char* >( pch ) ) );
  584. }
  585. static DWORD GetEnvironmentVariable( LPCWSTR pszVar, LPWSTR pszBuffer, DWORD dwSize ) throw()
  586. {
  587. return _GetEnvironmentVariableW( pszVar, pszBuffer, dwSize );
  588. }
  589. };
  590. #endif // _ATL_MIN_CRT
  591. template< typename _CharType = char >
  592. class ChTraitsOS :
  593. public ChTraitsBase< _CharType >
  594. {
  595. public:
  596. static int tclen(const _CharType* p) throw()
  597. {
  598. ATLASSERT(p != NULL);
  599. _CharType* pnext = CharNext(p);
  600. return ((pnext-p)>1) ? 2 : 1;
  601. }
  602. static _CharType* strchr(const _CharType* p, _CharType ch) throw()
  603. {
  604. ATLASSERT(p != NULL);
  605. //strchr for '\0' should succeed
  606. do
  607. {
  608. if (*p == ch)
  609. {
  610. return const_cast< _CharType* >( p );
  611. }
  612. p = CharNext(p);
  613. } while( *p != 0 );
  614. return NULL;
  615. }
  616. static _CharType* strchr_db(const _CharType* p, char ch1, char ch2) throw()
  617. {
  618. ATLASSERT(p != NULL);
  619. while (*p != 0)
  620. {
  621. if (*p == ch1 && *(p+1) == ch2)
  622. {
  623. return const_cast< _CharType* >( p );
  624. }
  625. p = CharNext(p);
  626. }
  627. return NULL;
  628. }
  629. static _CharType* strrchr(const _CharType* p, _CharType ch) throw()
  630. {
  631. ATLASSERT(p != NULL);
  632. const _CharType* pch = NULL;
  633. while (*p != 0)
  634. {
  635. if (*p == ch)
  636. pch = p;
  637. p = CharNext(p);
  638. }
  639. return const_cast< _CharType* >( pch );
  640. }
  641. static _CharType* _strrev(_CharType* psz) throw()
  642. {
  643. // Optimize NULL, zero-length, and single-char case.
  644. if ((psz == NULL) || (psz[0] == '\0') || (psz[1] == '\0'))
  645. return psz;
  646. _CharType* p = psz;
  647. while (p[1] != 0)
  648. {
  649. _CharType* pNext = CharNext(p);
  650. if(pNext > p + 1)
  651. {
  652. char p1 = *p;
  653. *p = *(p + 1);
  654. *(p + 1) = p1;
  655. }
  656. p = pNext;
  657. }
  658. _CharType* q = psz;
  659. while (q < p)
  660. {
  661. _CharType t = *q;
  662. *q = *p;
  663. *p = t;
  664. q++;
  665. p--;
  666. }
  667. return psz;
  668. }
  669. static _CharType* strstr(const _CharType* pStr, const _CharType* pCharSet) throw()
  670. {
  671. ATLASSERT(p != NULL);
  672. int nLen = lstrlenA(pCharSet);
  673. if (nLen == 0)
  674. return const_cast<_CharType*>(pStr);
  675. const _CharType* pMatch;
  676. const _CharType* pStart = pStr;
  677. while ((pMatch = strchr(pStart, *pCharSet)) != NULL)
  678. {
  679. if (memcmp(pMatch, pCharSet, nLen*sizeof(_CharType)) == 0)
  680. return const_cast<_CharType*>(pMatch);
  681. pStart = CharNextA(pMatch);
  682. }
  683. return NULL;
  684. }
  685. static int strspn(const _CharType* pStr, const _CharType* pCharSet) throw()
  686. {
  687. ATLASSERT(p != NULL);
  688. int nRet = 0;
  689. _CharType* p = pStr;
  690. while (*p != 0)
  691. {
  692. _CharType* pNext = CharNext(p);
  693. if(pNext > p + 1)
  694. {
  695. if(strchr_db(pCharSet, *p, *(p+1)) == NULL)
  696. break;
  697. nRet += 2;
  698. }
  699. else
  700. {
  701. if(strchr(pCharSet, *p) == NULL)
  702. break;
  703. nRet++;
  704. }
  705. p = pNext;
  706. }
  707. return nRet;
  708. }
  709. static int strcspn(const _CharType* pStr, const _CharType* pCharSet) throw()
  710. {
  711. ATLASSERT(p != NULL);
  712. int nRet = 0;
  713. _CharType* p = pStr;
  714. while (*p != 0)
  715. {
  716. _CharType* pNext = CharNext(p);
  717. if(pNext > p + 1)
  718. {
  719. if(strchr_db(pCharSet, *p, *(p+1)) != NULL)
  720. break;
  721. nRet += 2;
  722. }
  723. else
  724. {
  725. if(strchr(pCharSet, *p) != NULL)
  726. break;
  727. nRet++;
  728. }
  729. p = pNext;
  730. }
  731. return nRet;
  732. }
  733. static _CharType* strpbrk(const _CharType* p, const _CharType* lpszCharSet) throw()
  734. {
  735. ATLASSERT(p != NULL);
  736. while (*p != 0)
  737. {
  738. if (strchr(lpszCharSet, *p) != NULL)
  739. {
  740. return const_cast< _CharType* >( p );
  741. }
  742. p = CharNext(p);
  743. }
  744. return NULL;
  745. }
  746. static _CharType* CharNext(const _CharType* p) throw()
  747. {
  748. ATLASSERT(p != NULL);
  749. if (*p == '\0') // ::CharNextA won't increment if we're at a \0 already
  750. return const_cast<_CharType*>(p+1);
  751. else
  752. return ::CharNextA(p);
  753. }
  754. static int IsDigit(_CharType ch) throw()
  755. {
  756. WORD type;
  757. GetStringTypeExA(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
  758. return (type & C1_DIGIT) == C1_DIGIT;
  759. }
  760. static int IsSpace(_CharType ch) throw()
  761. {
  762. WORD type;
  763. GetStringTypeExA(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
  764. return (type & C1_SPACE) == C1_SPACE;
  765. }
  766. static int StringCompare(const _CharType* pstrOne,
  767. const _CharType* pstrOther) throw()
  768. {
  769. return lstrcmpA((LPCSTR) pstrOne, (LPCSTR) pstrOther);
  770. }
  771. static int StringCompareIgnore(const _CharType* pstrOne,
  772. const _CharType* pstrOther) throw()
  773. {
  774. return lstrcmpiA((LPCSTR) pstrOne, (LPCSTR) pstrOther);
  775. }
  776. static int StringCollate(const _CharType* pstrOne,
  777. const _CharType* pstrOther) throw()
  778. {
  779. int nRet = CompareStringA(GetThreadLocale(), 0, (LPCSTR)pstrOne, -1,
  780. (LPCSTR)pstrOther, -1);
  781. ATLASSERT(nRet != 0);
  782. return nRet-2; // Convert to strcmp convention. This really is documented.
  783. }
  784. static int StringCollateIgnore(const _CharType* pstrOne,
  785. const _CharType* pstrOther) throw()
  786. {
  787. int nRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, (LPCSTR)pstrOne, -1,
  788. (LPCSTR)pstrOther, -1);
  789. ATLASSERT(nRet != 0);
  790. return nRet-2; // Convert to strcmp convention. This really is documented.
  791. }
  792. static _CharType* StringFindString(const _CharType* pstrBlock,
  793. const _CharType* pstrMatch) throw()
  794. {
  795. return strstr(pstrBlock, pstrMatch);
  796. }
  797. static _CharType* StringFindChar(const _CharType* pstrBlock,
  798. _CharType pstrMatch) throw()
  799. {
  800. return strchr(pstrBlock, pstrMatch);
  801. }
  802. static _CharType* StringFindCharRev(const _CharType* pstr, _CharType ch) throw()
  803. {
  804. return strrchr(pstr, ch);
  805. }
  806. static _CharType* StringScanSet(const _CharType* pstrBlock,
  807. const _CharType* pstrMatch) throw()
  808. {
  809. return strpbrk(pstrBlock, pstrMatch);
  810. }
  811. static int StringSpanIncluding(const _CharType* pstrBlock,
  812. const _CharType* pstrSet) throw()
  813. {
  814. return strspn(pstrBlock, pstrSet);
  815. }
  816. static int StringSpanExcluding(const _CharType* pstrBlock,
  817. const _CharType* pstrSet) throw()
  818. {
  819. return strcspn(pstrBlock, pstrSet);
  820. }
  821. static _CharType* StringUppercase(_CharType* psz) throw()
  822. {
  823. return CharUpperA( psz );
  824. }
  825. static _CharType* StringLowercase(_CharType* psz) throw()
  826. {
  827. return CharLowerA( psz );
  828. }
  829. static _CharType* StringReverse(_CharType* psz) throw()
  830. {
  831. return _strrev( psz );
  832. }
  833. static int GetFormattedLength(const _CharType* pszFormat, va_list args) throw()
  834. {
  835. _CharType szBuffer[1028];
  836. // wvsprintf always truncates the output to 1024 character plus
  837. // the '\0'.
  838. int nLength = wvsprintfA(szBuffer, pszFormat, args);
  839. ATLASSERT(nLength >= 0);
  840. ATLASSERT(nLength <= 1024);
  841. return nLength;
  842. }
  843. static int Format(_CharType* pszBuffer, const _CharType* pszFormat,
  844. va_list args) throw()
  845. {
  846. return wvsprintfA(pszBuffer, pszFormat, args);
  847. }
  848. static int GetBaseTypeLength(const char* pszSrc) throw()
  849. {
  850. // Returns required buffer length in XCHARs
  851. return lstrlenA(pszSrc);
  852. }
  853. static int GetBaseTypeLength(const char* pszSrc, int nLength) throw()
  854. {
  855. (void)pszSrc;
  856. // Returns required buffer length in XCHARs
  857. return nLength;
  858. }
  859. static int GetBaseTypeLength(const wchar_t* pszSrc) throw()
  860. {
  861. // Returns required buffer length in XCHARs
  862. return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, -1, NULL, 0, NULL, NULL)-1;
  863. }
  864. static int GetBaseTypeLength(const wchar_t* pszSrc, int nLength) throw()
  865. {
  866. // Returns required buffer length in XCHARs
  867. return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0, NULL, NULL);
  868. }
  869. static void ConvertToBaseType(_CharType* pszDest, int nDestLength,
  870. const char* pszSrc, int nSrcLength = -1) throw()
  871. {
  872. (void)nSrcLength;
  873. // nLen is in chars
  874. memcpy(pszDest, pszSrc, nDestLength);
  875. }
  876. static void ConvertToBaseType(_CharType* pszDest, int nDestLength,
  877. const wchar_t* pszSrc, int nSrcLength = -1) throw()
  878. {
  879. // nLen is in XCHARs
  880. ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL);
  881. }
  882. static void ConvertToOem(_CharType* pstrString) throw()
  883. {
  884. ::AnsiToOem(pstrString, pstrString);
  885. }
  886. static void ConvertToAnsi(_CharType* pstrString) throw()
  887. {
  888. ::OemToAnsi(pstrString, pstrString);
  889. }
  890. static void FloodCharacters(_CharType ch, int nLength, _CharType* pstr) throw()
  891. {
  892. // nLength is in XCHARs
  893. memset(pstr, ch, nLength);
  894. }
  895. static BSTR AllocSysString(const _CharType* pchData, int nDataLength) throw()
  896. {
  897. int nLen = MultiByteToWideChar(_AtlGetConversionACP(), 0, pchData, nDataLength,
  898. NULL, NULL);
  899. BSTR bstr = ::SysAllocStringLen(NULL, nLen);
  900. if (bstr != NULL)
  901. {
  902. MultiByteToWideChar(_AtlGetConversionACP(), 0, pchData, nDataLength,
  903. bstr, nLen);
  904. }
  905. return bstr;
  906. }
  907. static BOOL ReAllocSysString(const _CharType* pchData, BSTR* pbstr,
  908. int nDataLength) throw()
  909. {
  910. int nLen = MultiByteToWideChar(_AtlGetConversionACP(), 0, pchData,
  911. nDataLength, NULL, NULL);
  912. BOOL bSuccess =::SysReAllocStringLen(pbstr, NULL, nLen);
  913. if (bSuccess)
  914. {
  915. MultiByteToWideChar(_AtlGetConversionACP(), 0, pchData, nDataLength,
  916. *pbstr, nLen);
  917. }
  918. return bSuccess;
  919. }
  920. static DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource,
  921. DWORD dwMessageID, DWORD dwLanguageID, char* pstrBuffer,
  922. DWORD nSize, va_list* pArguments) throw()
  923. {
  924. return ::FormatMessageA(dwFlags, lpSource, dwMessageID, dwLanguageID,
  925. pstrBuffer, nSize, pArguments);
  926. }
  927. static int SafeStringLen(const char* psz) throw()
  928. {
  929. // returns length in bytes
  930. return (psz != NULL) ? lstrlenA(psz) : 0;
  931. }
  932. static int SafeStringLen(const wchar_t* psz) throw()
  933. {
  934. // returns length in wchar_ts
  935. return (psz != NULL) ? lstrlenW(psz) : 0;
  936. }
  937. static int GetCharLen(const wchar_t*) throw()
  938. {
  939. // returns char length
  940. return 1;
  941. }
  942. static int GetCharLen(const char* psz) throw()
  943. {
  944. const char* p = ::CharNextA(psz);
  945. return (p - psz);
  946. }
  947. static DWORD GetEnvironmentVariable(const _CharType* pstrVar,
  948. _CharType* pstrBuffer, DWORD dwSize) throw()
  949. {
  950. return ::GetEnvironmentVariableA(pstrVar, pstrBuffer, dwSize);
  951. }
  952. };
  953. // specialization for wchar_t
  954. template<>
  955. class ChTraitsOS< wchar_t > :
  956. public ChTraitsBase< wchar_t >
  957. {
  958. protected:
  959. #if defined(_UNICODE) && !defined(_CSTRING_ALWAYS_THUNK)
  960. static int CompareStringW(LCID lcid, DWORD dwFlags,
  961. LPCWSTR pszString1, int nLength1, LPCWSTR pszString2, int nLength2)
  962. {
  963. return ::CompareStringW(lcid, dwFlags, pszString1, nLength1,
  964. pszString2, nLength2);
  965. }
  966. static BOOL GetStringTypeExW(LCID lcid, DWORD dwInfoType, LPCWSTR pszSrc,
  967. int nLength, LPWORD pwCharType)
  968. {
  969. return ::GetStringTypeExW(lcid, dwInfoType, pszSrc, nLength, pwCharType);
  970. }
  971. static int lstrcmpiW(LPCWSTR psz1, LPCWSTR psz2)
  972. {
  973. return ::lstrcmpiW(psz1, psz2);
  974. }
  975. static LPWSTR CharLowerW(LPWSTR psz)
  976. {
  977. return ::CharLowerW(psz);
  978. }
  979. static LPWSTR CharUpperW(LPWSTR psz)
  980. {
  981. return ::CharUpperW(psz);
  982. }
  983. static DWORD _GetEnvironmentVariableW(LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize)
  984. {
  985. return ::GetEnvironmentVariableW(pszName, pszBuffer, nSize);
  986. }
  987. #else // !_UNICODE
  988. static int WINAPI CompareStringW(LCID lcid, DWORD dwFlags,
  989. LPCWSTR pszString1, int nLength1, LPCWSTR pszString2, int nLength2)
  990. {
  991. return _strthunks.pfnCompareStringW(lcid, dwFlags, pszString1, nLength1, pszString2, nLength2);
  992. }
  993. static BOOL WINAPI GetStringTypeExW(LCID lcid, DWORD dwInfoType, LPCWSTR pszSrc,
  994. int nLength, LPWORD pwCharType)
  995. {
  996. return _strthunks.pfnGetStringTypeExW(lcid, dwInfoType, pszSrc, nLength, pwCharType);
  997. }
  998. static int WINAPI lstrcmpiW(LPCWSTR psz1, LPCWSTR psz2)
  999. {
  1000. return _strthunks.pfnlstrcmpiW(psz1, psz2);
  1001. }
  1002. static LPWSTR WINAPI CharLowerW(LPWSTR psz)
  1003. {
  1004. ATLASSERT(HIWORD(psz) != 0); // No single chars
  1005. return _strthunks.pfnCharLowerW(psz);
  1006. }
  1007. static LPWSTR WINAPI CharUpperW(LPWSTR psz)
  1008. {
  1009. ATLASSERT(HIWORD(psz) != 0); // No single chars
  1010. return _strthunks.pfnCharUpperW(psz);
  1011. }
  1012. static DWORD _GetEnvironmentVariableW(LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize)
  1013. {
  1014. return _strthunks.pfnGetEnvironmentVariableW(pszName, pszBuffer, nSize);
  1015. }
  1016. #endif // !_UNICODE
  1017. public:
  1018. static int tclen(const _CharType*) throw()
  1019. {
  1020. return 1;
  1021. }
  1022. static _CharType* strchr(const _CharType* p, _CharType ch) throw()
  1023. {
  1024. //strchr for '\0' should succeed
  1025. while (*p != 0)
  1026. {
  1027. if (*p == ch)
  1028. {
  1029. return const_cast< _CharType* >( p );
  1030. }
  1031. p++;
  1032. }
  1033. return const_cast< _CharType* >((*p == ch) ? p : NULL);
  1034. }
  1035. static _CharType* strrchr(const _CharType* p, _CharType ch) throw()
  1036. {
  1037. const _CharType* pch = p+lstrlenW(p);
  1038. while ((pch != p) && (*pch != ch))
  1039. {
  1040. pch--;
  1041. }
  1042. if (*pch == ch)
  1043. {
  1044. return const_cast<_CharType*>(pch);
  1045. }
  1046. else
  1047. {
  1048. return NULL;
  1049. }
  1050. }
  1051. static _CharType* _strrev(_CharType* psz) throw()
  1052. {
  1053. // Optimize NULL, zero-length, and single-char case.
  1054. if ((psz == NULL) || (psz[0] == L'\0') || (psz[1] == L'\0'))
  1055. return psz;
  1056. _CharType* p = psz+(lstrlenW( psz )-1);
  1057. _CharType* q = psz;
  1058. while(q < p)
  1059. {
  1060. _CharType t = *q;
  1061. *q = *p;
  1062. *p = t;
  1063. q++;
  1064. p--;
  1065. }
  1066. return psz;
  1067. }
  1068. static _CharType* strstr(const _CharType* pStr, const _CharType* pCharSet) throw()
  1069. {
  1070. int nLen = lstrlenW(pCharSet);
  1071. if (nLen == 0)
  1072. return const_cast<_CharType*>(pStr);
  1073. const _CharType* pMatch;
  1074. const _CharType* pStart = pStr;
  1075. while ((pMatch = strchr(pStart, *pCharSet)) != NULL)
  1076. {
  1077. if (memcmp(pMatch, pCharSet, nLen*sizeof(_CharType)) == 0)
  1078. return const_cast<_CharType*>(pMatch);
  1079. pStart++;
  1080. }
  1081. return NULL;
  1082. }
  1083. static int strspn(const _CharType* psz, const _CharType* pszCharSet) throw()
  1084. {
  1085. int nRet = 0;
  1086. const _CharType* p = psz;
  1087. while (*p != 0)
  1088. {
  1089. if(strchr(pszCharSet, *p) == NULL)
  1090. break;
  1091. nRet++;
  1092. p++;
  1093. }
  1094. return nRet;
  1095. }
  1096. static int strcspn(const _CharType* psz, const _CharType* pszCharSet) throw()
  1097. {
  1098. int nRet = 0;
  1099. const _CharType* p = psz;
  1100. while (*p != 0)
  1101. {
  1102. if(strchr(pszCharSet, *p) != NULL)
  1103. break;
  1104. nRet++;
  1105. p++;
  1106. }
  1107. return nRet;
  1108. }
  1109. static _CharType* strpbrk(const _CharType* psz, const _CharType* pszCharSet) throw()
  1110. {
  1111. const wchar_t* p = psz;
  1112. while (*p != 0)
  1113. {
  1114. if (strchr(pszCharSet, *p) != NULL)
  1115. return const_cast< wchar_t* >( p );
  1116. p++;
  1117. }
  1118. return NULL;
  1119. }
  1120. static wchar_t* CharNext(const wchar_t* p) throw()
  1121. {
  1122. return const_cast< wchar_t* >( p+1 );
  1123. }
  1124. static int IsDigit(_CharType ch) throw()
  1125. {
  1126. WORD type;
  1127. GetStringTypeExW(0, CT_CTYPE1, &ch, 1, &type);
  1128. return (type & C1_DIGIT) == C1_DIGIT;
  1129. }
  1130. static int IsSpace(_CharType ch) throw()
  1131. {
  1132. WORD type;
  1133. GetStringTypeExW(0, CT_CTYPE1, &ch, 1, &type);
  1134. return (type & C1_SPACE) == C1_SPACE;
  1135. }
  1136. static int StringCompare(const _CharType* pstrOne,
  1137. const _CharType* pstrOther) throw()
  1138. {
  1139. return wcscmp(pstrOne, pstrOther);
  1140. }
  1141. static int StringCompareIgnore(const _CharType* pstrOne,
  1142. const _CharType* pstrOther) throw()
  1143. {
  1144. return lstrcmpiW(pstrOne, pstrOther);
  1145. }
  1146. static int StringCollate(const _CharType* pstrOne,
  1147. const _CharType* pstrOther) throw()
  1148. {
  1149. int nRet;
  1150. nRet = CompareStringW(GetThreadLocale(), 0, pstrOne, -1, pstrOther, -1);
  1151. ATLASSERT(nRet != 0);
  1152. return nRet-2; // Convert to strcmp convention. This really is documented.
  1153. }
  1154. static int StringCollateIgnore(const _CharType* pstrOne,
  1155. const _CharType* pstrOther) throw()
  1156. {
  1157. int nRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
  1158. pstrOne, -1, pstrOther, -1);
  1159. ATLASSERT(nRet != 0);
  1160. return nRet-2; // Convert to strcmp convention. This really is documented.
  1161. }
  1162. static _CharType* StringFindString(const _CharType* pstrBlock,
  1163. const _CharType* pstrMatch) throw()
  1164. {
  1165. return strstr(pstrBlock, pstrMatch);
  1166. }
  1167. static _CharType* StringFindChar(const _CharType* pstrBlock,
  1168. _CharType pstrMatch) throw()
  1169. {
  1170. return strchr(pstrBlock, pstrMatch);
  1171. }
  1172. static _CharType* StringFindCharRev(const _CharType* pstr, _CharType ch) throw()
  1173. {
  1174. return strrchr(pstr, ch);
  1175. }
  1176. static _CharType* StringScanSet(const _CharType* pszBlock,
  1177. const _CharType* pszMatch) throw()
  1178. {
  1179. return strpbrk(pszBlock, pszMatch);
  1180. }
  1181. static int StringSpanIncluding(const _CharType* pszBlock,
  1182. const _CharType* pszSet) throw()
  1183. {
  1184. return strspn(pszBlock, pszSet);
  1185. }
  1186. static int StringSpanExcluding(const _CharType* pszBlock,
  1187. const _CharType* pszSet) throw()
  1188. {
  1189. return strcspn(pszBlock, pszSet);
  1190. }
  1191. static _CharType* StringUppercase(_CharType* psz) throw()
  1192. {
  1193. CharUpperW(psz);
  1194. return psz;
  1195. }
  1196. static _CharType* StringLowercase(_CharType* psz) throw()
  1197. {
  1198. CharLowerW(psz);
  1199. return psz;
  1200. }
  1201. static _CharType* StringReverse(_CharType* psz) throw()
  1202. {
  1203. return _strrev(psz);
  1204. }
  1205. #ifdef _UNICODE
  1206. static int GetFormattedLength(const _CharType* pszFormat, va_list args) throw()
  1207. {
  1208. _CharType szBuffer[1028];
  1209. // wvsprintf always truncates the output to 1024 character plus
  1210. // the '\0'.
  1211. int nLength = wvsprintfW(szBuffer, pszFormat, args);
  1212. ATLASSERT(nLength >= 0);
  1213. ATLASSERT(nLength <= 1024);
  1214. return nLength;
  1215. }
  1216. static int Format(_CharType* pszBuffer, const _CharType* pszFormat,
  1217. va_list args) throw()
  1218. {
  1219. return wvsprintfW(pszBuffer, pszFormat, args);
  1220. }
  1221. #endif
  1222. static int GetBaseTypeLength(const char* pszSrc) throw()
  1223. {
  1224. // Returns required buffer size in wchar_ts
  1225. return ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSrc, -1, NULL, 0)-1;
  1226. }
  1227. static int GetBaseTypeLength(const char* pszSrc, int nLength) throw()
  1228. {
  1229. // Returns required buffer size in wchar_ts
  1230. return ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0);
  1231. }
  1232. static int GetBaseTypeLength(const wchar_t* pszSrc) throw()
  1233. {
  1234. // Returns required buffer size in wchar_ts
  1235. return lstrlenW(pszSrc);
  1236. }
  1237. static int GetBaseTypeLength(const wchar_t* pszSrc, int nLength) throw()
  1238. {
  1239. (void)pszSrc;
  1240. // Returns required buffer size in wchar_ts
  1241. return nLength;
  1242. }
  1243. static void ConvertToBaseType(_CharType* pszDest, int nDestLength,
  1244. const char* pszSrc, int nSrcLength = -1) throw()
  1245. {
  1246. // nLen is in wchar_ts
  1247. ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength);
  1248. }
  1249. static void ConvertToBaseType(_CharType* pszDest, int nDestLength,
  1250. const wchar_t* pszSrc, int nSrcLength = -1) throw()
  1251. {
  1252. (void)nSrcLength;
  1253. // nLen is in wchar_ts
  1254. memcpy(pszDest, pszSrc, nDestLength*sizeof(wchar_t));
  1255. }
  1256. // this conversion on Unicode strings makes no sense
  1257. /*
  1258. static void ConvertToOem(_CharType*)
  1259. {
  1260. ATLASSERT(FALSE);
  1261. }
  1262. */
  1263. // this conversion on Unicode strings makes no sense
  1264. /*
  1265. static void ConvertToAnsi(_CharType*)
  1266. {
  1267. ATLASSERT(FALSE);
  1268. }
  1269. */
  1270. static void FloodCharacters(_CharType ch, int nLength, _CharType* pstr) throw()
  1271. {
  1272. // nLength is in XCHARs
  1273. for (int i = 0; i < nLength; i++)
  1274. pstr[i] = ch;
  1275. }
  1276. static BSTR AllocSysString(const _CharType* pchData, int nDataLength) throw()
  1277. {
  1278. BSTR bstr = ::SysAllocStringLen(pchData, nDataLength);
  1279. return bstr;
  1280. }
  1281. static BOOL ReAllocSysString(const _CharType* pchData, BSTR* pbstr,
  1282. int nDataLength) throw()
  1283. {
  1284. return ::SysReAllocStringLen(pbstr, pchData, nDataLength);
  1285. }
  1286. #ifdef _UNICODE
  1287. static DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource,
  1288. DWORD dwMessageID, DWORD dwLanguageID, wchar_t* pstrBuffer,
  1289. DWORD nSize, va_list* pArguments) throw()
  1290. {
  1291. return ::FormatMessageW(dwFlags, lpSource, dwMessageID, dwLanguageID,
  1292. pstrBuffer, nSize, pArguments);
  1293. }
  1294. #endif
  1295. static int SafeStringLen(const char* psz) throw()
  1296. {
  1297. // returns length in bytes
  1298. return (psz != NULL) ? lstrlenA(psz) : 0;
  1299. }
  1300. static int SafeStringLen(const wchar_t* psz) throw()
  1301. {
  1302. // returns length in wchar_ts
  1303. return (psz != NULL) ? lstrlenW(psz) : 0;
  1304. }
  1305. static int GetCharLen(const wchar_t*) throw()
  1306. {
  1307. // returns char length
  1308. return 1;
  1309. }
  1310. static int GetCharLen(const char* psz) throw()
  1311. {
  1312. LPCSTR p = ::CharNextA( psz );
  1313. return int( p-psz );
  1314. }
  1315. static DWORD GetEnvironmentVariable(const _CharType* pstrVar,
  1316. _CharType* pstrBuffer, DWORD dwSize) throw()
  1317. {
  1318. return ::GetEnvironmentVariableW(pstrVar, pstrBuffer, dwSize);
  1319. }
  1320. };
  1321. template< typename BaseType, class StringTraits >
  1322. class CStringT :
  1323. public CSimpleStringT< BaseType >
  1324. {
  1325. public:
  1326. typedef CSimpleStringT< BaseType > CThisSimpleString;
  1327. typedef StringTraits StrTraits;
  1328. public:
  1329. CStringT() throw() :
  1330. CThisSimpleString( StringTraits::GetDefaultManager() )
  1331. {
  1332. }
  1333. explicit CStringT( IAtlStringMgr* pStringMgr ) throw() :
  1334. CThisSimpleString( pStringMgr )
  1335. {
  1336. }
  1337. CStringT( const VARIANT& varSrc ) :
  1338. CThisSimpleString( StringTraits::GetDefaultManager() )
  1339. {
  1340. CComVariant varResult;
  1341. HRESULT hr = ::VariantChangeType( &varResult, const_cast< VARIANT* >( &varSrc ), 0, VT_BSTR );
  1342. if( FAILED( hr ) )
  1343. {
  1344. AtlThrow( hr );
  1345. }
  1346. *this = V_BSTR( &varResult );
  1347. }
  1348. CStringT( const VARIANT& varSrc, IAtlStringMgr* pStringMgr ) :
  1349. CThisSimpleString( pStringMgr )
  1350. {
  1351. CComVariant varResult;
  1352. HRESULT hr = ::VariantChangeType( &varResult, const_cast< VARIANT* >( &varSrc ), 0, VT_BSTR );
  1353. if( FAILED( hr ) )
  1354. {
  1355. AtlThrow( hr );
  1356. }
  1357. *this = V_BSTR( &varResult );
  1358. }
  1359. static void Construct( CStringT* pString )
  1360. {
  1361. new( pString ) CStringT;
  1362. }
  1363. // Copy constructor
  1364. CStringT( const CStringT& strSrc ) :
  1365. CThisSimpleString( strSrc )
  1366. {
  1367. }
  1368. // Construct from CSimpleStringT
  1369. CStringT( const CThisSimpleString& strSrc ) :
  1370. CThisSimpleString( strSrc )
  1371. {
  1372. }
  1373. CStringT( const XCHAR* pszSrc ) :
  1374. CThisSimpleString( StringTraits::GetDefaultManager() )
  1375. {
  1376. if( !CheckImplicitLoad( pszSrc ) )
  1377. {
  1378. // nDestLength is in XCHARs
  1379. *this = pszSrc;
  1380. }
  1381. }
  1382. CStringT( LPCSTR pszSrc, IAtlStringMgr* pStringMgr ) :
  1383. CThisSimpleString( pStringMgr )
  1384. {
  1385. if( !CheckImplicitLoad( pszSrc ) )
  1386. {
  1387. // nDestLength is in XCHARs
  1388. *this = pszSrc;
  1389. }
  1390. }
  1391. CSTRING_EXPLICIT CStringT( const YCHAR* pszSrc ) :
  1392. CThisSimpleString( StringTraits::GetDefaultManager() )
  1393. {
  1394. if( !CheckImplicitLoad( pszSrc ) )
  1395. {
  1396. *this = pszSrc;
  1397. }
  1398. }
  1399. CStringT( LPCWSTR pszSrc, IAtlStringMgr* pStringMgr ) :
  1400. CThisSimpleString( pStringMgr )
  1401. {
  1402. if( !CheckImplicitLoad( pszSrc ) )
  1403. {
  1404. *this = pszSrc;
  1405. }
  1406. }
  1407. #ifdef _MANAGED
  1408. CStringT( System::String* pString ) :
  1409. CThisSimpleString( StringTraits::GetDefaultManager() )
  1410. {
  1411. const wchar_t __pin* psz = PtrToStringChars( pString );
  1412. *this = psz;
  1413. }
  1414. #endif
  1415. CSTRING_EXPLICIT CStringT( const unsigned char* pszSrc ) :
  1416. CThisSimpleString( StringTraits::GetDefaultManager() )
  1417. {
  1418. *this = reinterpret_cast< const char* >( pszSrc );
  1419. }
  1420. CStringT( const unsigned char* pszSrc, IAtlStringMgr* pStringMgr ) :
  1421. CThisSimpleString( pStringMgr )
  1422. {
  1423. *this = reinterpret_cast< const char* >( pszSrc );
  1424. }
  1425. CSTRING_EXPLICIT CStringT( wchar_t ch, int nLength = 1 ) :
  1426. CThisSimpleString( StringTraits::GetDefaultManager() )
  1427. {
  1428. ATLASSERT( nLength >= 0 );
  1429. if( nLength > 0 )
  1430. {
  1431. PXSTR pszBuffer = GetBuffer( nLength );
  1432. StringTraits::FloodCharacters( XCHAR( ch ), nLength, pszBuffer );
  1433. ReleaseBuffer( nLength );
  1434. }
  1435. }
  1436. CStringT( const XCHAR* pch, int nLength ) :
  1437. CThisSimpleString( pch, nLength, StringTraits::GetDefaultManager() )
  1438. {
  1439. }
  1440. CStringT( const XCHAR* pch, int nLength, IAtlStringMgr* pStringMgr ) :
  1441. CThisSimpleString( pch, nLength, pStringMgr )
  1442. {
  1443. }
  1444. CStringT( const YCHAR* pch, int nLength ) :
  1445. CThisSimpleString( StringTraits::GetDefaultManager() )
  1446. {
  1447. ATLASSERT( nLength >= 0 );
  1448. if( nLength > 0 )
  1449. {
  1450. ATLASSERT( AtlIsValidAddress( pch, nLength*sizeof( YCHAR ), FALSE ) );
  1451. int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength );
  1452. PXSTR pszBuffer = GetBuffer( nDestLength );
  1453. StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength );
  1454. ReleaseBuffer( nDestLength );
  1455. }
  1456. }
  1457. CStringT( const YCHAR* pch, int nLength, IAtlStringMgr* pStringMgr ) :
  1458. CThisSimpleString( pStringMgr )
  1459. {
  1460. ATLASSERT( nLength >= 0 );
  1461. if( nLength > 0 )
  1462. {
  1463. ATLASSERT( AtlIsValidAddress( pch, nLength*sizeof( YCHAR ), FALSE ) );
  1464. int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength );
  1465. PXSTR pszBuffer = GetBuffer( nDestLength );
  1466. StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength );
  1467. ReleaseBuffer( nDestLength );
  1468. }
  1469. }
  1470. // Destructor
  1471. ~CStringT() throw()
  1472. {
  1473. }
  1474. // Assignment operators
  1475. CStringT& operator=( const CStringT& strSrc )
  1476. {
  1477. CThisSimpleString::operator=( strSrc );
  1478. return( *this );
  1479. }
  1480. CStringT& operator=( const CThisSimpleString& strSrc )
  1481. {
  1482. CThisSimpleString::operator=( strSrc );
  1483. return( *this );
  1484. }
  1485. CStringT& operator=( PCXSTR pszSrc )
  1486. {
  1487. CThisSimpleString::operator=( pszSrc );
  1488. return( *this );
  1489. }
  1490. CStringT& operator=( PCYSTR pszSrc )
  1491. {
  1492. // nDestLength is in XCHARs
  1493. int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength( pszSrc ) : 0;
  1494. if( nDestLength > 0 )
  1495. {
  1496. PXSTR pszBuffer = GetBuffer( nDestLength );
  1497. StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc );
  1498. ReleaseBuffer( nDestLength );
  1499. }
  1500. else
  1501. {
  1502. Empty();
  1503. }
  1504. return( *this );
  1505. }
  1506. CStringT& operator=( const unsigned char* pszSrc )
  1507. {
  1508. return( operator=( reinterpret_cast< const char* >( pszSrc ) ) );
  1509. }
  1510. CStringT& operator=( char ch )
  1511. {
  1512. char ach[2] = { ch, 0 };
  1513. return( operator=( ach ) );
  1514. }
  1515. CStringT& operator=( wchar_t ch )
  1516. {
  1517. wchar_t ach[2] = { ch, 0 };
  1518. return( operator=( ach ) );
  1519. }
  1520. CStringT& operator=( const VARIANT& var )
  1521. {
  1522. CComVariant varResult;
  1523. HRESULT hr = ::VariantChangeType( &varResult, const_cast< VARIANT* >( &var ), 0, VT_BSTR );
  1524. if( FAILED( hr ) )
  1525. {
  1526. AtlThrow( hr );
  1527. }
  1528. *this = V_BSTR( &varResult );
  1529. return( *this );
  1530. }
  1531. CStringT& operator+=( const CThisSimpleString& str )
  1532. {
  1533. CThisSimpleString::operator+=( str );
  1534. return( *this );
  1535. }
  1536. CStringT& operator+=( PCXSTR pszSrc )
  1537. {
  1538. CThisSimpleString::operator+=( pszSrc );
  1539. return( *this );
  1540. }
  1541. template< int t_nSize >
  1542. CStringT& operator+=( const CStaticString< XCHAR, t_nSize >& strSrc )
  1543. {
  1544. CThisSimpleString::operator+=( strSrc );
  1545. return( *this );
  1546. }
  1547. CStringT& operator+=( PCYSTR psz )
  1548. {
  1549. CStringT str( psz, GetManager() );
  1550. return( operator+=( str ) );
  1551. }
  1552. CStringT& operator+=( char ch )
  1553. {
  1554. CThisSimpleString::operator+=( ch );
  1555. return( *this );
  1556. }
  1557. CStringT& operator+=( unsigned char ch )
  1558. {
  1559. CThisSimpleString::operator+=( ch );
  1560. return( *this );
  1561. }
  1562. CStringT& operator+=( wchar_t ch )
  1563. {
  1564. CThisSimpleString::operator+=( ch );
  1565. return( *this );
  1566. }
  1567. CStringT& operator+=( const VARIANT& var )
  1568. {
  1569. CComVariant varResult;
  1570. HRESULT hr = ::VariantChangeType( &varResult, const_cast< VARIANT* >( &var ), 0, VT_BSTR );
  1571. if( FAILED( hr ) )
  1572. {
  1573. AtlThrow( hr );
  1574. }
  1575. *this += V_BSTR( &varResult );
  1576. return( *this );
  1577. }
  1578. // Comparison
  1579. int Compare( PCXSTR psz ) const throw()
  1580. {
  1581. ATLASSERT( AtlIsValidString( psz ) );
  1582. return( StringTraits::StringCompare( GetString(), psz ) );
  1583. }
  1584. int CompareNoCase( PCXSTR psz ) const throw()
  1585. {
  1586. ATLASSERT( AtlIsValidString( psz ) );
  1587. return( StringTraits::StringCompareIgnore( GetString(), psz ) );
  1588. }
  1589. int Collate( PCXSTR psz ) const throw()
  1590. {
  1591. ATLASSERT( AtlIsValidString( psz ) );
  1592. return( StringTraits::StringCollate( GetString(), psz ) );
  1593. }
  1594. int CollateNoCase( PCXSTR psz ) const throw()
  1595. {
  1596. ATLASSERT( AtlIsValidString( psz ) );
  1597. return( StringTraits::StringCollateIgnore( GetString(), psz ) );
  1598. }
  1599. // Advanced manipulation
  1600. // Delete 'nCount' characters, starting at index 'iIndex'
  1601. int Delete( int iIndex, int nCount = 1 )
  1602. {
  1603. ATLASSERT( iIndex >= 0 );
  1604. ATLASSERT( nCount >= 0 );
  1605. int nLength = GetLength();
  1606. if( (nCount+iIndex) > nLength )
  1607. {
  1608. nCount = nLength-iIndex;
  1609. }
  1610. if( nCount > 0 )
  1611. {
  1612. int nNewLength = nLength-nCount;
  1613. int nXCHARsToCopy = nLength-(iIndex+nCount)+1;
  1614. PXSTR pszBuffer = GetBuffer();
  1615. memmove( pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR ) );
  1616. ReleaseBuffer( nNewLength );
  1617. }
  1618. return( GetLength() );
  1619. }
  1620. // Insert character 'ch' before index 'iIndex'
  1621. int Insert( int iIndex, XCHAR ch )
  1622. {
  1623. ATLASSERT( iIndex >= 0 );
  1624. if( iIndex > GetLength() )
  1625. {
  1626. iIndex = GetLength();
  1627. }
  1628. int nNewLength = GetLength()+1;
  1629. PXSTR pszBuffer = GetBuffer( nNewLength );
  1630. // move existing bytes down
  1631. memmove( pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR ) );
  1632. pszBuffer[iIndex] = ch;
  1633. ReleaseBuffer( nNewLength );
  1634. return( nNewLength );
  1635. }
  1636. // Insert string 'psz' before index 'iIndex'
  1637. int Insert( int iIndex, PCXSTR psz )
  1638. {
  1639. ATLASSERT( iIndex >= 0 );
  1640. if( iIndex > GetLength() )
  1641. {
  1642. iIndex = GetLength();
  1643. }
  1644. // nInsertLength and nNewLength are in XCHARs
  1645. int nInsertLength = StringTraits::SafeStringLen( psz );
  1646. int nNewLength = GetLength();
  1647. if( nInsertLength > 0 )
  1648. {
  1649. nNewLength += nInsertLength;
  1650. PXSTR pszBuffer = GetBuffer( nNewLength );
  1651. // move existing bytes down
  1652. memmove( pszBuffer+iIndex+nInsertLength,
  1653. pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR ) );
  1654. memcpy( pszBuffer+iIndex, psz, nInsertLength*sizeof( XCHAR ) );
  1655. ReleaseBuffer( nNewLength );
  1656. }
  1657. return( nNewLength );
  1658. }
  1659. // Replace all occurrences of character 'chOld' with character 'chNew'
  1660. int Replace( XCHAR chOld, XCHAR chNew )
  1661. {
  1662. int nCount = 0;
  1663. // short-circuit the nop case
  1664. if( chOld != chNew )
  1665. {
  1666. // otherwise modify each character that matches in the string
  1667. bool bCopied = false;
  1668. PXSTR pszBuffer = const_cast< PXSTR >( GetString() ); // We don't actually write to pszBuffer until we've called GetBuffer().
  1669. int nLength = GetLength();
  1670. int iChar = 0;
  1671. while( iChar < nLength )
  1672. {
  1673. // replace instances of the specified character only
  1674. if( pszBuffer[iChar] == chOld )
  1675. {
  1676. if( !bCopied )
  1677. {
  1678. bCopied = true;
  1679. pszBuffer = GetBuffer( nLength );
  1680. }
  1681. pszBuffer[iChar] = chNew;
  1682. nCount++;
  1683. }
  1684. iChar = int( StringTraits::CharNext( pszBuffer+iChar )-pszBuffer );
  1685. }
  1686. if( bCopied )
  1687. {
  1688. ReleaseBuffer( nLength );
  1689. }
  1690. }
  1691. return( nCount );
  1692. }
  1693. // Replace all occurrences of string 'pszOld' with string 'pszNew'
  1694. int Replace( PCXSTR pszOld, PCXSTR pszNew )
  1695. {
  1696. // can't have empty or NULL lpszOld
  1697. // nSourceLen is in XCHARs
  1698. int nSourceLen = StringTraits::SafeStringLen( pszOld );
  1699. if( nSourceLen == 0 )
  1700. return( 0 );
  1701. // nReplacementLen is in XCHARs
  1702. int nReplacementLen = StringTraits::SafeStringLen( pszNew );
  1703. // loop once to figure out the size of the result string
  1704. int nCount = 0;
  1705. {
  1706. PCXSTR pszStart = GetString();
  1707. PCXSTR pszEnd = pszStart+GetLength();
  1708. while( pszStart < pszEnd )
  1709. {
  1710. PCXSTR pszTarget;
  1711. while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld ) ) != NULL)
  1712. {
  1713. nCount++;
  1714. pszStart = pszTarget+nSourceLen;
  1715. }
  1716. pszStart += StringTraits::SafeStringLen( pszStart )+1;
  1717. }
  1718. }
  1719. // if any changes were made, make them
  1720. if( nCount > 0 )
  1721. {
  1722. // if the buffer is too small, just
  1723. // allocate a new buffer (slow but sure)
  1724. int nOldLength = GetLength();
  1725. int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount;
  1726. PXSTR pszBuffer = GetBuffer( max( nNewLength, nOldLength ) );
  1727. PXSTR pszStart = pszBuffer;
  1728. PXSTR pszEnd = pszStart+nOldLength;
  1729. // loop again to actually do the work
  1730. while( pszStart < pszEnd )
  1731. {
  1732. PXSTR pszTarget;
  1733. while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld ) ) != NULL )
  1734. {
  1735. int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen);
  1736. memmove( pszTarget+nReplacementLen, pszTarget+nSourceLen, nBalance*sizeof( XCHAR ) );
  1737. memcpy( pszTarget, pszNew, nReplacementLen*sizeof( XCHAR ) );
  1738. pszStart = pszTarget+nReplacementLen;
  1739. pszTarget[nReplacementLen+nBalance] = 0;
  1740. nOldLength += (nReplacementLen-nSourceLen);
  1741. }
  1742. pszStart += StringTraits::SafeStringLen( pszStart )+1;
  1743. }
  1744. ATLASSERT( pszBuffer[nNewLength] == 0 );
  1745. ReleaseBuffer( nNewLength );
  1746. }
  1747. return( nCount );
  1748. }
  1749. // Remove all occurrences of character 'chRemove'
  1750. int Remove( XCHAR chRemove )
  1751. {
  1752. int nLength = GetLength();
  1753. PXSTR pszBuffer = GetBuffer( nLength );
  1754. PXSTR pszSource = pszBuffer;
  1755. PXSTR pszDest = pszBuffer;
  1756. PXSTR pszEnd = pszBuffer+nLength;
  1757. while( pszSource < pszEnd )
  1758. {
  1759. if( *pszSource != chRemove )
  1760. {
  1761. *pszDest = *pszSource;
  1762. pszDest = StringTraits::CharNext( pszDest );
  1763. }
  1764. pszSource = StringTraits::CharNext( pszSource );
  1765. }
  1766. *pszDest = 0;
  1767. int nCount = int( pszSource-pszDest );
  1768. ReleaseBuffer( nLength-nCount );
  1769. return( nCount );
  1770. }
  1771. CStringT Tokenize( PCXSTR pszTokens, int& iStart ) const
  1772. {
  1773. ATLASSERT( iStart >= 0 );
  1774. if( pszTokens == NULL )
  1775. {
  1776. return( *this );
  1777. }
  1778. PCXSTR pszPlace = GetString()+iStart;
  1779. PCXSTR pszEnd = GetString()+GetLength();
  1780. if( pszPlace < pszEnd )
  1781. {
  1782. int nIncluding = StringTraits::StringSpanIncluding( pszPlace,
  1783. pszTokens );
  1784. if( (pszPlace+nIncluding) < pszEnd )
  1785. {
  1786. pszPlace += nIncluding;
  1787. int nExcluding = StringTraits::StringSpanExcluding( pszPlace, pszTokens );
  1788. int iFrom = iStart+nIncluding;
  1789. int nUntil = nExcluding;
  1790. iStart = iFrom+nUntil+1;
  1791. return( Mid( iFrom, nUntil ) );
  1792. }
  1793. }
  1794. // return empty string, done tokenizing
  1795. iStart = -1;
  1796. return( CStringT( GetManager() ) );
  1797. }
  1798. // find routines
  1799. // Find the first occurrence of character 'ch', starting at index 'iStart'
  1800. int Find( XCHAR ch, int iStart = 0 ) const throw()
  1801. {
  1802. // iStart is in XCHARs
  1803. ATLASSERT( iStart >= 0 );
  1804. // nLength is in XCHARs
  1805. int nLength = GetLength();
  1806. if( iStart >= nLength)
  1807. {
  1808. return( -1 );
  1809. }
  1810. // find first single character
  1811. PCXSTR psz = StringTraits::StringFindChar( GetString()+iStart, ch );
  1812. // return -1 if not found and index otherwise
  1813. return( (psz == NULL) ? -1 : int( psz-GetString() ) );
  1814. }
  1815. // look for a specific sub-string
  1816. // Find the first occurrence of string 'pszSub', starting at index 'iStart'
  1817. int Find( PCXSTR pszSub, int iStart = 0 ) const throw()
  1818. {
  1819. // iStart is in XCHARs
  1820. ATLASSERT( iStart >= 0 );
  1821. ATLASSERT( AtlIsValidString( pszSub ) );
  1822. // nLength is in XCHARs
  1823. int nLength = GetLength();
  1824. if( iStart > nLength )
  1825. {
  1826. return( -1 );
  1827. }
  1828. // find first matching substring
  1829. PCXSTR psz = StringTraits::StringFindString( GetString()+iStart, pszSub );
  1830. // return -1 for not found, distance from beginning otherwise
  1831. return( (psz == NULL) ? -1 : int( psz-GetString() ) );
  1832. }
  1833. // Find the first occurrence of any of the characters in string 'pszCharSet'
  1834. int FindOneOf( PCXSTR pszCharSet ) const throw()
  1835. {
  1836. ATLASSERT( AtlIsValidString( pszCharSet ) );
  1837. PCXSTR psz = StringTraits::StringScanSet( GetString(), pszCharSet );
  1838. return( (psz == NULL) ? -1 : int( psz-GetString() ) );
  1839. }
  1840. // Find the last occurrence of character 'ch'
  1841. int ReverseFind( XCHAR ch ) const throw()
  1842. {
  1843. // find last single character
  1844. PCXSTR psz = StringTraits::StringFindCharRev( GetString(), ch );
  1845. // return -1 if not found, distance from beginning otherwise
  1846. return( (psz == NULL) ? -1 : int( psz-GetString() ) );
  1847. }
  1848. // manipulation
  1849. // Convert the string to uppercase
  1850. CStringT& MakeUpper()
  1851. {
  1852. int nLength = GetLength();
  1853. PXSTR pszBuffer = GetBuffer( nLength );
  1854. StringTraits::StringUppercase( pszBuffer );
  1855. ReleaseBuffer( nLength );
  1856. return( *this );
  1857. }
  1858. // Convert the string to lowercase
  1859. CStringT& MakeLower()
  1860. {
  1861. int nLength = GetLength();
  1862. PXSTR pszBuffer = GetBuffer( nLength );
  1863. StringTraits::StringLowercase( pszBuffer );
  1864. ReleaseBuffer( nLength );
  1865. return( *this );
  1866. }
  1867. // Reverse the string
  1868. CStringT& MakeReverse()
  1869. {
  1870. int nLength = GetLength();
  1871. PXSTR pszBuffer = GetBuffer( nLength );
  1872. StringTraits::StringReverse( pszBuffer );
  1873. ReleaseBuffer( nLength );
  1874. return( *this );
  1875. }
  1876. // trimming
  1877. // Remove all trailing whitespace
  1878. CStringT& TrimRight()
  1879. {
  1880. // find beginning of trailing spaces by starting
  1881. // at beginning (DBCS aware)
  1882. PCXSTR psz = GetString();
  1883. PCXSTR pszLast = NULL;
  1884. while( *psz != 0 )
  1885. {
  1886. if( StringTraits::IsSpace( *psz ) )
  1887. {
  1888. if( pszLast == NULL )
  1889. pszLast = psz;
  1890. }
  1891. else
  1892. {
  1893. pszLast = NULL;
  1894. }
  1895. psz = StringTraits::CharNext( psz );
  1896. }
  1897. if( pszLast != NULL )
  1898. {
  1899. // truncate at trailing space start
  1900. int iLast = int( pszLast-GetString() );
  1901. Truncate( iLast );
  1902. }
  1903. return( *this );
  1904. }
  1905. // Remove all leading whitespace
  1906. CStringT& TrimLeft()
  1907. {
  1908. // find first non-space character
  1909. PCXSTR psz = GetString();
  1910. while( StringTraits::IsSpace( *psz ) )
  1911. {
  1912. psz = StringTraits::CharNext( psz );
  1913. }
  1914. if( psz != GetString() )
  1915. {
  1916. // fix up data and length
  1917. int iFirst = int( psz-GetString() );
  1918. PXSTR pszBuffer = GetBuffer( GetLength() );
  1919. psz = pszBuffer+iFirst;
  1920. int nDataLength = GetLength()-iFirst;
  1921. memmove( pszBuffer, psz, (nDataLength+1)*sizeof( XCHAR ) );
  1922. ReleaseBuffer( nDataLength );
  1923. }
  1924. return( *this );
  1925. }
  1926. // Remove all leading and trailing whitespace
  1927. CStringT& Trim()
  1928. {
  1929. return( TrimRight().TrimLeft() );
  1930. }
  1931. // Remove all leading and trailing occurrences of character 'chTarget'
  1932. CStringT& Trim( XCHAR chTarget )
  1933. {
  1934. return( TrimRight( chTarget ).TrimLeft( chTarget ) );
  1935. }
  1936. // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets'
  1937. CStringT& Trim( PCXSTR pszTargets )
  1938. {
  1939. return( TrimRight( pszTargets ).TrimLeft( pszTargets ) );
  1940. }
  1941. // trimming anything (either side)
  1942. // Remove all trailing occurrences of character 'chTarget'
  1943. CStringT& TrimRight( XCHAR chTarget )
  1944. {
  1945. // find beginning of trailing matches
  1946. // by starting at beginning (DBCS aware)
  1947. PCXSTR psz = GetString();
  1948. PCXSTR pszLast = NULL;
  1949. while( *psz != 0 )
  1950. {
  1951. if( *psz == chTarget )
  1952. {
  1953. if( pszLast == NULL )
  1954. {
  1955. pszLast = psz;
  1956. }
  1957. }
  1958. else
  1959. {
  1960. pszLast = NULL;
  1961. }
  1962. psz = StringTraits::CharNext( psz );
  1963. }
  1964. if( pszLast != NULL )
  1965. {
  1966. // truncate at left-most matching character
  1967. int iLast = int( pszLast-GetString() );
  1968. Truncate( iLast );
  1969. }
  1970. return( *this );
  1971. }
  1972. // Remove all trailing occurrences of any of the characters in string 'pszTargets'
  1973. CStringT& TrimRight( PCXSTR pszTargets )
  1974. {
  1975. // if we're not trimming anything, we're not doing any work
  1976. if( (pszTargets == NULL) || (*pszTargets == 0) )
  1977. {
  1978. return( *this );
  1979. }
  1980. // find beginning of trailing matches
  1981. // by starting at beginning (DBCS aware)
  1982. PCXSTR psz = GetString();
  1983. PCXSTR pszLast = NULL;
  1984. while( *psz != 0 )
  1985. {
  1986. if( StringTraits::StringFindChar( pszTargets, *psz ) != NULL )
  1987. {
  1988. if( pszLast == NULL )
  1989. {
  1990. pszLast = psz;
  1991. }
  1992. }
  1993. else
  1994. {
  1995. pszLast = NULL;
  1996. }
  1997. psz = StringTraits::CharNext( psz );
  1998. }
  1999. if( pszLast != NULL )
  2000. {
  2001. // truncate at left-most matching character
  2002. int iLast = int( pszLast-GetString() );
  2003. Truncate( iLast );
  2004. }
  2005. return( *this );
  2006. }
  2007. // Remove all leading occurrences of character 'chTarget'
  2008. CStringT& TrimLeft( XCHAR chTarget )
  2009. {
  2010. // find first non-matching character
  2011. PCXSTR psz = GetString();
  2012. while( chTarget == *psz )
  2013. {
  2014. psz = StringTraits::CharNext( psz );
  2015. }
  2016. if( psz != GetString() )
  2017. {
  2018. // fix up data and length
  2019. int iFirst = int( psz-GetString() );
  2020. PXSTR pszBuffer = GetBuffer( GetLength() );
  2021. psz = pszBuffer+iFirst;
  2022. int nDataLength = GetLength()-iFirst;
  2023. memmove( pszBuffer, psz, (nDataLength+1)*sizeof( XCHAR ) );
  2024. ReleaseBuffer( nDataLength );
  2025. }
  2026. return( *this );
  2027. }
  2028. // Remove all leading occurrences of any of the characters in string 'pszTargets'
  2029. CStringT& TrimLeft( PCXSTR pszTargets )
  2030. {
  2031. // if we're not trimming anything, we're not doing any work
  2032. if( (pszTargets == NULL) || (*pszTargets == 0) )
  2033. {
  2034. return( *this );
  2035. }
  2036. PCXSTR psz = GetString();
  2037. while( (*psz != 0) && (StringTraits::StringFindChar( pszTargets, *psz ) != NULL) )
  2038. {
  2039. psz = StringTraits::CharNext( psz );
  2040. }
  2041. if( psz != GetString() )
  2042. {
  2043. // fix up data and length
  2044. int iFirst = int( psz-GetString() );
  2045. PXSTR pszBuffer = GetBuffer( GetLength() );
  2046. psz = pszBuffer+iFirst;
  2047. int nDataLength = GetLength()-iFirst;
  2048. memmove( pszBuffer, psz, (nDataLength+1)*sizeof( XCHAR ) );
  2049. ReleaseBuffer( nDataLength );
  2050. }
  2051. return( *this );
  2052. }
  2053. __if_exists( StringTraits::ConvertToOem )
  2054. {
  2055. // Convert the string to the OEM character set
  2056. void AnsiToOem()
  2057. {
  2058. int nLength = GetLength();
  2059. PXSTR pszBuffer = GetBuffer( nLength );
  2060. StringTraits::ConvertToOem( pszBuffer );
  2061. ReleaseBuffer( nLength );
  2062. }
  2063. }
  2064. __if_exists( StringTraits::ConvertToAnsi )
  2065. {
  2066. // Convert the string to the ANSI character set
  2067. void OemToAnsi()
  2068. {
  2069. int nLength = GetLength();
  2070. PXSTR pszBuffer = GetBuffer( nLength );
  2071. StringTraits::ConvertToAnsi( pszBuffer );
  2072. ReleaseBuffer( nLength );
  2073. }
  2074. }
  2075. // Very simple sub-string extraction
  2076. // Return the substring starting at index 'iFirst'
  2077. CStringT Mid( int iFirst ) const
  2078. {
  2079. return( Mid( iFirst, GetLength()-iFirst ) );
  2080. }
  2081. // Return the substring starting at index 'iFirst', with length 'nCount'
  2082. CStringT Mid( int iFirst, int nCount ) const
  2083. {
  2084. // nCount is in XCHARs
  2085. // out-of-bounds requests return sensible things
  2086. ATLASSERT( iFirst >= 0 );
  2087. ATLASSERT( nCount >= 0 );
  2088. if( (iFirst+nCount) > GetLength() )
  2089. {
  2090. nCount = GetLength()-iFirst;
  2091. }
  2092. if( iFirst > GetLength() )
  2093. {
  2094. nCount = 0;
  2095. }
  2096. ATLASSERT( (nCount == 0) || ((iFirst+nCount) <= GetLength()) );
  2097. // optimize case of returning entire string
  2098. if( (iFirst == 0) && ((iFirst+nCount) == GetLength()) )
  2099. {
  2100. return( *this );
  2101. }
  2102. CStringT strDest( GetManager() ); //GetString()+nFirst, nCount );
  2103. PXSTR pszBuffer = strDest.GetBufferSetLength( nCount );
  2104. memcpy( pszBuffer, GetString()+iFirst, nCount*sizeof( XCHAR ) );
  2105. strDest.ReleaseBuffer( nCount );
  2106. return( strDest );
  2107. }
  2108. // Return the substring consisting of the rightmost 'nCount' characters
  2109. CStringT Right( int nCount ) const
  2110. {
  2111. // nCount is in XCHARs
  2112. ATLASSERT( nCount >= 0 );
  2113. if( nCount >= GetLength() )
  2114. {
  2115. return( *this );
  2116. }
  2117. CStringT strDest( GetManager() );
  2118. PXSTR pszBuffer = strDest.GetBufferSetLength( nCount );
  2119. memcpy( pszBuffer, GetString()+GetLength()-nCount, nCount*sizeof( XCHAR ) );
  2120. strDest.ReleaseBuffer( nCount );
  2121. return( strDest );
  2122. }
  2123. // Return the substring consisting of the leftmost 'nCount' characters
  2124. CStringT Left( int nCount ) const
  2125. {
  2126. // nCount is in XCHARs
  2127. ATLASSERT( nCount >= 0 );
  2128. if( nCount >= GetLength() )
  2129. {
  2130. return( *this );
  2131. }
  2132. CStringT strDest( GetManager() );
  2133. PXSTR pszBuffer = strDest.GetBufferSetLength( nCount );
  2134. memcpy( pszBuffer, GetString(), nCount*sizeof( XCHAR ) );
  2135. strDest.ReleaseBuffer( nCount );
  2136. return( strDest );
  2137. }
  2138. // Return the substring consisting of the leftmost characters in the set 'pszCharSet'
  2139. CStringT SpanIncluding( PCXSTR pszCharSet ) const
  2140. {
  2141. ATLASSERT( AtlIsValidString( pszCharSet ) );
  2142. return( Left( StringTraits::StringSpanIncluding( GetString(), pszCharSet ) ) );
  2143. }
  2144. // Return the substring consisting of the leftmost characters not in the set 'pszCharSet'
  2145. CStringT SpanExcluding( PCXSTR pszCharSet ) const
  2146. {
  2147. ATLASSERT( AtlIsValidString( pszCharSet ) );
  2148. return( Left( StringTraits::StringSpanExcluding( GetString(), pszCharSet ) ) );
  2149. }
  2150. // Format data using format string 'pszFormat'
  2151. void __cdecl Format( PCXSTR pszFormat, ... )
  2152. {
  2153. ATLASSERT( AtlIsValidString( pszFormat ) );
  2154. va_list argList;
  2155. va_start( argList, pszFormat );
  2156. FormatV( pszFormat, argList );
  2157. va_end( argList );
  2158. }
  2159. // Format data using format string loaded from resource 'nFormatID'
  2160. void __cdecl Format( UINT nFormatID, ... )
  2161. {
  2162. CStringT strFormat( GetManager() );
  2163. ATLVERIFY( strFormat.LoadString( nFormatID ) );
  2164. va_list argList;
  2165. va_start( argList, nFormatID );
  2166. FormatV( strFormat, argList );
  2167. va_end( argList );
  2168. }
  2169. // Append formatted data using format string loaded from resource 'nFormatID'
  2170. void __cdecl AppendFormat( UINT nFormatID, ... )
  2171. {
  2172. CStringT strTemp( GetManager() );
  2173. va_list argList;
  2174. va_start( argList, nFormatID );
  2175. CStringT strFormat( GetManager() );
  2176. ATLVERIFY( strFormat.LoadString( nFormatID ) );
  2177. strTemp.FormatV( strFormat, argList );
  2178. operator+=( strTemp );
  2179. va_end( argList );
  2180. }
  2181. // Append formatted data using format string 'pszFormat'
  2182. void __cdecl AppendFormat( PCXSTR pszFormat, ... )
  2183. {
  2184. ATLASSERT( AtlIsValidString( pszFormat ) );
  2185. CStringT strTemp( GetManager() );
  2186. va_list argList;
  2187. va_start( argList, pszFormat );
  2188. strTemp.FormatV( pszFormat, argList );
  2189. operator+=( strTemp );
  2190. va_end( argList );
  2191. }
  2192. void FormatV( PCXSTR pszFormat, va_list args )
  2193. {
  2194. ATLASSERT( AtlIsValidString( pszFormat ) );
  2195. int nLength = StringTraits::GetFormattedLength( pszFormat, args );
  2196. PXSTR pszBuffer = GetBuffer( nLength );
  2197. StringTraits::Format( pszBuffer, pszFormat, args );
  2198. ReleaseBuffer( nLength );
  2199. }
  2200. __if_exists(StringTraits::FormatMessage)
  2201. {
  2202. // Format a message using format string 'pszFormat'
  2203. void __cdecl FormatMessage( PCXSTR pszFormat, ... )
  2204. {
  2205. va_list argList;
  2206. va_start( argList, pszFormat );
  2207. FormatMessageV( pszFormat, &argList );
  2208. va_end( argList );
  2209. }
  2210. // Format a message using format string loaded from resource 'nFormatID'
  2211. void __cdecl FormatMessage( UINT nFormatID, ... )
  2212. {
  2213. // get format string from string table
  2214. CStringT strFormat( GetManager() );
  2215. ATLVERIFY( strFormat.LoadString( nFormatID ) );
  2216. va_list argList;
  2217. va_start( argList, nFormatID );
  2218. FormatMessageV( strFormat, &argList );
  2219. va_end( argList );
  2220. }
  2221. }
  2222. // OLE BSTR support
  2223. // Allocate a BSTR containing a copy of the string
  2224. BSTR AllocSysString() const
  2225. {
  2226. BSTR bstrResult = StringTraits::AllocSysString( GetString(),
  2227. GetLength() );
  2228. if( bstrResult == NULL )
  2229. {
  2230. ThrowMemoryException();
  2231. }
  2232. return( bstrResult );
  2233. }
  2234. BSTR SetSysString( BSTR* pbstr ) const
  2235. {
  2236. ATLASSERT( AtlIsValidAddress( pbstr, sizeof( BSTR ) ) );
  2237. if( !StringTraits::ReAllocSysString( GetString(), pbstr,
  2238. GetLength() ) )
  2239. {
  2240. ThrowMemoryException();
  2241. }
  2242. ATLASSERT( *pbstr != NULL );
  2243. return( *pbstr );
  2244. }
  2245. // Set the string to the value of environment variable 'pszVar'
  2246. BOOL GetEnvironmentVariable( PCXSTR pszVar )
  2247. {
  2248. ULONG nLength = StringTraits::GetEnvironmentVariable( pszVar, NULL, 0 );
  2249. BOOL bRetVal = FALSE;
  2250. if( nLength == 0 )
  2251. {
  2252. Empty();
  2253. }
  2254. else
  2255. {
  2256. PXSTR pszBuffer = GetBuffer( nLength );
  2257. StringTraits::GetEnvironmentVariable( pszVar, pszBuffer, nLength );
  2258. ReleaseBuffer();
  2259. bRetVal = TRUE;
  2260. }
  2261. return( bRetVal );
  2262. }
  2263. // Load the string from resource 'nID'
  2264. BOOL LoadString( UINT nID )
  2265. {
  2266. HINSTANCE hInst = StringTraits::FindStringResourceInstance( nID );
  2267. if( hInst == NULL )
  2268. {
  2269. return( FALSE );
  2270. }
  2271. return( LoadString( hInst, nID ) );
  2272. }
  2273. // Load the string from resource 'nID' in module 'hInstance'
  2274. BOOL LoadString( HINSTANCE hInstance, UINT nID )
  2275. {
  2276. const ATLSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage( hInstance, nID );
  2277. if( pImage == NULL )
  2278. {
  2279. return( FALSE );
  2280. }
  2281. int nLength = StringTraits::GetBaseTypeLength( pImage->achString, pImage->nLength );
  2282. PXSTR pszBuffer = GetBuffer( nLength );
  2283. StringTraits::ConvertToBaseType( pszBuffer, nLength, pImage->achString, pImage->nLength );
  2284. ReleaseBuffer( nLength );
  2285. return( TRUE );
  2286. }
  2287. // Load the string from resource 'nID' in module 'hInstance', using language 'wLanguageID'
  2288. BOOL LoadString( HINSTANCE hInstance, UINT nID, WORD wLanguageID )
  2289. {
  2290. const ATLSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage( hInstance, nID, wLanguageID );
  2291. if( pImage == NULL )
  2292. {
  2293. return( FALSE );
  2294. }
  2295. int nLength = StringTraits::GetBaseTypeLength( pImage->achString, pImage->nLength );
  2296. PXSTR pszBuffer = GetBuffer( nLength );
  2297. StringTraits::ConvertToBaseType( pszBuffer, nLength, pImage->achString, pImage->nLength );
  2298. ReleaseBuffer( nLength );
  2299. return( TRUE );
  2300. }
  2301. friend CStringT operator+( const CStringT& str1, const CStringT& str2 )
  2302. {
  2303. CStringT strResult( str1.GetManager() );
  2304. Concatenate( strResult, str1, str1.GetLength(), str2, str2.GetLength() );
  2305. return( strResult );
  2306. }
  2307. friend CStringT operator+( const CStringT& str1, PCXSTR psz2 )
  2308. {
  2309. CStringT strResult( str1.GetManager() );
  2310. Concatenate( strResult, str1, str1.GetLength(), psz2, StringLength( psz2 ) );
  2311. return( strResult );
  2312. }
  2313. friend CStringT operator+( PCXSTR psz1, const CStringT& str2 )
  2314. {
  2315. CStringT strResult( str2.GetManager() );
  2316. Concatenate( strResult, psz1, StringLength( psz1 ), str2, str2.GetLength() );
  2317. return( strResult );
  2318. }
  2319. friend CStringT operator+( const CStringT& str1, wchar_t ch2 )
  2320. {
  2321. CStringT strResult( str1.GetManager() );
  2322. XCHAR chTemp = XCHAR( ch2 );
  2323. Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 );
  2324. return( strResult );
  2325. }
  2326. friend CStringT operator+( const CStringT& str1, char ch2 )
  2327. {
  2328. CStringT strResult( str1.GetManager() );
  2329. XCHAR chTemp = XCHAR( ch2 );
  2330. Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 );
  2331. return( strResult );
  2332. }
  2333. friend CStringT operator+( wchar_t ch1, const CStringT& str2 )
  2334. {
  2335. CStringT strResult( str2.GetManager() );
  2336. XCHAR chTemp = XCHAR( ch1 );
  2337. Concatenate( strResult, &chTemp, 1, str2, str2.GetLength() );
  2338. return( strResult );
  2339. }
  2340. friend CStringT operator+( char ch1, const CStringT& str2 )
  2341. {
  2342. CStringT strResult( str2.GetManager() );
  2343. XCHAR chTemp = XCHAR( ch1 );
  2344. Concatenate( strResult, &chTemp, 1, str2, str2.GetLength() );
  2345. return( strResult );
  2346. }
  2347. friend bool operator==( const CStringT& str1, const CStringT& str2 ) throw()
  2348. {
  2349. return( str1.Compare( str2 ) == 0 );
  2350. }
  2351. friend bool operator==(
  2352. const CStringT& str1, PCXSTR psz2 ) throw()
  2353. {
  2354. return( str1.Compare( psz2 ) == 0 );
  2355. }
  2356. friend bool operator==(
  2357. PCXSTR psz1, const CStringT& str2 ) throw()
  2358. {
  2359. return( str2.Compare( psz1 ) == 0 );
  2360. }
  2361. friend bool operator==(
  2362. const CStringT& str1, PCYSTR psz2 ) throw( ... )
  2363. {
  2364. CStringT str2( psz2, str1.GetManager() );
  2365. return( str1 == str2 );
  2366. }
  2367. friend bool operator==(
  2368. PCYSTR psz1, const CStringT& str2 ) throw( ... )
  2369. {
  2370. CStringT str1( psz1, str2.GetManager() );
  2371. return( str1 == str2 );
  2372. }
  2373. friend bool operator!=(
  2374. const CStringT& str1, const CStringT& str2 ) throw()
  2375. {
  2376. return( str1.Compare( str2 ) != 0 );
  2377. }
  2378. friend bool operator!=(
  2379. const CStringT& str1, PCXSTR psz2 ) throw()
  2380. {
  2381. return( str1.Compare( psz2 ) != 0 );
  2382. }
  2383. friend bool operator!=(
  2384. PCXSTR psz1, const CStringT& str2 ) throw()
  2385. {
  2386. return( str2.Compare( psz1 ) != 0 );
  2387. }
  2388. friend bool operator!=(
  2389. const CStringT& str1, PCYSTR psz2 ) throw( ... )
  2390. {
  2391. CStringT str2( psz2, str1.GetManager() );
  2392. return( str1 != str2 );
  2393. }
  2394. friend bool operator!=(
  2395. PCYSTR psz1, const CStringT& str2 ) throw( ... )
  2396. {
  2397. CStringT str1( psz1, str2.GetManager() );
  2398. return( str1 != str2 );
  2399. }
  2400. friend bool operator<( const CStringT& str1, const CStringT& str2 ) throw()
  2401. {
  2402. return( str1.Compare( str2 ) < 0 );
  2403. }
  2404. friend bool operator<( const CStringT& str1, PCXSTR psz2 ) throw()
  2405. {
  2406. return( str1.Compare( psz2 ) < 0 );
  2407. }
  2408. friend bool operator<( PCXSTR psz1, const CStringT& str2 ) throw()
  2409. {
  2410. return( str2.Compare( psz1 ) >= 0 );
  2411. }
  2412. friend bool operator>( const CStringT& str1, const CStringT& str2 ) throw()
  2413. {
  2414. return( str1.Compare( str2 ) > 0 );
  2415. }
  2416. friend bool operator>( const CStringT& str1, PCXSTR psz2 ) throw()
  2417. {
  2418. return( str1.Compare( psz2 ) > 0 );
  2419. }
  2420. friend bool operator>( PCXSTR psz1, const CStringT& str2 ) throw()
  2421. {
  2422. return( str2.Compare( psz1 ) <= 0 );
  2423. }
  2424. friend bool operator<=( const CStringT& str1, const CStringT& str2 ) throw()
  2425. {
  2426. return( str1.Compare( str2 ) <= 0 );
  2427. }
  2428. friend bool operator<=( const CStringT& str1, PCXSTR psz2 ) throw()
  2429. {
  2430. return( str1.Compare( psz2 ) <= 0 );
  2431. }
  2432. friend bool operator<=( PCXSTR psz1, const CStringT& str2 ) throw()
  2433. {
  2434. return( str2.Compare( psz1 ) > 0 );
  2435. }
  2436. friend bool operator>=( const CStringT& str1, const CStringT& str2 ) throw()
  2437. {
  2438. return( str1.Compare( str2 ) >= 0 );
  2439. }
  2440. friend bool operator>=( const CStringT& str1, PCXSTR psz2 ) throw()
  2441. {
  2442. return( str1.Compare( psz2 ) >= 0 );
  2443. }
  2444. friend bool operator>=( PCXSTR psz1, const CStringT& str2 ) throw()
  2445. {
  2446. return( str2.Compare( psz1 ) < 0 );
  2447. }
  2448. friend bool operator==( XCHAR ch1, const CStringT& str2 ) throw()
  2449. {
  2450. return( (str2.GetLength() == 1) && (str2[0] == ch1) );
  2451. }
  2452. friend bool operator==( const CStringT& str1, XCHAR ch2 ) throw()
  2453. {
  2454. return( (str1.GetLength() == 1) && (str1[0] == ch2) );
  2455. }
  2456. friend bool operator!=( XCHAR ch1, const CStringT& str2 ) throw()
  2457. {
  2458. return( (str2.GetLength() != 1) || (str2[0] != ch1) );
  2459. }
  2460. friend bool operator!=( const CStringT& str1, XCHAR ch2 ) throw()
  2461. {
  2462. return( (str1.GetLength() != 1) || (str1[0] != ch2) );
  2463. }
  2464. private:
  2465. bool CheckImplicitLoad( const void* pv )
  2466. {
  2467. bool bRet = false;
  2468. if( (pv != NULL) && IS_INTRESOURCE( pv ) )
  2469. {
  2470. UINT nID = LOWORD( reinterpret_cast< DWORD_PTR >( pv ) );
  2471. if( !LoadString( nID ) )
  2472. {
  2473. ATLTRACE( atlTraceString, 2, _T( "Warning: implicit LoadString(%u) failed\n" ), nID );
  2474. }
  2475. bRet = true;
  2476. }
  2477. return( bRet );
  2478. }
  2479. __if_exists( StringTraits::FormatMessage )
  2480. {
  2481. void FormatMessageV( PCXSTR pszFormat, va_list* pArgList )
  2482. {
  2483. // format message into temporary buffer pszTemp
  2484. CHeapPtr< XCHAR, CLocalAllocator > pszTemp;
  2485. DWORD dwResult = StringTraits::FormatMessage( FORMAT_MESSAGE_FROM_STRING|
  2486. FORMAT_MESSAGE_ALLOCATE_BUFFER, pszFormat, 0, 0, reinterpret_cast< PXSTR >( &pszTemp ),
  2487. 0, pArgList );
  2488. if( dwResult == 0 )
  2489. {
  2490. ThrowMemoryException();
  2491. }
  2492. *this = pszTemp;
  2493. }
  2494. }
  2495. };
  2496. class IFixedStringLog
  2497. {
  2498. public:
  2499. virtual void OnAllocateSpill( int nActualChars, int nFixedChars, const CStringData* pData ) throw() = 0;
  2500. virtual void OnReallocateSpill( int nActualChars, int nFixedChars, const CStringData* pData ) throw() = 0;
  2501. };
  2502. class CFixedStringMgr :
  2503. public IAtlStringMgr
  2504. {
  2505. public:
  2506. CFixedStringMgr( CStringData* pData, int nChars, IAtlStringMgr* pMgr = NULL ) throw() :
  2507. m_pData( pData ),
  2508. m_pMgr( pMgr )
  2509. {
  2510. m_pData->nRefs = -1;
  2511. m_pData->nDataLength = 0;
  2512. m_pData->nAllocLength = nChars;
  2513. m_pData->pStringMgr = this;
  2514. *static_cast< wchar_t* >( m_pData->data() ) = 0;
  2515. }
  2516. ~CFixedStringMgr() throw()
  2517. {
  2518. }
  2519. // IAtlStringMgr
  2520. public:
  2521. virtual CStringData* Allocate( int nChars, int nCharSize ) throw()
  2522. {
  2523. ATLASSERT( m_pData->nRefs == -1 );
  2524. ATLASSERT( m_pData->nDataLength == 0 );
  2525. if( nChars > m_pData->nAllocLength )
  2526. {
  2527. if( s_pLog != NULL )
  2528. {
  2529. s_pLog->OnAllocateSpill( nChars, m_pData->nAllocLength, m_pData );
  2530. }
  2531. CStringData* pData = m_pMgr->Allocate( nChars, nCharSize );
  2532. if( pData != NULL )
  2533. {
  2534. pData->pStringMgr = this;
  2535. pData->nRefs = -1; // Locked
  2536. }
  2537. return pData;
  2538. }
  2539. m_pData->nRefs = -1; // Locked
  2540. m_pData->nDataLength = 0;
  2541. m_pData->pStringMgr = this;
  2542. return m_pData;
  2543. }
  2544. virtual void Free( CStringData* pData ) throw()
  2545. {
  2546. ATLASSERT( pData->nRefs <= 0 );
  2547. if( pData != m_pData )
  2548. {
  2549. // Must have been allocated from the backup manager
  2550. pData->pStringMgr = m_pMgr;
  2551. m_pMgr->Free( pData );
  2552. }
  2553. // Always make sure the fixed buffer is ready to be used as the nil string.
  2554. m_pData->nRefs = -1;
  2555. m_pData->nDataLength = 0;
  2556. *static_cast< wchar_t* >( m_pData->data() ) = 0;
  2557. }
  2558. virtual CStringData* Reallocate( CStringData* pData, int nChars, int nCharSize ) throw()
  2559. {
  2560. CStringData* pNewData;
  2561. ATLASSERT( pData->nRefs < 0 );
  2562. if( pData != m_pData )
  2563. {
  2564. pData->pStringMgr = m_pMgr;
  2565. pNewData = m_pMgr->Reallocate( pData, nChars, nCharSize );
  2566. if( pNewData == NULL )
  2567. {
  2568. pData->pStringMgr = this;
  2569. }
  2570. else
  2571. {
  2572. pNewData->pStringMgr = this;
  2573. }
  2574. }
  2575. else
  2576. {
  2577. if( nChars > pData->nAllocLength )
  2578. {
  2579. if( s_pLog != NULL )
  2580. {
  2581. s_pLog->OnReallocateSpill( nChars, pData->nAllocLength, pData );
  2582. }
  2583. pNewData = m_pMgr->Allocate( nChars, nCharSize );
  2584. if( pNewData == NULL )
  2585. {
  2586. return NULL;
  2587. }
  2588. // Copy the string data
  2589. memcpy( pNewData->data(), pData->data(), (pData->nAllocLength+1)*nCharSize );
  2590. pNewData->nRefs = pData->nRefs; // Locked
  2591. pNewData->pStringMgr = this;
  2592. pNewData->nDataLength = pData->nDataLength;
  2593. }
  2594. else
  2595. {
  2596. // Don't do anything if the buffer is already big enough.
  2597. pNewData = pData;
  2598. }
  2599. }
  2600. return pNewData;
  2601. }
  2602. virtual CStringData* GetNilString() throw()
  2603. {
  2604. ATLASSERT( m_pData->nRefs == -1 );
  2605. ATLASSERT( m_pData->nDataLength == 0 );
  2606. return m_pData;
  2607. }
  2608. virtual IAtlStringMgr* Clone() throw()
  2609. {
  2610. return m_pMgr;
  2611. }
  2612. public:
  2613. static IFixedStringLog* s_pLog;
  2614. IAtlStringMgr* GetBackupManager() const throw()
  2615. {
  2616. return m_pMgr;
  2617. }
  2618. protected:
  2619. IAtlStringMgr* m_pMgr;
  2620. CStringData* m_pData;
  2621. };
  2622. __declspec( selectany ) IFixedStringLog* CFixedStringMgr::s_pLog = NULL;
  2623. #pragma warning( push )
  2624. #pragma warning( disable: 4355 ) // 'this' used in base member initializer list
  2625. template< class StringType, int t_nChars >
  2626. class CFixedStringT :
  2627. private CFixedStringMgr, // This class must be first, since it needs to be initialized before StringType
  2628. public StringType
  2629. {
  2630. public:
  2631. CFixedStringT() throw() :
  2632. CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
  2633. StringType( static_cast< CFixedStringMgr* >( this ) )
  2634. {
  2635. }
  2636. explicit CFixedStringT( IAtlStringMgr* pStringMgr ) throw() :
  2637. CFixedStringMgr( &m_data, t_nChars, pStringMgr ),
  2638. StringType( static_cast< CFixedStringMgr* >( this ) )
  2639. {
  2640. }
  2641. CFixedStringT( const CFixedStringT< StringType, t_nChars >& str ) :
  2642. CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
  2643. StringType( str.GetString(), str.GetLength(), static_cast< CFixedStringMgr* >( this ) )
  2644. {
  2645. }
  2646. CFixedStringT( const StringType& str ) :
  2647. CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
  2648. StringType( str.GetString(), str.GetLength(), static_cast< CFixedStringMgr* >( this ) )
  2649. {
  2650. }
  2651. CFixedStringT( const StringType::XCHAR* psz ) :
  2652. CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
  2653. StringType( psz, static_cast< CFixedStringMgr* >( this ) )
  2654. {
  2655. }
  2656. CFixedStringT( const StringType::XCHAR* psz, int nLength ) :
  2657. CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
  2658. StringType( psz, nLength, static_cast< CFixedStringMgr* >( this ) )
  2659. {
  2660. }
  2661. explicit CFixedStringT( const StringType::YCHAR* psz ) :
  2662. CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
  2663. StringType( psz, static_cast< CFixedStringMgr* >( this ) )
  2664. {
  2665. }
  2666. explicit CFixedStringT( const unsigned char* psz ) :
  2667. CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
  2668. StringType( psz, static_cast< CFixedStringMgr* >( this ) )
  2669. {
  2670. }
  2671. ~CFixedStringT() throw()
  2672. {
  2673. Empty();
  2674. }
  2675. CFixedStringT< StringType, t_nChars >& operator=( const CFixedStringT< StringType, t_nChars >& str )
  2676. {
  2677. StringType::operator=( str );
  2678. return *this;
  2679. }
  2680. CFixedStringT< StringType, t_nChars >& operator=( const char* psz )
  2681. {
  2682. StringType::operator=( psz );
  2683. return *this;
  2684. }
  2685. CFixedStringT< StringType, t_nChars >& operator=( const wchar_t* psz )
  2686. {
  2687. StringType::operator=( psz );
  2688. return *this;
  2689. }
  2690. CFixedStringT< StringType, t_nChars >& operator=( const unsigned char* psz )
  2691. {
  2692. StringType::operator=( psz );
  2693. return *this;
  2694. }
  2695. CFixedStringT< StringType, t_nChars >& operator=( const StringType& str )
  2696. {
  2697. StringType::operator=( str );
  2698. return *this;
  2699. }
  2700. // Implementation
  2701. protected:
  2702. CStringData m_data;
  2703. StringType::XCHAR m_achData[t_nChars+1];
  2704. };
  2705. #pragma warning( pop )
  2706. class CFixedStringLog :
  2707. public IFixedStringLog
  2708. {
  2709. public:
  2710. CFixedStringLog() throw()
  2711. {
  2712. CFixedStringMgr::s_pLog = this;
  2713. }
  2714. ~CFixedStringLog() throw()
  2715. {
  2716. CFixedStringMgr::s_pLog = NULL;
  2717. }
  2718. public:
  2719. void OnAllocateSpill( int nActualChars, int nFixedChars, const CStringData* pData ) throw()
  2720. {
  2721. (void)nActualChars;
  2722. (void)nFixedChars;
  2723. (void)pData;
  2724. ATLTRACE( atlTraceString, 0, _T( "CFixedStringMgr::Allocate() spilling to heap. %d chars (fixed size = %d chars)\n" ), nActualChars, nFixedChars );
  2725. }
  2726. void OnReallocateSpill( int nActualChars, int nFixedChars, const CStringData* pData ) throw()
  2727. {
  2728. (void)nActualChars;
  2729. (void)nFixedChars;
  2730. (void)pData;
  2731. ATLTRACE( atlTraceString, 0, _T( "CFixedStringMgr::Reallocate() spilling to heap. %d chars (fixed size = %d chars)\n" ), nActualChars, nFixedChars );
  2732. }
  2733. };
  2734. }; // namespace ATL
  2735. #pragma pop_macro("new")
  2736. #endif // __CSTRINGT_H__ (whole file)