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.

1053 lines
29 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998
  4. *
  5. * TITLE: SIMSTR.H
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 5/12/1998
  12. *
  13. * DESCRIPTION: Simple string classes
  14. *
  15. *******************************************************************************/
  16. #ifndef _SIMSTR_H_INCLUDED
  17. #define _SIMSTR_H_INCLUDED
  18. /*
  19. * Simple string class.
  20. *
  21. * Template class:
  22. * CSimpleStringBase<T>
  23. * Implementations:
  24. * CSimpleStringBase<wchar_t> CSimpleStringWide
  25. * CSimpleStringBase<char> CSimpleStringAnsi
  26. * CSimpleString = CSimpleString[Ansi|Wide] depending on UNICODE macro
  27. * Inline functions:
  28. * CSimpleStringAnsi CSimpleStringConvert::AnsiString(T n)
  29. * CSimpleStringWide CSimpleStringConvert::WideString(T n)
  30. * CSimpleString CSimpleStringConvert::NaturalString(T n)
  31. * Macros:
  32. * IS_CHAR(T)
  33. * IS_WCHAR(T)
  34. */
  35. #include <windows.h>
  36. #include <stdarg.h>
  37. #include <stdio.h>
  38. #include <tchar.h>
  39. #define IS_CHAR(x) (sizeof(x)==sizeof(char))
  40. #define IS_WCHAR(x) (sizeof(x)==sizeof(wchar_t))
  41. #ifndef ARRAYSIZE
  42. #define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
  43. #endif
  44. template <class T>
  45. class CSimpleStringBase
  46. {
  47. private:
  48. enum
  49. {
  50. m_nDefaultGranularity = 16, // Default number of extra characters to allocate when we have to grow
  51. m_nMaxLoadStringBuffer = 1024, // Maximum length of .RC string
  52. m_nMaxAutoDataLength = 128 // Length of non-dynamically allocated string
  53. };
  54. private:
  55. T *m_pstrData;
  56. T m_pstrAutoData[m_nMaxAutoDataLength];
  57. UINT m_nMaxSize;
  58. UINT m_nGranularity;
  59. private:
  60. static int Min( int a, int b )
  61. {
  62. return((a < b) ? a : b);
  63. }
  64. public:
  65. // Replacements (in some cases just wrappers) for strlen, strcpy, ...
  66. static inline T *GenericCopy( T *pstrTgtStr, const T *pstrSrcStr );
  67. static inline T *GenericCopyLength( T *pstrTgtStr, const T *pstrSrcStr, UINT nSize );
  68. static inline UINT GenericLength( const T *pstrStr );
  69. static inline T *GenericConcatenate( T *pstrTgtStr, const T *pstrSrcStr );
  70. static inline int GenericCompare( const T *pstrTgtStr, const T *pstrSrcStr );
  71. static inline int GenericCompareNoCase( const T *pstrStrA, const T *pstrStrB );
  72. static inline int GenericCompareLength( const T *pstrTgtStr, const T *pstrSrcStr, UINT nLength );
  73. static inline T *GenericCharNext( const T *pszStr );
  74. public:
  75. // Constructors and destructor
  76. CSimpleStringBase( void );
  77. CSimpleStringBase( const CSimpleStringBase & );
  78. CSimpleStringBase( const T *szStr );
  79. CSimpleStringBase( T ch );
  80. CSimpleStringBase( UINT nResId, HMODULE hModule );
  81. virtual ~CSimpleStringBase(void);
  82. bool EnsureLength( UINT nMaxSize );
  83. UINT Length(void) const;
  84. void Concat( const CSimpleStringBase &other );
  85. int Resize(void);
  86. UINT Truncate( UINT nLen );
  87. bool Assign( const T *szStr );
  88. bool Assign( const CSimpleStringBase & );
  89. void DeleteStorage(void);
  90. static inline T *CreateStorage( UINT nCount );
  91. void Destroy(void);
  92. CSimpleStringBase &Format( const T *strFmt, ... );
  93. CSimpleStringBase &Format( int nResId, HINSTANCE hInst, ... );
  94. // Handy Win32 wrappers
  95. CSimpleStringBase &GetWindowText( HWND hWnd );
  96. bool SetWindowText( HWND hWnd );
  97. bool LoadString( UINT nResId, HMODULE hModule );
  98. bool Load( HKEY hRegKey, const T *pszValueName, const T *pszDefault=NULL );
  99. bool Store( HKEY hRegKey, const T *pszValueName, DWORD nType = REG_SZ );
  100. void SetAt( UINT nIndex, T chValue );
  101. CSimpleStringBase &operator=( const CSimpleStringBase &other );
  102. CSimpleStringBase &operator=( const T *other );
  103. CSimpleStringBase &operator+=( const CSimpleStringBase &other );
  104. CSimpleStringBase operator+( const CSimpleStringBase &other ) const;
  105. T &operator[](int index);
  106. const T &operator[](int index) const;
  107. CSimpleStringBase ToUpper(void) const;
  108. CSimpleStringBase ToLower(void) const;
  109. CSimpleStringBase &MakeUpper(void);
  110. CSimpleStringBase &MakeLower(void);
  111. CSimpleStringBase &TrimRight(void);
  112. CSimpleStringBase &TrimLeft(void);
  113. CSimpleStringBase &Trim(void);
  114. CSimpleStringBase &Reverse(void);
  115. int Find( T cChar ) const;
  116. int Find( const CSimpleStringBase &other, UINT nStart=0 ) const;
  117. int ReverseFind( T cChar ) const;
  118. int ReverseFind( const CSimpleStringBase &other ) const;
  119. CSimpleStringBase SubStr( int nStart, int nCount=-1 ) const;
  120. int CompareNoCase( const CSimpleStringBase &other, int nLength=-1 ) const;
  121. int Compare( const CSimpleStringBase &other, int nLength=-1 ) const;
  122. bool MatchLastCharacter( T cChar ) const;
  123. // Some useful inlines
  124. UINT Granularity( UINT nGranularity ) { if (nGranularity>0) m_nGranularity = nGranularity;return m_nGranularity;}
  125. UINT Granularity( void ) const { return m_nGranularity;}
  126. CSimpleStringBase Left( int nCount ) const { return SubStr( 0, nCount );}
  127. CSimpleStringBase Right( int nCount ) const { return SubStr( max(0,(int)Length()-nCount), -1 );}
  128. bool operator<( const CSimpleStringBase &other ) const { return(Compare(other) < 0);}
  129. bool operator<=( const CSimpleStringBase &other ) const { return(Compare(other) <= 0);}
  130. bool operator==( const CSimpleStringBase &other ) const { return(Compare(other) == 0);}
  131. bool operator!=( const CSimpleStringBase &other ) const { return(Compare(other) != 0);}
  132. bool operator>=( const CSimpleStringBase &other ) const { return(Compare(other) >= 0);}
  133. bool operator>( const CSimpleStringBase &other ) const { return(Compare(other) > 0);}
  134. const T *String(void) const { return m_pstrData;}
  135. operator const T *(void) const { return String();}
  136. bool IsValid(void) const { return(NULL != m_pstrData);}
  137. };
  138. template <class T>
  139. inline T *CSimpleStringBase<T>::GenericCopy( T *pszDest, const T *pszSource )
  140. {
  141. T *pCurr = pszDest;
  142. while (*pCurr++ = *pszSource++)
  143. ;
  144. return(pszDest);
  145. }
  146. template <class T>
  147. inline T *CSimpleStringBase<T>::GenericCharNext( const T *pszStr )
  148. {
  149. if (IS_CHAR(*pszStr))
  150. return (T*)CharNextA((LPCSTR)pszStr);
  151. else if (!*pszStr)
  152. return (T*)pszStr;
  153. else return (T*)((LPWSTR)pszStr + 1);
  154. }
  155. template <class T>
  156. inline T *CSimpleStringBase<T>::GenericCopyLength( T *pszDest, const T *source, UINT count )
  157. {
  158. T *start = pszDest;
  159. while (count && (*pszDest++ = *source++))
  160. count--;
  161. if (count)
  162. while (--count)
  163. *pszDest++ = 0;
  164. return(start);
  165. }
  166. template <class T>
  167. inline UINT CSimpleStringBase<T>::GenericLength( const T *pszString )
  168. {
  169. const T *eos = pszString;
  170. while (*eos++)
  171. ;
  172. return((UINT)(eos - pszString - 1));
  173. }
  174. template <class T>
  175. inline T*CSimpleStringBase<T>::GenericConcatenate( T *pszDest, const T *pszSource )
  176. {
  177. T *pCurr = pszDest;
  178. while (*pCurr)
  179. pCurr++;
  180. while (*pCurr++ = *pszSource++)
  181. ;
  182. return( pszDest );
  183. }
  184. template <class T>
  185. inline int CSimpleStringBase<T>::GenericCompare( const T *pszSource, const T *pszDest )
  186. {
  187. #if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
  188. if (sizeof(T) == sizeof(wchar_t))
  189. {
  190. OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
  191. }
  192. #endif
  193. int nRes = IS_CHAR(*pszSource) ?
  194. CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszSource, -1, (LPCSTR)pszDest, -1 ) :
  195. CompareStringW( LOCALE_USER_DEFAULT, 0, (LPCWSTR)pszSource, -1, (LPCWSTR)pszDest, -1 );
  196. switch (nRes)
  197. {
  198. case CSTR_LESS_THAN:
  199. return -1;
  200. case CSTR_GREATER_THAN:
  201. return 1;
  202. default:
  203. return 0;
  204. }
  205. }
  206. template <class T>
  207. inline int CSimpleStringBase<T>::GenericCompareNoCase( const T *pszSource, const T *pszDest )
  208. {
  209. #if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
  210. if (sizeof(T) == sizeof(wchar_t))
  211. {
  212. OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
  213. }
  214. #endif
  215. int nRes = IS_CHAR(*pszSource) ?
  216. CompareStringA( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCSTR)pszSource, -1, (LPCSTR)pszDest, -1 ) :
  217. CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCWSTR)pszSource, -1, (LPCWSTR)pszDest, -1 );
  218. switch (nRes)
  219. {
  220. case CSTR_LESS_THAN:
  221. return -1;
  222. case CSTR_GREATER_THAN:
  223. return 1;
  224. default:
  225. return 0;
  226. }
  227. }
  228. template <class T>
  229. inline int CSimpleStringBase<T>::GenericCompareLength( const T *pszStringA, const T *pszStringB, UINT nLength )
  230. {
  231. #if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
  232. if (sizeof(T) == sizeof(wchar_t))
  233. {
  234. OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
  235. }
  236. #endif
  237. if (!nLength)
  238. return(0);
  239. int nRes = IS_CHAR(*pszStringA) ?
  240. CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszStringA, Min(nLength,CSimpleStringBase<CHAR>::GenericLength((LPCSTR)pszStringA)), (LPCSTR)pszStringB, Min(nLength,CSimpleStringBase<CHAR>::GenericLength((LPCSTR)pszStringB)) ) :
  241. CompareStringW( LOCALE_USER_DEFAULT, 0, (LPWSTR)pszStringA, Min(nLength,CSimpleStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringA)), (LPCWSTR)pszStringB, Min(nLength,CSimpleStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringB)) );
  242. switch (nRes)
  243. {
  244. case CSTR_LESS_THAN:
  245. return -1;
  246. case CSTR_GREATER_THAN:
  247. return 1;
  248. default:
  249. return 0;
  250. }
  251. }
  252. template <class T>
  253. bool CSimpleStringBase<T>::EnsureLength( UINT nMaxSize )
  254. {
  255. //
  256. // If the string is already long enough, just return true
  257. //
  258. if (m_nMaxSize >= nMaxSize)
  259. {
  260. return true;
  261. }
  262. //
  263. // Save the old max size
  264. //
  265. UINT nOldMaxSize = m_nMaxSize;
  266. //
  267. // Get the new size
  268. //
  269. UINT nNewMaxSize = nMaxSize + m_nGranularity;
  270. //
  271. // Allocate the new buffer
  272. //
  273. T *pszTmp = CreateStorage(nNewMaxSize);
  274. //
  275. // Make sure the allocation succeded
  276. //
  277. if (pszTmp)
  278. {
  279. //
  280. // If we have an existing string, copy it and delete it
  281. //
  282. if (m_pstrData)
  283. {
  284. GenericCopy(pszTmp,m_pstrData);
  285. DeleteStorage();
  286. }
  287. //
  288. // Save the new max size
  289. //
  290. m_nMaxSize = nNewMaxSize;
  291. //
  292. // Save this new string
  293. //
  294. m_pstrData = pszTmp;
  295. //
  296. // Return success
  297. //
  298. return true;
  299. }
  300. //
  301. // Couldn't allocate memory
  302. //
  303. return false;
  304. }
  305. template <class T>
  306. CSimpleStringBase<T> &CSimpleStringBase<T>::GetWindowText( HWND hWnd )
  307. {
  308. Destroy();
  309. // Assume it didn't work
  310. bool bSuccess = false;
  311. int nLen = ::GetWindowTextLength(hWnd);
  312. if (nLen)
  313. {
  314. if (EnsureLength(nLen+1))
  315. {
  316. if (::GetWindowText( hWnd, m_pstrData, (nLen+1) ))
  317. {
  318. bSuccess = true;
  319. }
  320. }
  321. }
  322. if (!bSuccess)
  323. Destroy();
  324. return *this;
  325. }
  326. template <class T>
  327. bool CSimpleStringBase<T>::SetWindowText( HWND hWnd )
  328. {
  329. return(::SetWindowText( hWnd, String() ) != FALSE);
  330. }
  331. template <class T>
  332. UINT CSimpleStringBase<T>::Truncate( UINT nLen )
  333. {
  334. if (Length() < nLen)
  335. return Length();
  336. if (!nLen)
  337. return 0;
  338. m_pstrData[nLen-1] = 0;
  339. Resize();
  340. return Length();
  341. }
  342. template <class T>
  343. int CSimpleStringBase<T>::Resize(void)
  344. {
  345. m_nMaxSize = m_pstrData ? GenericLength(m_pstrData) : 0;
  346. ++m_nMaxSize;
  347. T *pszTmp = CreateStorage(m_nMaxSize);
  348. if (pszTmp)
  349. {
  350. if (m_pstrData)
  351. {
  352. GenericCopy(pszTmp,m_pstrData);
  353. DeleteStorage();
  354. }
  355. else *pszTmp = 0;
  356. m_pstrData = pszTmp;
  357. }
  358. return Length();
  359. }
  360. template <class T>
  361. CSimpleStringBase<T>::CSimpleStringBase(void)
  362. : m_pstrData(m_pstrAutoData),m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),m_nGranularity(m_nDefaultGranularity)
  363. {
  364. m_pstrAutoData[0] = 0;
  365. T szTmp[1] = { 0};
  366. Assign(szTmp);
  367. }
  368. template <class T>
  369. CSimpleStringBase<T>::CSimpleStringBase( const CSimpleStringBase &other )
  370. : m_pstrData(m_pstrAutoData),m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),m_nGranularity(m_nDefaultGranularity)
  371. {
  372. m_pstrAutoData[0] = 0;
  373. Assign(other.String());
  374. }
  375. template <class T>
  376. CSimpleStringBase<T>::CSimpleStringBase( const T *szStr )
  377. : m_pstrData(m_pstrAutoData),m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),m_nGranularity(m_nDefaultGranularity)
  378. {
  379. m_pstrAutoData[0] = 0;
  380. Assign(szStr);
  381. }
  382. template <class T>
  383. CSimpleStringBase<T>::CSimpleStringBase( T ch )
  384. : m_pstrData(m_pstrAutoData),m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),m_nGranularity(m_nDefaultGranularity)
  385. {
  386. m_pstrAutoData[0] = 0;
  387. T szTmp[2];
  388. szTmp[0] = ch;
  389. szTmp[1] = 0;
  390. Assign(szTmp);
  391. }
  392. template <class T>
  393. CSimpleStringBase<T>::CSimpleStringBase( UINT nResId, HMODULE hModule )
  394. : m_pstrData(m_pstrAutoData),m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),m_nGranularity(m_nDefaultGranularity)
  395. {
  396. m_pstrAutoData[0] = 0;
  397. LoadString( nResId, hModule );
  398. }
  399. template <class T>
  400. CSimpleStringBase<T> &CSimpleStringBase<T>::Format( const T *strFmt, ... )
  401. {
  402. T szTmp[1024];
  403. va_list arglist;
  404. va_start(arglist, strFmt);
  405. int nRet = IS_CHAR(*m_pstrData) ?
  406. _vsnprintf((LPSTR)szTmp, ARRAYSIZE(szTmp), (LPCSTR)strFmt, arglist) :
  407. _vsnwprintf((LPWSTR)szTmp, ARRAYSIZE(szTmp), (LPCWSTR)strFmt, arglist);
  408. va_end(arglist);
  409. Assign(szTmp);
  410. return *this;
  411. }
  412. template <class T>
  413. CSimpleStringBase<T> &CSimpleStringBase<T>::Format( int nResId, HINSTANCE hInst, ... )
  414. {
  415. CSimpleStringBase<T> strFmt;
  416. va_list arglist;
  417. if (strFmt.LoadString(nResId,hInst))
  418. {
  419. T szTmp[1024];
  420. va_start(arglist, hInst);
  421. int nRet = IS_CHAR(*m_pstrData) ?
  422. _vsnprintf((LPSTR)szTmp, ARRAYSIZE(szTmp), (LPCSTR)strFmt.String(), arglist) :
  423. _vsnwprintf((LPWSTR)szTmp, ARRAYSIZE(szTmp), (LPCWSTR)strFmt.String(), arglist);
  424. va_end(arglist);
  425. Assign(szTmp);
  426. }
  427. else Assign(NULL);
  428. return *this;
  429. }
  430. template <class T>
  431. bool CSimpleStringBase<T>::LoadString( UINT nResId, HMODULE hModule )
  432. {
  433. if (!hModule)
  434. hModule = GetModuleHandle(NULL);
  435. T szTmp[m_nMaxLoadStringBuffer];
  436. int nRet = IS_CHAR(*m_pstrData) ?
  437. ::LoadStringA( hModule, nResId, (LPSTR)szTmp, ARRAYSIZE(szTmp)) :
  438. ::LoadStringW( hModule, nResId, (LPWSTR)szTmp, ARRAYSIZE(szTmp));
  439. if (nRet)
  440. return Assign(szTmp);
  441. else return Assign(NULL);
  442. }
  443. template <class T>
  444. CSimpleStringBase<T>::~CSimpleStringBase(void)
  445. {
  446. Destroy();
  447. }
  448. template <class T>
  449. void CSimpleStringBase<T>::DeleteStorage(void)
  450. {
  451. //
  452. // Only delete the string if it is non-NULL and not pointing to our non-dynamically allocated buffer
  453. //
  454. if (m_pstrData && m_pstrData != m_pstrAutoData)
  455. {
  456. delete[] m_pstrData;
  457. }
  458. m_pstrData = NULL;
  459. }
  460. template <class T>
  461. T *CSimpleStringBase<T>::CreateStorage( UINT nCount )
  462. {
  463. return new T[nCount];
  464. }
  465. template <class T>
  466. void CSimpleStringBase<T>::Destroy(void)
  467. {
  468. DeleteStorage();
  469. m_nMaxSize = 0;
  470. }
  471. template <class T>
  472. UINT CSimpleStringBase<T>::Length(void) const
  473. {
  474. return(m_pstrData ? GenericLength(m_pstrData) : 0);
  475. }
  476. template <class T>
  477. CSimpleStringBase<T> &CSimpleStringBase<T>::operator=( const CSimpleStringBase &other )
  478. {
  479. if (&other != this)
  480. {
  481. Assign(other.String());
  482. }
  483. return *this;
  484. }
  485. template <class T>
  486. CSimpleStringBase<T> &CSimpleStringBase<T>::operator=( const T *other )
  487. {
  488. if (other != String())
  489. {
  490. Assign(other);
  491. }
  492. return *this;
  493. }
  494. template <class T>
  495. CSimpleStringBase<T> &CSimpleStringBase<T>::operator+=( const CSimpleStringBase &other )
  496. {
  497. Concat(other.String());
  498. return *this;
  499. }
  500. template <class T>
  501. CSimpleStringBase<T> CSimpleStringBase<T>::operator+( const CSimpleStringBase &other ) const
  502. {
  503. CSimpleStringBase tmp(*this);
  504. tmp.Concat(other);
  505. return tmp;
  506. }
  507. template <class T>
  508. bool CSimpleStringBase<T>::Assign( const T *szStr )
  509. {
  510. if (szStr && EnsureLength(GenericLength(szStr)+1))
  511. {
  512. GenericCopy(m_pstrData,szStr);
  513. }
  514. else if (EnsureLength(1))
  515. {
  516. *m_pstrData = 0;
  517. }
  518. else Destroy();
  519. return(NULL != m_pstrData);
  520. }
  521. template <class T>
  522. bool CSimpleStringBase<T>::Assign( const CSimpleStringBase &other )
  523. {
  524. return Assign( other.String() );
  525. }
  526. template <class T>
  527. void CSimpleStringBase<T>::SetAt( UINT nIndex, T chValue )
  528. {
  529. //
  530. // Make sure we don't go off the end of the string or overwrite the '\0'
  531. //
  532. if (m_pstrData && Length() > nIndex)
  533. {
  534. m_pstrData[nIndex] = chValue;
  535. }
  536. }
  537. template <class T>
  538. void CSimpleStringBase<T>::Concat( const CSimpleStringBase &other )
  539. {
  540. if (EnsureLength( Length() + other.Length() + 1 ))
  541. {
  542. GenericConcatenate(m_pstrData,other.String());
  543. }
  544. }
  545. template <class T>
  546. CSimpleStringBase<T> &CSimpleStringBase<T>::MakeUpper(void)
  547. {
  548. //
  549. // Make sure the string is not NULL
  550. //
  551. if (m_pstrData)
  552. {
  553. IS_CHAR(*m_pstrData) ? CharUpperBuffA( (LPSTR)m_pstrData, Length() ) : CharUpperBuffW( (LPWSTR)m_pstrData, Length() );
  554. }
  555. return *this;
  556. }
  557. template <class T>
  558. CSimpleStringBase<T> &CSimpleStringBase<T>::MakeLower(void)
  559. {
  560. //
  561. // Make sure the string is not NULL
  562. //
  563. if (m_pstrData)
  564. {
  565. IS_CHAR(*m_pstrData) ? CharLowerBuffA( (LPSTR)m_pstrData, Length() ) : CharLowerBuffW( (LPWSTR)m_pstrData, Length() );
  566. }
  567. return *this;
  568. }
  569. template <class T>
  570. CSimpleStringBase<T> CSimpleStringBase<T>::ToUpper(void) const
  571. {
  572. CSimpleStringBase str(*this);
  573. str.MakeUpper();
  574. return str;
  575. }
  576. template <class T>
  577. CSimpleStringBase<T> CSimpleStringBase<T>::ToLower(void) const
  578. {
  579. CSimpleStringBase str(*this);
  580. str.MakeLower();
  581. return str;
  582. }
  583. template <class T>
  584. T &CSimpleStringBase<T>::operator[](int nIndex)
  585. {
  586. return m_pstrData[nIndex];
  587. }
  588. template <class T>
  589. const T &CSimpleStringBase<T>::operator[](int index) const
  590. {
  591. return m_pstrData[index];
  592. }
  593. template <class T>
  594. CSimpleStringBase<T> &CSimpleStringBase<T>::TrimRight(void)
  595. {
  596. T *pFirstWhitespaceCharacterInSequence = NULL;
  597. bool bInWhiteSpace = false;
  598. T *pszPtr = m_pstrData;
  599. while (pszPtr && *pszPtr)
  600. {
  601. if (*pszPtr == L' ' || *pszPtr == L'\t' || *pszPtr == L'\n' || *pszPtr == L'\r')
  602. {
  603. if (!bInWhiteSpace)
  604. {
  605. pFirstWhitespaceCharacterInSequence = pszPtr;
  606. bInWhiteSpace = true;
  607. }
  608. }
  609. else
  610. {
  611. bInWhiteSpace = false;
  612. }
  613. pszPtr = GenericCharNext(pszPtr);
  614. }
  615. if (pFirstWhitespaceCharacterInSequence && bInWhiteSpace)
  616. *pFirstWhitespaceCharacterInSequence = 0;
  617. return *this;
  618. }
  619. template <class T>
  620. CSimpleStringBase<T> &CSimpleStringBase<T>::TrimLeft(void)
  621. {
  622. T *pszPtr = m_pstrData;
  623. while (pszPtr && *pszPtr)
  624. {
  625. if (*pszPtr == L' ' || *pszPtr == L'\t' || *pszPtr == L'\n' || *pszPtr == L'\r')
  626. {
  627. pszPtr = GenericCharNext(pszPtr);
  628. }
  629. else break;
  630. }
  631. Assign(CSimpleStringBase<T>(pszPtr).String());
  632. return *this;
  633. }
  634. template <class T>
  635. inline CSimpleStringBase<T> &CSimpleStringBase<T>::Trim(void)
  636. {
  637. TrimLeft();
  638. TrimRight();
  639. return *this;
  640. }
  641. //
  642. // Note that this function WILL NOT WORK CORRECTLY for multi-byte characters in ANSI strings
  643. //
  644. template <class T>
  645. CSimpleStringBase<T> &CSimpleStringBase<T>::Reverse(void)
  646. {
  647. UINT nLen = Length();
  648. for (UINT i = 0;i<nLen/2;i++)
  649. {
  650. T tmp = m_pstrData[i];
  651. m_pstrData[i] = m_pstrData[nLen-i-1];
  652. m_pstrData[nLen-i-1] = tmp;
  653. }
  654. return *this;
  655. }
  656. template <class T>
  657. int CSimpleStringBase<T>::Find( T cChar ) const
  658. {
  659. T strTemp[2] = { cChar, 0};
  660. return Find(strTemp);
  661. }
  662. template <class T>
  663. int CSimpleStringBase<T>::Find( const CSimpleStringBase &other, UINT nStart ) const
  664. {
  665. if (!m_pstrData)
  666. return -1;
  667. if (nStart > Length())
  668. return -1;
  669. T *pstrCurr = m_pstrData+nStart, *pstrSrc, *pstrSubStr;
  670. while (*pstrCurr)
  671. {
  672. pstrSrc = pstrCurr;
  673. pstrSubStr = (T *)other.String();
  674. while (*pstrSrc && *pstrSubStr && *pstrSrc == *pstrSubStr)
  675. {
  676. pstrSrc = GenericCharNext(pstrSrc);
  677. pstrSubStr = GenericCharNext(pstrSubStr);
  678. }
  679. if (!*pstrSubStr)
  680. return static_cast<int>(pstrCurr-m_pstrData);
  681. pstrCurr = GenericCharNext(pstrCurr);
  682. }
  683. return -1;
  684. }
  685. template <class T>
  686. int CSimpleStringBase<T>::ReverseFind( T cChar ) const
  687. {
  688. T strTemp[2] = { cChar, 0};
  689. return ReverseFind(strTemp);
  690. }
  691. template <class T>
  692. int CSimpleStringBase<T>::ReverseFind( const CSimpleStringBase &srcStr ) const
  693. {
  694. int nLastFind = -1, nFind=0;
  695. while ((nFind = Find( srcStr, nFind )) >= 0)
  696. {
  697. nLastFind = nFind;
  698. ++nFind;
  699. }
  700. return nLastFind;
  701. }
  702. template <class T>
  703. CSimpleStringBase<T> CSimpleStringBase<T>::SubStr( int nStart, int nCount ) const
  704. {
  705. if (nStart >= (int)Length() || nStart < 0)
  706. return CSimpleStringBase<T>();
  707. if (nCount < 0)
  708. nCount = Length() - nStart;
  709. CSimpleStringBase<T> strTmp;
  710. T *pszTmp = CreateStorage(nCount+1);
  711. if (pszTmp)
  712. {
  713. GenericCopyLength( pszTmp, m_pstrData+nStart, nCount+1 );
  714. pszTmp[nCount] = 0;
  715. strTmp = pszTmp;
  716. delete[] pszTmp;
  717. }
  718. return strTmp;
  719. }
  720. template <class T>
  721. int CSimpleStringBase<T>::CompareNoCase( const CSimpleStringBase &other, int nLength ) const
  722. {
  723. if (nLength < 0)
  724. {
  725. //
  726. // Make sure both strings are non-NULL
  727. //
  728. if (!String() && !other.String())
  729. {
  730. return 0;
  731. }
  732. else if (!String())
  733. {
  734. return -1;
  735. }
  736. else if (!other.String())
  737. {
  738. return 1;
  739. }
  740. else return GenericCompareNoCase(m_pstrData,other.String());
  741. }
  742. CSimpleStringBase<T> strSrc(*this);
  743. CSimpleStringBase<T> strTgt(other);
  744. strSrc.MakeUpper();
  745. strTgt.MakeUpper();
  746. //
  747. // Make sure both strings are non-NULL
  748. //
  749. if (!strSrc.String() && !strTgt.String())
  750. {
  751. return 0;
  752. }
  753. else if (!strSrc.String())
  754. {
  755. return -1;
  756. }
  757. else if (!strTgt.String())
  758. {
  759. return 1;
  760. }
  761. else return GenericCompareLength(strSrc.String(),strTgt.String(),nLength);
  762. }
  763. template <class T>
  764. int CSimpleStringBase<T>::Compare( const CSimpleStringBase &other, int nLength ) const
  765. {
  766. //
  767. // Make sure both strings are non-NULL
  768. //
  769. if (!String() && !other.String())
  770. {
  771. return 0;
  772. }
  773. else if (!String())
  774. {
  775. return -1;
  776. }
  777. else if (!other.String())
  778. {
  779. return 1;
  780. }
  781. if (nLength < 0)
  782. {
  783. return GenericCompare(String(),other.String());
  784. }
  785. return GenericCompareLength(String(),other.String(),nLength);
  786. }
  787. template <class T>
  788. bool CSimpleStringBase<T>::MatchLastCharacter( T cChar ) const
  789. {
  790. int nFind = ReverseFind(cChar);
  791. if (nFind < 0)
  792. return false;
  793. if (nFind == (int)Length()-1)
  794. return true;
  795. else return false;
  796. }
  797. template <class T>
  798. bool CSimpleStringBase<T>::Load( HKEY hRegKey, const T *pszValueName, const T *pszDefault )
  799. {
  800. bool bResult = false;
  801. Assign(pszDefault);
  802. DWORD nType=0;
  803. DWORD nSize=0;
  804. LONG nRet;
  805. if (IS_CHAR(*m_pstrData))
  806. nRet = RegQueryValueExA( hRegKey, (LPCSTR)pszValueName, NULL, &nType, NULL, &nSize);
  807. else nRet = RegQueryValueExW( hRegKey, (LPCWSTR)pszValueName, NULL, &nType, NULL, &nSize);
  808. if (ERROR_SUCCESS == nRet)
  809. {
  810. if ((nType == REG_SZ) || (nType == REG_EXPAND_SZ))
  811. {
  812. // Round up to the nearest 2
  813. nSize = ((nSize + 1) & 0xFFFFFFFE);
  814. T *pstrTemp = CreateStorage(nSize / sizeof(T));
  815. if (pstrTemp)
  816. {
  817. if (IS_CHAR(*m_pstrData))
  818. nRet = RegQueryValueExA( hRegKey, (LPCSTR)pszValueName, NULL, &nType, (PBYTE)pstrTemp, &nSize);
  819. else nRet = RegQueryValueExW( hRegKey, (LPCWSTR)pszValueName, NULL, &nType, (PBYTE)pstrTemp, &nSize);
  820. if (ERROR_SUCCESS == nRet)
  821. {
  822. Assign(pstrTemp);
  823. bResult = true;
  824. }
  825. delete pstrTemp;
  826. }
  827. }
  828. }
  829. return bResult;
  830. }
  831. template <class T>
  832. bool CSimpleStringBase<T>::Store( HKEY hRegKey, const T *pszValueName, DWORD nType )
  833. {
  834. bool bResult = false;
  835. long nRet;
  836. if (Length())
  837. {
  838. if (IS_CHAR(*m_pstrData))
  839. nRet = RegSetValueExA( hRegKey, (LPCSTR)pszValueName, 0, nType, (PBYTE)m_pstrData, sizeof(*m_pstrData)*(Length()+1) );
  840. else nRet = RegSetValueExW( hRegKey, (LPCWSTR)pszValueName, 0, nType, (PBYTE)m_pstrData, sizeof(*m_pstrData)*(Length()+1) );
  841. }
  842. else
  843. {
  844. T strBlank = 0;
  845. if (IS_CHAR(*m_pstrData))
  846. nRet = RegSetValueExA( hRegKey, (LPCSTR)pszValueName, 0, nType, (PBYTE)&strBlank, sizeof(T) );
  847. else nRet = RegSetValueExW( hRegKey, (LPCWSTR)pszValueName, 0, nType, (PBYTE)&strBlank, sizeof(T) );
  848. }
  849. return(ERROR_SUCCESS == nRet);
  850. }
  851. typedef CSimpleStringBase<char> CSimpleStringAnsi;
  852. typedef CSimpleStringBase<wchar_t> CSimpleStringWide;
  853. #if defined(UNICODE) || defined(_UNICODE)
  854. #define CSimpleString CSimpleStringWide
  855. #else
  856. #define CSimpleString CSimpleStringAnsi
  857. #endif
  858. namespace CSimpleStringConvert
  859. {
  860. template <class T>
  861. CSimpleStringWide WideString(const T &str)
  862. {
  863. if (IS_WCHAR(str[0]))
  864. return CSimpleStringWide((LPCWSTR)str.String());
  865. else
  866. {
  867. if (!str.Length())
  868. return CSimpleStringWide(L"");
  869. int iLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, (LPCSTR)str.String(), str.Length()+1, NULL, 0 );
  870. CSimpleStringWide sswTmp;
  871. LPWSTR pwszTmp = new WCHAR[iLen];
  872. if (pwszTmp)
  873. {
  874. MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, (LPCSTR)str.String(), str.Length()+1, pwszTmp, iLen );
  875. sswTmp = pwszTmp;
  876. delete[] pwszTmp;
  877. }
  878. return sswTmp;
  879. }
  880. }
  881. template <class T>
  882. CSimpleStringAnsi AnsiString(const T &str)
  883. {
  884. if (IS_CHAR(str[0]))
  885. return CSimpleStringAnsi((LPCSTR)str.String());
  886. else
  887. {
  888. if (!str.Length())
  889. return CSimpleStringAnsi("");
  890. int iLen = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)str.String(), str.Length()+1, NULL, 0, NULL, NULL );
  891. CSimpleStringAnsi ssaTmp;
  892. LPSTR pszTmp = new CHAR[iLen];
  893. if (pszTmp)
  894. {
  895. WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)str.String(), str.Length()+1, pszTmp, iLen, NULL, NULL );
  896. ssaTmp = pszTmp;
  897. delete[] pszTmp;
  898. }
  899. return ssaTmp;
  900. }
  901. }
  902. #if defined(_UNICODE) || defined(UNICODE)
  903. template <class T>
  904. CSimpleStringWide NaturalString(const T &str)
  905. {
  906. return WideString(str);
  907. }
  908. #else
  909. template <class T>
  910. CSimpleStringAnsi NaturalString(const T &str)
  911. {
  912. return AnsiString(str);
  913. }
  914. #endif
  915. inline CSimpleString NumberToString( int nNumber, LCID Locale=LOCALE_USER_DEFAULT )
  916. {
  917. TCHAR szTmp[MAX_PATH]=TEXT("");
  918. TCHAR szNumberStr[MAX_PATH]=TEXT("");
  919. TCHAR szDigitGrouping[32]=TEXT("");
  920. TCHAR szThousandsSeparator[32]=TEXT("");
  921. TCHAR szDecimalSeparator[32]=TEXT("");
  922. // Initialize the number format
  923. NUMBERFMT NumberFormat;
  924. NumberFormat.NumDigits = 0;
  925. NumberFormat.LeadingZero = 0;
  926. NumberFormat.NegativeOrder = 0;
  927. // This turns a string into a number, like so: 3;2;0=32 or 3;0 = 3 or 1;2;3;4;5;6;0 = 123456. Got it?
  928. GetLocaleInfo( Locale, LOCALE_SGROUPING, szDigitGrouping, ARRAYSIZE(szDigitGrouping));
  929. NumberFormat.Grouping = 0;
  930. LPTSTR pszCurr = szDigitGrouping;
  931. while (*pszCurr && *pszCurr >= TEXT('1') && *pszCurr <= TEXT('9'))
  932. {
  933. NumberFormat.Grouping *= 10;
  934. NumberFormat.Grouping += (*pszCurr - TEXT('0'));
  935. pszCurr += 2;
  936. }
  937. GetLocaleInfo( Locale, LOCALE_STHOUSAND, szThousandsSeparator, ARRAYSIZE(szThousandsSeparator));
  938. NumberFormat.lpThousandSep = szThousandsSeparator;
  939. GetLocaleInfo( Locale, LOCALE_SDECIMAL, szDecimalSeparator, ARRAYSIZE(szDecimalSeparator));
  940. NumberFormat.lpDecimalSep = szDecimalSeparator;
  941. // Create the number string
  942. _sntprintf( szTmp, ARRAYSIZE(szTmp), TEXT("%d"), nNumber );
  943. if (GetNumberFormat( Locale, 0, szTmp, &NumberFormat, szNumberStr, ARRAYSIZE(szNumberStr)))
  944. return szNumberStr;
  945. else return TEXT("");
  946. }
  947. } // End CSimpleStringConvert namespace
  948. #endif // ifndef _SIMSTR_H_INCLUDED