diff --git a/include/steamnetworkingsockets/isteamnetworkingsockets.h b/include/steamnetworkingsockets/isteamnetworkingsockets.h index bfda1dc..59afc1d 100644 --- a/include/steamnetworkingsockets/isteamnetworkingsockets.h +++ b/include/steamnetworkingsockets/isteamnetworkingsockets.h @@ -161,9 +161,8 @@ public: /// Set a name for the connection, used mostly for debugging virtual void SetConnectionName( HSteamNetConnection hPeer, const char *pszName ) = 0; - /// Fetch connection user data. Returns -1 if handle is invalid - /// or if you haven't set any userdata on the connection. - virtual void GetConnectionName( HSteamNetConnection hPeer, char *ppszName, int nMaxLen ) = 0; + /// Fetch connection name. Returns false if handle is invalid + virtual bool GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen ) = 0; /// Send a message to the remote host on the connected socket. /// diff --git a/src/meson.build b/src/meson.build index db69909..4cc34fb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -119,7 +119,6 @@ sources = [ 'tier1/netadr.cpp', 'tier1/utlbuffer.cpp', 'tier1/utlmemory.cpp', - 'tier1/utlstring.cpp', 'vstdlib/strtools.cpp', ] diff --git a/src/public/tier1/utlbuffer.h b/src/public/tier1/utlbuffer.h index 2c410b5..c4f6204 100644 --- a/src/public/tier1/utlbuffer.h +++ b/src/public/tier1/utlbuffer.h @@ -17,7 +17,7 @@ #include "tier1/utlmemory.h" #include "tier0/validator.h" #include -#include "tier1/utlstring.h" +//SDR_PUBLIC #include "tier1/utlstring.h" //----------------------------------------------------------------------------- // Description of character conversions for string output @@ -292,7 +292,7 @@ public: // Returns the base as a const char*, only valid in text mode. const char *String() const; // Copies the content of the buffer into a string (valid for binary and text mode). - void CopyToString( CUtlString &strText ) const; + //SDR_PUBLIC void CopyToString( CUtlString &strText ) const; // memory allocation size, does *not* reflect size written or read, // use TellPut or TellGet for that @@ -747,10 +747,10 @@ inline const char *CUtlBuffer::String() const return ""; } -inline void CUtlBuffer::CopyToString( CUtlString &strText ) const -{ - strText.SetDirect( (const char *)Base(), TellMaxPut() ); -} +//SDR_PUBLIC inline void CUtlBuffer::CopyToString( CUtlString &strText ) const +//SDR_PUBLIC { +//SDR_PUBLIC strText.SetDirect( (const char *)Base(), TellMaxPut() ); +//SDR_PUBLIC } inline int CUtlBuffer::Size() const // FIXME delete soon diff --git a/src/public/tier1/utlhashmap.h b/src/public/tier1/utlhashmap.h index 81de94f..b866f3b 100644 --- a/src/public/tier1/utlhashmap.h +++ b/src/public/tier1/utlhashmap.h @@ -15,7 +15,7 @@ #include "tier0/dbg.h" #include "tier1/bitstring.h" #include "tier1/generichash.h" -#include "tier1/utlstring.h" +//SDR_PUBLIC #include "tier1/utlstring.h" #include "tier1/utliterator.h" #include "tier1/utlvector.h" @@ -81,19 +81,19 @@ public: inline bool operator!() const { return false; } }; -// Specialization to compare char * AS strings -template <> -class CDefEquals < CUtlString > -{ -public: - CDefEquals() {} - CDefEquals( int i ) {} - inline bool operator()( CUtlString lhs, CUtlString rhs ) const - { - return (V_strcmp( lhs.String(), rhs.String() ) == 0); - } - inline bool operator!() const { return false; } -}; +//SDR_PUBLIC // Specialization to compare char * AS strings +//SDR_PUBLIC template <> +//SDR_PUBLIC class CDefEquals < CUtlString > +//SDR_PUBLIC { +//SDR_PUBLIC public: +//SDR_PUBLIC CDefEquals() {} +//SDR_PUBLIC CDefEquals( int i ) {} +//SDR_PUBLIC inline bool operator()( CUtlString lhs, CUtlString rhs ) const +//SDR_PUBLIC { +//SDR_PUBLIC return (V_strcmp( lhs.String(), rhs.String() ) == 0); +//SDR_PUBLIC } +//SDR_PUBLIC inline bool operator!() const { return false; } +//SDR_PUBLIC }; //----------------------------------------------------------------------------- // Purpose: Case insensitive const char * comparison diff --git a/src/public/tier1/utlstring.h b/src/public/tier1/utlstring.h deleted file mode 100644 index 7aa27d8..0000000 --- a/src/public/tier1/utlstring.h +++ /dev/null @@ -1,1765 +0,0 @@ -//====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ===== -// -// Purpose: -// -//============================================================================= - -#ifndef UTLSTRING_H -#define UTLSTRING_H -#ifdef _WIN32 -#pragma once -#endif - -#include "tier0/dbg.h" -#include "tier0/validator.h" -#include "tier0/platform.h" -#include "vstdlib/strtools.h" -#include "tier1/generichash.h" - - -#include "tier0/memdbgon.h" - -class CUtlString; -class CUtlStringBuilder; - -// -// Maximum number of allowable characters in a CUtlString. -// V_strlen and its ilk are currently coded to return an unsigned int, but -// in many places in the code it gets treated as a signed int -// -const uint k_cchMaxString = 0x7fff0000; - - -//----------------------------------------------------------------------------- -// Purpose: simple wrapper class around a char * -// relies on the small-block heap existing for efficient memory allocation -// as compact as possible, no virtuals or extraneous data -// to be used primarily to replace of char array buffers -// tries to match CUtlSymbol interface wherever possible -//----------------------------------------------------------------------------- -class CUtlString -{ -public: - CUtlString(); - CUtlString( const char *pchString ); - CUtlString( CUtlString const &string ); - explicit CUtlString( size_t nPreallocateBytes ); - ~CUtlString(); - - // operator= - CUtlString &operator=( CUtlString const &src ); - CUtlString &operator=( const char *pchString ); - - // operator== - bool operator==( CUtlString const &src ) const; - bool operator==( const char *pchString ) const; - - // operator!= - bool operator!=( CUtlString const &src ) const; - bool operator!=( const char *pchString ) const; - - // operator , performs case sensitive comparison - bool operator<( const CUtlString &val ) const; - bool operator<( const char *pchString ) const; - bool operator>( const CUtlString &val ) const; - bool operator>( const char *pchString ) const; - - // operator+= - CUtlString &operator+=( const char *rhs ); - - // is valid? - bool IsValid() const; - - // gets the string - // never returns NULL, use IsValid() to see if it's never been set - const char *String() const; - const char *Get() const { return String(); } - operator const char *() const { return String(); } - - // returns the string directly (could be NULL) - // useful for doing inline operations on the string - char *Access() { return m_pchString; } - - // If you want to take ownership of the ptr, you can use this. - char *DetachRawPtr() { char *psz = m_pchString; m_pchString = NULL; return psz; } - - // append in-place, causing a re-allocation - void Append( const char *pchAddition ); - void Append( const char *pchAddition, size_t cbLen ); - - // append in-place for a single or repeated run of characters - void AppendChar( char ch ) { Append( &ch, 1 ); } - void AppendRepeat( char ch, int cCount ); - - // sets the string - void SetValue( const char *pchString ); - void Set( const char *pchString ); - void Clear() { SetValue( NULL ); } - void SetPtr( char *pchString ); - void Swap( CUtlString &src ); - void Swap( CUtlStringBuilder &src ); - - void ToLower(); - void ToUpper(); - - void Wipe(); - - // Set directly and don't look for a null terminator in pValue. - void SetDirect( const char *pValue, size_t nChars ); - - // Get the length of the string in characters. - uint32 Length() const; - bool IsEmpty() const; - - // Format like sprintf. - size_t Format( PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 ); - - // format, then append what we crated in the format - size_t AppendFormat( PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 ); - - // convert bytes to hex string and append - void AppendHex( const uint8 *pbInput, size_t cubInput, bool bLowercase = true ); - - // replace a single character with another, returns hit count - size_t Replace( char chTarget, char chReplacement ); - - // replace a string with another string, returns hit count - // replacement string might be NULL or "" to remove target substring - size_t Replace( const char *pstrTarget, const char *pstrReplacement ); - size_t ReplaceCaseless( const char *pstrTarget, const char *pstrReplacement ); - - ptrdiff_t IndexOf( const char *pstrTarget ) const; - bool BEndsWith( const char *pchString ) const; - bool BEndsWithCaseless( const char *pchString ) const; - bool BStartsWith( const char *pchString ) const; - bool BStartsWithCaseless( const char *pchString ) const; - - // remove whitespace from the string; anything that is isspace() - size_t RemoveWhitespace( ); - - // trim whitespace from the beginning and end of the string - size_t TrimWhitespace(); - - // trim whitespace from the end of the string - size_t TrimTrailingWhitespace(); - - void SecureZero() { SecureZeroMemory( m_pchString, Length() ); } - -#ifdef DBGFLAG_VALIDATE - void Validate( CValidator &validator, const char *pchName ) const; // validate our internal structures -#endif // DBGFLAG_VALIDATE - - size_t FormatV( const char *pFormat, va_list args ); - size_t VAppendFormat( const char *pFormat, va_list args ); - void Truncate( size_t nChars ); - - // Both TruncateUTF8 methods guarantee truncation of the string to a length less-than-or-equal-to the - // specified number of bytes or characters. Both return false and truncate early if invalid UTF8 sequences - // are encountered before the cap is reached. - // As a result, the string is guaranteed to be valid UTF-8 upon completion of the operation. - bool TruncateUTF8Bytes( size_t unMaxBytes ) { return TruncateUTF8Internal( (size_t)-1, unMaxBytes ); } - bool TruncateUTF8Chars( size_t unMaxChars ) { return TruncateUTF8Internal( unMaxChars, (size_t)-1 ); } - -#ifdef VALVE_RVALUE_REFS - // Move construction, rvalue assignment from like type - CUtlString( CUtlString &&string ) : m_pchString( string.m_pchString ) { string.m_pchString = NULL; } - CUtlString &operator=( CUtlString &&string ) { Swap( string ); return *this; } - void Set( CUtlString &&string ) { Swap( string ); } - - // Move construction, rvalue assignment from CUtlStringBuilder - explicit CUtlString( CUtlStringBuilder &&string ); - CUtlString &operator=( CUtlStringBuilder &&string ); -#endif - -private: - bool TruncateUTF8Internal( size_t unMaxChars, size_t unMaxBytes ); - size_t ReplaceInternal( const char *pstrTarget, const char *pstrReplacement, const char *pfnCompare(const char*, const char*) ); - static void AssertStringTooLong(); - char *m_pchString; -}; - - -//----------------------------------------------------------------------------- -// Purpose: constructor -//----------------------------------------------------------------------------- -inline CUtlString::CUtlString() : m_pchString( NULL ) -{ -} - - -//----------------------------------------------------------------------------- -// Purpose: constructor -//----------------------------------------------------------------------------- -inline CUtlString::CUtlString( size_t nPreallocateBytes ) -{ - if ( nPreallocateBytes > 0 ) - { - if ( nPreallocateBytes > k_cchMaxString ) - AssertStringTooLong(); - m_pchString = (char*) PvAlloc( nPreallocateBytes ); - m_pchString[0] = 0; - } - else - { - m_pchString = NULL; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: constructor -//----------------------------------------------------------------------------- -inline CUtlString::CUtlString( const char *pchString ) : m_pchString( NULL ) -{ - SetValue( pchString ); -} - - -//----------------------------------------------------------------------------- -// Purpose: constructor -//----------------------------------------------------------------------------- -inline CUtlString::CUtlString( CUtlString const &string ) : m_pchString( NULL ) -{ - SetValue( string.String() ); -} - - -//----------------------------------------------------------------------------- -// Purpose: destructor -//----------------------------------------------------------------------------- -inline CUtlString::~CUtlString() -{ - FreePv( m_pchString ); -} - - -//----------------------------------------------------------------------------- -// Purpose: ask if the string has anything in it -//----------------------------------------------------------------------------- -inline bool CUtlString::IsEmpty() const -{ - if ( m_pchString == NULL ) - return true; - - return m_pchString[0] == 0; -} - - -//----------------------------------------------------------------------------- -// Purpose: assignment -//----------------------------------------------------------------------------- -inline CUtlString &CUtlString::operator=( const char *pchString ) -{ - SetValue( pchString ); - return *this; -} - - -//----------------------------------------------------------------------------- -// Purpose: assignment -//----------------------------------------------------------------------------- -inline CUtlString &CUtlString::operator=( CUtlString const &src ) -{ - SetValue( src.String() ); - return *this; -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlString::operator==( CUtlString const &src ) const -{ - return !V_strcmp( String(), src.String() ); -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlString::operator==( const char *pchString ) const -{ - return !V_strcmp( String(), pchString ); -} - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlString::operator!=( CUtlString const &src ) const -{ - return !( *this == src ); -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlString::operator!=( const char *pchString ) const -{ - return !( *this == pchString ); -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlString::operator<( CUtlString const &val ) const -{ - return operator<( val.String() ); -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlString::operator<( const char *pchString ) const -{ - return V_strcmp( String(), pchString ) < 0; -} - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlString::operator>( CUtlString const &val ) const -{ - return V_strcmp( String(), val.String() ) > 0; -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlString::operator>( const char *pchString ) const -{ - return V_strcmp( String(), pchString ) > 0; -} - - -//----------------------------------------------------------------------------- -// Return a string with this string and rhs joined together. -inline CUtlString& CUtlString::operator+=( const char *rhs ) -{ - Append( rhs ); - return *this; -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string is not null -//----------------------------------------------------------------------------- -inline bool CUtlString::IsValid() const -{ - return ( m_pchString != NULL ); -} - - -//----------------------------------------------------------------------------- -// Purpose: data accessor -//----------------------------------------------------------------------------- -inline const char *CUtlString::String() const -{ - return m_pchString ? m_pchString : ""; -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the string to be the new value, taking a copy of it -//----------------------------------------------------------------------------- -inline void CUtlString::SetValue( const char *pchString ) -{ - if ( m_pchString != pchString ) - { - FreePv( m_pchString ); - - if ( pchString && *pchString ) - { - size_t nLength = 1 + strlen( pchString ); - if ( nLength > k_cchMaxString ) - AssertStringTooLong( ); - m_pchString = (char*)PvAlloc( nLength ); - V_memcpy( m_pchString, pchString, nLength ); - } - else - { - m_pchString = NULL; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Converts the string to lower case in-place. Not necessarily clean -// about all possibly localization issues. -//----------------------------------------------------------------------------- -inline void CUtlString::ToLower() -{ - if ( m_pchString != NULL ) - { - for ( int i = 0; m_pchString[i]; i++ ) - { - m_pchString[i] = (char)tolower( (int)(unsigned char)m_pchString[i] ); - } - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Converts the string to upper case in-place. Not necessarily clean -// about all possibly localization issues. -//----------------------------------------------------------------------------- -inline void CUtlString::ToUpper() -{ - if ( m_pchString != NULL ) - { - for ( int i = 0; m_pchString[i]; i++ ) - { - m_pchString[i] = ( char )toupper( ( int )( unsigned char )m_pchString[i] ); - } - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Clear the string from memory, then free it. -//----------------------------------------------------------------------------- -inline void CUtlString::Wipe() -{ - // - // Overwrite the current buffer - // - if ( m_pchString ) - { - SecureZeroMemory( m_pchString, V_strlen( m_pchString ) ); - } - SetValue( NULL ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Set directly and don't look for a null terminator in pValue. -//----------------------------------------------------------------------------- -inline void CUtlString::SetDirect( const char *pValue, size_t nChars ) -{ - FreePv( m_pchString ); - m_pchString = NULL; - - if ( nChars > 0 ) - { - if ( nChars + 1 > k_cchMaxString ) - AssertStringTooLong(); - m_pchString = (char*)PvAlloc( nChars + 1 ); - V_memcpy( m_pchString, pValue, nChars ); - m_pchString[nChars] = 0; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the string to be the new value, taking a copy of it -//----------------------------------------------------------------------------- -inline void CUtlString::Set( const char *pchString ) -{ - SetValue( pchString ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the string to be the new value, taking ownership of the pointer -//----------------------------------------------------------------------------- -inline void CUtlString::SetPtr( char *pchString ) -{ - FreePv( m_pchString ); - m_pchString = pchString; -} - - -inline uint32 CUtlString::Length() const -{ - if ( !m_pchString ) - return 0; - - return (uint32) V_strlen( m_pchString ); -} - - -//----------------------------------------------------------------------------- -// Purpose: format something sprintf() style, and take it as the new value of this CUtlString -//----------------------------------------------------------------------------- -inline size_t CUtlString::Format( const char *pFormat, ... ) -{ - va_list args; - va_start( args, pFormat ); - size_t len = FormatV( pFormat, args ); - va_end( args ); - return len; -} - -//----------------------------------------------------------------------------- -// format a string and append the result to the string we hold -//----------------------------------------------------------------------------- -inline size_t CUtlString::AppendFormat( const char *pFormat, ... ) -{ - va_list args; - va_start( args, pFormat ); - size_t len = VAppendFormat( pFormat, args ); - va_end( args ); - return len; -} - -//----------------------------------------------------------------------------- -// Purpose: concatenate the provided string to our current content -//----------------------------------------------------------------------------- -inline void CUtlString::Append( const char *pchAddition ) -{ - if ( pchAddition && pchAddition[0] ) - { - size_t cchLen = V_strlen( pchAddition ); - Append( pchAddition, cchLen ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: concatenate the provided string to our current content -// when the additional string length is known -//----------------------------------------------------------------------------- -inline void CUtlString::Append( const char *pchAddition, size_t cbLen ) -{ - if ( m_pchString == NULL ) - { - SetDirect( pchAddition, cbLen ); - } - else if ( pchAddition && pchAddition[0] ) - { - size_t cbOld = V_strlen( m_pchString ); - if ( 1 + cbOld + cbLen > k_cchMaxString ) - AssertStringTooLong(); - char *pstrNew = (char *) PvAlloc( 1 + cbOld + cbLen ); - - V_memcpy( pstrNew, m_pchString, cbOld ); - V_memcpy( pstrNew + cbOld, pchAddition, cbLen ); - pstrNew[ cbOld + cbLen ] = '\0'; - - FreePv( m_pchString ); - m_pchString = pstrNew; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: repeat the passed character a specified number of times and -// concatenate those characters to our existing content -//----------------------------------------------------------------------------- -inline void CUtlString::AppendRepeat( char ch, int cCount ) -{ - if ( m_pchString == NULL ) - { - if ( cCount + 1 > k_cchMaxString ) - AssertStringTooLong(); - char *pchNew = (char *) PvAlloc( cCount + 1 ); - for ( int n = 0; n < cCount; n++ ) - pchNew[n] = ch; - pchNew[cCount] = 0; - m_pchString = pchNew; - } - else - { - size_t cbOld = strlen( m_pchString ); - if ( 1 + cbOld + cCount > k_cchMaxString ) - AssertStringTooLong(); - char *pchNew = (char *) PvAlloc( 1 + cbOld + cCount ); - - V_memcpy( pchNew, m_pchString, cbOld ); - for ( int n = 0; n < cCount; n++ ) - pchNew[n + cbOld] = ch; - pchNew[cCount + cbOld] = 0; - - FreePv( m_pchString ); - m_pchString = pchNew; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Swaps string contents -//----------------------------------------------------------------------------- -inline void CUtlString::Swap( CUtlString &src ) -{ - char *tmp = src.m_pchString; - src.m_pchString = m_pchString; - m_pchString = tmp; -} - - -//----------------------------------------------------------------------------- -// Purpose: replace all occurrences of one character with another -//----------------------------------------------------------------------------- -inline size_t CUtlString::Replace( char chTarget, char chReplacement ) -{ - size_t cReplacements = 0; - - if ( m_pchString != NULL ) - { - for ( char *pstrWalker = m_pchString; *pstrWalker != 0; pstrWalker++ ) - { - if ( *pstrWalker == chTarget ) - { - *pstrWalker = chReplacement; - cReplacements++; - } - } - } - - return cReplacements; -} - - -//----------------------------------------------------------------------------- -// Purpose: Truncates the string to the specified number of characters -//----------------------------------------------------------------------------- -inline void CUtlString::Truncate( size_t nChars ) -{ - if ( !m_pchString ) - return; - - size_t nLen = V_strlen( m_pchString ); - if ( nLen <= nChars ) - return; - - m_pchString[nChars] = '\0'; -} - - -//----------------------------------------------------------------------------- -// Data and memory validation -//----------------------------------------------------------------------------- -#ifdef DBGFLAG_VALIDATE -inline void CUtlString::Validate( CValidator &validator, const char *pchName ) const -{ -#ifdef _WIN32 - validator.Push( typeid(*this).raw_name(), (void*) this, pchName ); -#else - validator.Push( typeid(*this).name(), (void*) this, pchName ); -#endif - - if ( NULL != m_pchString ) - validator.ClaimMemory( m_pchString ); - - validator.Pop(); -} -#endif // DBGFLAG_VALIDATE - - -//----------------------------------------------------------------------------- -// Purpose: Case insensitive CUtlString comparison -//----------------------------------------------------------------------------- -class CDefCaselessUtlStringEquals -{ -public: - CDefCaselessUtlStringEquals() {} - CDefCaselessUtlStringEquals( int i ) {} - inline bool operator()( const CUtlString &lhs, const CUtlString &rhs ) const - { - return ( V_stricmp( lhs.String(), rhs.String() ) == 0 ); - } - inline bool operator!() const { return false; } -}; -class CDefCaselessUtlStringLess -{ -public: - CDefCaselessUtlStringLess() {} - CDefCaselessUtlStringLess( int i ) {} - inline bool operator()( const CUtlString &lhs, const CUtlString &rhs ) const - { - return ( V_stricmp( lhs.String(), rhs.String() ) < 0 ); - } - inline bool operator!() const { return false; } -}; - -// Hash specialization for CUtlStrings -template<> -struct HashFunctor -{ - uint32 operator()(const CUtlString &strKey) const - { - return HashString( strKey.String() ); - } -}; - -struct HashFunctorUtlStringCaseless -{ - typedef uint32 TargetType; - TargetType operator()(const CUtlString &strKey) const - { - return HashStringCaseless( strKey.String() ); - } -}; - -// HashItem() overload that works automatically with our hash containers -template<> -inline uint32 HashItem( const CUtlString &item ) -{ - return HashString( item ); -} - - -//----------------------------------------------------------------------------- -// Purpose: General purpose string class good for when it -// is rarely expected to be empty, and/or will undergo -// many modifications/appends. -//----------------------------------------------------------------------------- -class CUtlStringBuilder -{ -public: - CUtlStringBuilder(); - CUtlStringBuilder( const char *pchString ); - CUtlStringBuilder( CUtlStringBuilder const &string ); - explicit CUtlStringBuilder( size_t nPreallocateBytes ); - - ~CUtlStringBuilder(); - -#ifdef VALVE_RVALUE_REFS - // Create a new CUtlString by concatenating any number of arguments. This will call the - // appropriate += operator if one exists. - template < typename ...Types > - static CUtlString Concat( Types&&... args ) - { - CUtlStringBuilder sBuilder; - ConcatHelper( sBuilder, std::forward( args )... ); - return sBuilder.DetachString(); - } -#endif // VALVE_RVALUE_REFS - - // operator= - CUtlStringBuilder &operator=( const CUtlStringBuilder &src ); - CUtlStringBuilder &operator=( const char *pchString ); - - // operator== - bool operator==( CUtlStringBuilder const &src ) const; - bool operator==( const char *pchString ) const; - - // operator!= - bool operator!=( CUtlStringBuilder const &src ) const; - bool operator!=( const char *pchString ) const; - - // operator , performs case sensitive comparison - bool operator<( const CUtlStringBuilder &val ) const; - bool operator<( const char *pchString ) const; - bool operator>( const CUtlStringBuilder &val ) const; - bool operator>( const char *pchString ) const; - - // operator+= - CUtlStringBuilder &operator+=( const char *rhs ); - - // is valid? - bool IsValid() const; - - // gets the string - // never returns NULL, use IsValid() to see if it's never been set - const char *String() const; - const char *Get() const { return String(); } - operator const char *() const { return String(); } - - // returns the string directly (could be NULL) - // useful for doing inline operations on the string - char *Access() - { - // aggressive warning that there has been a bad error; - // probably should not be retrieving the string by pointer. - Assert(!m_data.HasError()); - - if ( !IsValid() || ( Capacity() == 0 ) ) - return NULL; - - return m_data.Access(); - } - - // return false if capacity can't be set. If false is returned, - // the error state is set. - bool EnsureCapacity( size_t nLength ); - - // append in-place, causing a re-allocation - void Append( const char *pchAddition ); - void Append( const char *pchAddition, size_t cbLen ); - void Append( const CUtlStringBuilder &str ) { Append( str.String(), str.Length() ); } - void AppendChar( char ch ) { Append( &ch, 1 ); } - void AppendRepeat( char ch, int cCount ); - - // sets the string - void SetValue( const char *pchString ); - void Set( const char *pchString ); - void Clear() { m_data.Clear(); } - void SetPtr( char *pchString ); - void SetPtr( char *pchString, size_t nLength ); - void Swap( CUtlStringBuilder &src ); - void Swap( CUtlString &src ); - - // Set directly and don't look for a null terminator in pValue. - // nChars is the string length. "abcd" nChars==3 would copy and null - // terminate "abc" in the string object. - void SetDirect( const char *pchString, size_t nChars ); - - // Get the length of the string in characters. - uint32 Length() const; - bool IsEmpty() const; - size_t Capacity() const { return m_data.Capacity(); } // how much room is there to scribble - - // Format like sprintf. - size_t Format( PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 ); - // format, then append what we crated in the format - size_t AppendFormat( PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 ); - - // convert bytes to hex string and append - void AppendHex( const uint8 *pbInput, size_t cubInput, bool bLowercase = true ); - - // replace a single character with another, returns hit count - size_t Replace( char chTarget, char chReplacement ); - - // replace a string with another string, returns hit count - // replacement string might be NULL or "" to remove target substring - size_t Replace( const char *pstrTarget, const char *pstrReplacement ); - size_t ReplaceCaseless( const char *pstrTarget, const char *pstrReplacement ); - - ptrdiff_t IndexOf( const char *pstrTarget ) const; - bool BEndsWith( const char *pchString ) const; - bool BEndsWithCaseless( const char *pchString ) const; - bool BStartsWith( const char *pchString ) const; - bool BStartsWithCaseless( const char *pchString ) const; - - // remove whitespace from the string; anything that is isspace() - size_t RemoveWhitespace( ); - - // trim whitespace from the beginning and end of the string - size_t TrimWhitespace( ); - - // trim whitespace from the end of the string - size_t TrimTrailingWhitespace(); - - // Allows setting the size to anything under the current - // capacity. Typically should not be used unless there was a specific - // reason to scribble on the string. Will not touch the string contents, - // but will append a NULL. Returns true if the length was changed. - bool SetLength( size_t nLen ); - - // Transfer ownership to a PvAlloc-allocated string, clearing internal contents. - char *DetachRawPtr( size_t *pnLen = NULL, size_t *pnCapacity = NULL ); - - // Transfer ownership to an anonymous CUtlString, clearing internal contents. - // Can be efficiently implemented by compilers that support C++11 rvalue refs. - CUtlString DetachString(); - - // For operations that are long and/or complex - if something fails - // along the way, the error will be set and can be queried at the end. - // The string is undefined in the error state, but will likely hold the - // last value before the error occurred. The string is cleared - // if ClearError() is called. The error can be set be the user, and it - // will also be set if a dynamic allocation fails in string operations - // where it needs to grow the capacity. - void SetError() { m_data.SetError(true); } - void ClearError() { m_data.ClearError(); } - bool HasError() const { return m_data.HasError(); } - -#ifdef DBGFLAG_VALIDATE - void Validate( CValidator &validator, const char *pchName ) const; // validate our internal structures -#endif // DBGFLAG_VALIDATE - - size_t VFormat( const char *pFormat, va_list args ); - size_t VAppendFormat( const char *pFormat, va_list args ); - void Truncate( size_t nChars ); - - // Access() With no assertion check - should only be used for tests - char *AccessNoAssert() - { - if ( !IsValid() ) - return NULL; - return m_data.Access(); - } - - // SetError() With no assertion check - should only be used for tests - void SetErrorNoAssert() { m_data.SetError(false); } - -#ifdef VALVE_RVALUE_REFS - // Move construction, rvalue assignment from same type - CUtlStringBuilder( CUtlStringBuilder &&string ) { m_data.Raw = string.m_data.Raw; string.m_data.Construct(); } - CUtlStringBuilder &operator=( CUtlStringBuilder &&string ) { Swap( string ); return *this; } - void Set( CUtlStringBuilder &&string ) { Swap( string ); } - - // Move construction, rvalue assignment from CUtlString - explicit CUtlStringBuilder( CUtlString &&string ) { m_data.Construct(); Swap( string ); } - CUtlStringBuilder &operator=( CUtlString &&string ) { Swap( string ); return *this; } - void Set( CUtlString &&string ) { Swap( string ); } -#endif - -private: -#ifdef VALVE_RVALUE_REFS - // Append one element to our string builder at a time. Supports any argument type that CUtlStringBuilder += - // supports. - template < typename FirstType, typename ...Types > - static void ConcatHelper( CUtlStringBuilder& sBuilder, FirstType&& arg, Types&&... args ) - { - sBuilder += arg; - return ConcatHelper( sBuilder, std::forward( args )... ); - } - - // Empty recursive end for when we run out of varargs. - static void ConcatHelper( CUtlStringBuilder& sBuilder ) { } -#endif // VALVE_RVALUE_REFS - - size_t ReplaceInternal( const char *pstrTarget, const char *pstrReplacement, const char *pfnCompare(const char*, const char*) ); - operator bool () const { return IsValid(); } - - // nChars is the number of characters you want, NOT including the null - char *PrepareBuffer( size_t nChars, bool bCopyOld = false, size_t nMinCapacity = 0 ) - { - char *pszString = NULL; - size_t nCapacity = m_data.Capacity(); - if ( ( nChars <= nCapacity ) && ( nMinCapacity <= nCapacity ) ) - { - // early out leaving it all alone, just update the length, - // even if it shortens an existing heap string to a width - // that would fit in the stack buffer. - pszString = m_data.SetLength( nChars ); - - // SetLength will have added the null. Pointer might - // be NULL if there is an error state and no buffer - Assert( !pszString || pszString[nChars] == '\0' ); - - return pszString; - } - - if ( HasError() ) - return NULL; - - // Need to actually adjust the capacity - return InternalPrepareBuffer( nChars, bCopyOld, Max( nChars, nMinCapacity ) ); - } - - char *InternalPrepareBuffer( size_t nChars, bool bCopyOld, size_t nMinCapacity ); - - enum - { - // These are set as bitflags in the sentinel byte (aka space-remaining byte) of Data - STRING_TYPE_SENTINEL = 0x80, - STRING_TYPE_ERROR = 0x40, - - // The max length of a string changes depending on 32- or 64-bit struct definitions - MAX_STACK_STRLEN = ( sizeof(void*) == 4 ? 15 : 23 ) - }; - - union Data - { - struct _Raw - { - // 16 bytes on 32-bit, 24 bytes on 64-bit - uintp m_raw[ sizeof(void*) == 4 ? 4 : 3 ]; - } Raw; - - struct _Heap - { // sentinel == 0xff if Heap is the active union item - private: - char *m_pchString; - uint32 m_nLength; - uint32 m_nCapacity; // without trailing null; ie: m_pchString[m_nCapacity] = '\0' is not out of bounds - uint8 scrap[sizeof(void*)-1]; - uint8 sentinel; - public: - friend union Data; - friend char *CUtlStringBuilder::InternalPrepareBuffer(size_t, bool, size_t); - } Heap; - - struct _Stack - { - private: - // last byte is doing a hack double duty. It holds how many bytes - // are left in the string; so when the string is 'full' it will be - // '0' and thus suffice as the terminating null. This is why - // we hold remaining chars instead of 'string length' - char m_szString[MAX_STACK_STRLEN+1]; - public: - uint8 BytesLeft() const { return (uint8)(m_szString[MAX_STACK_STRLEN]); } - void SetBytesLeft( char n ) { m_szString[MAX_STACK_STRLEN] = n; } - - friend char *CUtlStringBuilder::InternalPrepareBuffer(size_t, bool, size_t); - friend union Data; - } Stack; - - // set to a clear state without looking at the current state - void Construct() - { - Stack.m_szString[0] = '\0'; - Stack.SetBytesLeft( MAX_STACK_STRLEN ); - } - - // If we have heap allocated data, free it - void FreeHeap() - { - if ( IsHeap() ) - FreePv( Heap.m_pchString ); - } - - // Back to a clean state, but retain the error state. - void Clear() - { - if ( HasError() ) - return; - - FreeHeap(); - Heap.m_pchString = NULL; - - Construct(); - } - - bool IsHeap() const { return ( (Heap.sentinel & STRING_TYPE_SENTINEL) != 0 ); } - - char *Access() { return IsHeap() ? Heap.m_pchString : Stack.m_szString; } - const char *String() const { return IsHeap() ? Heap.m_pchString : Stack.m_szString; } - - size_t Length() const { return IsHeap() ? Heap.m_nLength : ( (size_t)MAX_STACK_STRLEN - Stack.BytesLeft() ); } - bool IsEmpty() const - { - if ( IsHeap() ) - return Heap.m_nLength == 0; - else - return Stack.BytesLeft() == (uint8)MAX_STACK_STRLEN; // empty if all the bytes are available - } - - size_t Capacity() const { return IsHeap() ? Heap.m_nCapacity : (size_t)MAX_STACK_STRLEN; } - - // Internally the code often needs the char * after setting the length, so just return it - // from here for conveniences. Returns NULL if nChars is invalid (larger than capacity). - char *SetLength( size_t nChars ); - - // Give the string away and set to an empty state - char *DetachHeapString( size_t &nLen, size_t &nCapacity ); - - void SetPtr( char *pchString, size_t nLength ); - - // Set the string to an error state - void SetError( bool bEnableAssert ); - - // clear the error state and reset the string - void ClearError(); - - // If string is in the heap and the error bit is set in the sentinel - // the error state is true. - bool HasError() const { return IsHeap() && ( (Heap.sentinel & STRING_TYPE_ERROR) != 0 ); } - - // If it's stack based, get it to the heap and return if it is - // successfully on the heap (or already was) - bool MoveToHeap(); - - private: - //----------------------------------------------------------------------------- - // Purpose: Needed facts for string class to work - //----------------------------------------------------------------------------- - void StaticAssertTests() - { - // If this fails when the heap sentinel and where the stack string stores its bytes left - // aren't aliases. This is needed so that regardless of how the 'sentinel' to mark - // that the string is on the heap is set, it is set as expected on both sides of the union. - COMPILE_TIME_ASSERT( offsetof( _Heap, sentinel ) == (offsetof( _Stack, m_szString ) + MAX_STACK_STRLEN) ); - COMPILE_TIME_ASSERT( sizeof( _Heap ) == sizeof( _Stack ) ); - COMPILE_TIME_ASSERT( sizeof( _Stack ) == sizeof( _Raw ) ); - - // Lots of code assumes it can look at m_data.Stack.m_nBytesLeft for an empty string; which - // means that it will equal MAX_STACK_STRLEN. Therefor it must be a different value than - // the STRING_TYPE_SENTINEL which will be set if the string is in the heap. - COMPILE_TIME_ASSERT( MAX_STACK_STRLEN < STRING_TYPE_SENTINEL ); - COMPILE_TIME_ASSERT( MAX_STACK_STRLEN < STRING_TYPE_ERROR ); - - // this is a no brainer, and I don't know anywhere in the world this isn't true, - // but this code does take this dependency. - COMPILE_TIME_ASSERT( 0 == '\0'); - } - }; - -private: // data - Data m_data; - - friend class CUtlString; -}; - -//----------------------------------------------------------------------------- -// Purpose: constructor -//----------------------------------------------------------------------------- -inline CUtlStringBuilder::CUtlStringBuilder() -{ - m_data.Construct(); -} - - -//----------------------------------------------------------------------------- -// Purpose: constructor -//----------------------------------------------------------------------------- -inline CUtlStringBuilder::CUtlStringBuilder( size_t nPreallocateBytes ) -{ - if ( nPreallocateBytes <= MAX_STACK_STRLEN ) - { - m_data.Construct(); - } - else - { - m_data.Construct(); - PrepareBuffer( 0, false, nPreallocateBytes ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: constructor -//----------------------------------------------------------------------------- -inline CUtlStringBuilder::CUtlStringBuilder( const char *pchString ) -{ - m_data.Construct(); - SetDirect( pchString, pchString ? strlen( pchString ) : 0 ); -} - - -//----------------------------------------------------------------------------- -// Purpose: constructor -//----------------------------------------------------------------------------- -inline CUtlStringBuilder::CUtlStringBuilder( CUtlStringBuilder const &string ) -{ - m_data.Construct(); - SetDirect( string.String(), string.Length() ); - - // attempt the copy before checking for error. On the off chance there - // is data there that can be set, it will help with debugging. - if ( string.HasError() ) - m_data.SetError( false ); -} - - -//----------------------------------------------------------------------------- -// Purpose: destructor -//----------------------------------------------------------------------------- -inline CUtlStringBuilder::~CUtlStringBuilder() -{ - m_data.FreeHeap(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Pre-Widen a string to an expected length -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::EnsureCapacity( size_t nLength ) -{ - return PrepareBuffer( Length(), true, nLength ) != NULL; -} - - -//----------------------------------------------------------------------------- -// Purpose: ask if the string has anything in it -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::IsEmpty() const -{ - return m_data.IsEmpty(); -} - -//----------------------------------------------------------------------------- -// Purpose: assignment -//----------------------------------------------------------------------------- -inline CUtlStringBuilder &CUtlStringBuilder::operator=( const char *pchString ) -{ - SetDirect( pchString, pchString ? strlen( pchString ) : 0 ); - return *this; -} - -//----------------------------------------------------------------------------- -// Purpose: assignment -//----------------------------------------------------------------------------- -inline CUtlStringBuilder &CUtlStringBuilder::operator=( CUtlStringBuilder const &src ) -{ - if ( &src != this ) - { - SetDirect( src.String(), src.Length() ); - // error propagate - if ( src.HasError() ) - m_data.SetError( false ); - } - - return *this; -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::operator==( CUtlStringBuilder const &src ) const -{ - return !V_strcmp( String(), src.String() ); -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::operator==( const char *pchString ) const -{ - return !V_strcmp( String(), pchString ); -} - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::operator!=( CUtlStringBuilder const &src ) const -{ - return !( *this == src ); -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::operator!=( const char *pchString ) const -{ - return !( *this == pchString ); -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::operator<( CUtlStringBuilder const &val ) const -{ - return operator<( val.String() ); -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::operator<( const char *pchString ) const -{ - return V_strcmp( String(), pchString ) < 0; -} - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::operator>( CUtlStringBuilder const &val ) const -{ - return V_strcmp( String(), val.String() ) > 0; -} - - -//----------------------------------------------------------------------------- -// Purpose: comparison -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::operator>( const char *pchString ) const -{ - return V_strcmp( String(), pchString ) > 0; -} - - -//----------------------------------------------------------------------------- -// Return a string with this string and rhs joined together. -inline CUtlStringBuilder& CUtlStringBuilder::operator+=( const char *rhs ) -{ - Append( rhs ); - return *this; -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string is not null -//----------------------------------------------------------------------------- -inline bool CUtlStringBuilder::IsValid() const -{ - return !HasError(); -} - - -//----------------------------------------------------------------------------- -// Purpose: data accessor -//----------------------------------------------------------------------------- -inline const char *CUtlStringBuilder::String() const -{ - const char *pszString = m_data.String(); - if ( pszString ) - return pszString; - - // pszString can be NULL in the error state. For const char* - // never return NULL. - return ""; -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the string to be the new value, taking a copy of it -//----------------------------------------------------------------------------- -inline void CUtlStringBuilder::SetValue( const char *pchString ) -{ - size_t nLen = ( pchString ? strlen( pchString ) : 0 ); - SetDirect( pchString, nLen ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Set directly and don't look for a null terminator in pValue. -//----------------------------------------------------------------------------- -inline void CUtlStringBuilder::SetDirect( const char *pchSource, size_t nChars ) -{ - if ( HasError() ) - return; - - if ( m_data.IsHeap() && Get() == pchSource ) - return; - - if ( !pchSource || !nChars ) - { - m_data.Clear(); - return; - } - - char *pszString = PrepareBuffer( nChars ); - - if ( pszString ) - { - V_memcpy( pszString, pchSource, nChars ); - // PrepareBuffer already allocated space for the terminating null, - // and inserted it for us. Make sure we didn't clobber it. - // Also assign it anyways so we don't risk the caller having a buffer - // running into random bytes. -#ifdef _DEBUG - // Suppress a bogus noisy warning: - // warning C6385: Invalid data: accessing 'pszString', the readable size is 'nChars' bytes, but '1001' bytes might be read - ANALYZE_SUPPRESS(6385); - Assert( pszString[nChars] == '\0' ); - pszString[nChars] = '\0'; -#endif - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the string to be the new value, taking a copy of it -//----------------------------------------------------------------------------- -inline void CUtlStringBuilder::Set( const char *pchString ) -{ - SetValue( pchString ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the string to be the new value, taking ownership of the pointer -//----------------------------------------------------------------------------- -inline void CUtlStringBuilder::SetPtr( char *pchString ) -{ - size_t nLength = pchString ? strlen( pchString ) : 0; - SetPtr( pchString, nLength ); -} - -//----------------------------------------------------------------------------- -// Purpose: Sets the string to be the new value, taking ownership of the pointer -// This API will clear the error state if it was set. -//----------------------------------------------------------------------------- -inline void CUtlStringBuilder::SetPtr( char *pchString, size_t nLength ) -{ - m_data.Clear(); - - if ( !pchString || !nLength ) - { - FreePv( pchString ); // we don't hang onto empty strings. - return; - } - - m_data.SetPtr( pchString, nLength ); -} - -//----------------------------------------------------------------------------- -// Purpose: return the conceptual 'strlen' of the string. -//----------------------------------------------------------------------------- -inline uint32 CUtlStringBuilder::Length() const -{ - return (uint32)m_data.Length(); -} - - -//----------------------------------------------------------------------------- -// Purpose: format something sprintf() style, and take it as the new value of this CUtlStringBuilder -//----------------------------------------------------------------------------- -inline size_t CUtlStringBuilder::Format( const char *pFormat, ... ) -{ - va_list args; - va_start( args, pFormat ); - size_t nLen = VFormat( pFormat, args ); - va_end( args ); - return nLen; -} - - -//----------------------------------------------------------------------------- -// Purpose: Helper for Format() method -//----------------------------------------------------------------------------- -inline size_t CUtlStringBuilder::VFormat( const char *pFormat, va_list args ) -{ - if ( HasError() ) - return 0; - - int len = 0; -#ifdef _WIN32 - // how much space will we need? - len = _vscprintf( pFormat, args ); -#else - - // ISO spec defines the NULL/0 case as being valid and will return the - // needed length. Verified on PS3 as well. Ignore that bsd/linux/mac - // have vasprintf which will allocate a buffer. We'd rather have the - // self growing buffer management ourselves. Even the best implementations - // There does not seem to be a magic vasprintf that is significantly - // faster than 2 passes (some guess and get lucky). - - // Scope ReuseArgs. - { - CReuseVaList ReuseArgs( args ); - len = vsnprintf( NULL, 0, pFormat, ReuseArgs.m_ReuseList ); - } -#endif - if ( len > 0 ) - { - // get it - char *pszString = PrepareBuffer( len, true ); - if ( pszString ) - len = _vsnprintf( pszString, len + 1, pFormat, args ); - else - len = 0; - } - - Assert( len > 0 || HasError() ); - return len; -} - - -//----------------------------------------------------------------------------- -// format a string and append the result to the string we hold -//----------------------------------------------------------------------------- -inline size_t CUtlStringBuilder::AppendFormat( const char *pFormat, ... ) -{ - va_list args; - va_start( args, pFormat ); - size_t nLen = VAppendFormat( pFormat, args ); - va_end( args ); - return nLen; -} - - - -//----------------------------------------------------------------------------- -// Purpose: implementation helper for AppendFormat() -//----------------------------------------------------------------------------- -inline size_t CUtlStringBuilder::VAppendFormat( const char *pFormat, va_list args ) -{ - if ( HasError() ) - return 0; - - int len = 0; -#ifdef _WIN32 - // how much space will we need? - len = _vscprintf( pFormat, args ); -#else - - // ISO spec defines the NULL/0 case as being valid and will return the - // needed length. Verified on PS3 as well. Ignore that bsd/linux/mac - // have vasprintf which will allocate a buffer. We'd rather have the - // self growing buffer management ourselves. Even the best implementations - // There does not seem to be a magic vasprintf that is significantly - // faster than 2 passes (some guess and get lucky). - - // Scope ReuseArgs. - { - CReuseVaList ReuseArgs( args ); - len = vsnprintf( NULL, 0, pFormat, ReuseArgs.m_ReuseList ); - } -#endif - size_t nOldLen = Length(); - - if ( len > 0 ) - { - // get it - - char *pszString = PrepareBuffer( nOldLen + len, true ); - if ( pszString ) - len = _vsnprintf( &pszString[nOldLen], len + 1, pFormat, args ); - else - len = 0; - } - - Assert( len > 0 || HasError() ); - return nOldLen + len; -} - -//----------------------------------------------------------------------------- -// Purpose: concatenate the provided string to our current content -//----------------------------------------------------------------------------- -inline void CUtlStringBuilder::Append( const char *pchAddition ) -{ - if ( pchAddition && pchAddition[0] ) - { - size_t cchLen = strlen( pchAddition ); - Append( pchAddition, cchLen ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: concatenate the provided string to our current content -// when the additional string length is known -//----------------------------------------------------------------------------- -inline void CUtlStringBuilder::Append( const char *pchAddition, size_t cbLen ) -{ - if ( pchAddition && cbLen ) - { - if ( IsEmpty() ) - { - SetDirect( pchAddition, cbLen ); - } - else - { - size_t cbOld = Length(); - char *pstrNew = PrepareBuffer( cbOld + cbLen, true ); - - if ( pstrNew ) - V_memcpy( pstrNew + cbOld, pchAddition, cbLen ); - } - } -} - - -//----------------------------------------------------------------------------- -// Purpose: append a repeated series of a single character -//----------------------------------------------------------------------------- -inline void CUtlStringBuilder::AppendRepeat( char ch, int cCount ) -{ - size_t cbOld = Length(); - char *pstrNew = PrepareBuffer( cbOld + cCount, true ); - if ( pstrNew ) - memset( pstrNew + cbOld, ch, cCount ); -} - - -//----------------------------------------------------------------------------- -// Data and memory validation -//----------------------------------------------------------------------------- -#ifdef DBGFLAG_VALIDATE -inline void CUtlStringBuilder::Validate( CValidator &validator, const char *pchName ) const -{ -#ifdef _WIN32 - validator.Push( typeid(*this).raw_name(), (void*) this, pchName ); -#else - validator.Push( typeid(*this).name(), (void*) this, pchName ); -#endif - - if ( m_data.IsHeap() ) - validator.ClaimMemory( (void*) m_data.String() ); - - validator.Pop(); -} -#endif // DBGFLAG_VALIDATE - - -//----------------------------------------------------------------------------- - - - -//----------------------------------------------------------------------------- -// The CUtlFmtString class: -// Simple helper class to create a format string from a constructor -// placed in its own class to avoid ambiguous calls to constructor -//----------------------------------------------------------------------------- -class CUtlFmtString : public CUtlStringBuilder -{ -public: - CUtlFmtString( PRINTF_FORMAT_STRING const char *pchFormat, ... ) FMTFUNCTION( 2, 3 ) - { - va_list args; - va_start( args, pchFormat ); - VFormat( pchFormat, args ); - va_end( args ); - } -}; - - -//----------------------------------------------------------------------------- -// Purpose: version of CUtlString that will zero it's memory on destruct -//----------------------------------------------------------------------------- -class CUtlStringAutoWipe : public CUtlString -{ -public: - CUtlStringAutoWipe() : CUtlString() {} - CUtlStringAutoWipe( const char *pchString ) : CUtlString( pchString ) {} - CUtlStringAutoWipe( CUtlString const &string ) : CUtlString( string ) {} - ~CUtlStringAutoWipe() - { - Wipe(); - } -}; - - -//----------------------------------------------------------------------------- -// The CUtlStringWrap class: -// Transforms a const char* string into a const CUtlString object without -// performing any buffer allocations or string copies. Can be passed -// wherever a const CUtlString parameter is expected. -//----------------------------------------------------------------------------- -class CUtlStringWrap -{ -public: - explicit CUtlStringWrap( const char * pszString ) - { - m_str.SetPtr( const_cast( pszString ) ); - } - - ~CUtlStringWrap() - { - m_str.DetachRawPtr(); - } - - operator const CUtlString & () const - { - return m_str; - } - -private: - CUtlString m_str; -}; - - -//----------------------------------------------------------------------------- -// The CUtlAllocation class: -// A single allocation in the style of CUtlMemory/CUtlString/CUtlBuffer -// as compact as possible, no virtuals or extraneous data -// to be used primarily to replace CUtlBuffer -//----------------------------------------------------------------------------- -class CUtlAllocation -{ -public: - - // constructor, destructor - CUtlAllocation() - { - m_pMemory = NULL; - } - CUtlAllocation( const void *pMemory, int cub ) - { - m_pMemory = NULL; - Copy( pMemory, cub ); - } - CUtlAllocation( CUtlAllocation const &src ) - { - m_pMemory = NULL; - Copy( src ); - } - ~CUtlAllocation() - { - Purge(); - } - - CUtlAllocation &operator=( CUtlAllocation const &src ) - { - Copy( src ); - return *this; - } - - bool operator==( CUtlAllocation const &src ) - { - if ( Count() != src.Count() ) - return false; - return V_memcmp( Base(), src.Base(), Count() ) == 0; - } - - void Copy( const void *pMemory, int cub ) - { - if ( cub == 0 || pMemory == NULL ) - { - Purge(); - return; - } - if ( cub != Count() ) - { - Purge(); - m_pMemory = (ActualMemory_t *)PvAlloc( cub + sizeof( int ) ); - m_pMemory->cub = cub; - } - V_memcpy( Base(), pMemory, cub ); - } - // Gets the base address - uint8* Base() - { - if ( m_pMemory == NULL ) - return NULL; - return m_pMemory->rgub; - } - const uint8* Base() const - { - if ( m_pMemory == NULL ) - return NULL; - return m_pMemory->rgub; - } - - // Size - int Count() const - { - if ( m_pMemory == NULL ) - return 0; - return m_pMemory->cub; - } - - // Memory deallocation - void Purge() - { - FreePv( m_pMemory ); - m_pMemory = NULL; - } - - void Copy( const CUtlAllocation &alloc ) - { - Copy( alloc.Base(), alloc.Count() ); - } - - void Swap( CUtlAllocation &alloc ) - { - ActualMemory_t *pTemp = m_pMemory; - m_pMemory = alloc.m_pMemory; - alloc.m_pMemory = pTemp; - } - - void Alloc( int cub ) - { - Purge(); - m_pMemory = (ActualMemory_t *)PvAlloc( cub + sizeof( int ) ); - m_pMemory->cub = cub; - } - -#ifdef DBGFLAG_VALIDATE - void Validate( CValidator &validator, const char *pchName ) - { - validator.Push( "CUtlAllocation", this, pchName ); - - if ( NULL != m_pMemory ) - validator.ClaimMemory( m_pMemory ); - - validator.Pop(); - } -#endif // DBGFLAG_VALIDATE - -private: - struct ActualMemory_t - { - int cub; - uint8 rgub[4]; // i'd prefer to make this 0 but the compiler whines when i do - }; - - ActualMemory_t *m_pMemory; -}; - -// Hash specialization for CUtlStringBuilders -template<> -struct HashFunctor -{ - uint32 operator()(const CUtlStringBuilder &strKey) const - { - return HashString( strKey.String(), strKey.Length() ); - } -}; - -#endif // UTLSTRING_H diff --git a/src/steamnetworkingsockets/certtool/steamnetworkingsockets_certtool.cpp b/src/steamnetworkingsockets/certtool/steamnetworkingsockets_certtool.cpp index 04e5b4f..19906fa 100644 --- a/src/steamnetworkingsockets/certtool/steamnetworkingsockets_certtool.cpp +++ b/src/steamnetworkingsockets/certtool/steamnetworkingsockets_certtool.cpp @@ -11,7 +11,6 @@ #include "../steamnetworkingsockets_internal.h" #include "crypto.h" #include "keypair.h" -#include #include //#include "curl/curl.h" @@ -116,21 +115,23 @@ void GenKeyPair() DbgVerify( nKeyID != 0 ); // Generate the key comment - CUtlStringBuilder szComment; + std::string sComment; for ( uint32 id: s_vecDataCenterIDs ) { char szTemp[ 8 ]; GetSteamNetworkingLocationPOPStringFromID( id, szTemp ); - szComment.AppendFormat( "%s-", szTemp ); + sComment += szTemp; + sComment += '-'; } - // AppID? - szComment.AppendFormat( "ID%llu", nKeyID ); + // Key ID + sComment += "ID"; + sComment += nKeyID; uint32 cbText = 0; char text[ 16000 ]; - DbgVerify( s_keyCertPub.GetAsOpenSSHAuthorizedKeys( text, sizeof(text), &cbText, szComment.String() ) ); + DbgVerify( s_keyCertPub.GetAsOpenSSHAuthorizedKeys( text, sizeof(text), &cbText, sComment.c_str() ) ); Msg( "\nPublic key:\n" ); Msg( "%s\n", text ); @@ -156,8 +157,10 @@ void GenKeyPair() static const char k_szSDRCertPEMHeader[] = "-----BEGIN STEAMDATAGRAM CERT-----"; static const char k_szSDRCertPEMFooter[] = "-----END STEAMDATAGRAM CERT-----"; -void PrintCertInfo( const CMsgSteamDatagramCertificateSigned &msgSigned, CUtlStringBuilder &buf, const char *pszJSONIndent ) +void PrintCertInfo( const CMsgSteamDatagramCertificateSigned &msgSigned, std::string &sOutResult, const char *pszJSONIndent ) { + char szTemp[ 256 ]; + CMsgSteamDatagramCertificate msgCert; msgCert.ParseFromString( msgSigned.cert() ); @@ -175,45 +178,58 @@ void PrintCertInfo( const CMsgSteamDatagramCertificateSigned &msgSigned, CUtlStr Plat_ctime( &timeExpiry, szTimeExpiry, sizeof(szTimeExpiry) ); V_StripTrailingWhitespaceASCII( szTimeExpiry ); - CUtlString sDataCenterIDs; + std::string sDataCenterIDs; for ( uint32 id: msgCert.gameserver_datacenter_ids() ) { - char szTemp[ 8 ]; GetSteamNetworkingLocationPOPStringFromID( id, szTemp ); if ( pszJSONIndent ) { - if ( !sDataCenterIDs.IsEmpty() ) - sDataCenterIDs.AppendChar( ',' ); - sDataCenterIDs.AppendChar( '\"' ); - sDataCenterIDs.Append( szTemp ); - sDataCenterIDs.AppendChar( '\"' ); + if ( !sDataCenterIDs.empty() ) + sDataCenterIDs += ','; + sDataCenterIDs += '\"'; + sDataCenterIDs += szTemp; + sDataCenterIDs += '\"'; } else { - if ( !sDataCenterIDs.IsEmpty() ) - sDataCenterIDs.AppendChar( ' ' ); - sDataCenterIDs.Append( szTemp ); + if ( !sDataCenterIDs.empty() ) + sDataCenterIDs += ' '; + sDataCenterIDs += szTemp; } } if ( pszJSONIndent ) { - buf.AppendFormat( "%s\"key_id\": %llu,\n", pszJSONIndent, CalculatePublicKeyID( pubKey ) ); - if ( !sDataCenterIDs.IsEmpty() ) - buf.AppendFormat( "%s\"data_centers\": [ %s ],\n", pszJSONIndent, sDataCenterIDs.String() ); - buf.AppendFormat( "%s\"created\": \"%s\",\n", pszJSONIndent, szTimeCreated ); - buf.AppendFormat( "%s\"expires\": \"%s\",\n", pszJSONIndent, szTimeExpiry ); - buf.AppendFormat( "%s\"ca_key_id\": %" PRIu64 "\n", pszJSONIndent, msgSigned.ca_key_id() ); + V_sprintf_safe( szTemp, "%s\"key_id\": %llu,\n", pszJSONIndent, CalculatePublicKeyID( pubKey ) ); + sOutResult += szTemp; + if ( !sDataCenterIDs.empty() ) + { + V_sprintf_safe( szTemp, "%s\"data_centers\": [ %s ],\n", pszJSONIndent, sDataCenterIDs.c_str() ); + sOutResult += szTemp; + } + V_sprintf_safe( szTemp, "%s\"created\": \"%s\",\n", pszJSONIndent, szTimeCreated ); + sOutResult += szTemp; + V_sprintf_safe( szTemp, "%s\"expires\": \"%s\",\n", pszJSONIndent, szTimeExpiry ); + sOutResult += szTemp; + V_sprintf_safe( szTemp, "%s\"ca_key_id\": %" PRIu64 "\n", pszJSONIndent, msgSigned.ca_key_id() ); + sOutResult += szTemp; } else { - buf.AppendFormat( "Public key ID. . : %llu\n", CalculatePublicKeyID( pubKey ) ); - buf.AppendFormat( "Created. . . . . : %s\n", szTimeCreated ); - buf.AppendFormat( "Expires. . . . . : %s\n", szTimeExpiry ); - buf.AppendFormat( "CA key ID. . . . : %" PRIu64 "\n", msgSigned.ca_key_id() ); - if ( sDataCenterIDs ) - buf.AppendFormat( "Data center(s) . : %s\n", sDataCenterIDs.String() ); + V_sprintf_safe( szTemp, "Public key ID. . : %llu\n", CalculatePublicKeyID( pubKey ) ); + sOutResult += szTemp; + V_sprintf_safe( szTemp, "Created. . . . . : %s\n", szTimeCreated ); + sOutResult += szTemp; + V_sprintf_safe( szTemp, "Expires. . . . . : %s\n", szTimeExpiry ); + sOutResult += szTemp; + V_sprintf_safe( szTemp, "CA key ID. . . . : %" PRIu64 "\n", msgSigned.ca_key_id() ); + sOutResult += szTemp; + if ( !sDataCenterIDs.empty() ) + { + V_sprintf_safe( szTemp, "Data center(s) . : %s\n", sDataCenterIDs.c_str() ); + sOutResult += szTemp; + } } } @@ -272,9 +288,9 @@ void CreateCert() Msg( "%s\n", k_szSDRCertPEMHeader ); Msg( "%s\n", text ); Msg( "%s\n", k_szSDRCertPEMFooter ); - CUtlStringBuilder sDetails; + std::string sDetails; PrintCertInfo( msgSigned, sDetails, nullptr ); - Msg( "%s", sDetails.String() ); + Msg( "%s", sDetails.c_str() ); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.cpp b/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.cpp index d7e8352..ccb7358 100644 --- a/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.cpp +++ b/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.cpp @@ -650,13 +650,14 @@ void CSteamNetworkingSockets::SetConnectionName( HSteamNetConnection hPeer, cons pConn->SetName( pszName ); } -void CSteamNetworkingSockets::GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen ) +bool CSteamNetworkingSockets::GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen ) { SteamDatagramTransportLock scopeLock; CSteamNetworkConnectionBase *pConn = GetConnectionByHandle( hPeer ); if ( !pConn ) - return; - pConn->GetName( pszName, nMaxLen ); + return false; + V_strncpy( pszName, pConn->GetName(), nMaxLen ); + return true; } EResult CSteamNetworkingSockets::SendMessageToConnection( HSteamNetConnection hConn, const void *pData, uint32 cbData, ESteamNetworkingSendType eSendType ) diff --git a/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.h b/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.h index 29437e6..7b1d519 100644 --- a/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.h +++ b/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.h @@ -173,7 +173,7 @@ public: virtual bool SetConnectionUserData( HSteamNetConnection hPeer, int64 nUserData ) OVERRIDE; virtual int64 GetConnectionUserData( HSteamNetConnection hPeer ) OVERRIDE; virtual void SetConnectionName( HSteamNetConnection hPeer, const char *pszName ) OVERRIDE; - virtual void GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen ) OVERRIDE; + virtual bool GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen ) OVERRIDE; virtual EResult SendMessageToConnection( HSteamNetConnection hConn, const void *pData, uint32 cbData, ESteamNetworkingSendType eSendType ) OVERRIDE; virtual EResult FlushMessagesOnConnection( HSteamNetConnection hConn ); virtual int ReceiveMessagesOnConnection( HSteamNetConnection hConn, ISteamNetworkingMessage **ppOutMessages, int nMaxMessages ) OVERRIDE; diff --git a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.cpp b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.cpp index a5ffc85..193a7b6 100644 --- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.cpp +++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.cpp @@ -559,9 +559,11 @@ bool CSteamNetworkConnectionBase::BInitConnection( uint32 nPeerProtocolVersion, m_hConnectionSelf = g_listConnections.AddToTail( this ) | s_nUpperBits; // Set a default name if we haven't been given one - if ( m_sName.IsEmpty() ) + if ( m_sName.empty() ) { - m_sName.Format( "%d", m_hConnectionSelf & ~s_nUpperBits ); + char temp[ 64 ]; + V_sprintf_safe( temp, "%d", m_hConnectionSelf & ~s_nUpperBits ); + m_sName = temp; } // Clear everything out @@ -1320,13 +1322,6 @@ bool CSteamNetworkConnectionBase::RecvDataChunk( uint16 unSeqNum, const void *pC return SNP_RecvDataChunk( unSeqNum, arDecryptedChunk, cbDecrypted, cbPacketSize, usecNow ); } -bool CSteamNetworkConnectionBase::GetDebugText( char *pszOut, int nOutCCH ) -{ - CUtlString snpDebug = SNP_GetDebugText(); - V_strncpy( pszOut, snpDebug.String(), nOutCCH ); - return true; -} - void CSteamNetworkConnectionBase::APICloseConnection( int nReason, const char *pszDebug, bool bEnableLinger ) { diff --git a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.h b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.h index 28e052d..a9116e5 100644 --- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.h +++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.h @@ -13,7 +13,6 @@ #include #include #include -#include #include "steamnetworkingsockets_lowlevel.h" #include "keypair.h" #include @@ -240,7 +239,7 @@ public: void SetUserData( int64 nUserData ); // Get/set name - inline void GetName( char *pszName, int nMaxLen ) const { V_strncpy( pszName, m_sName.String(), nMaxLen); } + inline const char *GetName() const { return m_sName.c_str(); } void SetName( const char *pszName ) { m_sName = pszName; } /// High level state of the connection @@ -331,7 +330,7 @@ public: /// Called when we receive an (end-to-end) packet with a sequence number void RecvNonDataSequencedPacket( uint16 nWireSeqNum, SteamNetworkingMicroseconds usecNow ); - bool GetDebugText( char *pszOut, int nOutCCH ); + void GetDebugText( char *pszOut, int nOutCCH ); // Called from SNP to update transmit/receive speeds void UpdateSpeeds( int nTXSpeed, int nRXSpeed ); @@ -385,7 +384,7 @@ protected: int64 m_nUserData; /// Name (for debugging) - CUtlString m_sName; + std::string m_sName; // Implements IThinker. // Connections do not override this. Do any periodic work in ThinkConnection() @@ -505,7 +504,7 @@ protected: void SNP_CheckForReliable( SteamNetworkingMicroseconds usecNow ); void SNP_UpdateX( SteamNetworkingMicroseconds usecNow ); bool SNP_InsertSegment( SSNPBuffer *p_buf, uint8 flags, int nSize ); - CUtlString SNP_GetDebugText(); + std::string SNP_GetDebugText(); void SNP_PopulateDetailedStats( SteamDatagramLinkStats &info ) const; void SNP_PopulateQuickStats( SteamNetworkingQuickConnectionStatus &info, SteamNetworkingMicroseconds usecNow ); bool SNP_UpdateIMean( uint16 unSeqNum, SteamNetworkingMicroseconds usecNow ); diff --git a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_snp.cpp b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_snp.cpp index 856fd93..0341912 100644 --- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_snp.cpp +++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_snp.cpp @@ -106,7 +106,7 @@ void CSteamNetworkConnectionBase::SNP_InitializeConnection( SteamNetworkingMicro if ( steamdatagram_snp_log_x ) SpewMsg( "%12llu %s: INITIAL X=%d rtt=%dms tx_s=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_senderState.m_n_x, m_statsEndToEnd.m_ping.m_nSmoothedPing, m_senderState.m_n_tx_s ); @@ -171,7 +171,7 @@ EResult CSteamNetworkConnectionBase::SNP_SendMessage( SteamNetworkingMicrosecond if ( steamdatagram_snp_log_message ) SpewMsg( "%12llu %s: SendMessage %s: MsgNum=%d sz=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), pSendMessage->m_bReliable ? "RELIABLE" : "UNRELIABLE", pSendMessage->m_unMsgNum, pSendMessage->m_nSize ); @@ -187,7 +187,7 @@ EResult CSteamNetworkConnectionBase::SNP_SendMessage( SteamNetworkingMicrosecond if ( steamdatagram_snp_log_nagle ) SpewMsg( "%12llu %s: NAGLE cleared nagle timer because pendingBytes %d > %d\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_senderState.PendingBytesTotal(), k_cbSteamNetworkingSocketsMaxMessageNoFragment ); m_senderState.FlushNagle(); @@ -198,7 +198,7 @@ EResult CSteamNetworkConnectionBase::SNP_SendMessage( SteamNetworkingMicrosecond if ( steamdatagram_snp_log_nagle ) SpewMsg( "%12llu %s: NAGLE cleared nagle timer because message was sent with type %d\n", usecNow, - m_sName.String(), + m_sName.c_str(), eSendType ); m_senderState.FlushNagle(); } @@ -208,7 +208,7 @@ EResult CSteamNetworkConnectionBase::SNP_SendMessage( SteamNetworkingMicrosecond if ( steamdatagram_snp_log_nagle ) SpewMsg( "%12llu %s: NAGLE SET to %llu (%d delay)\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_senderState.m_t_nagle, steamdatagram_snp_nagle_time ); } @@ -221,7 +221,7 @@ EResult CSteamNetworkConnectionBase::SNP_SendMessage( SteamNetworkingMicrosecond { SpewVerbose( "%12llu %s: RATELIM QueueTime is %.1fms, SendRate=%.1fk, BytesQueued=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_senderState.CalcTimeUntilNextSend() * 1e-3, m_senderState.m_n_x * ( 1.0/1024.0), m_senderState.PendingBytesTotal() @@ -242,7 +242,7 @@ EResult CSteamNetworkConnectionBase::SNP_FlushMessage( SteamNetworkingMicrosecon if ( steamdatagram_snp_log_nagle ) SpewMsg( "%12llu %s: NAGLE FlushMessasge\n", usecNow, - m_sName.String() ); + m_sName.c_str() ); m_senderState.FlushNagle(); @@ -395,7 +395,7 @@ void CSteamNetworkConnectionBase::SNP_CheckForReliable( SteamNetworkingMicroseco if ( steamdatagram_snp_log_reliable ) SpewMsg( "%12llu %s: %s CheckForReliable: sentMsgNum=%d, recvMsgNum=%d, recvSeqNum=%d, sendSeqNum=%d sendSeqOffset=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), pMsg == m_senderState.m_pSendMessages ? "SEND" : "SENT", pMsg->m_unMsgNum, m_senderState.m_unRecvMsgNumReliable, @@ -409,7 +409,7 @@ void CSteamNetworkConnectionBase::SNP_CheckForReliable( SteamNetworkingMicroseco if ( steamdatagram_snp_log_reliable ) SpewMsg( "%12llu %s: %s ACK recvMsgNum %d is after sentMsgNum %d, acknowledged\n", usecNow, - m_sName.String(), + m_sName.c_str(), pMsg == m_senderState.m_pSendMessages ? "SEND" : "SENT", m_senderState.m_unRecvMsgNumReliable, pMsg->m_unMsgNum ); @@ -440,7 +440,7 @@ void CSteamNetworkConnectionBase::SNP_CheckForReliable( SteamNetworkingMicroseco if ( steamdatagram_snp_log_reliable ) SpewMsg( "%12llu %s: %s NAK sentMsgNum %d: recvSeqNum %d is GTE sentSeqNum %d, but ack is previous msg %d:%u\n", usecNow, - m_sName.String(), + m_sName.c_str(), pMsg == m_senderState.m_pSendMessages ? "SEND" : "SENT", pMsg->m_unMsgNum, m_senderState.m_unRecvSeqNum, @@ -456,7 +456,7 @@ void CSteamNetworkConnectionBase::SNP_CheckForReliable( SteamNetworkingMicroseco if ( steamdatagram_snp_log_reliable ) SpewMsg( "%12llu %s: %s recvMsgNum %d != sentMsgNum %d, lastAck %d:%u\n", usecNow, - m_sName.String(), + m_sName.c_str(), pMsg == m_senderState.m_pSendMessages ? "SEND" : "SENT", m_senderState.m_unRecvMsgNumReliable, pMsg->m_unMsgNum, @@ -478,7 +478,7 @@ void CSteamNetworkConnectionBase::SNP_CheckForReliable( SteamNetworkingMicroseco if ( steamdatagram_snp_log_reliable ) SpewMsg( "%12llu %s: %s NAK sentMsgNum %d: recvSeqNum %d is GTE sentSeqNum %d, but m_unRecvMsgAmt %d is less than m_nSentAmt %d\n", usecNow, - m_sName.String(), + m_sName.c_str(), pMsg == m_senderState.m_pSendMessages ? "SEND" : "SENT", pMsg->m_unMsgNum, m_senderState.m_unRecvSeqNum, @@ -493,7 +493,7 @@ void CSteamNetworkConnectionBase::SNP_CheckForReliable( SteamNetworkingMicroseco if ( steamdatagram_snp_log_reliable ) SpewMsg( "%12llu %s: %s ACK sentMsgNum %d: recvSeqNum %d is GTE sentSeqNum %d, m_unRecvMsgAmt %d is GTE than m_nSentAmt %d\n", usecNow, - m_sName.String(), + m_sName.c_str(), pMsg == m_senderState.m_pSendMessages ? "SEND" : "SENT", pMsg->m_unMsgNum, m_senderState.m_unRecvSeqNum, @@ -515,7 +515,7 @@ void CSteamNetworkConnectionBase::SNP_CheckForReliable( SteamNetworkingMicroseco if ( steamdatagram_snp_log_reliable ) SpewMsg( "%12llu %s: SENT Finished sentMsgNum %d lastAck %d:%u\n", usecNow, - m_sName.String(), + m_sName.c_str(), pMsg->m_unMsgNum, m_senderState.m_unRecvMsgNumReliable, m_senderState.m_unRecvMsgAmtReliable ); @@ -545,7 +545,7 @@ void CSteamNetworkConnectionBase::SNP_CheckForReliable( SteamNetworkingMicroseco if ( steamdatagram_snp_log_reliable || steamdatagram_snp_log_loss ) SpewMsg( "%12llu %s: RTO sentMsgNum %d\n", usecNow, - m_sName.String(), + m_sName.c_str(), pMsg->m_unMsgNum ); // Set for retransmit due to timeout @@ -575,7 +575,7 @@ void CSteamNetworkConnectionBase::SNP_PrepareFeedback( SteamNetworkingMicrosecon if ( steamdatagram_snp_log_feedback ) SpewMsg( "%12llu %s: TFRC_FBACK_PERIODIC usec_delta=%llu bytes_recv=%d n_x_recv=%d m_n_x_recv=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), usec_delta, m_receiverState.m_n_bytes_recv, n_x_recv, @@ -746,7 +746,7 @@ bool CSteamNetworkConnectionBase::SNP_AddLossEvent( uint16 unSeqNum, SteamNetwor if ( steamdatagram_snp_log_loss ) SpewMsg( "%12llu %s: LOSS INITIAL: x_recv: %d, cur_p: %.8f len: %d\n", usecNow, - m_sName.String(), + m_sName.c_str(), n_x_recv, cur_p, len ); @@ -852,7 +852,7 @@ void CSteamNetworkConnectionBase::SNP_NoFeedbackTimer( SteamNetworkingMicrosecon if ( steamdatagram_snp_log_feedback ) SpewMsg( "%12llu %s: NO FEEDBACK TIMER X=%d, was %d, timer is %llu (rtt is %dms)\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_senderState.m_n_x, n_old_x, m_senderState.m_usec_nfb - usecNow, @@ -871,7 +871,7 @@ int CSteamNetworkConnectionBase::SNP_CheckForLoss( uint16 unSeqNum, SteamNetwork { SpewMsg( "%12llu %s: RECV OOO PACKET(S) %d (wanted %d)\n", usecNow, - m_sName.String(), + m_sName.c_str(), unSeqNum, ( uint16 )( m_receiverState.m_queue_rx_hist.back().m_unRecvSeqNum + 1 ) ); @@ -884,7 +884,7 @@ int CSteamNetworkConnectionBase::SNP_CheckForLoss( uint16 unSeqNum, SteamNetwork if ( steamdatagram_snp_log_packet || steamdatagram_snp_log_loss ) SpewMsg( "%12llu %s: RECV LOST %d PACKET(S) %d - %d\n", usecNow, - m_sName.String(), + m_sName.c_str(), nSeqDelta - 1, first, second ); @@ -931,7 +931,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_packet ) SpewMsg( "%12llu %s: RECV PACKET %d usecNow=%llu sz=%d(%d) recvSeqNum:%d recvMsgNum:%d recvMsgAmt:%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), unSeqNum, usecNow, cbChunk, @@ -1024,7 +1024,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_feedback ) SpewMsg( "%12llu %s: RECV FEEDBACK %d x_recv:%d t_delay:%d p:%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), unSeqNum, LittleDWord( pFeedback->m_un_X_recv ), LittleDWord( pFeedback->m_un_t_delay ), @@ -1065,7 +1065,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_rtt ) SpewMsg( "%12llu %s: RECV UPDATE RTT rtt:%dms seqNum:%d ts:%d r_sample:%llu diff_ts:%llu t_delay:%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_statsEndToEnd.m_ping.m_nSmoothedPing, m_senderState.m_unRecvSeqNum, (int)( tx_hist_entry.m_usec_ts / 1000 ), @@ -1144,7 +1144,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_segments ) SpewMsg( "%12llu %s: Unexpected reliable message segment %d:%u sz=%d (expected %d)\n", usecNow, - m_sName.String(), + m_sName.c_str(), unMsgNum, unOffset, nSegmentSize, @@ -1157,7 +1157,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_segments ) SpewMsg( "%12llu %s: Unexpected reliable message offset %d:%u sz=%d (expected %d:%u)\n", usecNow, - m_sName.String(), + m_sName.c_str(), unMsgNum, unOffset, nSegmentSize, @@ -1174,7 +1174,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_segments ) SpewMsg( "%12llu %s: RELIABLE %d: msgNum %d offset=%d recvAmt=%d segmentSize=%d%s\n", usecNow, - m_sName.String(), + m_sName.c_str(), unSeqNum, unMsgNum, unOffset, @@ -1190,7 +1190,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_message || steamdatagram_snp_log_reliable ) SpewMsg( "%12llu %s: RecvMessage RELIABLE: MsgNum=%d sz=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), unMsgNum, recvBuf.TellPut() ); @@ -1212,7 +1212,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_segments ) SpewMsg( "%12llu %s: Throwing away unreliable message %d sz=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_receiverState.m_unRecvMsgNum, recvBuf.TellPut() ); recvBuf.Purge(); @@ -1228,7 +1228,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_segments ) SpewMsg( "%12llu %s: Unexpected reliable message offset %d:%u sz=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), unMsgNum, unOffset, nSegmentSize ); @@ -1242,7 +1242,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_segments ) SpewMsg( "%12llu %s: UNRELIABLE %d: msgNum %d offset=%d recvAmt=%d segmentSize=%d%s\n", usecNow, - m_sName.String(), + m_sName.c_str(), unSeqNum, unMsgNum, unOffset, @@ -1258,7 +1258,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_message ) SpewMsg( "%12llu %s: RecvMessage UNRELIABLE: MsgNum=%d sz=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), unMsgNum, recvBuf.TellPut() ); @@ -1274,7 +1274,7 @@ bool CSteamNetworkConnectionBase::SNP_RecvDataChunk( uint16 unSeqNum, const void if ( steamdatagram_snp_log_segments ) SpewMsg( "%12llu %s: MSG recieved unreliable message %d section offset %u (sz=%d)\n", usecNow, - m_sName.String(), + m_sName.c_str(), unMsgNum, unOffset, nSegmentSize ); @@ -1368,7 +1368,7 @@ void CSteamNetworkConnectionBase::SNP_UpdateX( SteamNetworkingMicroseconds usecN if ( steamdatagram_snp_log_x ) SpewMsg( "%12llu %s: UPDATE X=%d (was %d) x_recv=%d min_rate=%d p=%u x_calc=%d tx_s=%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_senderState.m_n_x, n_old_x, m_senderState.m_n_x_recv, @@ -1568,7 +1568,7 @@ int CSteamNetworkConnectionBase::SNP_SendPacket( SteamNetworkingMicroseconds use if ( steamdatagram_snp_log_packet ) SpewMsg( "%12llu %s: SEND PACKET %d usecNow=%llu sz=%d(%d) recvSeqNum:%d recvMsgNum:%d recvMsgAmt:%d\n", usecNow, - m_sName.String(), + m_sName.c_str(), sendSeqNum, usecNow, sendBuf.m_nSize, @@ -1610,7 +1610,7 @@ int CSteamNetworkConnectionBase::SNP_SendPacket( SteamNetworkingMicroseconds use if ( steamdatagram_snp_log_segments ) SpewMsg( "%12llu %s: %s %d: msgNum %d offset=%d sendAmt=%d segmentSize=%d%s\n", usecNow, - m_sName.String(), + m_sName.c_str(), sendPacketEntryMsg.m_bReliable ? "RELIABLE " : "UNRELIABLE", sendSeqNum, sendPacketEntryMsg.m_pMsg->m_unMsgNum, @@ -1664,14 +1664,14 @@ void CSteamNetworkConnectionBase::SNP_ThinkSendState( SteamNetworkingMicrosecond if ( steamdatagram_snp_log_nagle ) SpewMsg( "%12llu %s: NAGLE WAIT %llu to go\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_senderState.m_t_nagle - usecNow ); break; } if ( steamdatagram_snp_log_nagle ) SpewMsg( "%12llu %s: NAGLE cleared (pending send), %llu early\n", usecNow, - m_sName.String(), + m_sName.c_str(), m_senderState.m_t_nagle - usecNow ); m_senderState.m_t_nagle = 0; } @@ -1684,7 +1684,7 @@ void CSteamNetworkConnectionBase::SNP_ThinkSendState( SteamNetworkingMicrosecond { SpewMsg( "%12llu %s: NAGLE REACHED (cleared)\n", usecNow, - m_sName.String() ); + m_sName.c_str() ); } } @@ -1697,7 +1697,7 @@ void CSteamNetworkConnectionBase::SNP_ThinkSendState( SteamNetworkingMicrosecond if ( steamdatagram_snp_log_feedback ) SpewMsg( "%12llu %s: TFRC_SSTATE_FBACK_REQ due to rto/2 timeout\n", usecNow, - m_sName.String() ); + m_sName.c_str() ); } if ( !m_senderState.m_usec_rto && usecNow - m_receiverState.m_usec_tstamp_last_feedback > TCP_RTO_MIN / 2 ) { @@ -1705,7 +1705,7 @@ void CSteamNetworkConnectionBase::SNP_ThinkSendState( SteamNetworkingMicrosecond if ( steamdatagram_snp_log_feedback ) SpewMsg( "%12llu %s: TFRC_SSTATE_FBACK_REQ due to TCP_RTO_MIN/2 timeout\n", usecNow, - m_sName.String() ); + m_sName.c_str() ); } } @@ -1871,11 +1871,9 @@ void CSteamNetworkConnectionBase::SetMaximumRate( int nRate ) m_senderState.m_n_x = nRate; } -CUtlString CSteamNetworkConnectionBase::SNP_GetDebugText() +void CSteamNetworkConnectionBase::GetDebugText( char *pszOut, int nOutCCH ) { - CUtlString text; - - text.Format( "%s\n" + V_snprintf( pszOut, nOutCCH, "%s\n" "SenderState\n" " x . . . . . . %d\n" " x_recv. . . . %d\n" @@ -1898,7 +1896,7 @@ CUtlString CSteamNetworkConnectionBase::SNP_GetDebugText() " i_mean. . . . %d (%.8f)\n" " msgsReliable. %lld\n" " msgs. . . . . %lld\n", - m_sName.String(), + m_sName.c_str(), m_senderState.m_n_x, m_senderState.m_n_x_recv, m_senderState.m_n_x_calc, @@ -1921,8 +1919,6 @@ CUtlString CSteamNetworkConnectionBase::SNP_GetDebugText() m_receiverState.m_nMessagesRecvReliable, m_receiverState.m_nMessagesRecvUnreliable ); - - return text; } } // namespace SteamNetworkingSocketsLib diff --git a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_snp.h b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_snp.h index 87f31d1..5c93d49 100644 --- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_snp.h +++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_snp.h @@ -10,7 +10,6 @@ #include #include -#include struct P2PSessionState_t; diff --git a/src/tier1/utlstring.cpp b/src/tier1/utlstring.cpp deleted file mode 100644 index 61b9d76..0000000 --- a/src/tier1/utlstring.cpp +++ /dev/null @@ -1,1272 +0,0 @@ -//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Larger string functions go here. -// -// $Header: $ -// $NoKeywords: $ -//=============================================================================// - -#ifndef _XBOX -#pragma warning (disable:4514) -#endif - -#include "tier1/utlstring.h" -#include "tier0/t0constants.h" -#include "tier1/utlvector.h" - -#include "tier0/memdbgon.h" - - -//----------------------------------------------------------------------------- -// Purpose: Helper: Find s substring -//----------------------------------------------------------------------------- -static ptrdiff_t IndexOf( const char *pstrToSearch, const char *pstrTarget ) -{ - const char *pstrHit = V_strstr( pstrToSearch, pstrTarget ); - if ( pstrHit == NULL ) - { - return -1; // Not found. - } - return ( pstrHit - pstrToSearch ); -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string ends with the string passed in -//----------------------------------------------------------------------------- -static bool BEndsWith( const char *pstrToSearch, const char *pstrToFind, bool bCaseless ) -{ - if ( !pstrToSearch ) - return false; - - if ( !pstrToFind ) - return true; - - size_t nThisLength = V_strlen( pstrToSearch ); - size_t nThatLength = V_strlen( pstrToFind ); - - if ( nThatLength == 0 ) - return true; - - if ( nThatLength > nThisLength ) - return false; - - size_t nIndex = nThisLength - nThatLength; - - if ( bCaseless ) - return V_stricmp( pstrToSearch + nIndex, pstrToFind ) == 0; - else - return V_strcmp( pstrToSearch + nIndex, pstrToFind ) == 0; -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string starts with the string passed in -//----------------------------------------------------------------------------- -static bool BStartsWith( const char *pstrToSearch, const char *pstrToFind, bool bCaseless ) -{ - if ( !pstrToSearch ) - return false; - - if ( !pstrToFind ) - return true; - - if ( bCaseless ) - { - int nThatLength = V_strlen( pstrToFind ); - - if ( nThatLength == 0 ) - return true; - - return V_strnicmp( pstrToSearch, pstrToFind, nThatLength ) == 0; - } - else - return V_strstr( pstrToSearch, pstrToFind ) == pstrToSearch; -} - - -//----------------------------------------------------------------------------- -// Purpose: Helper: kill all whitespace. -//----------------------------------------------------------------------------- -static size_t RemoveWhitespace( char *pszString ) -{ - if ( pszString == NULL ) - return 0; - - char *pstrDest = pszString; - size_t cRemoved = 0; - for ( char *pstrWalker = pszString; *pstrWalker != 0; pstrWalker++ ) - { - if ( !isspace( (unsigned char)*pstrWalker ) ) - { - *pstrDest = *pstrWalker; - pstrDest++; - } - else - cRemoved += 1; - } - *pstrDest = 0; - - return cRemoved; -} - - -#ifdef VALVE_RVALUE_REFS -//----------------------------------------------------------------------------- -// Purpose: move-constructor from CUtlStringBuilder to CUtlString -//----------------------------------------------------------------------------- -CUtlString::CUtlString( class CUtlStringBuilder &&string ) -{ - m_pchString = string.DetachRawPtr(); -} - -//----------------------------------------------------------------------------- -// Purpose: move-assignment from CUtlStringBuilder to CUtlString -//----------------------------------------------------------------------------- -CUtlString & CUtlString::operator=(class CUtlStringBuilder &&string) -{ - SetPtr( string.DetachRawPtr() ); - return *this; -} -#endif - - -//----------------------------------------------------------------------------- -// Purpose: Helper for Format() method -//----------------------------------------------------------------------------- -size_t CUtlString::FormatV( const char *pFormat, va_list args ) -{ - size_t len = 0; -#ifdef _WIN32 - // how much space will we need? - size_t mlen = _vscprintf( pFormat, args ); - - // get it - FreePv( m_pchString ); - m_pchString = NULL; - m_pchString = (char*) PvAlloc( mlen+1 ); - - // format into that space, which is certainly enough - len = _vsnprintf( m_pchString, mlen+1, pFormat, args ); - - Assert( len >= 0 ); - Assert( len <= mlen ); - -#elif defined ( _PS3 ) - - // ignore the PS3 documentation about vsnprintf returning -1 when the string is too small. vsprintf seems to do the right thing (least at time of - // implementation) and returns the number of characters needed when you pass in a buffer that is too small - - FreePv( m_pchString ); - m_pchString = NULL; - - len = vsnprintf( NULL, 0, pFormat, args ); - if ( len > 0 ) - { - m_pchString = (char*) PvAlloc( len + 1 ); - len = vsnprintf( m_pchString, len + 1, pFormat, args ); - } - -#elif defined( POSIX ) - - char *buf = NULL; - len = vasprintf( &buf, pFormat, args ); - - // Len < 0 represents an overflow - if( buf ) - { - // We need to get the string into PvFree-compatible memory, which - // we can't assume is directly interoperable with the malloc memory - // that vasprintf returned (definitely not compatible with a debug - // allocator, for example). - Set( buf ); - real_free( buf ); - } - -#else -#error "define vsnprintf type." -#endif - return len; -} - - -//----------------------------------------------------------------------------- -// Purpose: implementation helper for AppendFormat() -//----------------------------------------------------------------------------- -size_t CUtlString::VAppendFormat( const char *pFormat, va_list args ) -{ - size_t len = 0; - char *pstrFormatted = NULL; -#ifdef _WIN32 - // how much space will we need? - size_t mlen = _vscprintf( pFormat, args ); - - // get it - pstrFormatted = (char*) PvAlloc( mlen+1 ); - - // format into that space, which is certainly enough - len = _vsnprintf( pstrFormatted, mlen+1, pFormat, args ); - - Assert( len > 0 ); - Assert( len <= mlen ); - -#elif defined ( _PS3 ) - - // ignore the PS3 documentation about vsnprintf returning -1 when the string is too small. vsprintf seems to do the right thing (least at time of - // implementation) and returns the number of characters needed when you pass in a buffer that is too small - - len = vsnprintf( NULL, 0, pFormat, args ); - if ( len > 0 ) - { - pstrFormatted = (char*) PvAlloc( len + 1 ); - len = vsnprintf( pstrFormatted, len + 1, pFormat, args ); - } - -#elif defined( POSIX ) - - len = vasprintf( &pstrFormatted, pFormat, args ); - -#else -#error "define vsnprintf type." -#endif - - // if we ended with a formatted string, append and free it - if ( pstrFormatted != NULL ) - { - Append( pstrFormatted, len ); -#if defined( POSIX ) - real_free( pstrFormatted ); -#else - FreePv( pstrFormatted ); -#endif - } - - return len; -} - - -//----------------------------------------------------------------------------- -// Purpose: replace all occurrences of one string with another -// replacement string may be NULL or "" to remove target string -//----------------------------------------------------------------------------- -size_t CUtlString::Replace( const char *pstrTarget, const char *pstrReplacement ) -{ - return ReplaceInternal( pstrTarget, pstrReplacement, V_strstr ); -} - - -//----------------------------------------------------------------------------- -// Purpose: replace all occurrences of one string with another -// replacement string may be NULL or "" to remove target string -//----------------------------------------------------------------------------- -size_t CUtlString::ReplaceCaseless( const char *pstrTarget, const char *pstrReplacement ) -{ - return ReplaceInternal( pstrTarget, pstrReplacement, V_stristr ); -} - -//----------------------------------------------------------------------------- -// Purpose: replace all occurrences of one string with another -// replacement string may be NULL or "" to remove target string -//----------------------------------------------------------------------------- -size_t CUtlString::ReplaceInternal( const char *pstrTarget, const char *pstrReplacement, const char *pfnCompare(const char*, const char*) ) -{ - size_t cReplacements = 0; - if ( pstrReplacement == NULL ) - pstrReplacement = ""; - - size_t nTargetLength = V_strlen( pstrTarget ); - size_t nReplacementLength = V_strlen( pstrReplacement ); - - if ( m_pchString != NULL && pstrTarget != NULL ) - { - // walk the string counting hits - const char *pstrHit = m_pchString; - for ( pstrHit = pfnCompare( pstrHit, pstrTarget ); pstrHit != NULL && *pstrHit != 0; /* inside */ ) - { - cReplacements++; - // look for the next target and keep looping - pstrHit = pfnCompare( pstrHit + nTargetLength, pstrTarget ); - } - - // if we didn't miss, get to work - if ( cReplacements > 0 ) - { - // reallocate only once; how big will we need? - size_t nNewLength = 1 + V_strlen( m_pchString ) + cReplacements * ( nReplacementLength - nTargetLength ); - - char *pstrNew = (char*) PvAlloc( nNewLength ); - if ( nNewLength == 1 ) - { - // shortcut simple case, even if rare - *pstrNew = 0; - } - else - { - const char *pstrPreviousHit = NULL; - char *pstrDestination = pstrNew; - pstrHit = m_pchString; - size_t cActualReplacements = 0; - for ( pstrHit = pfnCompare( m_pchString, pstrTarget ); pstrHit != NULL && *pstrHit != 0; /* inside */ ) - { - cActualReplacements++; - - // copy from the previous hit to the match - if ( pstrPreviousHit == NULL ) - pstrPreviousHit = m_pchString; - memcpy( pstrDestination, pstrPreviousHit, pstrHit - pstrPreviousHit ); - pstrDestination += ( pstrHit - pstrPreviousHit ); - - // push the replacement string in - memcpy( pstrDestination, pstrReplacement, nReplacementLength ); - pstrDestination += nReplacementLength; - - pstrPreviousHit = pstrHit + nTargetLength; - pstrHit = pfnCompare( pstrPreviousHit, pstrTarget ); - } - - while ( pstrPreviousHit != NULL && *pstrPreviousHit != 0 ) - { - *pstrDestination = *pstrPreviousHit; - pstrDestination++; - pstrPreviousHit++; - } - *pstrDestination = 0; - - Assert( pstrNew + nNewLength == pstrDestination + 1); - Assert( cActualReplacements == cReplacements ); - } - - // release the old string, set the new one - FreePv( m_pchString ); - m_pchString = pstrNew; - - } - } - - return cReplacements; -} - -//----------------------------------------------------------------------------- -// Purpose: Indicates if the target string exists in this instance. -// The index is negative if the target string is not found, otherwise it is the index in the string. -//----------------------------------------------------------------------------- -ptrdiff_t CUtlString::IndexOf( const char *pstrTarget ) const -{ - return ::IndexOf( String(), pstrTarget ); -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string ends with the string passed in -//----------------------------------------------------------------------------- -bool CUtlString::BEndsWith( const char *pchString ) const -{ - return ::BEndsWith( String(), pchString, false ); -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string ends with the string passed in (caseless) -//----------------------------------------------------------------------------- -bool CUtlString::BEndsWithCaseless( const char *pchString ) const -{ - return ::BEndsWith( String(), pchString, true ); -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string starts with the string passed in -//----------------------------------------------------------------------------- -bool CUtlString::BStartsWith( const char *pchString ) const -{ - return ::BStartsWith( String(), pchString, false ); -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string ends with the string passed in (caseless) -//----------------------------------------------------------------------------- -bool CUtlString::BStartsWithCaseless( const char *pchString ) const -{ - return ::BStartsWith( String(), pchString, true ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// remove whitespace -- anything that is isspace() -- from the string -//----------------------------------------------------------------------------- -size_t CUtlString::RemoveWhitespace() -{ - return ::RemoveWhitespace( m_pchString ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// trim whitespace from front and back of string -//----------------------------------------------------------------------------- -size_t CUtlString::TrimWhitespace() -{ - if ( m_pchString == NULL ) - return 0; - - int cChars = V_StrTrim( m_pchString ); - return cChars; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// trim whitespace from back of string -//----------------------------------------------------------------------------- -size_t CUtlString::TrimTrailingWhitespace() -{ - if ( m_pchString == NULL ) - return 0; - - uint32 cChars = Length(); - if ( cChars == 0 ) - return 0; - - char *pCur = &m_pchString[cChars - 1]; - while ( pCur >= m_pchString && isspace( *pCur ) ) - { - *pCur = '\0'; - pCur--; - } - - return pCur - m_pchString + 1; -} - - -//----------------------------------------------------------------------------- -// Purpose: out-of-line assertion to keep code generation size down -//----------------------------------------------------------------------------- -void CUtlString::AssertStringTooLong() -{ - AssertMsg( false, "Assertion failed: length > k_cchMaxString" ); -} - - -//----------------------------------------------------------------------------- -// Purpose: format binary data as hex characters, appending to existing data -//----------------------------------------------------------------------------- -void CUtlString::AppendHex( const uint8 *pbInput, size_t cubInput, bool bLowercase /*= true*/ ) -{ - if ( !cubInput ) - return; - - size_t existingLen = Length(); - if ( existingLen >= k_cchMaxString || cubInput*2 >= k_cchMaxString - existingLen ) - { - Assert( existingLen < k_cchMaxString && cubInput * 2 < k_cchMaxString - existingLen ); - return; - } - - const char *pchHexLookup = bLowercase ? "0123456789abcdef" : "0123456789ABCDEF"; - CUtlString newValue( existingLen + cubInput * 2 + 1 ); - V_memcpy( newValue.Access(), Access(), existingLen ); - char *pOut = newValue.Access() + existingLen; - for ( ; cubInput; --cubInput, ++pbInput ) - { - uint8 val = *pbInput; - *pOut++ = pchHexLookup[val >> 4]; - *pOut++ = pchHexLookup[val & 15]; - } - *pOut = '\0'; - Swap( newValue ); -} - - -// Catch invalid UTF-8 sequences and return false if found, or true if the sequence is correct -static bool BVerifyValidUTF8Continuation( size_t unStart, size_t unContinuationLength, const uint8 *pbCharacters ) -{ - for ( size_t i = 0; i < unContinuationLength; ++ i ) - { - // Make sure byte is of the form 10xxxxxx - // Note: this also catches an unexpected NULL terminator and prevents us from overrunning the string - if ( ( pbCharacters[i + unStart] & 0xC0 ) != 0x80 ) - return false; - } - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Caps the string to the specified number of bytes/chars, -// while respecting UTF-8 character blocks. Resulting string will be -// strictly less than unMaxChars and unMaxBytes. -//----------------------------------------------------------------------------- -bool CUtlString::TruncateUTF8Internal( size_t unMaxChars, size_t unMaxBytes ) -{ - if ( !m_pchString ) - return false; - - const uint8 *pbCharacters = ( const uint8 * )m_pchString; - size_t unBytes = 0; - size_t unChars = 0; - bool bSuccess = true; - - while ( unBytes < unMaxBytes && unChars < unMaxChars && pbCharacters[unBytes] != '\0' ) - { - if ( ( pbCharacters[unBytes] & 0x80 ) == 0 ) - { - // standard ASCII - unBytes ++; - } - else if ( ( pbCharacters[unBytes] & 0xE0 ) == 0xC0 ) // check for 110xxxxx bit pattern, indicates 2 byte character - { - if ( !BVerifyValidUTF8Continuation( unBytes, 1, pbCharacters + 1 ) ) - { - bSuccess = false; - break; - } - - unBytes += 2; - } - else if ( ( pbCharacters[unBytes] & 0xF0 ) == 0xE0 ) // check for 1110xxxx bit pattern, indicates 3 byte character - { - if ( !BVerifyValidUTF8Continuation( unBytes, 2, pbCharacters + 1 ) ) - { - bSuccess = false; - break; - } - - unBytes += 3; - } - else if ( ( pbCharacters[unBytes] & 0xF8 ) == 0xF0 ) // check for 11110xxx bit pattern, indicates 4 byte character - { - if ( !BVerifyValidUTF8Continuation( unBytes, 3, pbCharacters + 1 ) ) - { - bSuccess = false; - break; - } - - unBytes += 4; - } - else if ( ( pbCharacters[unBytes] & 0xFC ) == 0xF8 ) // check for 111110xx bit pattern, indicates 5 byte character - { - if ( !BVerifyValidUTF8Continuation( unBytes, 4, pbCharacters + 1 ) ) - { - bSuccess = false; - break; - } - - unBytes += 5; - } - else if ( ( pbCharacters[unBytes] & 0xFE ) == 0xFC ) // check for 1111110x bit pattern, indicates 6 byte character - { - if ( !BVerifyValidUTF8Continuation( unBytes, 5, pbCharacters + 1 ) ) - { - bSuccess = false; - break; - } - - unBytes += 6; - } - else - { - // Unexpected character - bSuccess = false; - break; - } - - unChars ++; - } - - m_pchString[unBytes] = '\0'; - - return bSuccess; -} - - -//----------------------------------------------------------------------------- -// Purpose: spill routine for making sure our buffer is big enough for an -// incoming string set/modify. -//----------------------------------------------------------------------------- -char *CUtlStringBuilder::InternalPrepareBuffer( size_t nChars, bool bCopyOld, size_t nMinCapacity ) -{ - Assert( nMinCapacity > Capacity() ); - Assert( nMinCapacity >= nChars ); - // Don't use this class if you want a single 2GB+ string. - static const size_t k_nMaxStringSize = 0x7FFFFFFFu; - Assert( nMinCapacity <= k_nMaxStringSize ); - - if ( nMinCapacity > k_nMaxStringSize ) - { - SetError(); - return NULL; - } - - bool bWasHeap = m_data.IsHeap(); - // add this to whatever we are going to grow so we don't start out too slow - char *pszString = NULL; - if ( nMinCapacity > MAX_STACK_STRLEN ) - { - // Allocate 1.5 times what is requested, plus a small initial ramp - // value so we don't spend too much time re-allocating tiny buffers. - // A good allocator will prevent this anyways, but this makes it safer. - // We cap it at +1 million to not get crazy. Code actually avoides - // computing power of two numbers since allocations almost always - // have header/bookkeeping overhead. Don't do the dynamic sizing - // if the user asked for a specific capacity. - static const int k_nInitialMinRamp = 32; - size_t nNewSize; - if ( nMinCapacity > nChars ) - nNewSize = nMinCapacity; - else - nNewSize = nChars + Min( (nChars >> 1) + k_nInitialMinRamp, k_nMillion ); - - char *pszOld = m_data.Access(); - size_t nLenOld = m_data.Length(); - - // order of operations is very important per comment - // above. Make sure we copy it before changing m_data - // in any way - if ( bWasHeap && bCopyOld ) - { - // maybe we'll get lucky and get the same buffer back. - pszString = (char*) PvRealloc( pszOld, nNewSize + 1 ); - if ( !pszString ) - { - SetError(); - return NULL; - } - } - else // Either it's already on the stack; or we don't need to copy - { - // if the current pointer is on the heap, we aren't doing a copy - // (or we would have used the previous realloc code. So - // if we aren't doing a copy, don't use realloc since it will - // copy the data if it needs to make a new allocation. - if ( bWasHeap ) - FreePv( pszOld ); - - pszString = (char*) PvAlloc( nNewSize + 1 ); - if ( !pszString ) - { - SetError(); - return NULL; - } - - // still need to do the copy if we are going from small buffer to large - if ( bCopyOld ) - memcpy( pszString, pszOld, nLenOld ); // null will be added at end of func. - } - - // just in case the user grabs .Access() and scribbles over the terminator at - // 'length', make sure they don't run off the rails as long as they obey Capacity. - // We don't offer this protection for the 'on stack' string. - pszString[nNewSize] = '\0'; - - m_data.Heap.m_pchString = pszString; - m_data.Heap.m_nCapacity = (uint32)nNewSize; // capacity is the max #chars, not including the null. - m_data.Heap.m_nLength = (uint32)nChars; - m_data.Heap.sentinel = STRING_TYPE_SENTINEL; - } - else - { - // Rare case. Only happens if someone did a SetPtr with a length - // less than MAX_STACK_STRLEN, or maybe a .Replace() shrunk the - // length down. - pszString = m_data.Stack.m_szString; - m_data.Stack.SetBytesLeft( MAX_STACK_STRLEN - (uint8)nChars ); - - if ( bWasHeap ) - { - char *pszOldString = m_data.Heap.m_pchString; - if ( bCopyOld ) - memcpy( pszString, pszOldString, nChars ); // null will be added at end of func. - - FreePv( pszOldString ); - } - } - - pszString[nChars] = '\0'; - return pszString; -} - - -//----------------------------------------------------------------------------- -// Purpose: replace all occurrences of one string with another -// replacement string may be NULL or "" to remove target string -//----------------------------------------------------------------------------- -size_t CUtlStringBuilder::Replace( const char *pstrTarget, const char *pstrReplacement ) -{ - return ReplaceInternal( pstrTarget, pstrReplacement, V_strstr ); -} - - -//----------------------------------------------------------------------------- -// Purpose: replace all occurrences of one character with another -//----------------------------------------------------------------------------- -size_t CUtlStringBuilder::Replace( char chTarget, char chReplacement ) -{ - size_t cReplacements = 0; - - if ( !IsEmpty() && !HasError() ) - { - char *pszString = Access(); - for ( char *pstrWalker = pszString; *pstrWalker != 0; pstrWalker++ ) - { - if ( *pstrWalker == chTarget ) - { - *pstrWalker = chReplacement; - cReplacements++; - } - } - } - - return cReplacements; -} - - -//----------------------------------------------------------------------------- -// Purpose: Truncates the string to the specified number of characters -//----------------------------------------------------------------------------- -void CUtlStringBuilder::Truncate( size_t nChars ) -{ - if ( IsEmpty() || HasError() ) - return; - - size_t nLen = Length(); - if ( nLen <= nChars ) - return; - - // we may be shortening enough to fit in the small buffer, but - // the external buffer is already allocated, so just keep using it. - m_data.SetLength( nChars ); -} - - -//----------------------------------------------------------------------------- -// Purpose: replace all occurrences of one string with another -// replacement string may be NULL or "" to remove target string -//----------------------------------------------------------------------------- -size_t CUtlStringBuilder::ReplaceCaseless( const char *pstrTarget, const char *pstrReplacement ) -{ - return ReplaceInternal( pstrTarget, pstrReplacement, V_stristr ); -} - - -//----------------------------------------------------------------------------- -// Purpose: replace all occurrences of one string with another -// replacement string may be NULL or "" to remove target string -//----------------------------------------------------------------------------- -size_t CUtlStringBuilder::ReplaceInternal( const char *pstrTarget, const char *pstrReplacement, const char *pfnCompare(const char*, const char*) ) -{ - if ( HasError() ) - return 0; - - if ( pstrReplacement == NULL ) - pstrReplacement = ""; - - size_t nTargetLength = V_strlen( pstrTarget ); - size_t nReplacementLength = V_strlen( pstrReplacement ); - - CUtlVector vecMatches; - vecMatches.EnsureCapacity( 8 ); - - if ( !IsEmpty() && pstrTarget && *pstrTarget ) - { - char *pszString = Access(); - - // walk the string counting hits - const char *pstrHit = pszString; - for ( pstrHit = pfnCompare( pstrHit, pstrTarget ); pstrHit != NULL && *pstrHit != 0; /* inside */ ) - { - vecMatches.AddToTail( pstrHit ); - // look for the next target and keep looping - pstrHit = pfnCompare( pstrHit + nTargetLength, pstrTarget ); - } - - // if we didn't miss, get to work - if ( vecMatches.Count() > 0 ) - { - // reallocate only once; how big will we need? - size_t nOldLength = Length(); - size_t nNewLength = nOldLength + ( vecMatches.Count() * ( nReplacementLength - nTargetLength ) ); - - if ( nNewLength == 0 ) - { - // shortcut simple case, even if rare - m_data.Clear(); - } - else if ( nNewLength > nOldLength ) - { - // New string will be bigger than the old, but don't re-alloc unless - // it is also larger than capacity. If it fits in capacity, we will - // be adjusting the string 'in place'. The replacement string is larger - // than the target string, so if we copied front to back we would screw up - // the existing data in the 'in place' case. - char *pstrNew; - if ( nNewLength > Capacity() ) - { - pstrNew = (char*) PvAlloc( nNewLength + 1 ); - if ( !pstrNew ) - { - SetError(); - return 0; - } - } - else - { - pstrNew = PrepareBuffer( nNewLength ); - Assert( pstrNew == pszString ); - } - - const char *pstrPreviousHit = pszString + nOldLength; // end of original string - char *pstrDestination = pstrNew + nNewLength; // end of target - *pstrDestination = '\0'; - // Go backwards as noted above. - FOR_EACH_VEC_BACK( vecMatches, i ) - { - pstrHit = vecMatches[i]; - size_t nRemainder = pstrPreviousHit - (pstrHit + nTargetLength); - // copy the bit after the match, back up the destination and move forward from the hit - memmove( pstrDestination - nRemainder, pstrPreviousHit-nRemainder, nRemainder ); - pstrDestination -= ( nRemainder + nReplacementLength ); - - // push the replacement string in - memcpy( pstrDestination, pstrReplacement, nReplacementLength ); - pstrPreviousHit = pstrHit; - } - - // copy trailing stuff - size_t nRemainder = pstrPreviousHit - pszString; - pstrDestination -= nRemainder; - if ( pstrDestination != pszString ) - { - memmove( pstrDestination, pszString, nRemainder ); - } - - Assert( pstrNew == pstrDestination ); - - // Need to set the pointer if we did were larger than capacity. - if ( pstrNew != pszString ) - SetPtr( pstrNew, nNewLength ); - } - else // new is shorter than or same length as old, move in place - { - char *pstrNew = Access(); - char *pstrPreviousHit = pstrNew; - char *pstrDestination = pstrNew; - FOR_EACH_VEC( vecMatches, i ) - { - pstrHit = vecMatches[i]; - if ( pstrDestination != pstrPreviousHit ) - { - // memmove very important as it is ok with overlaps. - memmove( pstrDestination, pstrPreviousHit, pstrHit - pstrPreviousHit ); - } - pstrDestination += ( pstrHit - pstrPreviousHit ); - memcpy( pstrDestination, pstrReplacement, nReplacementLength ); - pstrDestination += nReplacementLength; - pstrPreviousHit = const_cast(pstrHit) + nTargetLength; - } - - // copy trailing stuff - if ( pstrDestination != pstrPreviousHit ) - { - // memmove very important as it is ok with overlaps. - size_t nRemainder = (pstrNew + nOldLength) - pstrPreviousHit; - memmove( pstrDestination, pstrPreviousHit, nRemainder ); - } - - Assert( PrepareBuffer( nNewLength ) == pstrNew ); - } - - } - } - - return vecMatches.Count(); -} - -//----------------------------------------------------------------------------- -// Purpose: Indicates if the target string exists in this instance. -// The index is negative if the target string is not found, otherwise it is the index in the string. -//----------------------------------------------------------------------------- -ptrdiff_t CUtlStringBuilder::IndexOf( const char *pstrTarget ) const -{ - return ::IndexOf( String(), pstrTarget ); -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string ends with the string passed in -//----------------------------------------------------------------------------- -bool CUtlStringBuilder::BEndsWith( const char *pchString ) const -{ - return ::BEndsWith( String(), pchString, false ); -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string ends with the string passed in (caseless) -//----------------------------------------------------------------------------- -bool CUtlStringBuilder::BEndsWithCaseless( const char *pchString ) const -{ - return ::BEndsWith( String(), pchString, true ); -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string starts with the string passed in -//----------------------------------------------------------------------------- -bool CUtlStringBuilder::BStartsWith( const char *pchString ) const -{ - return ::BStartsWith( String(), pchString, false ); -} - - -//----------------------------------------------------------------------------- -// Purpose: returns true if the string ends with the string passed in (caseless) -//----------------------------------------------------------------------------- -bool CUtlStringBuilder::BStartsWithCaseless( const char *pchString ) const -{ - return ::BStartsWith( String(), pchString, true ); -} - - -//----------------------------------------------------------------------------- -// Purpose: format binary data as hex characters, appending to existing data -//----------------------------------------------------------------------------- -void CUtlStringBuilder::AppendHex( const uint8 *pbInput, size_t cubInput, bool bLowercase /* = true */ ) -{ - size_t cbOld = Length(); - char *pstrNew = PrepareBuffer( cbOld + cubInput*2, true ); - if ( pstrNew ) - { - const char *pchHexLookup = bLowercase ? "0123456789abcdef" : "0123456789ABCDEF"; - char *pOut = pstrNew + cbOld; - for ( ; cubInput; --cubInput, ++pbInput ) - { - uint8 val = *pbInput; - *pOut++ = pchHexLookup[val >> 4]; - *pOut++ = pchHexLookup[val & 15]; - } - } -} - - -//----------------------------------------------------------------------------- -// Purpose: -// remove whitespace -- anything that is isspace() -- from the string -//----------------------------------------------------------------------------- -size_t CUtlStringBuilder::RemoveWhitespace( ) -{ - if ( HasError() ) - return 0; - - char *pstrDest = m_data.Access(); - size_t cRemoved = ::RemoveWhitespace(pstrDest); - - size_t nNewLength = m_data.Length() - cRemoved; - - if ( cRemoved ) - SetLength( nNewLength ); - - pstrDest = m_data.Access(); - Assert( pstrDest[nNewLength] == '\0' ); // SetLength should have set this - - return cRemoved; -} - - -//----------------------------------------------------------------------------- -// Purpose: Allows setting the size to anything under the current -// capacity. Typically should not be used unless there was a specific -// reason to scribble on the string. Will not touch the string contents, -// but will append a NULL. Returns true if the length was changed. -//----------------------------------------------------------------------------- -bool CUtlStringBuilder::SetLength( size_t nLen ) -{ - if ( nLen == 0 ) - { - bool bRet = Length() > 0; - Clear(); - return bRet; - } - - return m_data.SetLength( nLen ) != NULL; -} - - -//----------------------------------------------------------------------------- -// Purpose: Convert to heap string if needed, and give it away. -//----------------------------------------------------------------------------- -char *CUtlStringBuilder::DetachRawPtr( size_t *pnLen, size_t *pnCapacity ) -{ - size_t nLen = 0; - size_t nCapacity = 0; - char *psz = m_data.DetachHeapString( nLen, nCapacity ); - - if ( pnLen ) - *pnLen = nLen; - - if ( pnCapacity ) - *pnCapacity = nCapacity; - - return psz; -} - - -//----------------------------------------------------------------------------- -// Purpose: Convert to heap string if needed, and give it away. -//----------------------------------------------------------------------------- -CUtlString CUtlStringBuilder::DetachString() -{ - CUtlString ret; - if ( Length() ) - { - size_t nLen = 0; - size_t nCapacity = 0; - ret.SetPtr( m_data.DetachHeapString( nLen, nCapacity ) ); - } - return ret; -} - - - -//----------------------------------------------------------------------------- -// Purpose: -// trim whitespace from front and back of string -//----------------------------------------------------------------------------- -size_t CUtlStringBuilder::TrimWhitespace() -{ - if ( HasError() ) - return 0; - - char *pchString = m_data.Access(); - int cChars = V_StrTrim( pchString ); - - SetLength( cChars ); - - return cChars; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// trim whitespace from back of string -//----------------------------------------------------------------------------- -size_t CUtlStringBuilder::TrimTrailingWhitespace() -{ - if ( HasError() ) - return 0; - - char *pchString = m_data.Access(); - uint32 cChars = Length(); - if ( cChars == 0 ) - return 0; - - char *pCur = &pchString[cChars - 1]; - while ( pCur >= pchString && isspace( *pCur ) ) - { - *pCur = '\0'; - pCur--; - } - - size_t ret = pCur - pchString + 1; - SetLength( ret ); - - return ret; -} - - -//----------------------------------------------------------------------------- -// Purpose: Swaps string contents -//----------------------------------------------------------------------------- -void CUtlStringBuilder::Swap( CUtlStringBuilder &src ) -{ - // swapping m_data.Raw instead of '*this' prevents having to - // copy dynamic strings. Important that m_data doesn't know - // any lifetime rules about its members (ie: it should not have - // a destructor that frees the dynamic string pointer). - Data temp; - temp.Raw = src.m_data.Raw; - src.m_data.Raw = m_data.Raw; - m_data.Raw = temp.Raw; -} - - -//----------------------------------------------------------------------------- -// Purpose: Swaps string contents between CUtlString and CUtlStringBuilder -//----------------------------------------------------------------------------- -void CUtlStringBuilder::Swap( CUtlString &src ) -{ - char *sz = src.DetachRawPtr(); - if ( !IsEmpty() ) - { - src.SetPtr( DetachRawPtr() ); - } - if ( sz && sz[0] ) - { - m_data.FreeHeap(); - m_data.SetPtr( sz, V_strlen( sz ) ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Swaps string contents between CUtlString and CUtlStringBuilder -//----------------------------------------------------------------------------- -void CUtlString::Swap( CUtlStringBuilder &src ) -{ - src.Swap( *this ); -} - - -//----------------------------------------------------------------------------- -// Purpose: adjust length and add null terminator, within capacity bounds -//----------------------------------------------------------------------------- -char *CUtlStringBuilder::Data::SetLength( size_t nChars ) -{ - // heap/stack must be set correctly, and will not - // be changed by this routine. - if ( IsHeap() ) - { - if ( !Heap.m_pchString || nChars > Heap.m_nCapacity ) - return NULL; - Heap.m_nLength = (uint32)nChars; - Heap.m_pchString[nChars] = '\0'; - return Heap.m_pchString; - } - if ( nChars > MAX_STACK_STRLEN ) - return NULL; - Stack.m_szString[nChars] = '\0'; - Stack.SetBytesLeft( MAX_STACK_STRLEN - (uint8)nChars ); - return Stack.m_szString; -} - - -//----------------------------------------------------------------------------- -// Purpose: Give the string away and set to an empty state -//----------------------------------------------------------------------------- -char *CUtlStringBuilder::Data::DetachHeapString( size_t &nLen, size_t &nCapacity ) -{ - MoveToHeap(); - - if ( HasError() ) - { - nLen = 0; - nCapacity = 0; - return NULL; - } - - nLen = Heap.m_nLength; - nCapacity = Heap.m_nCapacity; - char *psz = Heap.m_pchString; - Construct(); - return psz; -} - - -//----------------------------------------------------------------------------- -// Purpose: Allows setting the raw pointer and taking ownership -//----------------------------------------------------------------------------- -void CUtlStringBuilder::Data::SetPtr( char *pchString, size_t nLength ) -{ - // We don't care about the error state since we are totally replacing - // the string. - - // ok, length may be small enough to fit in our short buffer - // but we've already got a dynamically allocated string, so let - // it be in the heap buffer anyways. - Heap.m_pchString = pchString; - Heap.m_nCapacity = (uint32)nLength; - Heap.m_nLength = (uint32)nLength; - Heap.sentinel = STRING_TYPE_SENTINEL; - - // their buffer must have room for the null - Heap.m_pchString[nLength] = '\0'; -} - - -//----------------------------------------------------------------------------- -// Purpose: Enable the error state, moving the string to the heap if -// it isn't there. -//----------------------------------------------------------------------------- -void CUtlStringBuilder::Data::SetError( bool bEnableAssert ) -{ - if ( HasError() ) - return; - - // This is not meant to be used as a status bit. Setting the error state should - // mean something very unexpected happened that you would want a call stack for. - // That is why this asserts unconditionally when the state is being flipped. - if ( bEnableAssert ) - AssertMsg( false, "Error State on string being set." ); - - MoveToHeap(); - - Heap.sentinel = ( STRING_TYPE_SENTINEL | STRING_TYPE_ERROR ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Set string to empty state -//----------------------------------------------------------------------------- -void CUtlStringBuilder::Data::ClearError() -{ - if ( HasError() ) - { - Heap.sentinel = STRING_TYPE_SENTINEL; - Clear(); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: If the string is on the stack, move it to the heap. -// create a null heap string if memory can't be allocated. -// Callers of this /need/ the string to be in the heap state -// when done. -//----------------------------------------------------------------------------- -bool CUtlStringBuilder::Data::MoveToHeap() -{ - bool bSuccess = true; - - if ( !IsHeap() ) - { - // try to recover the string at the point of failure, to help with debugging - size_t nLen = Length(); - char *pszHeapString = (char*)PvAlloc( nLen+1 ); - if ( pszHeapString ) - { - // get the string copy before corrupting the stack union - char *pszStackString = Access(); - memcpy( pszHeapString, pszStackString, nLen ); - pszHeapString[nLen] = 0; - - Heap.m_pchString = pszHeapString; - Heap.m_nLength = (uint32)nLen; - Heap.m_nCapacity = (uint32)nLen; - Heap.sentinel = STRING_TYPE_SENTINEL; - } - else - { - Heap.m_pchString = NULL; - Heap.m_nLength = 0; - Heap.m_nCapacity = 0; - bSuccess = false; - Heap.sentinel = ( STRING_TYPE_SENTINEL | STRING_TYPE_ERROR ); - } - - } - - return bSuccess; -} - -#if defined(POSIX) && !defined(NO_MALLOC_OVERRIDE) - -#include "tier0/memdbgoff.h" - -// Some places call CRT routines that return malloc'ed memory, -// so we need a way to call the real CRT free. -void real_free( void *pMem ) -{ - free( pMem ); -} - -#endif