diff options
Diffstat (limited to 'mp/src/tier1/utlstring.cpp')
| -rw-r--r-- | mp/src/tier1/utlstring.cpp | 548 |
1 files changed, 548 insertions, 0 deletions
diff --git a/mp/src/tier1/utlstring.cpp b/mp/src/tier1/utlstring.cpp new file mode 100644 index 00000000..10920db9 --- /dev/null +++ b/mp/src/tier1/utlstring.cpp @@ -0,0 +1,548 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "tier1/utlstring.h"
+#include "tier1/strtools.h"
+#include <ctype.h>
+
+// NOTE: This has to be the last file included!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Base class, containing simple memory management
+//-----------------------------------------------------------------------------
+CUtlBinaryBlock::CUtlBinaryBlock( int growSize, int initSize )
+{
+ MEM_ALLOC_CREDIT();
+ m_Memory.Init( growSize, initSize );
+
+ m_nActualLength = 0;
+}
+
+CUtlBinaryBlock::CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Memory( (unsigned char*)pMemory, nSizeInBytes )
+{
+ m_nActualLength = nInitialLength;
+}
+
+CUtlBinaryBlock::CUtlBinaryBlock( const void* pMemory, int nSizeInBytes ) : m_Memory( (const unsigned char*)pMemory, nSizeInBytes )
+{
+ m_nActualLength = nSizeInBytes;
+}
+
+CUtlBinaryBlock::CUtlBinaryBlock( const CUtlBinaryBlock& src )
+{
+ Set( src.Get(), src.Length() );
+}
+
+void CUtlBinaryBlock::Get( void *pValue, int nLen ) const
+{
+ Assert( nLen > 0 );
+ if ( m_nActualLength < nLen )
+ {
+ nLen = m_nActualLength;
+ }
+
+ if ( nLen > 0 )
+ {
+ memcpy( pValue, m_Memory.Base(), nLen );
+ }
+}
+
+void CUtlBinaryBlock::SetLength( int nLength )
+{
+ MEM_ALLOC_CREDIT();
+ Assert( !m_Memory.IsReadOnly() );
+
+ m_nActualLength = nLength;
+ if ( nLength > m_Memory.NumAllocated() )
+ {
+ int nOverFlow = nLength - m_Memory.NumAllocated();
+ m_Memory.Grow( nOverFlow );
+
+ // If the reallocation failed, clamp length
+ if ( nLength > m_Memory.NumAllocated() )
+ {
+ m_nActualLength = m_Memory.NumAllocated();
+ }
+ }
+
+#ifdef _DEBUG
+ if ( m_Memory.NumAllocated() > m_nActualLength )
+ {
+ memset( ( ( char * )m_Memory.Base() ) + m_nActualLength, 0xEB, m_Memory.NumAllocated() - m_nActualLength );
+ }
+#endif
+}
+
+
+void CUtlBinaryBlock::Set( const void *pValue, int nLen )
+{
+ Assert( !m_Memory.IsReadOnly() );
+
+ if ( !pValue )
+ {
+ nLen = 0;
+ }
+
+ SetLength( nLen );
+
+ if ( m_nActualLength )
+ {
+ if ( ( ( const char * )m_Memory.Base() ) >= ( ( const char * )pValue ) + nLen ||
+ ( ( const char * )m_Memory.Base() ) + m_nActualLength <= ( ( const char * )pValue ) )
+ {
+ memcpy( m_Memory.Base(), pValue, m_nActualLength );
+ }
+ else
+ {
+ memmove( m_Memory.Base(), pValue, m_nActualLength );
+ }
+ }
+}
+
+
+CUtlBinaryBlock &CUtlBinaryBlock::operator=( const CUtlBinaryBlock &src )
+{
+ Assert( !m_Memory.IsReadOnly() );
+ Set( src.Get(), src.Length() );
+ return *this;
+}
+
+
+bool CUtlBinaryBlock::operator==( const CUtlBinaryBlock &src ) const
+{
+ if ( src.Length() != Length() )
+ return false;
+
+ return !memcmp( src.Get(), Get(), Length() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Simple string class.
+//-----------------------------------------------------------------------------
+CUtlString::CUtlString()
+{
+}
+
+CUtlString::CUtlString( const char *pString )
+{
+ Set( pString );
+}
+
+CUtlString::CUtlString( const CUtlString& string )
+{
+ Set( string.Get() );
+}
+
+// Attaches the string to external memory. Useful for avoiding a copy
+CUtlString::CUtlString( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Storage( pMemory, nSizeInBytes, nInitialLength )
+{
+}
+
+CUtlString::CUtlString( const void* pMemory, int nSizeInBytes ) : m_Storage( pMemory, nSizeInBytes )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Set directly and don't look for a null terminator in pValue.
+//-----------------------------------------------------------------------------
+void CUtlString::SetDirect( const char *pValue, int nChars )
+{
+ Assert( !m_Storage.IsReadOnly() );
+ m_Storage.Set( pValue, nChars + 1 );
+
+ // Make sure to null terminate the copied string
+ *(((char *)m_Storage.Get()) + nChars) = NULL;
+}
+
+
+void CUtlString::Set( const char *pValue )
+{
+ Assert( !m_Storage.IsReadOnly() );
+ int nLen = pValue ? Q_strlen(pValue) + 1 : 0;
+ m_Storage.Set( pValue, nLen );
+}
+
+
+// Returns strlen
+int CUtlString::Length() const
+{
+ return m_Storage.Length() ? m_Storage.Length() - 1 : 0;
+}
+
+// Sets the length (used to serialize into the buffer )
+void CUtlString::SetLength( int nLen )
+{
+ Assert( !m_Storage.IsReadOnly() );
+
+ // Add 1 to account for the NULL
+ m_Storage.SetLength( nLen > 0 ? nLen + 1 : 0 );
+}
+
+const char *CUtlString::Get( ) const
+{
+ if ( m_Storage.Length() == 0 )
+ {
+ return "";
+ }
+
+ return reinterpret_cast< const char* >( m_Storage.Get() );
+}
+
+// Converts to c-strings
+CUtlString::operator const char*() const
+{
+ return Get();
+}
+
+char *CUtlString::Get()
+{
+ Assert( !m_Storage.IsReadOnly() );
+
+ if ( m_Storage.Length() == 0 )
+ {
+ // In general, we optimise away small mallocs for empty strings
+ // but if you ask for the non-const bytes, they must be writable
+ // so we can't return "" here, like we do for the const version - jd
+ m_Storage.SetLength( 1 );
+ m_Storage[ 0 ] = '\0';
+ }
+
+ return reinterpret_cast< char* >( m_Storage.Get() );
+}
+
+void CUtlString::Purge()
+{
+ m_Storage.Purge();
+}
+
+
+void CUtlString::ToLower()
+{
+ for( int nLength = Length() - 1; nLength >= 0; nLength-- )
+ {
+ m_Storage[ nLength ] = tolower( m_Storage[ nLength ] );
+ }
+}
+
+
+void CUtlString::ToUpper()
+{
+ for( int nLength = Length() - 1; nLength >= 0; nLength-- )
+ {
+ m_Storage[ nLength ] = toupper( m_Storage[ nLength ] );
+ }
+}
+
+
+CUtlString &CUtlString::operator=( const CUtlString &src )
+{
+ Assert( !m_Storage.IsReadOnly() );
+ m_Storage = src.m_Storage;
+ return *this;
+}
+
+CUtlString &CUtlString::operator=( const char *src )
+{
+ Assert( !m_Storage.IsReadOnly() );
+ Set( src );
+ return *this;
+}
+
+bool CUtlString::operator==( const CUtlString &src ) const
+{
+ return m_Storage == src.m_Storage;
+}
+
+bool CUtlString::operator==( const char *src ) const
+{
+ return ( strcmp( Get(), src ) == 0 );
+}
+
+CUtlString &CUtlString::operator+=( const CUtlString &rhs )
+{
+ Assert( !m_Storage.IsReadOnly() );
+
+ const int lhsLength( Length() );
+ const int rhsLength( rhs.Length() );
+ const int requestedLength( lhsLength + rhsLength );
+
+ SetLength( requestedLength );
+ const int allocatedLength( Length() );
+ const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
+ memcpy( Get() + lhsLength, rhs.Get(), copyLength );
+ m_Storage[ allocatedLength ] = '\0';
+
+ return *this;
+}
+
+CUtlString &CUtlString::operator+=( const char *rhs )
+{
+ Assert( !m_Storage.IsReadOnly() );
+
+ const int lhsLength( Length() );
+ const int rhsLength( Q_strlen( rhs ) );
+ const int requestedLength( lhsLength + rhsLength );
+
+ SetLength( requestedLength );
+ const int allocatedLength( Length() );
+ const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
+ memcpy( Get() + lhsLength, rhs, copyLength );
+ m_Storage[ allocatedLength ] = '\0';
+
+ return *this;
+}
+
+CUtlString &CUtlString::operator+=( char c )
+{
+ Assert( !m_Storage.IsReadOnly() );
+
+ int nLength = Length();
+ SetLength( nLength + 1 );
+ m_Storage[ nLength ] = c;
+ m_Storage[ nLength+1 ] = '\0';
+ return *this;
+}
+
+CUtlString &CUtlString::operator+=( int rhs )
+{
+ Assert( !m_Storage.IsReadOnly() );
+ Assert( sizeof( rhs ) == 4 );
+
+ char tmpBuf[ 12 ]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ]
+ Q_snprintf( tmpBuf, sizeof( tmpBuf ), "%d", rhs );
+ tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
+
+ return operator+=( tmpBuf );
+}
+
+CUtlString &CUtlString::operator+=( double rhs )
+{
+ Assert( !m_Storage.IsReadOnly() );
+
+ char tmpBuf[ 256 ]; // How big can doubles be??? Dunno.
+ Q_snprintf( tmpBuf, sizeof( tmpBuf ), "%lg", rhs );
+ tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
+
+ return operator+=( tmpBuf );
+}
+
+bool CUtlString::MatchesPattern( const CUtlString &Pattern, int nFlags )
+{
+ const char *pszSource = String();
+ const char *pszPattern = Pattern.String();
+ bool bExact = true;
+
+ while( 1 )
+ {
+ if ( ( *pszPattern ) == 0 )
+ {
+ return ( (*pszSource ) == 0 );
+ }
+
+ if ( ( *pszPattern ) == '*' )
+ {
+ pszPattern++;
+
+ if ( ( *pszPattern ) == 0 )
+ {
+ return true;
+ }
+
+ bExact = false;
+ continue;
+ }
+
+ int nLength = 0;
+
+ while( ( *pszPattern ) != '*' && ( *pszPattern ) != 0 )
+ {
+ nLength++;
+ pszPattern++;
+ }
+
+ while( 1 )
+ {
+ const char *pszStartPattern = pszPattern - nLength;
+ const char *pszSearch = pszSource;
+
+ for( int i = 0; i < nLength; i++, pszSearch++, pszStartPattern++ )
+ {
+ if ( ( *pszSearch ) == 0 )
+ {
+ return false;
+ }
+
+ if ( ( *pszSearch ) != ( *pszStartPattern ) )
+ {
+ break;
+ }
+ }
+
+ if ( pszSearch - pszSource == nLength )
+ {
+ break;
+ }
+
+ if ( bExact == true )
+ {
+ return false;
+ }
+
+ if ( ( nFlags & PATTERN_DIRECTORY ) != 0 )
+ {
+ if ( ( *pszPattern ) != '/' && ( *pszSource ) == '/' )
+ {
+ return false;
+ }
+ }
+
+ pszSource++;
+ }
+
+ pszSource += nLength;
+ }
+}
+
+
+int CUtlString::Format( const char *pFormat, ... )
+{
+ Assert( !m_Storage.IsReadOnly() );
+
+ char tmpBuf[ 4096 ]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer
+
+ va_list marker;
+
+ va_start( marker, pFormat );
+#ifdef _WIN32
+ int len = _vsnprintf( tmpBuf, sizeof( tmpBuf ) - 1, pFormat, marker );
+#elif POSIX
+ int len = vsnprintf( tmpBuf, sizeof( tmpBuf ) - 1, pFormat, marker );
+#else
+#error "define vsnprintf type."
+#endif
+ va_end( marker );
+
+ // Len > maxLen represents an overflow on POSIX, < 0 is an overflow on windows
+ if( len < 0 || len >= sizeof( tmpBuf ) - 1 )
+ {
+ len = sizeof( tmpBuf ) - 1;
+ tmpBuf[sizeof( tmpBuf ) - 1] = 0;
+ }
+
+ Set( tmpBuf );
+
+ return len;
+}
+
+//-----------------------------------------------------------------------------
+// Strips the trailing slash
+//-----------------------------------------------------------------------------
+void CUtlString::StripTrailingSlash()
+{
+ if ( IsEmpty() )
+ return;
+
+ int nLastChar = Length() - 1;
+ char c = m_Storage[ nLastChar ];
+ if ( c == '\\' || c == '/' )
+ {
+ m_Storage[ nLastChar ] = 0;
+ m_Storage.SetLength( m_Storage.Length() - 1 );
+ }
+}
+
+CUtlString CUtlString::Slice( int32 nStart, int32 nEnd )
+{
+ if ( nStart < 0 )
+ nStart = Length() - (-nStart % Length());
+ else if ( nStart >= Length() )
+ nStart = Length();
+
+ if ( nEnd == 0x7FFFFFFF )
+ nEnd = Length();
+ else if ( nEnd < 0 )
+ nEnd = Length() - (-nEnd % Length());
+ else if ( nEnd >= Length() )
+ nEnd = Length();
+
+ if ( nStart >= nEnd )
+ return CUtlString( "" );
+
+ const char *pIn = String();
+
+ CUtlString ret;
+ ret.m_Storage.SetLength( nEnd - nStart + 1 );
+ char *pOut = (char*)ret.m_Storage.Get();
+
+ memcpy( ret.m_Storage.Get(), &pIn[nStart], nEnd - nStart );
+ pOut[nEnd - nStart] = 0;
+
+ return ret;
+}
+
+// Grab a substring starting from the left or the right side.
+CUtlString CUtlString::Left( int32 nChars )
+{
+ return Slice( 0, nChars );
+}
+
+CUtlString CUtlString::Right( int32 nChars )
+{
+ return Slice( -nChars );
+}
+
+CUtlString CUtlString::Replace( char cFrom, char cTo )
+{
+ CUtlString ret = *this;
+ int len = ret.Length();
+ for ( int i=0; i < len; i++ )
+ {
+ if ( ret.m_Storage[i] == cFrom )
+ ret.m_Storage[i] = cTo;
+ }
+
+ return ret;
+}
+
+CUtlString CUtlString::AbsPath( const char *pStartingDir )
+{
+ char szNew[MAX_PATH];
+ V_MakeAbsolutePath( szNew, sizeof( szNew ), this->String(), pStartingDir );
+ return CUtlString( szNew );
+}
+
+CUtlString CUtlString::UnqualifiedFilename()
+{
+ const char *pFilename = V_UnqualifiedFileName( this->String() );
+ return CUtlString( pFilename );
+}
+
+CUtlString CUtlString::DirName()
+{
+ CUtlString ret( this->String() );
+ V_StripLastDir( (char*)ret.m_Storage.Get(), ret.m_Storage.Length() );
+ V_StripTrailingSlash( (char*)ret.m_Storage.Get() );
+ return ret;
+}
+
+CUtlString CUtlString::PathJoin( const char *pStr1, const char *pStr2 )
+{
+ char szPath[MAX_PATH];
+ V_ComposeFileName( pStr1, pStr2, szPath, sizeof( szPath ) );
+ return CUtlString( szPath );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: concatenate the provided string to our current content
+//-----------------------------------------------------------------------------
+void CUtlString::Append( const char *pchAddition )
+{
+ *this += pchAddition;
+}
|