Counter Strike : Global Offensive Source Code
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.

1214 lines
31 KiB

  1. //========= Copyright (c) Valve Corporation, All rights reserved. =============
  2. //
  3. // Purpose: CUtlBinaryBlock and CUtlString implementation
  4. //
  5. //=============================================================================
  6. #include "tier1/utlstring.h"
  7. #include "tier1/utlvector.h"
  8. #include "tier1/strtools.h"
  9. #include <ctype.h>
  10. // NOTE: This has to be the last file included!
  11. #include "tier0/memdbgon.h"
  12. static const int64 k_nMillion = 1000000;
  13. //-----------------------------------------------------------------------------
  14. // Purpose: Helper: Find s substring
  15. //-----------------------------------------------------------------------------
  16. static ptrdiff_t IndexOf(const char *pstrToSearch, const char *pstrTarget)
  17. {
  18. const char *pstrHit = V_strstr(pstrToSearch, pstrTarget);
  19. if (pstrHit == NULL)
  20. {
  21. return -1; // Not found.
  22. }
  23. return (pstrHit - pstrToSearch);
  24. }
  25. //-----------------------------------------------------------------------------
  26. // Purpose: Helper: kill all whitespace.
  27. //-----------------------------------------------------------------------------
  28. static size_t RemoveWhitespace(char *pszString)
  29. {
  30. if (pszString == NULL)
  31. return 0;
  32. char *pstrDest = pszString;
  33. size_t cRemoved = 0;
  34. for (char *pstrWalker = pszString; *pstrWalker != 0; pstrWalker++)
  35. {
  36. if (!V_isspace((unsigned char)*pstrWalker))
  37. {
  38. *pstrDest = *pstrWalker;
  39. pstrDest++;
  40. }
  41. else
  42. cRemoved += 1;
  43. }
  44. *pstrDest = 0;
  45. return cRemoved;
  46. }
  47. int V_vscprintf(const char *format, va_list params)
  48. {
  49. #ifdef _WIN32
  50. return _vscprintf(format, params);
  51. #else
  52. return vsnprintf(NULL, 0, format, params);
  53. #endif
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Base class, containing simple memory management
  57. //-----------------------------------------------------------------------------
  58. CUtlBinaryBlock::CUtlBinaryBlock( int growSize, int initSize )
  59. {
  60. MEM_ALLOC_CREDIT();
  61. m_Memory.Init( growSize, initSize );
  62. m_nActualLength = 0;
  63. }
  64. CUtlBinaryBlock::CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Memory( (unsigned char*)pMemory, nSizeInBytes )
  65. {
  66. m_nActualLength = nInitialLength;
  67. }
  68. CUtlBinaryBlock::CUtlBinaryBlock( const void* pMemory, int nSizeInBytes ) : m_Memory( (const unsigned char*)pMemory, nSizeInBytes )
  69. {
  70. m_nActualLength = nSizeInBytes;
  71. }
  72. CUtlBinaryBlock::CUtlBinaryBlock( const CUtlBinaryBlock& src )
  73. {
  74. Set( src.Get(), src.Length() );
  75. }
  76. void CUtlBinaryBlock::Get( void *pValue, int nLen ) const
  77. {
  78. Assert( nLen > 0 );
  79. if ( m_nActualLength < nLen )
  80. {
  81. nLen = m_nActualLength;
  82. }
  83. if ( nLen > 0 )
  84. {
  85. memcpy( pValue, m_Memory.Base(), nLen );
  86. }
  87. }
  88. void CUtlBinaryBlock::SetLength( int nLength )
  89. {
  90. MEM_ALLOC_CREDIT();
  91. Assert( !m_Memory.IsReadOnly() );
  92. m_nActualLength = nLength;
  93. if ( nLength > m_Memory.NumAllocated() )
  94. {
  95. int nOverFlow = nLength - m_Memory.NumAllocated();
  96. m_Memory.Grow( nOverFlow );
  97. // If the reallocation failed, clamp length
  98. if ( nLength > m_Memory.NumAllocated() )
  99. {
  100. m_nActualLength = m_Memory.NumAllocated();
  101. }
  102. }
  103. #ifdef _DEBUG
  104. if ( m_Memory.NumAllocated() > m_nActualLength )
  105. {
  106. memset( ( ( char * )m_Memory.Base() ) + m_nActualLength, 0xEB, m_Memory.NumAllocated() - m_nActualLength );
  107. }
  108. #endif
  109. }
  110. void CUtlBinaryBlock::Set( const void *pValue, int nLen )
  111. {
  112. Assert( !m_Memory.IsReadOnly() );
  113. if ( !pValue )
  114. {
  115. nLen = 0;
  116. }
  117. SetLength( nLen );
  118. if ( m_nActualLength )
  119. {
  120. if ( ( ( const char * )m_Memory.Base() ) >= ( ( const char * )pValue ) + nLen ||
  121. ( ( const char * )m_Memory.Base() ) + m_nActualLength <= ( ( const char * )pValue ) )
  122. {
  123. memcpy( m_Memory.Base(), pValue, m_nActualLength );
  124. }
  125. else
  126. {
  127. memmove( m_Memory.Base(), pValue, m_nActualLength );
  128. }
  129. }
  130. }
  131. CUtlBinaryBlock &CUtlBinaryBlock::operator=( const CUtlBinaryBlock &src )
  132. {
  133. Assert( !m_Memory.IsReadOnly() );
  134. Set( src.Get(), src.Length() );
  135. return *this;
  136. }
  137. bool CUtlBinaryBlock::operator==( const CUtlBinaryBlock &src ) const
  138. {
  139. if ( src.Length() != Length() )
  140. return false;
  141. return !memcmp( src.Get(), Get(), Length() );
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Simple string class.
  145. //-----------------------------------------------------------------------------
  146. CUtlString::CUtlString()
  147. {
  148. }
  149. CUtlString::CUtlString( const char *pString )
  150. {
  151. Set( pString );
  152. }
  153. CUtlString::CUtlString( const CUtlString& string )
  154. {
  155. Set( string.Get() );
  156. }
  157. // Attaches the string to external memory. Useful for avoiding a copy
  158. CUtlString::CUtlString( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Storage( pMemory, nSizeInBytes, nInitialLength )
  159. {
  160. }
  161. CUtlString::CUtlString( const void* pMemory, int nSizeInBytes ) : m_Storage( pMemory, nSizeInBytes )
  162. {
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose: Set directly and don't look for a null terminator in pValue.
  166. //-----------------------------------------------------------------------------
  167. void CUtlString::SetDirect( const char *pValue, int nChars )
  168. {
  169. if ( nChars > 0 )
  170. {
  171. m_Storage.SetLength( nChars+1 );
  172. m_Storage.Set( pValue, nChars+1 );
  173. m_Storage[nChars] = 0;
  174. }
  175. else
  176. {
  177. m_Storage.SetLength( 0 );
  178. }
  179. }
  180. void CUtlString::Set( const char *pValue )
  181. {
  182. Assert( !m_Storage.IsReadOnly() );
  183. int nLen = pValue ? Q_strlen(pValue) + 1 : 0;
  184. m_Storage.Set( pValue, nLen );
  185. }
  186. // Returns strlen
  187. int CUtlString::Length() const
  188. {
  189. return m_Storage.Length() ? m_Storage.Length() - 1 : 0;
  190. }
  191. // Sets the length (used to serialize into the buffer )
  192. void CUtlString::SetLength( int nLen )
  193. {
  194. Assert( !m_Storage.IsReadOnly() );
  195. // Add 1 to account for the NULL
  196. m_Storage.SetLength( nLen > 0 ? nLen + 1 : 0 );
  197. }
  198. const char *CUtlString::Get( ) const
  199. {
  200. if ( m_Storage.Length() == 0 )
  201. {
  202. return "";
  203. }
  204. return reinterpret_cast< const char* >( m_Storage.Get() );
  205. }
  206. char *CUtlString::Get()
  207. {
  208. Assert( !m_Storage.IsReadOnly() );
  209. if ( m_Storage.Length() == 0 )
  210. {
  211. // In general, we optimise away small mallocs for empty strings
  212. // but if you ask for the non-const bytes, they must be writable
  213. // so we can't return "" here, like we do for the const version - jd
  214. m_Storage.SetLength( 1 );
  215. m_Storage[ 0 ] = '\0';
  216. }
  217. return reinterpret_cast< char* >( m_Storage.Get() );
  218. }
  219. char *CUtlString::GetForModify()
  220. {
  221. return Get();
  222. }
  223. void CUtlString::Purge()
  224. {
  225. m_Storage.Purge();
  226. }
  227. void CUtlString::ToUpper()
  228. {
  229. for (int nLength = Length() - 1; nLength >= 0; nLength--)
  230. {
  231. m_Storage[nLength] = toupper(m_Storage[nLength]);
  232. }
  233. }
  234. void CUtlString::ToLower()
  235. {
  236. for( int nLength = Length() - 1; nLength >= 0; nLength-- )
  237. {
  238. m_Storage[ nLength ] = tolower( m_Storage[ nLength ] );
  239. }
  240. }
  241. CUtlString &CUtlString::operator=( const CUtlString &src )
  242. {
  243. Assert( !m_Storage.IsReadOnly() );
  244. m_Storage = src.m_Storage;
  245. return *this;
  246. }
  247. CUtlString &CUtlString::operator=( const char *src )
  248. {
  249. Assert( !m_Storage.IsReadOnly() );
  250. Set( src );
  251. return *this;
  252. }
  253. bool CUtlString::operator==( const CUtlString &src ) const
  254. {
  255. return m_Storage == src.m_Storage;
  256. }
  257. bool CUtlString::operator==( const char *src ) const
  258. {
  259. return ( strcmp( Get(), src ) == 0 );
  260. }
  261. CUtlString &CUtlString::operator+=( const CUtlString &rhs )
  262. {
  263. Assert( !m_Storage.IsReadOnly() );
  264. const int lhsLength( Length() );
  265. const int rhsLength( rhs.Length() );
  266. const int requestedLength( lhsLength + rhsLength );
  267. SetLength( requestedLength );
  268. const int allocatedLength( Length() );
  269. const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
  270. memcpy( Get() + lhsLength, rhs.Get(), copyLength );
  271. m_Storage[ allocatedLength ] = '\0';
  272. return *this;
  273. }
  274. CUtlString &CUtlString::operator+=( const char *rhs )
  275. {
  276. Assert( !m_Storage.IsReadOnly() );
  277. const int lhsLength( Length() );
  278. const int rhsLength( Q_strlen( rhs ) );
  279. const int requestedLength( lhsLength + rhsLength );
  280. SetLength( requestedLength );
  281. const int allocatedLength( Length() );
  282. const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
  283. memcpy( Get() + lhsLength, rhs, copyLength );
  284. m_Storage[ allocatedLength ] = '\0';
  285. return *this;
  286. }
  287. CUtlString &CUtlString::operator+=( char c )
  288. {
  289. Assert( !m_Storage.IsReadOnly() );
  290. int nLength = Length();
  291. SetLength( nLength + 1 );
  292. m_Storage[ nLength ] = c;
  293. m_Storage[ nLength+1 ] = '\0';
  294. return *this;
  295. }
  296. CUtlString &CUtlString::operator+=( int rhs )
  297. {
  298. Assert( !m_Storage.IsReadOnly() );
  299. Assert( sizeof( rhs ) == 4 );
  300. char tmpBuf[ 12 ]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ]
  301. Q_snprintf( tmpBuf, sizeof( tmpBuf ), "%d", rhs );
  302. tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
  303. return operator+=( tmpBuf );
  304. }
  305. CUtlString &CUtlString::operator+=( double rhs )
  306. {
  307. Assert( !m_Storage.IsReadOnly() );
  308. char tmpBuf[ 256 ]; // How big can doubles be??? Dunno.
  309. Q_snprintf( tmpBuf, sizeof( tmpBuf ), "%lg", rhs );
  310. tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
  311. return operator+=( tmpBuf );
  312. }
  313. bool CUtlString::MatchesPattern( const CUtlString &Pattern, int nFlags )
  314. {
  315. const char *pszSource = String();
  316. const char *pszPattern = Pattern.String();
  317. return V_StringMatchesPattern( pszSource, pszPattern, nFlags );
  318. }
  319. int CUtlString::Format( const char *pFormat, ... )
  320. {
  321. va_list marker;
  322. va_start( marker, pFormat );
  323. int len = FormatV( pFormat, marker );
  324. va_end( marker );
  325. return len;
  326. }
  327. //--------------------------------------------------------------------------------------------------
  328. // This can be called from functions that take varargs.
  329. //--------------------------------------------------------------------------------------------------
  330. int CUtlString::FormatV( const char *pFormat, va_list marker )
  331. {
  332. char tmpBuf[ 4096 ]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer
  333. //va_start( marker, pFormat );
  334. int len = V_vsprintf_safe( tmpBuf, pFormat, marker );
  335. //va_end( marker );
  336. Set( tmpBuf );
  337. return len;
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Strips the trailing slash
  341. //-----------------------------------------------------------------------------
  342. void CUtlString::StripTrailingSlash()
  343. {
  344. if ( IsEmpty() )
  345. return;
  346. int nLastChar = Length() - 1;
  347. char c = m_Storage[ nLastChar ];
  348. if ( c == '\\' || c == '/' )
  349. {
  350. m_Storage[ nLastChar ] = 0;
  351. m_Storage.SetLength( m_Storage.Length() - 1 );
  352. }
  353. }
  354. CUtlString CUtlString::Slice( int32 nStart, int32 nEnd )
  355. {
  356. if ( nStart < 0 )
  357. nStart = Length() - (-nStart % Length());
  358. else if ( nStart >= Length() )
  359. nStart = Length();
  360. if ( nEnd == INT32_MAX )
  361. nEnd = Length();
  362. else if ( nEnd < 0 )
  363. nEnd = Length() - (-nEnd % Length());
  364. else if ( nEnd >= Length() )
  365. nEnd = Length();
  366. if ( nStart >= nEnd )
  367. return CUtlString( "" );
  368. const char *pIn = String();
  369. CUtlString ret;
  370. ret.m_Storage.SetLength( nEnd - nStart + 1 );
  371. char *pOut = (char*)ret.m_Storage.Get();
  372. memcpy( ret.m_Storage.Get(), &pIn[nStart], nEnd - nStart );
  373. pOut[nEnd - nStart] = 0;
  374. return ret;
  375. }
  376. // Grab a substring starting from the left or the right side.
  377. CUtlString CUtlString::Left( int32 nChars )
  378. {
  379. return Slice( 0, nChars );
  380. }
  381. CUtlString CUtlString::Right( int32 nChars )
  382. {
  383. return Slice( -nChars );
  384. }
  385. // Get a string with the specified substring removed
  386. CUtlString CUtlString::Remove( char const *pTextToRemove, bool bCaseSensitive ) const
  387. {
  388. int nTextToRemoveLength = pTextToRemove ? V_strlen( pTextToRemove ) : 0;
  389. CUtlString outputString;
  390. const char *pSrc = Get();
  391. if ( pSrc )
  392. {
  393. while ( *pSrc )
  394. {
  395. char const *pNextOccurrence = bCaseSensitive ? V_strstr( pSrc, pTextToRemove ) : V_stristr( pSrc, pTextToRemove );
  396. if ( !pNextOccurrence )
  397. {
  398. // append remaining string
  399. outputString += pSrc;
  400. break;
  401. }
  402. int nNumCharsToCopy = pNextOccurrence - pSrc;
  403. if ( nNumCharsToCopy )
  404. {
  405. // append up to the undesired substring
  406. CUtlString temp = pSrc;
  407. temp = temp.Left( nNumCharsToCopy );
  408. outputString += temp;
  409. }
  410. // skip past undesired substring
  411. pSrc = pNextOccurrence + nTextToRemoveLength;
  412. }
  413. }
  414. return outputString;
  415. }
  416. CUtlString CUtlString::Replace( char const *pchFrom, const char *pchTo, bool bCaseSensitive /*= false*/ ) const
  417. {
  418. if ( !pchTo )
  419. {
  420. return Remove( pchFrom, bCaseSensitive );
  421. }
  422. int nTextToReplaceLength = pchFrom ? V_strlen( pchFrom ) : 0;
  423. CUtlString outputString;
  424. const char *pSrc = Get();
  425. if ( pSrc )
  426. {
  427. while ( *pSrc )
  428. {
  429. char const *pNextOccurrence = bCaseSensitive ? V_strstr( pSrc, pchFrom ) : V_stristr( pSrc, pchFrom );
  430. if ( !pNextOccurrence )
  431. {
  432. // append remaining string
  433. outputString += pSrc;
  434. break;
  435. }
  436. int nNumCharsToCopy = pNextOccurrence - pSrc;
  437. if ( nNumCharsToCopy )
  438. {
  439. // append up to the undesired substring
  440. CUtlString temp = pSrc;
  441. temp = temp.Left( nNumCharsToCopy );
  442. outputString += temp;
  443. }
  444. // Append the replacement
  445. outputString += pchTo;
  446. // skip past undesired substring
  447. pSrc = pNextOccurrence + nTextToReplaceLength;
  448. }
  449. }
  450. return outputString;
  451. }
  452. CUtlString CUtlString::Replace( char cFrom, char cTo )
  453. {
  454. CUtlString ret = *this;
  455. int len = ret.Length();
  456. for ( int i=0; i < len; i++ )
  457. {
  458. if ( ret.m_Storage[i] == cFrom )
  459. ret.m_Storage[i] = cTo;
  460. }
  461. return ret;
  462. }
  463. void CUtlString::RemoveDotSlashes(char separator)
  464. {
  465. V_RemoveDotSlashes(Get(), separator);
  466. }
  467. void CUtlString::Swap( CUtlString &src )
  468. {
  469. CUtlString tmp = src;
  470. src = *this;
  471. *this = tmp;
  472. }
  473. CUtlString CUtlString::AbsPath( const char *pStartingDir ) const
  474. {
  475. char szNew[MAX_PATH];
  476. V_MakeAbsolutePath( szNew, sizeof( szNew ), this->String(), pStartingDir );
  477. return CUtlString( szNew );
  478. }
  479. CUtlString CUtlString::UnqualifiedFilename() const
  480. {
  481. const char *pFilename = V_UnqualifiedFileName( this->String() );
  482. return CUtlString( pFilename );
  483. }
  484. CUtlString CUtlString::DirName()
  485. {
  486. CUtlString ret( this->String() );
  487. V_StripLastDir( (char*)ret.m_Storage.Get(), ret.m_Storage.Length() );
  488. V_StripTrailingSlash( (char*)ret.m_Storage.Get() );
  489. return ret;
  490. }
  491. CUtlString CUtlString::StripExtension() const
  492. {
  493. char szTemp[MAX_FILEPATH];
  494. V_StripExtension( String(), szTemp, sizeof( szTemp ) );
  495. return CUtlString( szTemp );
  496. }
  497. CUtlString CUtlString::StripFilename() const
  498. {
  499. const char *pFilename = V_UnqualifiedFileName( Get() ); // NOTE: returns 'Get()' on failure, never NULL
  500. int nCharsToCopy = pFilename - Get();
  501. CUtlString result;
  502. result.SetDirect( Get(), nCharsToCopy );
  503. result.StripTrailingSlash();
  504. return result;
  505. }
  506. CUtlString CUtlString::GetBaseFilename() const
  507. {
  508. char szTemp[MAX_FILEPATH];
  509. V_FileBase( String(), szTemp, sizeof( szTemp ) );
  510. return CUtlString( szTemp );
  511. }
  512. CUtlString CUtlString::GetExtension() const
  513. {
  514. char szTemp[MAX_FILEPATH];
  515. V_ExtractFileExtension( String(), szTemp, sizeof( szTemp ) );
  516. return CUtlString( szTemp );
  517. }
  518. CUtlString CUtlString::PathJoin( const char *pStr1, const char *pStr2 )
  519. {
  520. char szPath[MAX_PATH];
  521. V_ComposeFileName( pStr1, pStr2, szPath, sizeof( szPath ) );
  522. return CUtlString( szPath );
  523. }
  524. //-----------------------------------------------------------------------------
  525. // Purpose: concatenate the provided string to our current content
  526. //-----------------------------------------------------------------------------
  527. void CUtlString::Append( const char *pchAddition )
  528. {
  529. (*this) += pchAddition;
  530. }
  531. void CUtlString::Append(const char *pchAddition, int nMaxChars)
  532. {
  533. const int nLen = V_strlen(pchAddition);
  534. if (nMaxChars < 0 || nLen <= nMaxChars)
  535. {
  536. Append(pchAddition);
  537. }
  538. else
  539. {
  540. char* pchAdditionDup = V_strdup(pchAddition);
  541. pchAdditionDup[nMaxChars] = 0;
  542. Append(pchAdditionDup);
  543. delete[] pchAdditionDup;
  544. }
  545. }
  546. //--------------------------------------------------------------------------------------------------
  547. // Trim
  548. //--------------------------------------------------------------------------------------------------
  549. void CUtlString::TrimLeft( const char *szTargets )
  550. {
  551. int i;
  552. if ( IsEmpty() )
  553. {
  554. return;
  555. }
  556. char* pSrc = Get();
  557. for ( i = 0; pSrc[ i ] != 0; i++ )
  558. {
  559. bool bWhitespace = false;
  560. for ( int j = 0; szTargets[ j ] != 0; j++ )
  561. {
  562. if ( pSrc[ i ] == szTargets[ j ] )
  563. {
  564. bWhitespace = true;
  565. break;
  566. }
  567. }
  568. if ( !bWhitespace )
  569. {
  570. break;
  571. }
  572. }
  573. // We have some whitespace to remove
  574. if ( i > 0 )
  575. {
  576. memmove( pSrc, &pSrc[ i ], Length() - i );
  577. SetLength( Length() - i );
  578. m_Storage[ Length() ] = '\0';
  579. }
  580. }
  581. void CUtlString::TrimRight( const char *szTargets )
  582. {
  583. const int nLastCharIndex = Length() - 1;
  584. int i;
  585. char* pSrc = Get();
  586. for ( i = nLastCharIndex; i >= 0; i-- )
  587. {
  588. bool bWhitespace = false;
  589. for ( int j = 0; szTargets[ j ] != 0; j++ )
  590. {
  591. if ( pSrc[ i ] == szTargets[ j ] )
  592. {
  593. bWhitespace = true;
  594. break;
  595. }
  596. }
  597. if ( !bWhitespace )
  598. {
  599. break;
  600. }
  601. }
  602. // We have some whitespace to remove
  603. if ( i < nLastCharIndex )
  604. {
  605. pSrc[ i + 1 ] = 0;
  606. SetLength( i + 1 );
  607. }
  608. }
  609. void CUtlString::Trim( const char *szTargets )
  610. {
  611. TrimLeft( szTargets );
  612. TrimRight( szTargets );
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Purpose: spill routine for making sure our buffer is big enough for an
  616. // incoming string set/modify.
  617. //-----------------------------------------------------------------------------
  618. char *CUtlStringBuilder::InternalPrepareBuffer(size_t nChars, bool bCopyOld, size_t nMinCapacity)
  619. {
  620. Assert(nMinCapacity > Capacity());
  621. Assert(nMinCapacity >= nChars);
  622. // Don't use this class if you want a single 2GB+ string.
  623. static const size_t k_nMaxStringSize = 0x7FFFFFFFu;
  624. Assert(nMinCapacity <= k_nMaxStringSize);
  625. if (nMinCapacity > k_nMaxStringSize)
  626. {
  627. SetError();
  628. return NULL;
  629. }
  630. bool bWasHeap = m_data.IsHeap();
  631. // add this to whatever we are going to grow so we don't start out too slow
  632. char *pszString = NULL;
  633. if (nMinCapacity > MAX_STACK_STRLEN)
  634. {
  635. // Allocate 1.5 times what is requested, plus a small initial ramp
  636. // value so we don't spend too much time re-allocating tiny buffers.
  637. // A good allocator will prevent this anyways, but this makes it safer.
  638. // We cap it at +1 million to not get crazy. Code actually avoides
  639. // computing power of two numbers since allocations almost always
  640. // have header/bookkeeping overhead. Don't do the dynamic sizing
  641. // if the user asked for a specific capacity.
  642. static const int k_nInitialMinRamp = 32;
  643. size_t nNewSize;
  644. if (nMinCapacity > nChars)
  645. nNewSize = nMinCapacity;
  646. else
  647. nNewSize = nChars + Min<size_t>((nChars >> 1) + k_nInitialMinRamp, k_nMillion);
  648. char *pszOld = m_data.Access();
  649. size_t nLenOld = m_data.Length();
  650. // order of operations is very important per comment
  651. // above. Make sure we copy it before changing m_data
  652. // in any way
  653. if (bWasHeap && bCopyOld)
  654. {
  655. // maybe we'll get lucky and get the same buffer back.
  656. pszString = (char*)realloc(pszOld, nNewSize + 1);
  657. if (!pszString)
  658. {
  659. SetError();
  660. return NULL;
  661. }
  662. }
  663. else // Either it's already on the stack; or we don't need to copy
  664. {
  665. // if the current pointer is on the heap, we aren't doing a copy
  666. // (or we would have used the previous realloc code. So
  667. // if we aren't doing a copy, don't use realloc since it will
  668. // copy the data if it needs to make a new allocation.
  669. if (bWasHeap)
  670. free(pszOld);
  671. pszString = (char*)malloc(nNewSize + 1);
  672. if (!pszString)
  673. {
  674. SetError();
  675. return NULL;
  676. }
  677. // still need to do the copy if we are going from small buffer to large
  678. if (bCopyOld)
  679. memcpy(pszString, pszOld, nLenOld); // null will be added at end of func.
  680. }
  681. // just in case the user grabs .Access() and scribbles over the terminator at
  682. // 'length', make sure they don't run off the rails as long as they obey Capacity.
  683. // We don't offer this protection for the 'on stack' string.
  684. pszString[nNewSize] = '\0';
  685. m_data.Heap.m_pchString = pszString;
  686. m_data.Heap.m_nCapacity = (uint32)nNewSize; // capacity is the max #chars, not including the null.
  687. m_data.Heap.m_nLength = (uint32)nChars;
  688. m_data.Heap.sentinel = STRING_TYPE_SENTINEL;
  689. }
  690. else
  691. {
  692. // Rare case. Only happens if someone did a SetPtr with a length
  693. // less than MAX_STACK_STRLEN, or maybe a .Replace() shrunk the
  694. // length down.
  695. pszString = m_data.Stack.m_szString;
  696. m_data.Stack.SetBytesLeft(MAX_STACK_STRLEN - (uint8)nChars);
  697. if (bWasHeap)
  698. {
  699. char *pszOldString = m_data.Heap.m_pchString;
  700. if (bCopyOld)
  701. memcpy(pszString, pszOldString, nChars); // null will be added at end of func.
  702. free(pszOldString);
  703. }
  704. }
  705. pszString[nChars] = '\0';
  706. return pszString;
  707. }
  708. //-----------------------------------------------------------------------------
  709. // Purpose: replace all occurrences of one string with another
  710. // replacement string may be NULL or "" to remove target string
  711. //-----------------------------------------------------------------------------
  712. size_t CUtlStringBuilder::Replace(const char *pstrTarget, const char *pstrReplacement)
  713. {
  714. return ReplaceInternal(pstrTarget, pstrReplacement, (const char *(*)(const char *, const char *))_V_strstr);
  715. }
  716. //-----------------------------------------------------------------------------
  717. // Purpose: replace all occurrences of one string with another
  718. // replacement string may be NULL or "" to remove target string
  719. //-----------------------------------------------------------------------------
  720. size_t CUtlStringBuilder::ReplaceFastCaseless(const char *pstrTarget, const char *pstrReplacement)
  721. {
  722. return ReplaceInternal(pstrTarget, pstrReplacement, V_stristr_fast);
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Purpose: replace all occurrences of one string with another
  726. // replacement string may be NULL or "" to remove target string
  727. //-----------------------------------------------------------------------------
  728. size_t CUtlStringBuilder::ReplaceInternal(const char *pstrTarget, const char *pstrReplacement, const char *pfnCompare(const char*, const char*))
  729. {
  730. if (HasError())
  731. return 0;
  732. if (pstrReplacement == NULL)
  733. pstrReplacement = "";
  734. size_t nTargetLength = V_strlen(pstrTarget);
  735. size_t nReplacementLength = V_strlen(pstrReplacement);
  736. CUtlVector<const char *> vecMatches;
  737. vecMatches.EnsureCapacity(8);
  738. if (!IsEmpty() && pstrTarget && *pstrTarget)
  739. {
  740. char *pszString = Access();
  741. // walk the string counting hits
  742. const char *pstrHit = pszString;
  743. for (pstrHit = pfnCompare(pstrHit, pstrTarget); pstrHit != NULL && *pstrHit != 0; /* inside */)
  744. {
  745. vecMatches.AddToTail(pstrHit);
  746. // look for the next target and keep looping
  747. pstrHit = pfnCompare(pstrHit + nTargetLength, pstrTarget);
  748. }
  749. // if we didn't miss, get to work
  750. if (vecMatches.Count() > 0)
  751. {
  752. // reallocate only once; how big will we need?
  753. size_t nOldLength = Length();
  754. size_t nNewLength = nOldLength + (vecMatches.Count() * (int)(nReplacementLength - nTargetLength));
  755. if (nNewLength == 0)
  756. {
  757. // shortcut simple case, even if rare
  758. m_data.Clear();
  759. }
  760. else if (nNewLength > nOldLength)
  761. {
  762. // New string will be bigger than the old, but don't re-alloc unless
  763. // it is also larger than capacity. If it fits in capacity, we will
  764. // be adjusting the string 'in place'. The replacement string is larger
  765. // than the target string, so if we copied front to back we would screw up
  766. // the existing data in the 'in place' case.
  767. char *pstrNew;
  768. if (nNewLength > Capacity())
  769. {
  770. pstrNew = (char*)malloc(nNewLength + 1);
  771. if (!pstrNew)
  772. {
  773. SetError();
  774. return 0;
  775. }
  776. }
  777. else
  778. {
  779. pstrNew = PrepareBuffer(nNewLength);
  780. Assert(pstrNew == pszString);
  781. }
  782. const char *pstrPreviousHit = pszString + nOldLength; // end of original string
  783. char *pstrDestination = pstrNew + nNewLength; // end of target
  784. *pstrDestination = '\0';
  785. // Go backwards as noted above.
  786. FOR_EACH_VEC_BACK(vecMatches, i)
  787. {
  788. pstrHit = vecMatches[i];
  789. size_t nRemainder = pstrPreviousHit - (pstrHit + nTargetLength);
  790. // copy the bit after the match, back up the destination and move forward from the hit
  791. memmove(pstrDestination - nRemainder, pstrPreviousHit - nRemainder, nRemainder);
  792. pstrDestination -= (nRemainder + nReplacementLength);
  793. // push the replacement string in
  794. memcpy(pstrDestination, pstrReplacement, nReplacementLength);
  795. pstrPreviousHit = pstrHit;
  796. }
  797. // copy trailing stuff
  798. size_t nRemainder = pstrPreviousHit - pszString;
  799. pstrDestination -= nRemainder;
  800. if (pstrDestination != pszString)
  801. {
  802. memmove(pstrDestination, pszString, nRemainder);
  803. }
  804. Assert(pstrNew == pstrDestination);
  805. // Need to set the pointer if we did were larger than capacity.
  806. if (pstrNew != pszString)
  807. SetPtr(pstrNew, nNewLength);
  808. }
  809. else // new is shorter than or same length as old, move in place
  810. {
  811. char *pstrNew = Access();
  812. char *pstrPreviousHit = pstrNew;
  813. char *pstrDestination = pstrNew;
  814. FOR_EACH_VEC(vecMatches, i)
  815. {
  816. pstrHit = vecMatches[i];
  817. if (pstrDestination != pstrPreviousHit)
  818. {
  819. // memmove very important as it is ok with overlaps.
  820. memmove(pstrDestination, pstrPreviousHit, pstrHit - pstrPreviousHit);
  821. }
  822. pstrDestination += (pstrHit - pstrPreviousHit);
  823. memcpy(pstrDestination, pstrReplacement, nReplacementLength);
  824. pstrDestination += nReplacementLength;
  825. pstrPreviousHit = const_cast<char*>(pstrHit)+nTargetLength;
  826. }
  827. // copy trailing stuff
  828. if (pstrDestination != pstrPreviousHit)
  829. {
  830. // memmove very important as it is ok with overlaps.
  831. size_t nRemainder = (pstrNew + nOldLength) - pstrPreviousHit;
  832. memmove(pstrDestination, pstrPreviousHit, nRemainder);
  833. }
  834. Verify(PrepareBuffer(nNewLength) == pstrNew);
  835. }
  836. }
  837. }
  838. return vecMatches.Count();
  839. }
  840. //-----------------------------------------------------------------------------
  841. // Purpose: Indicates if the target string exists in this instance.
  842. // The index is negative if the target string is not found, otherwise it is the index in the string.
  843. //-----------------------------------------------------------------------------
  844. ptrdiff_t CUtlStringBuilder::IndexOf(const char *pstrTarget) const
  845. {
  846. return ::IndexOf(String(), pstrTarget);
  847. }
  848. //-----------------------------------------------------------------------------
  849. // Purpose:
  850. // remove whitespace -- anything that is isspace() -- from the string
  851. //-----------------------------------------------------------------------------
  852. size_t CUtlStringBuilder::RemoveWhitespace()
  853. {
  854. if (HasError())
  855. return 0;
  856. char *pstrDest = m_data.Access();
  857. size_t cRemoved = ::RemoveWhitespace(pstrDest);
  858. size_t nNewLength = m_data.Length() - cRemoved;
  859. if (cRemoved)
  860. m_data.SetLength(nNewLength);
  861. Assert(pstrDest[nNewLength] == '\0'); // SetLength should have set this
  862. return cRemoved;
  863. }
  864. //-----------------------------------------------------------------------------
  865. // Purpose: Allows setting the size to anything under the current
  866. // capacity. Typically should not be used unless there was a specific
  867. // reason to scribble on the string. Will not touch the string contents,
  868. // but will append a NULL. Returns true if the length was changed.
  869. //-----------------------------------------------------------------------------
  870. bool CUtlStringBuilder::SetLength(size_t nLen)
  871. {
  872. return m_data.SetLength(nLen) != NULL;
  873. }
  874. //-----------------------------------------------------------------------------
  875. // Purpose: Convert to heap string if needed, and give it away.
  876. //-----------------------------------------------------------------------------
  877. char *CUtlStringBuilder::TakeOwnership(size_t *pnLen, size_t *pnCapacity)
  878. {
  879. size_t nLen = 0;
  880. size_t nCapacity = 0;
  881. char *psz = m_data.TakeOwnership(nLen, nCapacity);
  882. if (pnLen)
  883. *pnLen = nLen;
  884. if (pnCapacity)
  885. *pnCapacity = nCapacity;
  886. return psz;
  887. }
  888. //-----------------------------------------------------------------------------
  889. // Purpose:
  890. // trim whitespace from front and back of string
  891. //-----------------------------------------------------------------------------
  892. size_t CUtlStringBuilder::TrimWhitespace()
  893. {
  894. if (HasError())
  895. return 0;
  896. char *pchString = m_data.Access();
  897. int cChars = V_StrTrim(pchString);
  898. if (cChars)
  899. m_data.SetLength(cChars);
  900. return cChars;
  901. }
  902. //-----------------------------------------------------------------------------
  903. // Purpose: adjust length and add null terminator, within capacity bounds
  904. //-----------------------------------------------------------------------------
  905. char *CUtlStringBuilder::Data::SetLength(size_t nChars)
  906. {
  907. // heap/stack must be set correctly, and will not
  908. // be changed by this routine.
  909. if (IsHeap())
  910. {
  911. if (!Heap.m_pchString || nChars > Heap.m_nCapacity)
  912. return NULL;
  913. Heap.m_nLength = (uint32)nChars;
  914. Heap.m_pchString[nChars] = '\0';
  915. return Heap.m_pchString;
  916. }
  917. if (nChars > MAX_STACK_STRLEN)
  918. return NULL;
  919. Stack.m_szString[nChars] = '\0';
  920. Stack.SetBytesLeft(MAX_STACK_STRLEN - (uint8)nChars);
  921. return Stack.m_szString;
  922. }
  923. //-----------------------------------------------------------------------------
  924. // Purpose: Allows setting the raw pointer and taking ownership
  925. //-----------------------------------------------------------------------------
  926. void CUtlStringBuilder::Data::SetPtr(char *pchString, size_t nLength)
  927. {
  928. // We don't care about the error state since we are totally replacing
  929. // the string.
  930. // ok, length may be small enough to fit in our short buffer
  931. // but we've already got a dynamically allocated string, so let
  932. // it be in the heap buffer anyways.
  933. Heap.m_pchString = pchString;
  934. Heap.m_nCapacity = (uint32)nLength;
  935. Heap.m_nLength = (uint32)nLength;
  936. Heap.sentinel = STRING_TYPE_SENTINEL;
  937. // their buffer must have room for the null
  938. Heap.m_pchString[nLength] = '\0';
  939. }
  940. //-----------------------------------------------------------------------------
  941. // Purpose: Enable the error state, moving the string to the heap if
  942. // it isn't there.
  943. //-----------------------------------------------------------------------------
  944. void CUtlStringBuilder::Data::SetError(bool bEnableAssert)
  945. {
  946. if (HasError())
  947. return;
  948. // This is not meant to be used as a status bit. Setting the error state should
  949. // mean something very unexpected happened that you would want a call stack for.
  950. // That is why this asserts unconditionally when the state is being flipped.
  951. if (bEnableAssert)
  952. AssertMsg(false, "Error State on string being set.");
  953. MoveToHeap();
  954. Heap.sentinel = (STRING_TYPE_SENTINEL | STRING_TYPE_ERROR);
  955. }
  956. //-----------------------------------------------------------------------------
  957. // Purpose: Set string to empty state
  958. //-----------------------------------------------------------------------------
  959. void CUtlStringBuilder::Data::ClearError()
  960. {
  961. if (HasError())
  962. {
  963. Heap.sentinel = STRING_TYPE_SENTINEL;
  964. Clear();
  965. }
  966. }
  967. //-----------------------------------------------------------------------------
  968. // Purpose: If the string is on the stack, move it to the heap.
  969. // create a null heap string if memory can't be allocated.
  970. // Callers of this /need/ the string to be in the heap state
  971. // when done.
  972. //-----------------------------------------------------------------------------
  973. bool CUtlStringBuilder::Data::MoveToHeap()
  974. {
  975. bool bSuccess = true;
  976. if (!IsHeap())
  977. {
  978. // try to recover the string at the point of failure, to help with debugging
  979. size_t nLen = Length();
  980. char *pszHeapString = (char*)malloc(nLen + 1);
  981. if (pszHeapString)
  982. {
  983. // get the string copy before corrupting the stack union
  984. char *pszStackString = Access();
  985. memcpy(pszHeapString, pszStackString, nLen);
  986. pszHeapString[nLen] = 0;
  987. Heap.m_pchString = pszHeapString;
  988. Heap.m_nLength = (uint32)nLen;
  989. Heap.m_nCapacity = (uint32)nLen;
  990. Heap.sentinel = STRING_TYPE_SENTINEL;
  991. }
  992. else
  993. {
  994. Heap.m_pchString = NULL;
  995. Heap.m_nLength = 0;
  996. Heap.m_nCapacity = 0;
  997. bSuccess = false;
  998. Heap.sentinel = (STRING_TYPE_SENTINEL | STRING_TYPE_ERROR);
  999. }
  1000. }
  1001. return bSuccess;
  1002. }