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.

942 lines
26 KiB

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