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.

554 lines
12 KiB

  1. //====== Copyright 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "tier1/utlstring.h"
  7. #include "tier1/strtools.h"
  8. #include <ctype.h>
  9. // NOTE: This has to be the last file included!
  10. #include "tier0/memdbgon.h"
  11. //-----------------------------------------------------------------------------
  12. // Base class, containing simple memory management
  13. //-----------------------------------------------------------------------------
  14. CUtlBinaryBlock::CUtlBinaryBlock( int growSize, int initSize )
  15. {
  16. MEM_ALLOC_CREDIT();
  17. m_Memory.Init( growSize, initSize );
  18. m_nActualLength = 0;
  19. }
  20. CUtlBinaryBlock::CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Memory( (unsigned char*)pMemory, nSizeInBytes )
  21. {
  22. m_nActualLength = nInitialLength;
  23. }
  24. CUtlBinaryBlock::CUtlBinaryBlock( const void* pMemory, int nSizeInBytes ) : m_Memory( (const unsigned char*)pMemory, nSizeInBytes )
  25. {
  26. m_nActualLength = nSizeInBytes;
  27. }
  28. CUtlBinaryBlock::CUtlBinaryBlock( const CUtlBinaryBlock& src )
  29. {
  30. Set( src.Get(), src.Length() );
  31. }
  32. void CUtlBinaryBlock::Get( void *pValue, int nLen ) const
  33. {
  34. Assert( nLen > 0 );
  35. if ( m_nActualLength < nLen )
  36. {
  37. nLen = m_nActualLength;
  38. }
  39. if ( nLen > 0 )
  40. {
  41. memcpy( pValue, m_Memory.Base(), nLen );
  42. }
  43. }
  44. void CUtlBinaryBlock::SetLength( int nLength )
  45. {
  46. MEM_ALLOC_CREDIT();
  47. Assert( !m_Memory.IsReadOnly() );
  48. m_nActualLength = nLength;
  49. if ( nLength > m_Memory.NumAllocated() )
  50. {
  51. int nOverFlow = nLength - m_Memory.NumAllocated();
  52. m_Memory.Grow( nOverFlow );
  53. // If the reallocation failed, clamp length
  54. if ( nLength > m_Memory.NumAllocated() )
  55. {
  56. m_nActualLength = m_Memory.NumAllocated();
  57. }
  58. }
  59. #ifdef _DEBUG
  60. if ( m_Memory.NumAllocated() > m_nActualLength )
  61. {
  62. memset( ( ( char * )m_Memory.Base() ) + m_nActualLength, 0xEB, m_Memory.NumAllocated() - m_nActualLength );
  63. }
  64. #endif
  65. }
  66. void CUtlBinaryBlock::Set( const void *pValue, int nLen )
  67. {
  68. Assert( !m_Memory.IsReadOnly() );
  69. if ( !pValue )
  70. {
  71. nLen = 0;
  72. }
  73. SetLength( nLen );
  74. if ( m_nActualLength )
  75. {
  76. if ( ( ( const char * )m_Memory.Base() ) >= ( ( const char * )pValue ) + nLen ||
  77. ( ( const char * )m_Memory.Base() ) + m_nActualLength <= ( ( const char * )pValue ) )
  78. {
  79. memcpy( m_Memory.Base(), pValue, m_nActualLength );
  80. }
  81. else
  82. {
  83. memmove( m_Memory.Base(), pValue, m_nActualLength );
  84. }
  85. }
  86. }
  87. CUtlBinaryBlock &CUtlBinaryBlock::operator=( const CUtlBinaryBlock &src )
  88. {
  89. Assert( !m_Memory.IsReadOnly() );
  90. Set( src.Get(), src.Length() );
  91. return *this;
  92. }
  93. bool CUtlBinaryBlock::operator==( const CUtlBinaryBlock &src ) const
  94. {
  95. if ( src.Length() != Length() )
  96. return false;
  97. return !memcmp( src.Get(), Get(), Length() );
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Simple string class.
  101. //-----------------------------------------------------------------------------
  102. CUtlString::CUtlString()
  103. {
  104. }
  105. CUtlString::CUtlString( const char *pString )
  106. {
  107. Set( pString );
  108. }
  109. CUtlString::CUtlString( const CUtlString& string )
  110. {
  111. Set( string.Get() );
  112. }
  113. // Attaches the string to external memory. Useful for avoiding a copy
  114. CUtlString::CUtlString( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Storage( pMemory, nSizeInBytes, nInitialLength )
  115. {
  116. }
  117. CUtlString::CUtlString( const void* pMemory, int nSizeInBytes ) : m_Storage( pMemory, nSizeInBytes )
  118. {
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose: Set directly and don't look for a null terminator in pValue.
  122. //-----------------------------------------------------------------------------
  123. void CUtlString::SetDirect( const char *pValue, int nChars )
  124. {
  125. if ( nChars > 0 )
  126. {
  127. m_Storage.SetLength( nChars+1 );
  128. m_Storage.Set( pValue, nChars );
  129. m_Storage[nChars] = 0;
  130. }
  131. else
  132. {
  133. m_Storage.SetLength( 0 );
  134. }
  135. }
  136. void CUtlString::Set( const char *pValue )
  137. {
  138. Assert( !m_Storage.IsReadOnly() );
  139. int nLen = pValue ? V_strlen(pValue) + 1 : 0;
  140. m_Storage.Set( pValue, nLen );
  141. }
  142. // Returns strlen
  143. int CUtlString::Length() const
  144. {
  145. return m_Storage.Length() ? m_Storage.Length() - 1 : 0;
  146. }
  147. // Sets the length (used to serialize into the buffer )
  148. void CUtlString::SetLength( int nLen )
  149. {
  150. Assert( !m_Storage.IsReadOnly() );
  151. // Add 1 to account for the NULL
  152. m_Storage.SetLength( nLen > 0 ? nLen + 1 : 0 );
  153. }
  154. const char *CUtlString::Get( ) const
  155. {
  156. if ( m_Storage.Length() == 0 )
  157. {
  158. return "";
  159. }
  160. return reinterpret_cast< const char* >( m_Storage.Get() );
  161. }
  162. // Converts to c-strings
  163. CUtlString::operator const char*() const
  164. {
  165. return Get();
  166. }
  167. char *CUtlString::Get()
  168. {
  169. Assert( !m_Storage.IsReadOnly() );
  170. if ( m_Storage.Length() == 0 )
  171. {
  172. // In general, we optimise away small mallocs for empty strings
  173. // but if you ask for the non-const bytes, they must be writable
  174. // so we can't return "" here, like we do for the const version - jd
  175. m_Storage.SetLength( 1 );
  176. m_Storage[ 0 ] = '\0';
  177. }
  178. return reinterpret_cast< char* >( m_Storage.Get() );
  179. }
  180. void CUtlString::Purge()
  181. {
  182. m_Storage.Purge();
  183. }
  184. void CUtlString::ToLower()
  185. {
  186. for( int nLength = Length() - 1; nLength >= 0; nLength-- )
  187. {
  188. m_Storage[ nLength ] = tolower( m_Storage[ nLength ] );
  189. }
  190. }
  191. CUtlString &CUtlString::operator=( const CUtlString &src )
  192. {
  193. Assert( !m_Storage.IsReadOnly() );
  194. m_Storage = src.m_Storage;
  195. return *this;
  196. }
  197. CUtlString &CUtlString::operator=( const char *src )
  198. {
  199. Assert( !m_Storage.IsReadOnly() );
  200. Set( src );
  201. return *this;
  202. }
  203. bool CUtlString::operator==( const CUtlString &src ) const
  204. {
  205. return m_Storage == src.m_Storage;
  206. }
  207. bool CUtlString::operator==( const char *src ) const
  208. {
  209. return ( strcmp( Get(), src ) == 0 );
  210. }
  211. CUtlString &CUtlString::operator+=( const CUtlString &rhs )
  212. {
  213. Assert( !m_Storage.IsReadOnly() );
  214. const int lhsLength( Length() );
  215. const int rhsLength( rhs.Length() );
  216. const int requestedLength( lhsLength + rhsLength );
  217. SetLength( requestedLength );
  218. const int allocatedLength( Length() );
  219. const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
  220. memcpy( Get() + lhsLength, rhs.Get(), copyLength );
  221. m_Storage[ allocatedLength ] = '\0';
  222. return *this;
  223. }
  224. CUtlString &CUtlString::operator+=( const char *rhs )
  225. {
  226. Assert( !m_Storage.IsReadOnly() );
  227. const int lhsLength( Length() );
  228. const int rhsLength( V_strlen( rhs ) );
  229. const int requestedLength( lhsLength + rhsLength );
  230. SetLength( requestedLength );
  231. const int allocatedLength( Length() );
  232. const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
  233. memcpy( Get() + lhsLength, rhs, copyLength );
  234. m_Storage[ allocatedLength ] = '\0';
  235. return *this;
  236. }
  237. CUtlString &CUtlString::operator+=( char c )
  238. {
  239. Assert( !m_Storage.IsReadOnly() );
  240. int nLength = Length();
  241. SetLength( nLength + 1 );
  242. m_Storage[ nLength ] = c;
  243. m_Storage[ nLength+1 ] = '\0';
  244. return *this;
  245. }
  246. CUtlString &CUtlString::operator+=( int rhs )
  247. {
  248. Assert( !m_Storage.IsReadOnly() );
  249. Assert( sizeof( rhs ) == 4 );
  250. char tmpBuf[ 12 ]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ]
  251. V_snprintf( tmpBuf, sizeof( tmpBuf ), "%d", rhs );
  252. tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
  253. return operator+=( tmpBuf );
  254. }
  255. CUtlString &CUtlString::operator+=( double rhs )
  256. {
  257. Assert( !m_Storage.IsReadOnly() );
  258. char tmpBuf[ 256 ]; // How big can doubles be??? Dunno.
  259. V_snprintf( tmpBuf, sizeof( tmpBuf ), "%lg", rhs );
  260. tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
  261. return operator+=( tmpBuf );
  262. }
  263. bool CUtlString::MatchesPattern( const CUtlString &Pattern, int nFlags ) const
  264. {
  265. const char *pszSource = String();
  266. const char *pszPattern = Pattern.String();
  267. bool bExact = true;
  268. while( 1 )
  269. {
  270. if ( ( *pszPattern ) == 0 )
  271. {
  272. return ( (*pszSource ) == 0 );
  273. }
  274. if ( ( *pszPattern ) == '*' )
  275. {
  276. pszPattern++;
  277. if ( ( *pszPattern ) == 0 )
  278. {
  279. return true;
  280. }
  281. bExact = false;
  282. continue;
  283. }
  284. int nLength = 0;
  285. while( ( *pszPattern ) != '*' && ( *pszPattern ) != 0 )
  286. {
  287. nLength++;
  288. pszPattern++;
  289. }
  290. while( 1 )
  291. {
  292. const char *pszStartPattern = pszPattern - nLength;
  293. const char *pszSearch = pszSource;
  294. for( int i = 0; i < nLength; i++, pszSearch++, pszStartPattern++ )
  295. {
  296. if ( ( *pszSearch ) == 0 )
  297. {
  298. return false;
  299. }
  300. if ( ( *pszSearch ) != ( *pszStartPattern ) )
  301. {
  302. break;
  303. }
  304. }
  305. if ( pszSearch - pszSource == nLength )
  306. {
  307. break;
  308. }
  309. if ( bExact == true )
  310. {
  311. return false;
  312. }
  313. if ( ( nFlags & PATTERN_DIRECTORY ) != 0 )
  314. {
  315. if ( ( *pszPattern ) != '/' && ( *pszSource ) == '/' )
  316. {
  317. return false;
  318. }
  319. }
  320. pszSource++;
  321. }
  322. pszSource += nLength;
  323. }
  324. }
  325. int CUtlString::Format( const char *pFormat, ... )
  326. {
  327. Assert( !m_Storage.IsReadOnly() );
  328. char tmpBuf[ 4096 ]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer
  329. va_list marker;
  330. va_start( marker, pFormat );
  331. #ifdef _WIN32
  332. int len = _vsnprintf( tmpBuf, sizeof( tmpBuf ) - 1, pFormat, marker );
  333. #elif POSIX
  334. int len = vsnprintf( tmpBuf, sizeof( tmpBuf ) - 1, pFormat, marker );
  335. #else
  336. #error "define vsnprintf type."
  337. #endif
  338. va_end( marker );
  339. // Len > maxLen represents an overflow on POSIX, < 0 is an overflow on windows
  340. if( len < 0 || len >= sizeof( tmpBuf ) - 1 )
  341. {
  342. len = sizeof( tmpBuf ) - 1;
  343. tmpBuf[sizeof( tmpBuf ) - 1] = 0;
  344. }
  345. Set( tmpBuf );
  346. return len;
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Strips the trailing slash
  350. //-----------------------------------------------------------------------------
  351. void CUtlString::StripTrailingSlash()
  352. {
  353. if ( IsEmpty() )
  354. return;
  355. int nLastChar = Length() - 1;
  356. char c = m_Storage[ nLastChar ];
  357. if ( c == '\\' || c == '/' )
  358. {
  359. m_Storage[ nLastChar ] = 0;
  360. m_Storage.SetLength( m_Storage.Length() - 1 );
  361. }
  362. }
  363. CUtlString CUtlString::Slice( int32 nStart, int32 nEnd ) const
  364. {
  365. if ( nStart < 0 )
  366. nStart = Length() - (-nStart % Length());
  367. else if ( nStart >= Length() )
  368. nStart = Length();
  369. if ( nEnd == INT32_MAX )
  370. nEnd = Length();
  371. else if ( nEnd < 0 )
  372. nEnd = Length() - (-nEnd % Length());
  373. else if ( nEnd >= Length() )
  374. nEnd = Length();
  375. if ( nStart >= nEnd )
  376. return CUtlString( "" );
  377. const char *pIn = String();
  378. CUtlString ret;
  379. ret.m_Storage.SetLength( nEnd - nStart + 1 );
  380. char *pOut = (char*)ret.m_Storage.Get();
  381. memcpy( ret.m_Storage.Get(), &pIn[nStart], nEnd - nStart );
  382. pOut[nEnd - nStart] = 0;
  383. return ret;
  384. }
  385. // Grab a substring starting from the left or the right side.
  386. CUtlString CUtlString::Left( int32 nChars ) const
  387. {
  388. return Slice( 0, nChars );
  389. }
  390. CUtlString CUtlString::Right( int32 nChars ) const
  391. {
  392. return Slice( -nChars );
  393. }
  394. CUtlString CUtlString::Replace( char cFrom, char cTo ) const
  395. {
  396. CUtlString ret = *this;
  397. int len = ret.Length();
  398. for ( int i=0; i < len; i++ )
  399. {
  400. if ( ret.m_Storage[i] == cFrom )
  401. ret.m_Storage[i] = cTo;
  402. }
  403. return ret;
  404. }
  405. CUtlString CUtlString::AbsPath( const char *pStartingDir ) const
  406. {
  407. char szNew[MAX_PATH];
  408. V_MakeAbsolutePath( szNew, sizeof( szNew ), this->String(), pStartingDir );
  409. return CUtlString( szNew );
  410. }
  411. CUtlString CUtlString::UnqualifiedFilename() const
  412. {
  413. const char *pFilename = V_UnqualifiedFileName( this->String() );
  414. return CUtlString( pFilename );
  415. }
  416. CUtlString CUtlString::DirName() const
  417. {
  418. CUtlString ret( this->String() );
  419. V_StripLastDir( (char*)ret.m_Storage.Get(), ret.m_Storage.Length() );
  420. V_StripTrailingSlash( (char*)ret.m_Storage.Get() );
  421. return ret;
  422. }
  423. CUtlString CUtlString::PathJoin( const char *pStr1, const char *pStr2 )
  424. {
  425. char szPath[MAX_PATH];
  426. V_ComposeFileName( pStr1, pStr2, szPath, sizeof( szPath ) );
  427. return CUtlString( szPath );
  428. }
  429. CUtlString CUtlString::operator+( const char *pOther ) const
  430. {
  431. CUtlString s = *this;
  432. s += pOther;
  433. return s;
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose: concatenate the provided string to our current content
  437. //-----------------------------------------------------------------------------
  438. void CUtlString::Append( const char *pchAddition )
  439. {
  440. CUtlString s = *this;
  441. s += pchAddition;
  442. }