Team Fortress 2 Source Code as on 22/4/2020
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.

767 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #define __STDC_LIMIT_MACROS
  7. #include <stdint.h>
  8. #include "tier1/utlstring.h"
  9. #include "tier1/strtools.h"
  10. #include <ctype.h>
  11. // NOTE: This has to be the last file included!
  12. #include "tier0/memdbgon.h"
  13. //-----------------------------------------------------------------------------
  14. // Simple string class.
  15. //-----------------------------------------------------------------------------
  16. //-----------------------------------------------------------------------------
  17. // Either allocates or reallocates memory to the length
  18. //
  19. // Allocated space for length characters. It automatically adds space for the
  20. // nul and the cached length at the start of the memory block. Will adjust
  21. // m_pString and explicitly set the nul at the end before returning.
  22. void *CUtlString::AllocMemory( uint32 length )
  23. {
  24. void *pMemoryBlock;
  25. if ( m_pString )
  26. {
  27. pMemoryBlock = realloc( m_pString, length + 1 );
  28. }
  29. else
  30. {
  31. pMemoryBlock = malloc( length + 1 );
  32. }
  33. m_pString = (char*)pMemoryBlock;
  34. m_pString[ length ] = 0;
  35. return pMemoryBlock;
  36. }
  37. //-----------------------------------------------------------------------------
  38. void CUtlString::SetDirect( const char *pValue, int nChars )
  39. {
  40. if ( pValue && nChars > 0 )
  41. {
  42. if ( pValue == m_pString )
  43. {
  44. AssertMsg( nChars == Q_strlen(m_pString), "CUtlString::SetDirect does not support resizing strings in place." );
  45. return; // Do nothing. Realloc in AllocMemory might move pValue's location resulting in a bad memcpy.
  46. }
  47. Assert( nChars <= Min<int>( strnlen(pValue, nChars) + 1, nChars ) );
  48. AllocMemory( nChars );
  49. Q_memcpy( m_pString, pValue, nChars );
  50. }
  51. else
  52. {
  53. Purge();
  54. }
  55. }
  56. void CUtlString::Set( const char *pValue )
  57. {
  58. int length = pValue ? V_strlen( pValue ) : 0;
  59. SetDirect( pValue, length );
  60. }
  61. // Sets the length (used to serialize into the buffer )
  62. void CUtlString::SetLength( int nLen )
  63. {
  64. if ( nLen > 0 )
  65. {
  66. #ifdef _DEBUG
  67. int prevLen = m_pString ? Length() : 0;
  68. #endif
  69. AllocMemory( nLen );
  70. #ifdef _DEBUG
  71. if ( nLen > prevLen )
  72. {
  73. V_memset( m_pString + prevLen, 0xEB, nLen - prevLen );
  74. }
  75. #endif
  76. }
  77. else
  78. {
  79. Purge();
  80. }
  81. }
  82. const char *CUtlString::Get( ) const
  83. {
  84. if (!m_pString)
  85. {
  86. return "";
  87. }
  88. return m_pString;
  89. }
  90. char *CUtlString::GetForModify()
  91. {
  92. if ( !m_pString )
  93. {
  94. // In general, we optimise away small mallocs for empty strings
  95. // but if you ask for the non-const bytes, they must be writable
  96. // so we can't return "" here, like we do for the const version - jd
  97. void *pMemoryBlock = malloc( 1 );
  98. m_pString = (char *)pMemoryBlock;
  99. *m_pString = 0;
  100. }
  101. return m_pString;
  102. }
  103. char CUtlString::operator[]( int i ) const
  104. {
  105. if ( !m_pString )
  106. return '\0';
  107. if ( i >= Length() )
  108. {
  109. return '\0';
  110. }
  111. return m_pString[i];
  112. }
  113. void CUtlString::Clear()
  114. {
  115. Purge();
  116. }
  117. void CUtlString::Purge()
  118. {
  119. free( m_pString );
  120. m_pString = NULL;
  121. }
  122. bool CUtlString::IsEqual_CaseSensitive( const char *src ) const
  123. {
  124. if ( !src )
  125. {
  126. return (Length() == 0);
  127. }
  128. return ( V_strcmp( Get(), src ) == 0 );
  129. }
  130. bool CUtlString::IsEqual_CaseInsensitive( const char *src ) const
  131. {
  132. if ( !src )
  133. {
  134. return (Length() == 0);
  135. }
  136. return ( V_stricmp( Get(), src ) == 0 );
  137. }
  138. void CUtlString::ToLower()
  139. {
  140. if ( !m_pString )
  141. {
  142. return;
  143. }
  144. V_strlower( m_pString );
  145. }
  146. void CUtlString::ToUpper()
  147. {
  148. if ( !m_pString )
  149. {
  150. return;
  151. }
  152. V_strupr( m_pString );
  153. }
  154. CUtlString &CUtlString::operator=( const CUtlString &src )
  155. {
  156. SetDirect( src.Get(), src.Length() );
  157. return *this;
  158. }
  159. CUtlString &CUtlString::operator=( const char *src )
  160. {
  161. Set( src );
  162. return *this;
  163. }
  164. bool CUtlString::operator==( const CUtlString &src ) const
  165. {
  166. if ( IsEmpty() )
  167. {
  168. if ( src.IsEmpty() )
  169. {
  170. return true;
  171. }
  172. return false;
  173. }
  174. else
  175. {
  176. if ( src.IsEmpty() )
  177. {
  178. return false;
  179. }
  180. return Q_strcmp( m_pString, src.m_pString ) == 0;
  181. }
  182. }
  183. CUtlString &CUtlString::operator+=( const CUtlString &rhs )
  184. {
  185. const int lhsLength( Length() );
  186. const int rhsLength( rhs.Length() );
  187. if (!rhsLength)
  188. {
  189. return *this;
  190. }
  191. const int requestedLength( lhsLength + rhsLength );
  192. AllocMemory( requestedLength );
  193. Q_memcpy( m_pString + lhsLength, rhs.m_pString, rhsLength );
  194. return *this;
  195. }
  196. CUtlString &CUtlString::operator+=( const char *rhs )
  197. {
  198. const int lhsLength( Length() );
  199. const int rhsLength( V_strlen( rhs ) );
  200. const int requestedLength( lhsLength + rhsLength );
  201. if (!requestedLength)
  202. {
  203. return *this;
  204. }
  205. AllocMemory( requestedLength );
  206. Q_memcpy( m_pString + lhsLength, rhs, rhsLength );
  207. return *this;
  208. }
  209. CUtlString &CUtlString::operator+=( char c )
  210. {
  211. const int lhsLength( Length() );
  212. AllocMemory( lhsLength + 1 );
  213. m_pString[ lhsLength ] = c;
  214. return *this;
  215. }
  216. CUtlString &CUtlString::operator+=( int rhs )
  217. {
  218. Assert( sizeof( rhs ) == 4 );
  219. char tmpBuf[ 12 ]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ]
  220. V_snprintf( tmpBuf, sizeof( tmpBuf ), "%d", rhs );
  221. tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
  222. return operator+=( tmpBuf );
  223. }
  224. CUtlString &CUtlString::operator+=( double rhs )
  225. {
  226. char tmpBuf[ 256 ]; // How big can doubles be??? Dunno.
  227. V_snprintf( tmpBuf, sizeof( tmpBuf ), "%lg", rhs );
  228. tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
  229. return operator+=( tmpBuf );
  230. }
  231. bool CUtlString::MatchesPattern( const CUtlString &Pattern, int nFlags ) const
  232. {
  233. const char *pszSource = String();
  234. const char *pszPattern = Pattern.String();
  235. bool bExact = true;
  236. while( 1 )
  237. {
  238. if ( ( *pszPattern ) == 0 )
  239. {
  240. return ( (*pszSource ) == 0 );
  241. }
  242. if ( ( *pszPattern ) == '*' )
  243. {
  244. pszPattern++;
  245. if ( ( *pszPattern ) == 0 )
  246. {
  247. return true;
  248. }
  249. bExact = false;
  250. continue;
  251. }
  252. int nLength = 0;
  253. while( ( *pszPattern ) != '*' && ( *pszPattern ) != 0 )
  254. {
  255. nLength++;
  256. pszPattern++;
  257. }
  258. while( 1 )
  259. {
  260. const char *pszStartPattern = pszPattern - nLength;
  261. const char *pszSearch = pszSource;
  262. for( int i = 0; i < nLength; i++, pszSearch++, pszStartPattern++ )
  263. {
  264. if ( ( *pszSearch ) == 0 )
  265. {
  266. return false;
  267. }
  268. if ( ( *pszSearch ) != ( *pszStartPattern ) )
  269. {
  270. break;
  271. }
  272. }
  273. if ( pszSearch - pszSource == nLength )
  274. {
  275. break;
  276. }
  277. if ( bExact == true )
  278. {
  279. return false;
  280. }
  281. if ( ( nFlags & PATTERN_DIRECTORY ) != 0 )
  282. {
  283. if ( ( *pszPattern ) != '/' && ( *pszSource ) == '/' )
  284. {
  285. return false;
  286. }
  287. }
  288. pszSource++;
  289. }
  290. pszSource += nLength;
  291. }
  292. }
  293. int CUtlString::Format( const char *pFormat, ... )
  294. {
  295. va_list marker;
  296. va_start( marker, pFormat );
  297. int len = FormatV( pFormat, marker );
  298. va_end( marker );
  299. return len;
  300. }
  301. //--------------------------------------------------------------------------------------------------
  302. // This can be called from functions that take varargs.
  303. //--------------------------------------------------------------------------------------------------
  304. int CUtlString::FormatV( const char *pFormat, va_list marker )
  305. {
  306. char tmpBuf[ 4096 ]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer
  307. //va_start( marker, pFormat );
  308. int len = V_vsprintf_safe( tmpBuf, pFormat, marker );
  309. //va_end( marker );
  310. Set( tmpBuf );
  311. return len;
  312. }
  313. //-----------------------------------------------------------------------------
  314. // Strips the trailing slash
  315. //-----------------------------------------------------------------------------
  316. void CUtlString::StripTrailingSlash()
  317. {
  318. if ( IsEmpty() )
  319. return;
  320. int nLastChar = Length() - 1;
  321. char c = m_pString[ nLastChar ];
  322. if ( c == '\\' || c == '/' )
  323. {
  324. SetLength( nLastChar );
  325. }
  326. }
  327. void CUtlString::FixSlashes( char cSeparator/*=CORRECT_PATH_SEPARATOR*/ )
  328. {
  329. if ( m_pString )
  330. {
  331. V_FixSlashes( m_pString, cSeparator );
  332. }
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Trim functions
  336. //-----------------------------------------------------------------------------
  337. void CUtlString::TrimLeft( char cTarget )
  338. {
  339. int nIndex = 0;
  340. if ( IsEmpty() )
  341. {
  342. return;
  343. }
  344. while( m_pString[nIndex] == cTarget )
  345. {
  346. ++nIndex;
  347. }
  348. // We have some whitespace to remove
  349. if ( nIndex > 0 )
  350. {
  351. memcpy( m_pString, &m_pString[nIndex], Length() - nIndex );
  352. SetLength( Length() - nIndex );
  353. }
  354. }
  355. void CUtlString::TrimLeft( const char *szTargets )
  356. {
  357. int i;
  358. if ( IsEmpty() )
  359. {
  360. return;
  361. }
  362. for( i = 0; m_pString[i] != 0; i++ )
  363. {
  364. bool bWhitespace = false;
  365. for( int j = 0; szTargets[j] != 0; j++ )
  366. {
  367. if ( m_pString[i] == szTargets[j] )
  368. {
  369. bWhitespace = true;
  370. break;
  371. }
  372. }
  373. if ( !bWhitespace )
  374. {
  375. break;
  376. }
  377. }
  378. // We have some whitespace to remove
  379. if ( i > 0 )
  380. {
  381. memcpy( m_pString, &m_pString[i], Length() - i );
  382. SetLength( Length() - i );
  383. }
  384. }
  385. void CUtlString::TrimRight( char cTarget )
  386. {
  387. const int nLastCharIndex = Length() - 1;
  388. int nIndex = nLastCharIndex;
  389. while ( nIndex >= 0 && m_pString[nIndex] == cTarget )
  390. {
  391. --nIndex;
  392. }
  393. // We have some whitespace to remove
  394. if ( nIndex < nLastCharIndex )
  395. {
  396. m_pString[nIndex + 1] = 0;
  397. SetLength( nIndex + 2 );
  398. }
  399. }
  400. void CUtlString::TrimRight( const char *szTargets )
  401. {
  402. const int nLastCharIndex = Length() - 1;
  403. int i;
  404. for( i = nLastCharIndex; i > 0; i-- )
  405. {
  406. bool bWhitespace = false;
  407. for( int j = 0; szTargets[j] != 0; j++ )
  408. {
  409. if ( m_pString[i] == szTargets[j] )
  410. {
  411. bWhitespace = true;
  412. break;
  413. }
  414. }
  415. if ( !bWhitespace )
  416. {
  417. break;
  418. }
  419. }
  420. // We have some whitespace to remove
  421. if ( i < nLastCharIndex )
  422. {
  423. m_pString[i + 1] = 0;
  424. SetLength( i + 2 );
  425. }
  426. }
  427. void CUtlString::Trim( char cTarget )
  428. {
  429. TrimLeft( cTarget );
  430. TrimRight( cTarget );
  431. }
  432. void CUtlString::Trim( const char *szTargets )
  433. {
  434. TrimLeft( szTargets );
  435. TrimRight( szTargets );
  436. }
  437. CUtlString CUtlString::Slice( int32 nStart, int32 nEnd ) const
  438. {
  439. int length = Length();
  440. if ( length == 0 )
  441. {
  442. return CUtlString();
  443. }
  444. if ( nStart < 0 )
  445. nStart = length - (-nStart % length);
  446. else if ( nStart >= length )
  447. nStart = length;
  448. if ( nEnd == INT32_MAX )
  449. nEnd = length;
  450. else if ( nEnd < 0 )
  451. nEnd = length - (-nEnd % length);
  452. else if ( nEnd >= length )
  453. nEnd = length;
  454. if ( nStart >= nEnd )
  455. return CUtlString();
  456. const char *pIn = String();
  457. CUtlString ret;
  458. ret.SetDirect( pIn + nStart, nEnd - nStart );
  459. return ret;
  460. }
  461. // Grab a substring starting from the left or the right side.
  462. CUtlString CUtlString::Left( int32 nChars ) const
  463. {
  464. return Slice( 0, nChars );
  465. }
  466. CUtlString CUtlString::Right( int32 nChars ) const
  467. {
  468. return Slice( -nChars );
  469. }
  470. CUtlString CUtlString::Replace( char cFrom, char cTo ) const
  471. {
  472. if (!m_pString)
  473. {
  474. return CUtlString();
  475. }
  476. CUtlString ret = *this;
  477. int len = ret.Length();
  478. for ( int i=0; i < len; i++ )
  479. {
  480. if ( ret.m_pString[i] == cFrom )
  481. ret.m_pString[i] = cTo;
  482. }
  483. return ret;
  484. }
  485. CUtlString CUtlString::Replace( const char *pszFrom, const char *pszTo ) const
  486. {
  487. Assert( pszTo ); // Can be 0 length, but not null
  488. Assert( pszFrom && *pszFrom ); // Must be valid and have one character.
  489. const char *pos = V_strstr( String(), pszFrom );
  490. if ( !pos )
  491. {
  492. return *this;
  493. }
  494. const char *pFirstFound = pos;
  495. // count number of search string
  496. int nSearchCount = 0;
  497. int nSearchLength = V_strlen( pszFrom );
  498. while ( pos )
  499. {
  500. nSearchCount++;
  501. int nSrcOffset = ( pos - String() ) + nSearchLength;
  502. pos = V_strstr( String() + nSrcOffset, pszFrom );
  503. }
  504. // allocate the new string
  505. int nReplaceLength = V_strlen( pszTo );
  506. int nAllocOffset = nSearchCount * ( nReplaceLength - nSearchLength );
  507. size_t srcLength = Length();
  508. CUtlString strDest;
  509. size_t destLength = srcLength + nAllocOffset;
  510. strDest.SetLength( destLength );
  511. // find and replace the search string
  512. pos = pFirstFound;
  513. int nDestOffset = 0;
  514. int nSrcOffset = 0;
  515. while ( pos )
  516. {
  517. // Found an instance
  518. int nCurrentSearchOffset = pos - String();
  519. int nCopyLength = nCurrentSearchOffset - nSrcOffset;
  520. V_strncpy( strDest.GetForModify() + nDestOffset, String() + nSrcOffset, nCopyLength + 1 );
  521. nDestOffset += nCopyLength;
  522. V_strncpy( strDest.GetForModify() + nDestOffset, pszTo, nReplaceLength + 1 );
  523. nDestOffset += nReplaceLength;
  524. nSrcOffset = nCurrentSearchOffset + nSearchLength;
  525. pos = V_strstr( String() + nSrcOffset, pszFrom );
  526. }
  527. // making sure that the left over string from the source is the same size as the left over dest buffer
  528. Assert( destLength - nDestOffset == srcLength - nSrcOffset );
  529. if ( destLength - nDestOffset > 0 )
  530. {
  531. V_strncpy( strDest.GetForModify() + nDestOffset, String() + nSrcOffset, destLength - nDestOffset + 1 );
  532. }
  533. return strDest;
  534. }
  535. CUtlString CUtlString::AbsPath( const char *pStartingDir ) const
  536. {
  537. char szNew[MAX_PATH];
  538. V_MakeAbsolutePath( szNew, sizeof( szNew ), this->String(), pStartingDir );
  539. return CUtlString( szNew );
  540. }
  541. CUtlString CUtlString::UnqualifiedFilename() const
  542. {
  543. const char *pFilename = V_UnqualifiedFileName( this->String() );
  544. return CUtlString( pFilename );
  545. }
  546. CUtlString CUtlString::DirName() const
  547. {
  548. CUtlString ret( this->String() );
  549. V_StripLastDir( (char*)ret.Get(), ret.Length() + 1 );
  550. V_StripTrailingSlash( (char*)ret.Get() );
  551. return ret;
  552. }
  553. CUtlString CUtlString::StripExtension() const
  554. {
  555. char szTemp[MAX_PATH];
  556. V_StripExtension( String(), szTemp, sizeof( szTemp ) );
  557. return CUtlString( szTemp );
  558. }
  559. CUtlString CUtlString::StripFilename() const
  560. {
  561. const char *pFilename = V_UnqualifiedFileName( Get() ); // NOTE: returns 'Get()' on failure, never NULL
  562. int nCharsToCopy = pFilename - Get();
  563. CUtlString result;
  564. result.SetDirect( Get(), nCharsToCopy );
  565. result.StripTrailingSlash();
  566. return result;
  567. }
  568. CUtlString CUtlString::GetBaseFilename() const
  569. {
  570. char szTemp[MAX_PATH];
  571. V_FileBase( String(), szTemp, sizeof( szTemp ) );
  572. return CUtlString( szTemp );
  573. }
  574. CUtlString CUtlString::GetExtension() const
  575. {
  576. char szTemp[MAX_PATH];
  577. V_ExtractFileExtension( String(), szTemp, sizeof( szTemp ) );
  578. return CUtlString( szTemp );
  579. }
  580. CUtlString CUtlString::PathJoin( const char *pStr1, const char *pStr2 )
  581. {
  582. char szPath[MAX_PATH];
  583. V_ComposeFileName( pStr1, pStr2, szPath, sizeof( szPath ) );
  584. return CUtlString( szPath );
  585. }
  586. CUtlString CUtlString::operator+( const char *pOther ) const
  587. {
  588. CUtlString s = *this;
  589. s += pOther;
  590. return s;
  591. }
  592. CUtlString CUtlString::operator+( const CUtlString &other ) const
  593. {
  594. CUtlString s = *this;
  595. s += other;
  596. return s;
  597. }
  598. CUtlString CUtlString::operator+( int rhs ) const
  599. {
  600. CUtlString ret = *this;
  601. ret += rhs;
  602. return ret;
  603. }
  604. //-----------------------------------------------------------------------------
  605. // Purpose: concatenate the provided string to our current content
  606. //-----------------------------------------------------------------------------
  607. void CUtlString::Append( const char *pchAddition )
  608. {
  609. (*this) += pchAddition;
  610. }
  611. void CUtlString::Append( const char *pchAddition, int nChars )
  612. {
  613. nChars = Min<int>( nChars, V_strlen( pchAddition ) );
  614. const int lhsLength( Length() );
  615. const int rhsLength( nChars );
  616. const int requestedLength( lhsLength + rhsLength );
  617. AllocMemory( requestedLength );
  618. const int allocatedLength( requestedLength );
  619. const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
  620. memcpy( GetForModify() + lhsLength, pchAddition, copyLength );
  621. m_pString[ allocatedLength ] = '\0';
  622. }
  623. // Shared static empty string.
  624. const CUtlString &CUtlString::GetEmptyString()
  625. {
  626. static const CUtlString s_emptyString;
  627. return s_emptyString;
  628. }