Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1496 lines
40 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<CharType>
  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(CharType n)
  29. * CSimpleStringWide CSimpleStringConvert::WideString(CharType n)
  30. * CSimpleString CSimpleStringConvert::NaturalString(CharType n)
  31. * Macros:
  32. * IS_CHAR(CharType)
  33. * IS_WCHAR(CharType)
  34. */
  35. #include <windows.h>
  36. #include <stdarg.h>
  37. #include <stdio.h>
  38. #include <tchar.h>
  39. //
  40. // Disable the "conditional expression is constant" warning that is caused by
  41. // the IS_CHAR and IS_WCHAR macros
  42. //
  43. #pragma warning( push )
  44. #pragma warning( disable : 4127 )
  45. #define IS_CHAR(x) (sizeof(x) & sizeof(char))
  46. #define IS_WCHAR(x) (sizeof(x) & sizeof(wchar_t))
  47. #ifndef ARRAYSIZE
  48. #define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
  49. #endif
  50. template <class CharType>
  51. class CSimpleStringBase
  52. {
  53. private:
  54. enum
  55. {
  56. c_nDefaultGranularity = 16, // Default number of extra characters to allocate when we have to grow
  57. c_nMaxLoadStringBuffer = 1024, // Maximum length of .RC string
  58. c_nMaxAutoDataLength = 128 // Length of non-dynamically allocated string
  59. };
  60. private:
  61. //
  62. // If the string is less than c_nMaxAutoDataLength characters, it will be
  63. // stored here, instead of in a dynamically allocated buffer
  64. //
  65. CharType m_pstrAutoData[c_nMaxAutoDataLength];
  66. //
  67. // If we have to allocated data, it will be stored here
  68. //
  69. CharType *m_pstrData;
  70. //
  71. // Current maximum buffer size
  72. //
  73. UINT m_nMaxSize;
  74. //
  75. // Amount of extra space we allocate when we have to grow the buffer
  76. //
  77. UINT m_nGranularity;
  78. private:
  79. //
  80. // Min, in case it isn't already defined
  81. //
  82. template <class NumberType>
  83. static NumberType Min( const NumberType &a, const NumberType &b )
  84. {
  85. return (a < b) ? a : b;
  86. }
  87. public:
  88. //
  89. // Replacements (in some cases just wrappers) for strlen, strcpy, ...
  90. //
  91. static inline CharType *GenericCopy( CharType *pstrTarget, const CharType *pstrSource );
  92. static inline CharType *GenericCopyLength( CharType *pstrTarget, const CharType *pstrSource, UINT nSize );
  93. static inline UINT GenericLength( const CharType *pstrStr );
  94. static inline CharType *GenericConcatenate( CharType *pstrTarget, const CharType *pstrSource );
  95. static inline int GenericCompare( const CharType *pstrTarget, const CharType *pstrSource );
  96. static inline int GenericCompareNoCase( const CharType *pstrStrA, const CharType *pstrStrB );
  97. static inline int GenericCompareLength( const CharType *pstrTarget, const CharType *pstrSource, UINT nLength );
  98. static inline CharType *GenericCharNext( const CharType *pszStr );
  99. private:
  100. //
  101. // Internal only helpers
  102. //
  103. bool EnsureLength( UINT nMaxSize );
  104. void DeleteStorage();
  105. static inline CharType *CreateStorage( UINT nCount );
  106. void Destroy();
  107. public:
  108. //
  109. // Constructors and destructor
  110. //
  111. CSimpleStringBase();
  112. CSimpleStringBase( const CSimpleStringBase & );
  113. CSimpleStringBase( const CharType *szStr );
  114. CSimpleStringBase( CharType ch );
  115. CSimpleStringBase( UINT nResId, HMODULE hModule );
  116. virtual ~CSimpleStringBase();
  117. //
  118. // Various helpers
  119. //
  120. UINT Length() const;
  121. void Concat( const CSimpleStringBase &other );
  122. int Resize();
  123. UINT Truncate( UINT nLen );
  124. bool Assign( const CharType *szStr );
  125. bool Assign( const CSimpleStringBase & );
  126. void SetAt( UINT nIndex, CharType chValue );
  127. CharType &operator[](int index);
  128. const CharType &operator[](int index) const;
  129. //
  130. // Handy Win32 wrappers
  131. //
  132. CSimpleStringBase &Format( const CharType *strFmt, ... );
  133. CSimpleStringBase &Format( int nResId, HINSTANCE hInst, ... );
  134. CSimpleStringBase &GetWindowText( HWND hWnd );
  135. bool SetWindowText( HWND hWnd );
  136. bool LoadString( UINT nResId, HMODULE hModule );
  137. bool Load( HKEY hRegKey, const CharType *pszValueName, const CharType *pszDefault=NULL );
  138. bool Store( HKEY hRegKey, const CharType *pszValueName, DWORD nType = REG_SZ );
  139. //
  140. // Operators
  141. //
  142. CSimpleStringBase &operator=( const CSimpleStringBase &other );
  143. CSimpleStringBase &operator=( const CharType *other );
  144. CSimpleStringBase &operator+=( const CSimpleStringBase &other );
  145. //
  146. // Convert this string and return the converted string
  147. //
  148. CSimpleStringBase ToUpper() const;
  149. CSimpleStringBase ToLower() const;
  150. //
  151. // Convert in place
  152. //
  153. CSimpleStringBase &MakeUpper();
  154. CSimpleStringBase &MakeLower();
  155. //
  156. // Remove leading and trailing spaces
  157. //
  158. CSimpleStringBase &TrimRight();
  159. CSimpleStringBase &TrimLeft();
  160. CSimpleStringBase &Trim();
  161. //
  162. // Reverse
  163. //
  164. CSimpleStringBase &Reverse();
  165. //
  166. // Searching
  167. //
  168. int Find( CharType cChar ) const;
  169. int Find( const CSimpleStringBase &other, UINT nStart=0 ) const;
  170. int ReverseFind( CharType cChar ) const;
  171. int ReverseFind( const CSimpleStringBase &other ) const;
  172. //
  173. // Substring copies
  174. //
  175. CSimpleStringBase SubStr( int nStart, int nCount=-1 ) const;
  176. CSimpleStringBase Left( int nCount ) const
  177. {
  178. return SubStr( 0, nCount );
  179. }
  180. CSimpleStringBase Right( int nCount ) const
  181. {
  182. return SubStr( max(0,(int)Length()-nCount), -1 );
  183. }
  184. //
  185. // Comparison functions
  186. //
  187. int CompareNoCase( const CSimpleStringBase &other, int nLength=-1 ) const;
  188. int Compare( const CSimpleStringBase &other, int nLength=-1 ) const;
  189. bool MatchLastCharacter( CharType cChar ) const;
  190. //
  191. // Direct manipulation
  192. //
  193. CharType *GetBuffer( int nLength )
  194. {
  195. //
  196. // If the user passed 0, or we are able to allocate a string of the
  197. // requested length, return a pointer to the actual data.
  198. //
  199. if (!nLength || EnsureLength(nLength+1))
  200. {
  201. return m_pstrData;
  202. }
  203. return NULL;
  204. }
  205. //
  206. // Useful inlines
  207. //
  208. const CharType *String() const
  209. {
  210. return m_pstrData;
  211. }
  212. UINT MaxSize() const
  213. {
  214. return m_nMaxSize;
  215. }
  216. UINT Granularity( UINT nGranularity )
  217. {
  218. if (nGranularity>0)
  219. {
  220. m_nGranularity = nGranularity;
  221. }
  222. return m_nGranularity;
  223. }
  224. UINT Granularity() const
  225. {
  226. return m_nGranularity;
  227. }
  228. //
  229. // Implicit cast operator
  230. //
  231. operator const CharType *() const
  232. {
  233. return String();
  234. }
  235. //
  236. // Sanity check
  237. //
  238. bool IsValid() const
  239. {
  240. return(NULL != m_pstrData);
  241. }
  242. };
  243. template <class CharType>
  244. inline CharType *CSimpleStringBase<CharType>::GenericCopy( CharType *pszDest, const CharType *pszSource )
  245. {
  246. CopyMemory( pszDest, pszSource, sizeof(CharType) * (GenericLength(pszSource) + 1) );
  247. return pszDest;
  248. }
  249. template <class CharType>
  250. inline CharType *CSimpleStringBase<CharType>::GenericCharNext( const CharType *pszStr )
  251. {
  252. if (IS_CHAR(*pszStr))
  253. return(CharType*)CharNextA((LPCSTR)pszStr);
  254. else if (!*pszStr)
  255. return(CharType*)pszStr;
  256. else return(CharType*)((LPWSTR)pszStr + 1);
  257. }
  258. template <class CharType>
  259. inline CharType *CSimpleStringBase<CharType>::GenericCopyLength( CharType *pszTarget, const CharType *pszSource, UINT nCount )
  260. {
  261. UINT nCopyLen = min( nCount, GenericLength(pszSource) + 1 );
  262. CopyMemory( pszTarget, pszSource, nCopyLen * sizeof(CharType) );
  263. if (nCopyLen < nCount)
  264. {
  265. pszTarget[nCopyLen] = 0;
  266. }
  267. return pszTarget;
  268. }
  269. template <class CharType>
  270. inline UINT CSimpleStringBase<CharType>::GenericLength( const CharType *pszString )
  271. {
  272. const CharType *eos = pszString;
  273. while (*eos++)
  274. ;
  275. return((UINT)(eos - pszString - 1));
  276. }
  277. template <class CharType>
  278. inline CharType*CSimpleStringBase<CharType>::GenericConcatenate( CharType *pszDest, const CharType *pszSource )
  279. {
  280. CharType *pCurr = pszDest;
  281. while (*pCurr)
  282. pCurr++;
  283. CopyMemory( pCurr, pszSource, sizeof(CharType) * (GenericLength(pszSource) + 1) );
  284. return pszDest;
  285. }
  286. template <class CharType>
  287. inline int CSimpleStringBase<CharType>::GenericCompare( const CharType *pszSource, const CharType *pszDest )
  288. {
  289. #if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
  290. if (sizeof(CharType) == sizeof(wchar_t))
  291. {
  292. OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
  293. }
  294. #endif
  295. int nRes = IS_CHAR(*pszSource) ?
  296. CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszSource, -1, (LPCSTR)pszDest, -1 ) :
  297. CompareStringW( LOCALE_USER_DEFAULT, 0, (LPCWSTR)pszSource, -1, (LPCWSTR)pszDest, -1 );
  298. switch (nRes)
  299. {
  300. case CSTR_LESS_THAN:
  301. return -1;
  302. case CSTR_GREATER_THAN:
  303. return 1;
  304. default:
  305. return 0;
  306. }
  307. }
  308. template <class CharType>
  309. inline int CSimpleStringBase<CharType>::GenericCompareNoCase( const CharType *pszSource, const CharType *pszDest )
  310. {
  311. #if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
  312. if (sizeof(CharType) == sizeof(wchar_t))
  313. {
  314. OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
  315. }
  316. #endif
  317. int nRes = IS_CHAR(*pszSource) ?
  318. CompareStringA( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCSTR)pszSource, -1, (LPCSTR)pszDest, -1 ) :
  319. CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCWSTR)pszSource, -1, (LPCWSTR)pszDest, -1 );
  320. switch (nRes)
  321. {
  322. case CSTR_LESS_THAN:
  323. return -1;
  324. case CSTR_GREATER_THAN:
  325. return 1;
  326. default:
  327. return 0;
  328. }
  329. }
  330. template <class CharType>
  331. inline int CSimpleStringBase<CharType>::GenericCompareLength( const CharType *pszStringA, const CharType *pszStringB, UINT nLength )
  332. {
  333. #if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
  334. if (sizeof(CharType) == sizeof(wchar_t))
  335. {
  336. OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
  337. }
  338. #endif
  339. if (!nLength)
  340. return(0);
  341. int nRes = IS_CHAR(*pszStringA) ?
  342. CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszStringA, Min(nLength,CSimpleStringBase<CHAR>::GenericLength((LPCSTR)pszStringA)), (LPCSTR)pszStringB, Min(nLength,CSimpleStringBase<CHAR>::GenericLength((LPCSTR)pszStringB)) ) :
  343. CompareStringW( LOCALE_USER_DEFAULT, 0, (LPWSTR)pszStringA, Min(nLength,CSimpleStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringA)), (LPCWSTR)pszStringB, Min(nLength,CSimpleStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringB)) );
  344. switch (nRes)
  345. {
  346. case CSTR_LESS_THAN:
  347. return -1;
  348. case CSTR_GREATER_THAN:
  349. return 1;
  350. default:
  351. return 0;
  352. }
  353. }
  354. template <class CharType>
  355. bool CSimpleStringBase<CharType>::EnsureLength( UINT nMaxSize )
  356. {
  357. //
  358. // If the string is already long enough, just return true
  359. //
  360. if (m_nMaxSize >= nMaxSize)
  361. {
  362. return true;
  363. }
  364. // Get the new size
  365. //
  366. UINT nNewMaxSize = nMaxSize + m_nGranularity;
  367. //
  368. // Allocate the new buffer
  369. //
  370. CharType *pszTmp = CreateStorage(nNewMaxSize);
  371. //
  372. // Make sure the allocation succeded
  373. //
  374. if (pszTmp)
  375. {
  376. //
  377. // If we have an existing string, copy it and delete it
  378. //
  379. if (m_pstrData)
  380. {
  381. GenericCopy(pszTmp,m_pstrData);
  382. DeleteStorage();
  383. }
  384. //
  385. // Save the new max size
  386. //
  387. m_nMaxSize = nNewMaxSize;
  388. //
  389. // Save this new string
  390. //
  391. m_pstrData = pszTmp;
  392. //
  393. // Return success
  394. //
  395. return true;
  396. }
  397. //
  398. // Couldn't allocate memory
  399. //
  400. return false;
  401. }
  402. template <class CharType>
  403. CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::GetWindowText( HWND hWnd )
  404. {
  405. Destroy();
  406. // Assume it didn't work
  407. bool bSuccess = false;
  408. int nLen = ::GetWindowTextLength(hWnd);
  409. if (nLen)
  410. {
  411. if (EnsureLength(nLen+1))
  412. {
  413. if (::GetWindowText( hWnd, m_pstrData, (nLen+1) ))
  414. {
  415. bSuccess = true;
  416. }
  417. }
  418. }
  419. if (!bSuccess)
  420. Destroy();
  421. return *this;
  422. }
  423. template <class CharType>
  424. bool CSimpleStringBase<CharType>::SetWindowText( HWND hWnd )
  425. {
  426. return(::SetWindowText( hWnd, String() ) != FALSE);
  427. }
  428. template <class CharType>
  429. UINT CSimpleStringBase<CharType>::Truncate( UINT nLen )
  430. {
  431. if (Length() < nLen)
  432. return Length();
  433. if (!nLen)
  434. return 0;
  435. m_pstrData[nLen-1] = 0;
  436. Resize();
  437. return Length();
  438. }
  439. template <class CharType>
  440. int CSimpleStringBase<CharType>::Resize()
  441. {
  442. m_nMaxSize = m_pstrData ? GenericLength(m_pstrData) : 0;
  443. ++m_nMaxSize;
  444. CharType *pszTmp = CreateStorage(m_nMaxSize);
  445. if (pszTmp)
  446. {
  447. if (m_pstrData)
  448. {
  449. GenericCopy(pszTmp,m_pstrData);
  450. DeleteStorage();
  451. }
  452. else *pszTmp = 0;
  453. m_pstrData = pszTmp;
  454. }
  455. return Length();
  456. }
  457. template <class CharType>
  458. CSimpleStringBase<CharType>::CSimpleStringBase()
  459. : m_pstrData(m_pstrAutoData),
  460. m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
  461. m_nGranularity(c_nDefaultGranularity)
  462. {
  463. m_pstrAutoData[0] = 0;
  464. CharType szTmp[1] = { 0};
  465. Assign(szTmp);
  466. }
  467. template <class CharType>
  468. CSimpleStringBase<CharType>::CSimpleStringBase( const CSimpleStringBase &other )
  469. : m_pstrData(m_pstrAutoData),
  470. m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
  471. m_nGranularity(c_nDefaultGranularity)
  472. {
  473. m_pstrAutoData[0] = 0;
  474. Assign(other.String());
  475. }
  476. template <class CharType>
  477. CSimpleStringBase<CharType>::CSimpleStringBase( const CharType *szStr )
  478. : m_pstrData(m_pstrAutoData),
  479. m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
  480. m_nGranularity(c_nDefaultGranularity)
  481. {
  482. m_pstrAutoData[0] = 0;
  483. Assign(szStr);
  484. }
  485. template <class CharType>
  486. CSimpleStringBase<CharType>::CSimpleStringBase( CharType ch )
  487. : m_pstrData(m_pstrAutoData),
  488. m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
  489. m_nGranularity(c_nDefaultGranularity)
  490. {
  491. m_pstrAutoData[0] = 0;
  492. CharType szTmp[2];
  493. szTmp[0] = ch;
  494. szTmp[1] = 0;
  495. Assign(szTmp);
  496. }
  497. template <class CharType>
  498. CSimpleStringBase<CharType>::CSimpleStringBase( UINT nResId, HMODULE hModule )
  499. : m_pstrData(m_pstrAutoData),
  500. m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
  501. m_nGranularity(c_nDefaultGranularity)
  502. {
  503. m_pstrAutoData[0] = 0;
  504. LoadString( nResId, hModule );
  505. }
  506. template <>
  507. inline CSimpleStringBase<WCHAR> &CSimpleStringBase<WCHAR>::Format( const WCHAR *strFmt, ... )
  508. {
  509. WCHAR szTmp[1024] = {0};
  510. va_list arglist;
  511. va_start(arglist, strFmt);
  512. _vsnwprintf( szTmp, ARRAYSIZE(szTmp)-1, strFmt, arglist );
  513. va_end(arglist);
  514. Assign(szTmp);
  515. return *this;
  516. }
  517. template <>
  518. inline CSimpleStringBase<CHAR> &CSimpleStringBase<CHAR>::Format( const CHAR *strFmt, ... )
  519. {
  520. CHAR szTmp[1024] = {0};
  521. va_list arglist;
  522. va_start(arglist, strFmt);
  523. _vsnprintf( szTmp, ARRAYSIZE(szTmp)-1, strFmt, arglist );
  524. va_end(arglist);
  525. Assign(szTmp);
  526. return *this;
  527. }
  528. template <>
  529. inline CSimpleStringBase<CHAR> &CSimpleStringBase<CHAR>::Format( int nResId, HINSTANCE hInst, ... )
  530. {
  531. CSimpleStringBase<CHAR> strFmt;
  532. if (strFmt.LoadString(nResId,hInst))
  533. {
  534. CHAR szTmp[1024] = {0};
  535. va_list arglist;
  536. va_start(arglist, hInst);
  537. _vsnprintf( szTmp, ARRAYSIZE(szTmp)-1, strFmt, arglist );
  538. va_end(arglist);
  539. Assign(szTmp);
  540. }
  541. else Assign(NULL);
  542. return *this;
  543. }
  544. template <>
  545. inline CSimpleStringBase<WCHAR> &CSimpleStringBase<WCHAR>::Format( int nResId, HINSTANCE hInst, ... )
  546. {
  547. CSimpleStringBase<WCHAR> strFmt;
  548. if (strFmt.LoadString(nResId,hInst))
  549. {
  550. WCHAR szTmp[1024] = {0};
  551. va_list arglist;
  552. va_start(arglist, hInst);
  553. _vsnwprintf( szTmp, ARRAYSIZE(szTmp)-1, strFmt, arglist );
  554. va_end(arglist);
  555. Assign(szTmp);
  556. }
  557. else Assign(NULL);
  558. return *this;
  559. }
  560. template <>
  561. inline bool CSimpleStringBase<CHAR>::LoadString( UINT nResId, HMODULE hModule )
  562. {
  563. if (!hModule)
  564. {
  565. hModule = GetModuleHandle(NULL);
  566. }
  567. CHAR szTmp[c_nMaxLoadStringBuffer] = {0};
  568. int nRet = ::LoadStringA( hModule, nResId, szTmp, ARRAYSIZE(szTmp));
  569. return nRet ? Assign(szTmp) : Assign(NULL);
  570. }
  571. template <>
  572. inline bool CSimpleStringBase<WCHAR>::LoadString( UINT nResId, HMODULE hModule )
  573. {
  574. if (!hModule)
  575. {
  576. hModule = GetModuleHandle(NULL);
  577. }
  578. WCHAR szTmp[c_nMaxLoadStringBuffer] = {0};
  579. int nRet = ::LoadStringW( hModule, nResId, szTmp, ARRAYSIZE(szTmp));
  580. return nRet ? Assign(szTmp) : Assign(NULL);
  581. }
  582. template <class CharType>
  583. CSimpleStringBase<CharType>::~CSimpleStringBase()
  584. {
  585. Destroy();
  586. }
  587. template <class CharType>
  588. void CSimpleStringBase<CharType>::DeleteStorage()
  589. {
  590. //
  591. // Only delete the string if it is non-NULL and not pointing to our non-dynamically allocated buffer
  592. //
  593. if (m_pstrData && m_pstrData != m_pstrAutoData)
  594. {
  595. delete[] m_pstrData;
  596. }
  597. m_pstrData = NULL;
  598. }
  599. template <class CharType>
  600. CharType *CSimpleStringBase<CharType>::CreateStorage( UINT nCount )
  601. {
  602. return new CharType[nCount];
  603. }
  604. template <class CharType>
  605. void CSimpleStringBase<CharType>::Destroy()
  606. {
  607. DeleteStorage();
  608. m_nMaxSize = 0;
  609. }
  610. template <class CharType>
  611. UINT CSimpleStringBase<CharType>::Length() const
  612. {
  613. return(m_pstrData ? GenericLength(m_pstrData) : 0);
  614. }
  615. template <class CharType>
  616. CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::operator=( const CSimpleStringBase &other )
  617. {
  618. if (&other != this)
  619. {
  620. Assign(other.String());
  621. }
  622. return *this;
  623. }
  624. template <class CharType>
  625. CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::operator=( const CharType *other )
  626. {
  627. if (other != String())
  628. {
  629. Assign(other);
  630. }
  631. return *this;
  632. }
  633. template <class CharType>
  634. CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::operator+=( const CSimpleStringBase &other )
  635. {
  636. Concat(other.String());
  637. return *this;
  638. }
  639. template <class CharType>
  640. bool CSimpleStringBase<CharType>::Assign( const CharType *szStr )
  641. {
  642. if (szStr && EnsureLength(GenericLength(szStr)+1))
  643. {
  644. GenericCopy(m_pstrData,szStr);
  645. }
  646. else if (EnsureLength(1))
  647. {
  648. *m_pstrData = 0;
  649. }
  650. else Destroy();
  651. return(NULL != m_pstrData);
  652. }
  653. template <class CharType>
  654. bool CSimpleStringBase<CharType>::Assign( const CSimpleStringBase &other )
  655. {
  656. return Assign( other.String() );
  657. }
  658. template <class CharType>
  659. void CSimpleStringBase<CharType>::SetAt( UINT nIndex, CharType chValue )
  660. {
  661. //
  662. // Make sure we don't go off the end of the string or overwrite the '\0'
  663. //
  664. if (m_pstrData && Length() > nIndex)
  665. {
  666. m_pstrData[nIndex] = chValue;
  667. }
  668. }
  669. template <class CharType>
  670. void CSimpleStringBase<CharType>::Concat( const CSimpleStringBase &other )
  671. {
  672. if (EnsureLength( Length() + other.Length() + 1 ))
  673. {
  674. GenericConcatenate(m_pstrData,other.String());
  675. }
  676. }
  677. template <class CharType>
  678. CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::MakeUpper()
  679. {
  680. //
  681. // Make sure the string is not NULL
  682. //
  683. if (m_pstrData)
  684. {
  685. IS_CHAR(*m_pstrData) ? CharUpperBuffA( (LPSTR)m_pstrData, Length() ) : CharUpperBuffW( (LPWSTR)m_pstrData, Length() );
  686. }
  687. return *this;
  688. }
  689. template <class CharType>
  690. CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::MakeLower()
  691. {
  692. //
  693. // Make sure the string is not NULL
  694. //
  695. if (m_pstrData)
  696. {
  697. IS_CHAR(*m_pstrData) ? CharLowerBuffA( (LPSTR)m_pstrData, Length() ) : CharLowerBuffW( (LPWSTR)m_pstrData, Length() );
  698. }
  699. return *this;
  700. }
  701. template <class CharType>
  702. CSimpleStringBase<CharType> CSimpleStringBase<CharType>::ToUpper() const
  703. {
  704. CSimpleStringBase str(*this);
  705. str.MakeUpper();
  706. return str;
  707. }
  708. template <class CharType>
  709. CSimpleStringBase<CharType> CSimpleStringBase<CharType>::ToLower() const
  710. {
  711. CSimpleStringBase str(*this);
  712. str.MakeLower();
  713. return str;
  714. }
  715. template <class CharType>
  716. CharType &CSimpleStringBase<CharType>::operator[](int nIndex)
  717. {
  718. return m_pstrData[nIndex];
  719. }
  720. template <class CharType>
  721. const CharType &CSimpleStringBase<CharType>::operator[](int index) const
  722. {
  723. return m_pstrData[index];
  724. }
  725. template <class CharType>
  726. CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::TrimRight()
  727. {
  728. CharType *pFirstWhitespaceCharacterInSequence = NULL;
  729. bool bInWhiteSpace = false;
  730. CharType *pszPtr = m_pstrData;
  731. while (pszPtr && *pszPtr)
  732. {
  733. if (*pszPtr == L' ' || *pszPtr == L'\t' || *pszPtr == L'\n' || *pszPtr == L'\r')
  734. {
  735. if (!bInWhiteSpace)
  736. {
  737. pFirstWhitespaceCharacterInSequence = pszPtr;
  738. bInWhiteSpace = true;
  739. }
  740. }
  741. else
  742. {
  743. bInWhiteSpace = false;
  744. }
  745. pszPtr = GenericCharNext(pszPtr);
  746. }
  747. if (pFirstWhitespaceCharacterInSequence && bInWhiteSpace)
  748. *pFirstWhitespaceCharacterInSequence = 0;
  749. return *this;
  750. }
  751. template <class CharType>
  752. CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::TrimLeft()
  753. {
  754. CharType *pszPtr = m_pstrData;
  755. while (pszPtr && *pszPtr)
  756. {
  757. if (*pszPtr == L' ' || *pszPtr == L'\t' || *pszPtr == L'\n' || *pszPtr == L'\r')
  758. {
  759. pszPtr = GenericCharNext(pszPtr);
  760. }
  761. else break;
  762. }
  763. Assign(CSimpleStringBase<CharType>(pszPtr).String());
  764. return *this;
  765. }
  766. template <class CharType>
  767. inline CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::Trim()
  768. {
  769. TrimLeft();
  770. TrimRight();
  771. return *this;
  772. }
  773. //
  774. // Note that this function WILL NOT WORK CORRECTLY for multi-byte characters in ANSI strings
  775. //
  776. template <class CharType>
  777. CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::Reverse()
  778. {
  779. UINT nLen = Length();
  780. for (UINT i = 0;i<nLen/2;i++)
  781. {
  782. CharType tmp = m_pstrData[i];
  783. m_pstrData[i] = m_pstrData[nLen-i-1];
  784. m_pstrData[nLen-i-1] = tmp;
  785. }
  786. return *this;
  787. }
  788. template <class CharType>
  789. int CSimpleStringBase<CharType>::Find( CharType cChar ) const
  790. {
  791. CharType strTemp[2] = { cChar, 0};
  792. return Find(strTemp);
  793. }
  794. template <class CharType>
  795. int CSimpleStringBase<CharType>::Find( const CSimpleStringBase &other, UINT nStart ) const
  796. {
  797. if (!m_pstrData)
  798. return -1;
  799. if (nStart > Length())
  800. return -1;
  801. CharType *pstrCurr = m_pstrData+nStart, *pstrSrc, *pstrSubStr;
  802. while (*pstrCurr)
  803. {
  804. pstrSrc = pstrCurr;
  805. pstrSubStr = (CharType *)other.String();
  806. while (*pstrSrc && *pstrSubStr && *pstrSrc == *pstrSubStr)
  807. {
  808. pstrSrc = GenericCharNext(pstrSrc);
  809. pstrSubStr = GenericCharNext(pstrSubStr);
  810. }
  811. if (!*pstrSubStr)
  812. return static_cast<int>(pstrCurr-m_pstrData);
  813. pstrCurr = GenericCharNext(pstrCurr);
  814. }
  815. return -1;
  816. }
  817. template <class CharType>
  818. int CSimpleStringBase<CharType>::ReverseFind( CharType cChar ) const
  819. {
  820. CharType strTemp[2] = { cChar, 0};
  821. return ReverseFind(strTemp);
  822. }
  823. template <class CharType>
  824. int CSimpleStringBase<CharType>::ReverseFind( const CSimpleStringBase &srcStr ) const
  825. {
  826. int nLastFind = -1, nFind=0;
  827. while ((nFind = Find( srcStr, nFind )) >= 0)
  828. {
  829. nLastFind = nFind;
  830. ++nFind;
  831. }
  832. return nLastFind;
  833. }
  834. template <class CharType>
  835. CSimpleStringBase<CharType> CSimpleStringBase<CharType>::SubStr( int nStart, int nCount ) const
  836. {
  837. if (nStart >= (int)Length() || nStart < 0)
  838. {
  839. return CSimpleStringBase<CharType>();
  840. }
  841. if (nCount < 0)
  842. {
  843. nCount = Length() - nStart;
  844. }
  845. CSimpleStringBase<CharType> strTmp;
  846. CharType *pszTmp = CreateStorage(nCount+1);
  847. if (pszTmp)
  848. {
  849. GenericCopyLength( pszTmp, m_pstrData+nStart, nCount+1 );
  850. pszTmp[nCount] = 0;
  851. strTmp = pszTmp;
  852. delete[] pszTmp;
  853. }
  854. return strTmp;
  855. }
  856. template <class CharType>
  857. int CSimpleStringBase<CharType>::CompareNoCase( const CSimpleStringBase &other, int nLength ) const
  858. {
  859. if (nLength < 0)
  860. {
  861. //
  862. // Make sure both strings are non-NULL
  863. //
  864. if (!String() && !other.String())
  865. {
  866. return 0;
  867. }
  868. else if (!String())
  869. {
  870. return -1;
  871. }
  872. else if (!other.String())
  873. {
  874. return 1;
  875. }
  876. else return GenericCompareNoCase(m_pstrData,other.String());
  877. }
  878. CSimpleStringBase<CharType> strSrc(*this);
  879. CSimpleStringBase<CharType> strTgt(other);
  880. strSrc.MakeUpper();
  881. strTgt.MakeUpper();
  882. //
  883. // Make sure both strings are non-NULL
  884. //
  885. if (!strSrc.String() && !strTgt.String())
  886. {
  887. return 0;
  888. }
  889. else if (!strSrc.String())
  890. {
  891. return -1;
  892. }
  893. else if (!strTgt.String())
  894. {
  895. return 1;
  896. }
  897. else return GenericCompareLength(strSrc.String(),strTgt.String(),nLength);
  898. }
  899. template <class CharType>
  900. int CSimpleStringBase<CharType>::Compare( const CSimpleStringBase &other, int nLength ) const
  901. {
  902. //
  903. // Make sure both strings are non-NULL
  904. //
  905. if (!String() && !other.String())
  906. {
  907. return 0;
  908. }
  909. else if (!String())
  910. {
  911. return -1;
  912. }
  913. else if (!other.String())
  914. {
  915. return 1;
  916. }
  917. if (nLength < 0)
  918. {
  919. return GenericCompare(String(),other.String());
  920. }
  921. return GenericCompareLength(String(),other.String(),nLength);
  922. }
  923. template <class CharType>
  924. bool CSimpleStringBase<CharType>::MatchLastCharacter( CharType cChar ) const
  925. {
  926. int nFind = ReverseFind(cChar);
  927. if (nFind < 0)
  928. return false;
  929. if (nFind == (int)Length()-1)
  930. return true;
  931. else return false;
  932. }
  933. template <class CharType>
  934. bool CSimpleStringBase<CharType>::Load( HKEY hRegKey, const CharType *pszValueName, const CharType *pszDefault )
  935. {
  936. bool bResult = false;
  937. Assign(pszDefault);
  938. DWORD nType=0;
  939. DWORD nSize=0;
  940. LONG nRet;
  941. if (IS_CHAR(*m_pstrData))
  942. nRet = RegQueryValueExA( hRegKey, (LPCSTR)pszValueName, NULL, &nType, NULL, &nSize);
  943. else nRet = RegQueryValueExW( hRegKey, (LPCWSTR)pszValueName, NULL, &nType, NULL, &nSize);
  944. if (ERROR_SUCCESS == nRet)
  945. {
  946. if ((nType == REG_SZ) || (nType == REG_EXPAND_SZ))
  947. {
  948. // Round up to the nearest 2
  949. nSize = ((nSize + 1) & 0xFFFFFFFE);
  950. CharType *pstrTemp = CreateStorage(nSize / sizeof(CharType));
  951. if (pstrTemp)
  952. {
  953. if (IS_CHAR(*m_pstrData))
  954. nRet = RegQueryValueExA( hRegKey, (LPCSTR)pszValueName, NULL, &nType, (PBYTE)pstrTemp, &nSize);
  955. else nRet = RegQueryValueExW( hRegKey, (LPCWSTR)pszValueName, NULL, &nType, (PBYTE)pstrTemp, &nSize);
  956. if (ERROR_SUCCESS == nRet)
  957. {
  958. Assign(pstrTemp);
  959. bResult = true;
  960. }
  961. delete pstrTemp;
  962. }
  963. }
  964. }
  965. return bResult;
  966. }
  967. template <class CharType>
  968. bool CSimpleStringBase<CharType>::Store( HKEY hRegKey, const CharType *pszValueName, DWORD nType )
  969. {
  970. long nRet;
  971. if (Length())
  972. {
  973. if (IS_CHAR(*m_pstrData))
  974. {
  975. nRet = RegSetValueExA( hRegKey, (LPCSTR)pszValueName, 0, nType, (PBYTE)m_pstrData, sizeof(*m_pstrData)*(Length()+1) );
  976. }
  977. else
  978. {
  979. nRet = RegSetValueExW( hRegKey, (LPCWSTR)pszValueName, 0, nType, (PBYTE)m_pstrData, sizeof(*m_pstrData)*(Length()+1) );
  980. }
  981. }
  982. else
  983. {
  984. CharType strBlank = 0;
  985. if (IS_CHAR(*m_pstrData))
  986. {
  987. nRet = RegSetValueExA( hRegKey, (LPCSTR)pszValueName, 0, nType, (PBYTE)&strBlank, sizeof(CharType) );
  988. }
  989. else
  990. {
  991. nRet = RegSetValueExW( hRegKey, (LPCWSTR)pszValueName, 0, nType, (PBYTE)&strBlank, sizeof(CharType) );
  992. }
  993. }
  994. return(ERROR_SUCCESS == nRet);
  995. }
  996. //
  997. // Two main typedefs
  998. //
  999. typedef CSimpleStringBase<char> CSimpleStringAnsi;
  1000. typedef CSimpleStringBase<wchar_t> CSimpleStringWide;
  1001. //
  1002. // LPCTSTR equivalents
  1003. //
  1004. #if defined(UNICODE) || defined(_UNICODE)
  1005. typedef CSimpleStringWide CSimpleString;
  1006. #else
  1007. typedef CSimpleStringAnsi CSimpleString;
  1008. #endif
  1009. //
  1010. // Operators
  1011. //
  1012. inline bool operator<( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
  1013. {
  1014. return a.Compare(b) < 0;
  1015. }
  1016. inline bool operator<( const CSimpleStringWide &a, const CSimpleStringWide &b )
  1017. {
  1018. return a.Compare(b) < 0;
  1019. }
  1020. inline bool operator<=( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
  1021. {
  1022. return a.Compare(b) <= 0;
  1023. }
  1024. inline bool operator<=( const CSimpleStringWide &a, const CSimpleStringWide &b )
  1025. {
  1026. return a.Compare(b) <= 0;
  1027. }
  1028. inline bool operator==( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
  1029. {
  1030. return a.Compare(b) == 0;
  1031. }
  1032. inline bool operator==( const CSimpleStringWide &a, const CSimpleStringWide &b )
  1033. {
  1034. return a.Compare(b) == 0;
  1035. }
  1036. inline bool operator!=( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
  1037. {
  1038. return a.Compare(b) != 0;
  1039. }
  1040. inline bool operator!=( const CSimpleStringWide &a, const CSimpleStringWide &b )
  1041. {
  1042. return a.Compare(b) != 0;
  1043. }
  1044. inline bool operator>=( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
  1045. {
  1046. return a.Compare(b) >= 0;
  1047. }
  1048. inline bool operator>=( const CSimpleStringWide &a, const CSimpleStringWide &b )
  1049. {
  1050. return a.Compare(b) >= 0;
  1051. }
  1052. inline bool operator>( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
  1053. {
  1054. return a.Compare(b) > 0;
  1055. }
  1056. inline bool operator>( const CSimpleStringWide &a, const CSimpleStringWide &b )
  1057. {
  1058. return a.Compare(b) > 0;
  1059. }
  1060. inline CSimpleStringWide operator+( const CSimpleStringWide &a, const CSimpleStringWide &b )
  1061. {
  1062. CSimpleStringWide strResult(a);
  1063. strResult.Concat(b);
  1064. return strResult;
  1065. }
  1066. inline CSimpleStringAnsi operator+( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
  1067. {
  1068. CSimpleStringAnsi strResult(a);
  1069. strResult.Concat(b);
  1070. return strResult;
  1071. }
  1072. namespace CSimpleStringConvert
  1073. {
  1074. inline
  1075. CSimpleStringWide WideString( const CSimpleStringWide &strSource )
  1076. {
  1077. //
  1078. // Just return the source string
  1079. //
  1080. return strSource;
  1081. }
  1082. inline
  1083. CSimpleStringAnsi AnsiString( const CSimpleStringAnsi &strSource )
  1084. {
  1085. //
  1086. // Just return the source string
  1087. //
  1088. return strSource;
  1089. }
  1090. inline
  1091. CSimpleStringWide WideString( const CSimpleStringAnsi &strSource )
  1092. {
  1093. //
  1094. // Declare the return value. If anything goes wrong, it will contain an empty string
  1095. //
  1096. CSimpleStringWide strResult;
  1097. //
  1098. // Make sure we have a string
  1099. //
  1100. if (strSource.Length())
  1101. {
  1102. //
  1103. // Find out how long it needs to be
  1104. //
  1105. int nLength = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, strSource.String(), strSource.Length()+1, NULL, 0 );
  1106. if (nLength)
  1107. {
  1108. //
  1109. // Allocate a temporary buffer to hold the converted string
  1110. //
  1111. LPWSTR pwszBuffer = new WCHAR[nLength];
  1112. if (pwszBuffer)
  1113. {
  1114. //
  1115. // Convert the string
  1116. //
  1117. if (MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, strSource.String(), strSource.Length()+1, pwszBuffer, nLength ))
  1118. {
  1119. //
  1120. // Save the result
  1121. //
  1122. strResult = pwszBuffer;
  1123. }
  1124. //
  1125. // Free the temporary buffer
  1126. //
  1127. delete[] pwszBuffer;
  1128. }
  1129. }
  1130. }
  1131. //
  1132. // Return the result
  1133. //
  1134. return strResult;
  1135. }
  1136. inline
  1137. CSimpleStringAnsi AnsiString( const CSimpleStringWide &strSource )
  1138. {
  1139. //
  1140. // Declare the return value. If anything goes wrong, it will contain an empty string
  1141. //
  1142. CSimpleStringAnsi strResult;
  1143. //
  1144. // Make sure we have a valid string
  1145. //
  1146. if (strSource.Length())
  1147. {
  1148. //
  1149. // Figure out how long it needs to be
  1150. //
  1151. int nLength = WideCharToMultiByte( CP_ACP, 0, strSource, strSource.Length()+1, NULL, 0, NULL, NULL );
  1152. if (nLength)
  1153. {
  1154. //
  1155. // Allocate a temporary buffer to hold it
  1156. //
  1157. LPSTR pszBuffer = new CHAR[nLength];
  1158. if (pszBuffer)
  1159. {
  1160. //
  1161. // Convert the string
  1162. //
  1163. if (WideCharToMultiByte( CP_ACP, 0, strSource, strSource.Length()+1, pszBuffer, nLength, NULL, NULL ))
  1164. {
  1165. //
  1166. // Save the result
  1167. //
  1168. strResult = pszBuffer;
  1169. }
  1170. //
  1171. // Save the temporary buffer
  1172. //
  1173. delete[] pszBuffer;
  1174. }
  1175. }
  1176. }
  1177. //
  1178. // Return the result
  1179. //
  1180. return strResult;
  1181. }
  1182. inline
  1183. CSimpleStringWide FromUtf8( const CSimpleStringAnsi &strSource )
  1184. {
  1185. //
  1186. // Declare the return value. If anything goes wrong, it will contain an empty string
  1187. //
  1188. CSimpleStringWide strResult;
  1189. //
  1190. // Make sure we have a valid source string
  1191. //
  1192. if (strSource.Length())
  1193. {
  1194. //
  1195. // Find the required target string length
  1196. //
  1197. int nLength = MultiByteToWideChar( CP_UTF8, 0, strSource, strSource.Length()+1, NULL, 0 );
  1198. if (nLength)
  1199. {
  1200. //
  1201. // Allocate a temporary buffer
  1202. //
  1203. LPWSTR pwszBuffer = new WCHAR[nLength];
  1204. if (pwszBuffer)
  1205. {
  1206. //
  1207. // Convert the string
  1208. //
  1209. if (MultiByteToWideChar( CP_UTF8, 0, strSource.String(), strSource.Length()+1, pwszBuffer, nLength ))
  1210. {
  1211. //
  1212. // Save the result
  1213. //
  1214. strResult = pwszBuffer;
  1215. }
  1216. //
  1217. // Delete the temporary buffer
  1218. //
  1219. delete[] pwszBuffer;
  1220. }
  1221. }
  1222. }
  1223. //
  1224. // Return the result
  1225. //
  1226. return strResult;
  1227. }
  1228. inline
  1229. CSimpleStringAnsi ToUtf8( const CSimpleStringWide &strSource )
  1230. {
  1231. //
  1232. // Declare the return value. If anything goes wrong, it will contain an empty string
  1233. //
  1234. CSimpleStringAnsi strResult;
  1235. //
  1236. // Make sure we have a valid source string
  1237. //
  1238. if (strSource.Length())
  1239. {
  1240. int nLength = WideCharToMultiByte( CP_UTF8, 0, strSource, strSource.Length()+1, NULL, 0, NULL, NULL );
  1241. if (nLength)
  1242. {
  1243. //
  1244. // Find the required target string length
  1245. //
  1246. LPSTR pszBuffer = new CHAR[nLength];
  1247. if (pszBuffer)
  1248. {
  1249. //
  1250. // Convert the string
  1251. //
  1252. if (WideCharToMultiByte( CP_UTF8, 0, strSource, strSource.Length()+1, pszBuffer, nLength, NULL, NULL ))
  1253. {
  1254. //
  1255. // Save the result
  1256. //
  1257. strResult = pszBuffer;
  1258. }
  1259. //
  1260. // Delete the temporary buffer
  1261. //
  1262. delete[] pszBuffer;
  1263. }
  1264. }
  1265. }
  1266. //
  1267. // Return the result
  1268. //
  1269. return strResult;
  1270. }
  1271. #if defined(_UNICODE) || defined(UNICODE)
  1272. template <class CharType>
  1273. CSimpleStringWide NaturalString(const CharType &strSource)
  1274. {
  1275. return WideString(strSource);
  1276. }
  1277. #else
  1278. template <class CharType>
  1279. CSimpleStringAnsi NaturalString(const CharType &strSource)
  1280. {
  1281. return AnsiString(strSource);
  1282. }
  1283. #endif
  1284. inline CSimpleString NumberToString( int nNumber, LCID Locale=LOCALE_USER_DEFAULT )
  1285. {
  1286. //
  1287. // 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?
  1288. //
  1289. TCHAR szDigitGrouping[32] = {0};
  1290. GetLocaleInfo( Locale, LOCALE_SGROUPING, szDigitGrouping, ARRAYSIZE(szDigitGrouping));
  1291. //
  1292. // Initialize the number format
  1293. //
  1294. NUMBERFMT NumberFormat = {0};
  1295. for (LPTSTR pszCurr = szDigitGrouping; *pszCurr && *pszCurr >= TEXT('1') && *pszCurr <= TEXT('9'); pszCurr += 2)
  1296. {
  1297. NumberFormat.Grouping *= 10;
  1298. NumberFormat.Grouping += (*pszCurr - TEXT('0'));
  1299. }
  1300. //
  1301. // Get the thousands separator
  1302. //
  1303. TCHAR szThousandsSeparator[32] = {0};
  1304. GetLocaleInfo( Locale, LOCALE_STHOUSAND, szThousandsSeparator, ARRAYSIZE(szThousandsSeparator));
  1305. NumberFormat.lpThousandSep = szThousandsSeparator;
  1306. //
  1307. // Get the decimal separator
  1308. //
  1309. TCHAR szDecimalSeparator[32] = {0};
  1310. GetLocaleInfo( Locale, LOCALE_SDECIMAL, szDecimalSeparator, ARRAYSIZE(szDecimalSeparator));
  1311. NumberFormat.lpDecimalSep = szDecimalSeparator;
  1312. //
  1313. // Create the raw number string
  1314. //
  1315. TCHAR szRawNumber[MAX_PATH] = {0};
  1316. _sntprintf( szRawNumber, ARRAYSIZE(szRawNumber)-1, TEXT("%d"), nNumber );
  1317. //
  1318. // Format the string
  1319. //
  1320. TCHAR szNumberStr[MAX_PATH] = {0};
  1321. if (GetNumberFormat( Locale, 0, szRawNumber, &NumberFormat, szNumberStr, ARRAYSIZE(szNumberStr)))
  1322. {
  1323. return szNumberStr;
  1324. }
  1325. else
  1326. {
  1327. return TEXT("");
  1328. }
  1329. }
  1330. } // End CSimpleStringConvert namespace
  1331. //
  1332. // Restore the warning state
  1333. //
  1334. #pragma warning( pop )
  1335. #endif // ifndef _SIMSTR_H_INCLUDED