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.

910 lines
20 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-2001 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10. #ifndef __ATLSIMPSTR_H__
  11. #define __ATLSIMPSTR_H__
  12. #pragma once
  13. #include <atldef.h>
  14. #include <atlbase.h>
  15. #include <atlexcept.h>
  16. #include <atlmem.h>
  17. namespace ATL
  18. {
  19. struct CStringData;
  20. __interface IAtlStringMgr
  21. {
  22. public:
  23. // Allocate a new CStringData
  24. CStringData* Allocate( int nAllocLength, int nCharSize ) throw();
  25. // Free an existing CStringData
  26. void Free( CStringData* pData ) throw();
  27. // Change the size of an existing CStringData
  28. CStringData* Reallocate( CStringData* pData, int nAllocLength, int nCharSize ) throw();
  29. // Get the CStringData for a Nil string
  30. CStringData* GetNilString() throw();
  31. IAtlStringMgr* Clone() throw();
  32. };
  33. #ifdef _M_IX86
  34. #ifndef _M_CEE
  35. extern "C"
  36. {
  37. LONG _InterlockedIncrement( LONG* pn );
  38. LONG _InterlockedDecrement( LONG* pn );
  39. };
  40. #pragma intrinsic( _InterlockedIncrement )
  41. #pragma intrinsic( _InterlockedDecrement )
  42. #else
  43. #define _InterlockedIncrement InterlockedIncrement
  44. #define _InterlockedDecrement InterlockedDecrement
  45. #endif // !_M_CEE
  46. #endif // _M_IX86_
  47. struct CStringData
  48. {
  49. IAtlStringMgr* pStringMgr; // String manager for this CStringData
  50. int nDataLength; // Length of currently used data in XCHARs (not including terminating null)
  51. int nAllocLength; // Length of allocated data in XCHARs (not including terminating null)
  52. long nRefs; // Reference count: negative == locked
  53. // XCHAR data[nAllocLength+1] // A CStringData is always followed in memory by the actual array of character data
  54. void* data() throw()
  55. {
  56. return (this+1);
  57. }
  58. void AddRef() throw()
  59. {
  60. ATLASSERT(nRefs > 0);
  61. _InterlockedIncrement(&nRefs);
  62. }
  63. bool IsLocked() const throw()
  64. {
  65. return nRefs < 0;
  66. }
  67. bool IsShared() const throw()
  68. {
  69. return( nRefs > 1 );
  70. }
  71. void Lock() throw()
  72. {
  73. ATLASSERT( nRefs <= 1 );
  74. nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary
  75. if( nRefs == 0 )
  76. {
  77. nRefs = -1;
  78. }
  79. }
  80. void Release() throw()
  81. {
  82. ATLASSERT( nRefs != 0 );
  83. if( _InterlockedDecrement( &nRefs ) <= 0 )
  84. {
  85. pStringMgr->Free( this );
  86. }
  87. }
  88. void Unlock() throw()
  89. {
  90. ATLASSERT( IsLocked() );
  91. nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary
  92. if( nRefs == 0 )
  93. {
  94. nRefs = 1;
  95. }
  96. }
  97. };
  98. class CNilStringData :
  99. public CStringData
  100. {
  101. public:
  102. CNilStringData() throw()
  103. {
  104. pStringMgr = NULL;
  105. nRefs = 2; // Never gets freed by IAtlStringMgr
  106. nDataLength = 0;
  107. nAllocLength = 0;
  108. achNil[0] = 0;
  109. achNil[1] = 0;
  110. }
  111. void SetManager( IAtlStringMgr* pMgr ) throw()
  112. {
  113. ATLASSERT( pStringMgr == NULL );
  114. pStringMgr = pMgr;
  115. }
  116. public:
  117. wchar_t achNil[2];
  118. };
  119. class CAtlStringMgr :
  120. public IAtlStringMgr
  121. {
  122. public:
  123. CAtlStringMgr( IAtlMemMgr* pMemMgr = NULL ) throw() :
  124. m_pMemMgr( pMemMgr )
  125. {
  126. m_nil.SetManager( this );
  127. }
  128. ~CAtlStringMgr() throw()
  129. {
  130. }
  131. void SetMemoryManager( IAtlMemMgr* pMemMgr ) throw()
  132. {
  133. ATLASSERT( m_pMemMgr == NULL );
  134. m_pMemMgr = pMemMgr;
  135. }
  136. // IAtlStringMgr
  137. public:
  138. virtual CStringData* Allocate( int nChars, int nCharSize ) throw()
  139. {
  140. size_t nTotalSize;
  141. CStringData* pData;
  142. size_t nDataBytes;
  143. nChars = AtlAlignUp( nChars + 1, 8 ); // Prevent excessive reallocation. The heap will usually round up anyway.
  144. nDataBytes = nChars*nCharSize;
  145. nTotalSize = sizeof( CStringData )+nDataBytes;
  146. pData = static_cast< CStringData* >( m_pMemMgr->Allocate( nTotalSize ) );
  147. if( pData == NULL )
  148. {
  149. return( NULL );
  150. }
  151. pData->pStringMgr = this;
  152. pData->nRefs = 1;
  153. pData->nAllocLength = nChars - 1;
  154. pData->nDataLength = 0;
  155. return( pData );
  156. }
  157. virtual void Free( CStringData* pData ) throw()
  158. {
  159. ATLASSERT( pData->pStringMgr == this );
  160. m_pMemMgr->Free( pData );
  161. }
  162. virtual CStringData* Reallocate( CStringData* pData, int nChars, int nCharSize ) throw()
  163. {
  164. CStringData* pNewData;
  165. ULONG nTotalSize;
  166. ULONG nDataBytes;
  167. ATLASSERT( pData->pStringMgr == this );
  168. nChars = AtlAlignUp( nChars+1, 8 ); // Prevent excessive reallocation. The heap will usually round up anyway.
  169. nDataBytes = nChars*nCharSize;
  170. nTotalSize = sizeof( CStringData )+nDataBytes;
  171. pNewData = static_cast< CStringData* >( m_pMemMgr->Reallocate( pData, nTotalSize ) );
  172. if( pNewData == NULL )
  173. {
  174. return NULL;
  175. }
  176. pNewData->nAllocLength = nChars - 1;
  177. return pNewData;
  178. }
  179. virtual CStringData* GetNilString() throw()
  180. {
  181. m_nil.AddRef();
  182. return &m_nil;
  183. }
  184. virtual IAtlStringMgr* Clone() throw()
  185. {
  186. return this;
  187. }
  188. protected:
  189. IAtlMemMgr* m_pMemMgr;
  190. CNilStringData m_nil;
  191. };
  192. template< typename BaseType, const int t_nSize >
  193. class CStaticString
  194. {
  195. public:
  196. CStaticString( const BaseType* psz ) :
  197. m_psz( psz )
  198. {
  199. }
  200. operator const BaseType*() const
  201. {
  202. return m_psz;
  203. }
  204. static int GetLength()
  205. {
  206. return (t_nSize/sizeof( BaseType ))-1;
  207. }
  208. private:
  209. const BaseType* m_psz;
  210. private:
  211. CStaticString( const CStaticString& str ) throw();
  212. CStaticString& operator=( const CStaticString& str ) throw();
  213. };
  214. #define _ST( psz ) ATL::CStaticString< TCHAR, sizeof( _T( psz ) ) >( _T( psz ) )
  215. #define _SA( psz ) ATL::CStaticString< char, sizeof( psz ) >( psz )
  216. #define _SW( psz ) ATL::CStaticString< wchar_t, sizeof( L##psz ) >( L##psz )
  217. #define _SO( psz ) _SW( psz )
  218. template< typename BaseType = char >
  219. class ChTraitsBase
  220. {
  221. public:
  222. typedef char XCHAR;
  223. typedef LPSTR PXSTR;
  224. typedef LPCSTR PCXSTR;
  225. typedef wchar_t YCHAR;
  226. typedef LPWSTR PYSTR;
  227. typedef LPCWSTR PCYSTR;
  228. };
  229. template<>
  230. class ChTraitsBase< wchar_t >
  231. {
  232. public:
  233. typedef wchar_t XCHAR;
  234. typedef LPWSTR PXSTR;
  235. typedef LPCWSTR PCXSTR;
  236. typedef char YCHAR;
  237. typedef LPSTR PYSTR;
  238. typedef LPCSTR PCYSTR;
  239. };
  240. template< typename BaseType >
  241. class CSimpleStringT
  242. {
  243. public:
  244. typedef ChTraitsBase< BaseType >::XCHAR XCHAR;
  245. typedef ChTraitsBase< BaseType >::PXSTR PXSTR;
  246. typedef ChTraitsBase< BaseType >::PCXSTR PCXSTR;
  247. typedef ChTraitsBase< BaseType >::YCHAR YCHAR;
  248. typedef ChTraitsBase< BaseType >::PYSTR PYSTR;
  249. typedef ChTraitsBase< BaseType >::PCYSTR PCYSTR;
  250. public:
  251. explicit CSimpleStringT( IAtlStringMgr* pStringMgr ) throw()
  252. {
  253. ATLASSERT( pStringMgr != NULL );
  254. CStringData* pData = pStringMgr->GetNilString();
  255. Attach( pData );
  256. }
  257. CSimpleStringT( const CSimpleStringT& strSrc )
  258. {
  259. CStringData* pSrcData = strSrc.GetData();
  260. CStringData* pNewData = CloneData( pSrcData );
  261. Attach( pNewData );
  262. }
  263. CSimpleStringT( PCXSTR pszSrc, IAtlStringMgr* pStringMgr )
  264. {
  265. ATLASSERT( pStringMgr != NULL );
  266. int nLength = StringLength( pszSrc );
  267. CStringData* pData = pStringMgr->Allocate( nLength, sizeof( XCHAR ) );
  268. if( pData == NULL )
  269. {
  270. ThrowMemoryException();
  271. }
  272. Attach( pData );
  273. SetLength( nLength );
  274. CopyChars( m_pszData, pszSrc, nLength );
  275. }
  276. CSimpleStringT( const XCHAR* pchSrc, int nLength, IAtlStringMgr* pStringMgr )
  277. {
  278. ATLASSERT( pStringMgr != NULL );
  279. CStringData* pData = pStringMgr->Allocate( nLength, sizeof( XCHAR ) );
  280. if( pData == NULL )
  281. {
  282. ThrowMemoryException();
  283. }
  284. Attach( pData );
  285. SetLength( nLength );
  286. CopyChars( m_pszData, pchSrc, nLength );
  287. }
  288. ~CSimpleStringT() throw()
  289. {
  290. CStringData* pData = GetData();
  291. pData->Release();
  292. }
  293. CSimpleStringT& operator=( const CSimpleStringT& strSrc )
  294. {
  295. CStringData* pSrcData = strSrc.GetData();
  296. CStringData* pOldData = GetData();
  297. if( pSrcData != pOldData )
  298. {
  299. if( pOldData->IsLocked() )
  300. {
  301. SetString( strSrc.GetString(), strSrc.GetLength() );
  302. }
  303. else
  304. {
  305. CStringData* pNewData = CloneData( pSrcData );
  306. pOldData->Release();
  307. Attach( pNewData );
  308. }
  309. }
  310. return( *this );
  311. }
  312. CSimpleStringT& operator=( PCXSTR pszSrc )
  313. {
  314. SetString( pszSrc );
  315. return( *this );
  316. }
  317. CSimpleStringT& operator+=( const CSimpleStringT& strSrc )
  318. {
  319. Append( strSrc );
  320. return( *this );
  321. }
  322. CSimpleStringT& operator+=( PCXSTR pszSrc )
  323. {
  324. Append( pszSrc );
  325. return( *this );
  326. }
  327. template< int t_nSize >
  328. CSimpleStringT& operator+=( const CStaticString< XCHAR, t_nSize >& strSrc )
  329. {
  330. Append( strSrc.m_psz, strSrc.GetLength() );
  331. return( *this );
  332. }
  333. CSimpleStringT& operator+=( char ch )
  334. {
  335. XCHAR chTemp = XCHAR( ch );
  336. Append( &chTemp, 1 );
  337. return( *this );
  338. }
  339. CSimpleStringT& operator+=( unsigned char ch )
  340. {
  341. XCHAR chTemp = XCHAR( ch );
  342. Append( &chTemp, 1 );
  343. return( *this );
  344. }
  345. CSimpleStringT& operator+=( wchar_t ch )
  346. {
  347. XCHAR chTemp = XCHAR( ch );
  348. Append( &chTemp, 1 );
  349. return( *this );
  350. }
  351. XCHAR operator[]( int iChar ) const throw()
  352. {
  353. ATLASSERT( (iChar >= 0) && (iChar <= GetLength()) ); // Indexing the '\0' is OK
  354. return( m_pszData[iChar] );
  355. }
  356. operator PCXSTR() const throw()
  357. {
  358. return( m_pszData );
  359. }
  360. void Append( PCXSTR pszSrc )
  361. {
  362. Append( pszSrc, StringLength( pszSrc ) );
  363. }
  364. void Append( PCXSTR pszSrc, int nLength )
  365. {
  366. // See comment in SetString() about why we do this
  367. UINT_PTR nOffset = pszSrc-GetString();
  368. UINT nOldLength = GetLength();
  369. int nNewLength = nOldLength+nLength;
  370. PXSTR pszBuffer = GetBuffer( nNewLength );
  371. if( nOffset <= nOldLength )
  372. {
  373. pszSrc = pszBuffer+nOffset;
  374. // No need to call CopyCharsOverlapped, since the destination is
  375. // beyond the end of the original buffer
  376. }
  377. CopyChars( pszBuffer+nOldLength, pszSrc, nLength );
  378. ReleaseBuffer( nNewLength );
  379. }
  380. void Append( const CSimpleStringT& strSrc )
  381. {
  382. Append( strSrc.GetString(), strSrc.GetLength() );
  383. }
  384. void Empty() throw()
  385. {
  386. CStringData* pOldData = GetData();
  387. IAtlStringMgr* pStringMgr = pOldData->pStringMgr;
  388. if( pOldData->nDataLength == 0 )
  389. {
  390. return;
  391. }
  392. if( pOldData->IsLocked() )
  393. {
  394. // Don't reallocate a locked buffer that's shrinking
  395. SetLength( 0 );
  396. }
  397. else
  398. {
  399. pOldData->Release();
  400. CStringData* pNewData = pStringMgr->GetNilString();
  401. Attach( pNewData );
  402. }
  403. }
  404. void FreeExtra() throw()
  405. {
  406. CStringData* pOldData = GetData();
  407. int nLength = pOldData->nDataLength;
  408. IAtlStringMgr* pStringMgr = pOldData->pStringMgr;
  409. if( pOldData->nAllocLength == nLength )
  410. {
  411. return;
  412. }
  413. if( !pOldData->IsLocked() ) // Don't reallocate a locked buffer that's shrinking
  414. {
  415. CStringData* pNewData = pStringMgr->Allocate( nLength, sizeof( XCHAR ) );
  416. if( pNewData == NULL )
  417. {
  418. SetLength( nLength );
  419. return;
  420. }
  421. CopyChars( PXSTR( pNewData->data() ), PCXSTR( pOldData->data() ), nLength );
  422. pOldData->Release();
  423. Attach( pNewData );
  424. SetLength( nLength );
  425. }
  426. }
  427. int GetAllocLength() const throw()
  428. {
  429. return( GetData()->nAllocLength );
  430. }
  431. XCHAR GetAt( int iChar ) const throw()
  432. {
  433. ATLASSERT( (iChar >= 0) && (iChar <= GetLength()) ); // Indexing the '\0' is OK
  434. return( m_pszData[iChar] );
  435. }
  436. PXSTR GetBuffer()
  437. {
  438. CStringData* pData = GetData();
  439. if( pData->IsShared() )
  440. {
  441. Fork( pData->nDataLength );
  442. }
  443. return( m_pszData );
  444. }
  445. PXSTR GetBuffer( int nMinBufferLength )
  446. {
  447. return( PrepareWrite( nMinBufferLength ) );
  448. }
  449. PXSTR GetBufferSetLength( int nLength )
  450. {
  451. PXSTR pszBuffer = GetBuffer( nLength );
  452. SetLength( nLength );
  453. return( pszBuffer );
  454. }
  455. int GetLength() const throw()
  456. {
  457. return( GetData()->nDataLength );
  458. }
  459. IAtlStringMgr* GetManager() const throw()
  460. {
  461. return( GetData()->pStringMgr->Clone() );
  462. }
  463. PCXSTR GetString() const throw()
  464. {
  465. return( m_pszData );
  466. }
  467. bool IsEmpty() const throw()
  468. {
  469. return( GetLength() == 0 );
  470. }
  471. PXSTR LockBuffer()
  472. {
  473. CStringData* pData = GetData();
  474. if( pData->IsShared() )
  475. {
  476. Fork( pData->nDataLength );
  477. pData = GetData(); // Do it again, because the fork might have changed it
  478. }
  479. pData->Lock();
  480. return( m_pszData );
  481. }
  482. void UnlockBuffer() throw()
  483. {
  484. CStringData* pData = GetData();
  485. pData->Unlock();
  486. }
  487. void Preallocate( int nLength )
  488. {
  489. PrepareWrite( nLength );
  490. }
  491. void ReleaseBuffer( int nNewLength = -1 ) throw()
  492. {
  493. if( nNewLength == -1 )
  494. {
  495. nNewLength = StringLength( m_pszData );
  496. }
  497. SetLength( nNewLength );
  498. }
  499. void Truncate( int nNewLength )
  500. {
  501. ATLASSERT( nNewLength <= GetLength() );
  502. GetBuffer( nNewLength );
  503. ReleaseBuffer( nNewLength );
  504. }
  505. void SetAt( int iChar, XCHAR ch )
  506. {
  507. ATLASSERT( (iChar >= 0) && (iChar < GetLength()) );
  508. int nLength = GetLength();
  509. PXSTR pszBuffer = GetBuffer();
  510. pszBuffer[iChar] = ch;
  511. ReleaseBuffer( nLength );
  512. }
  513. void SetManager( IAtlStringMgr* pStringMgr )
  514. {
  515. ATLASSERT( IsEmpty() );
  516. CStringData* pData = GetData();
  517. pData->Release();
  518. pData = pStringMgr->GetNilString();
  519. Attach( pData );
  520. }
  521. void SetString( PCXSTR pszSrc )
  522. {
  523. SetString( pszSrc, StringLength( pszSrc ) );
  524. }
  525. void SetString( PCXSTR pszSrc, int nLength )
  526. {
  527. if( nLength == 0 )
  528. {
  529. Empty();
  530. }
  531. else
  532. {
  533. // It is possible that pszSrc points to a location inside of our
  534. // buffer. GetBuffer() might change m_pszData if (1) the buffer
  535. // is shared or (2) the buffer is too small to hold the new
  536. // string. We detect this aliasing, and modify pszSrc to point
  537. // into the newly allocated buffer instead.
  538. UINT nOldLength = GetLength();
  539. UINT_PTR nOffset = pszSrc-GetString();
  540. // If 0 <= nOffset <= nOldLength, then pszSrc points into our
  541. // buffer
  542. PXSTR pszBuffer = GetBuffer( nLength );
  543. if( nOffset <= nOldLength )
  544. {
  545. CopyCharsOverlapped( pszBuffer, pszBuffer+nOffset, nLength );
  546. }
  547. else
  548. {
  549. CopyChars( pszBuffer, pszSrc, nLength );
  550. }
  551. ReleaseBuffer( nLength );
  552. }
  553. }
  554. public:
  555. friend CSimpleStringT operator+(
  556. const CSimpleStringT& str1,
  557. const CSimpleStringT& str2 )
  558. {
  559. CSimpleStringT s( str1.GetManager() );
  560. Concatenate( s, str1, str1.GetLength(), str2, str2.GetLength() );
  561. return( s );
  562. }
  563. friend CSimpleStringT operator+(
  564. const CSimpleStringT& str1,
  565. PCXSTR psz2 )
  566. {
  567. CSimpleStringT s( str1.GetManager() );
  568. Concatenate( s, str1, str1.GetLength(), psz2, StringLength( psz2 ) );
  569. return( s );
  570. }
  571. friend CSimpleStringT operator+(
  572. PCXSTR psz1,
  573. const CSimpleStringT& str2 )
  574. {
  575. CSimpleStringT s( str2.GetManager() );
  576. Concatenate( s, psz1, StringLength( psz1 ), str2, str2.GetLength() );
  577. return( s );
  578. }
  579. static void CopyChars( XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) throw()
  580. {
  581. memcpy( pchDest, pchSrc, nChars*sizeof( XCHAR ) );
  582. }
  583. static void CopyCharsOverlapped( XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) throw()
  584. {
  585. memmove( pchDest, pchSrc, nChars*sizeof( XCHAR ) );
  586. }
  587. #ifdef _ATL_MIN_CRT
  588. ATL_NOINLINE static int StringLength( PCXSTR psz ) throw()
  589. {
  590. int nLength = 0;
  591. if( psz != NULL )
  592. {
  593. const XCHAR* pch = psz;
  594. while( *pch != 0 )
  595. {
  596. nLength++;
  597. pch++;
  598. }
  599. }
  600. return( nLength );
  601. }
  602. #else
  603. static int StringLength( const char* psz ) throw()
  604. {
  605. if( psz == NULL )
  606. {
  607. return( 0 );
  608. }
  609. return( int( strlen( psz ) ) );
  610. }
  611. template<>
  612. static int StringLength( const wchar_t* psz ) throw()
  613. {
  614. if( psz == NULL )
  615. {
  616. return( 0 );
  617. }
  618. return( int( wcslen( psz ) ) );
  619. }
  620. #endif
  621. protected:
  622. static void Concatenate( CSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2 )
  623. {
  624. int nNewLength = nLength1+nLength2;
  625. PXSTR pszBuffer = strResult.GetBuffer( nNewLength );
  626. CopyChars( pszBuffer, psz1, nLength1 );
  627. CopyChars( pszBuffer+nLength1, psz2, nLength2 );
  628. strResult.ReleaseBuffer( nNewLength );
  629. }
  630. ATL_NOINLINE static void ThrowMemoryException()
  631. {
  632. AtlThrow( E_OUTOFMEMORY );
  633. }
  634. // Implementation
  635. private:
  636. void Attach( CStringData* pData ) throw()
  637. {
  638. m_pszData = static_cast< PXSTR >( pData->data() );
  639. }
  640. ATL_NOINLINE void Fork( int nLength )
  641. {
  642. CStringData* pOldData = GetData();
  643. int nOldLength = pOldData->nDataLength;
  644. CStringData* pNewData = pOldData->pStringMgr->Clone()->Allocate( nLength, sizeof( XCHAR ) );
  645. if( pNewData == NULL )
  646. {
  647. ThrowMemoryException();
  648. }
  649. int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength)+1; // Copy '\0'
  650. CopyChars( PXSTR( pNewData->data() ), PCXSTR( pOldData->data() ), nCharsToCopy );
  651. pNewData->nDataLength = nOldLength;
  652. pOldData->Release();
  653. Attach( pNewData );
  654. }
  655. CStringData* GetData() const throw()
  656. {
  657. return( reinterpret_cast< CStringData* >( m_pszData )-1 );
  658. }
  659. PXSTR PrepareWrite( int nLength )
  660. {
  661. CStringData* pOldData = GetData();
  662. int nShared = 1-pOldData->nRefs; // nShared < 0 means true, >= 0 means false
  663. int nTooShort = pOldData->nAllocLength-nLength; // nTooShort < 0 means true, >= 0 means false
  664. if( (nShared|nTooShort) < 0 ) // If either sign bit is set (i.e. either is less than zero), we need to copy data
  665. {
  666. PrepareWrite2( nLength );
  667. }
  668. return( m_pszData );
  669. }
  670. ATL_NOINLINE void PrepareWrite2( int nLength )
  671. {
  672. CStringData* pOldData = GetData();
  673. if( pOldData->nDataLength > nLength )
  674. {
  675. nLength = pOldData->nDataLength;
  676. }
  677. if( pOldData->IsShared() )
  678. {
  679. Fork( nLength );
  680. }
  681. else if( pOldData->nAllocLength < nLength )
  682. {
  683. // Grow exponentially, until we hit 1K.
  684. int nNewLength = pOldData->nAllocLength;
  685. if( nNewLength > 1024 )
  686. {
  687. nNewLength += 1024;
  688. }
  689. else
  690. {
  691. nNewLength *= 2;
  692. }
  693. if( nNewLength < nLength )
  694. {
  695. nNewLength = nLength;
  696. }
  697. Reallocate( nNewLength );
  698. }
  699. }
  700. ATL_NOINLINE void Reallocate( int nLength )
  701. {
  702. CStringData* pOldData = GetData();
  703. ATLASSERT( pOldData->nAllocLength < nLength );
  704. IAtlStringMgr* pStringMgr = pOldData->pStringMgr;
  705. CStringData* pNewData = pStringMgr->Reallocate( pOldData, nLength, sizeof( XCHAR ) );
  706. if( pNewData == NULL )
  707. {
  708. ThrowMemoryException();
  709. }
  710. Attach( pNewData );
  711. }
  712. void SetLength( int nLength ) throw()
  713. {
  714. ATLASSERT( nLength >= 0 );
  715. ATLASSERT( nLength <= GetData()->nAllocLength );
  716. GetData()->nDataLength = nLength;
  717. m_pszData[nLength] = 0;
  718. }
  719. static CStringData* CloneData( CStringData* pData )
  720. {
  721. CStringData* pNewData = NULL;
  722. IAtlStringMgr* pNewStringMgr = pData->pStringMgr->Clone();
  723. if( !pData->IsLocked() && (pNewStringMgr == pData->pStringMgr) )
  724. {
  725. pNewData = pData;
  726. pNewData->AddRef();
  727. }
  728. else
  729. {
  730. pNewData = pNewStringMgr->Allocate( pData->nDataLength, sizeof( XCHAR ) );
  731. if( pNewData == NULL )
  732. {
  733. ThrowMemoryException();
  734. }
  735. pNewData->nDataLength = pData->nDataLength;
  736. CopyChars( PXSTR( pNewData->data() ), PCXSTR( pData->data() ), pData->nDataLength+1 ); // Copy '\0'
  737. }
  738. return( pNewData );
  739. }
  740. private:
  741. PXSTR m_pszData;
  742. };
  743. template< typename TCharType >
  744. class CStrBufT
  745. {
  746. public:
  747. typedef CSimpleStringT< TCharType > StringType;
  748. typedef StringType::XCHAR XCHAR;
  749. typedef StringType::PXSTR PXSTR;
  750. typedef StringType::PCXSTR PCXSTR;
  751. static const DWORD AUTO_LENGTH = 0x01; // Automatically determine the new length of the string at release. The string must be null-terminated.
  752. static const DWORD SET_LENGTH = 0x02; // Set the length of the string object at GetBuffer time
  753. public:
  754. explicit CStrBufT( StringType& str ) throw( ... ) :
  755. m_str( str ),
  756. m_pszBuffer( NULL ),
  757. #ifdef _DEBUG
  758. m_nBufferLength( str.GetLength() ),
  759. #endif
  760. m_nLength( str.GetLength() )
  761. {
  762. m_pszBuffer = m_str.GetBuffer();
  763. }
  764. CStrBufT( StringType& str, int nMinLength, DWORD dwFlags = AUTO_LENGTH ) throw( ... ) :
  765. m_str( str ),
  766. m_pszBuffer( NULL ),
  767. #ifdef _DEBUG
  768. m_nBufferLength( nMinLength ),
  769. #endif
  770. m_nLength( (dwFlags&AUTO_LENGTH) ? -1 : nMinLength )
  771. {
  772. if( dwFlags&SET_LENGTH )
  773. {
  774. m_pszBuffer = m_str.GetBufferSetLength( nMinLength );
  775. }
  776. else
  777. {
  778. m_pszBuffer = m_str.GetBuffer( nMinLength );
  779. }
  780. }
  781. ~CStrBufT() throw()
  782. {
  783. m_str.ReleaseBuffer( m_nLength );
  784. }
  785. operator PXSTR() throw()
  786. {
  787. return( m_pszBuffer );
  788. }
  789. operator PCXSTR() const throw()
  790. {
  791. return( m_pszBuffer );
  792. }
  793. void SetLength( int nLength ) throw()
  794. {
  795. ATLASSERT( nLength <= m_nBufferLength );
  796. m_nLength = nLength;
  797. }
  798. // Implementation
  799. private:
  800. StringType& m_str;
  801. PXSTR m_pszBuffer;
  802. int m_nLength;
  803. #ifdef _DEBUG
  804. int m_nBufferLength;
  805. #endif
  806. // Private copy constructor and copy assignment operator to prevent accidental use
  807. private:
  808. CStrBufT( const CStrBufT& ) throw();
  809. CStrBufT& operator=( const CStrBufT& ) throw();
  810. };
  811. typedef CSimpleStringT< TCHAR > CSimpleString;
  812. typedef CSimpleStringT< char > CSimpleStringA;
  813. typedef CSimpleStringT< wchar_t > CSimpleStringW;
  814. typedef CStrBufT< TCHAR > CStrBuf;
  815. typedef CStrBufT< char > CStrBufA;
  816. typedef CStrBufT< wchar_t > CStrBufW;
  817. }; // namespace ATL
  818. #endif // __ATLSIMPSTR_H__