From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/tier1/utlbuffer.cpp | 3592 ++++++++++++++++++++++---------------------- 1 file changed, 1796 insertions(+), 1796 deletions(-) (limited to 'mp/src/tier1/utlbuffer.cpp') diff --git a/mp/src/tier1/utlbuffer.cpp b/mp/src/tier1/utlbuffer.cpp index 665c45fe..ff086171 100644 --- a/mp/src/tier1/utlbuffer.cpp +++ b/mp/src/tier1/utlbuffer.cpp @@ -1,1796 +1,1796 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// $Header: $ -// $NoKeywords: $ -// -// Serialization buffer -//===========================================================================// - -#pragma warning (disable : 4514) - -#include "utlbuffer.h" -#include -#include -#include -#include -#include -#include "tier1/strtools.h" -#include "tier1/characterset.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - - -//----------------------------------------------------------------------------- -// Character conversions for C strings -//----------------------------------------------------------------------------- -class CUtlCStringConversion : public CUtlCharConversion -{ -public: - CUtlCStringConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ); - - // Finds a conversion for the passed-in string, returns length - virtual char FindConversion( const char *pString, int *pLength ); - -private: - char m_pConversion[256]; -}; - - -//----------------------------------------------------------------------------- -// Character conversions for no-escape sequence strings -//----------------------------------------------------------------------------- -class CUtlNoEscConversion : public CUtlCharConversion -{ -public: - CUtlNoEscConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) : - CUtlCharConversion( nEscapeChar, pDelimiter, nCount, pArray ) {} - - // Finds a conversion for the passed-in string, returns length - virtual char FindConversion( const char *pString, int *pLength ) { *pLength = 0; return 0; } -}; - - -//----------------------------------------------------------------------------- -// List of character conversions -//----------------------------------------------------------------------------- -BEGIN_CUSTOM_CHAR_CONVERSION( CUtlCStringConversion, s_StringCharConversion, "\"", '\\' ) - { '\n', "n" }, - { '\t', "t" }, - { '\v', "v" }, - { '\b', "b" }, - { '\r', "r" }, - { '\f', "f" }, - { '\a', "a" }, - { '\\', "\\" }, - { '\?', "\?" }, - { '\'', "\'" }, - { '\"', "\"" }, -END_CUSTOM_CHAR_CONVERSION( CUtlCStringConversion, s_StringCharConversion, "\"", '\\' ) - -CUtlCharConversion *GetCStringCharConversion() -{ - return &s_StringCharConversion; -} - -BEGIN_CUSTOM_CHAR_CONVERSION( CUtlNoEscConversion, s_NoEscConversion, "\"", 0x7F ) - { 0x7F, "" }, -END_CUSTOM_CHAR_CONVERSION( CUtlNoEscConversion, s_NoEscConversion, "\"", 0x7F ) - -CUtlCharConversion *GetNoEscCharConversion() -{ - return &s_NoEscConversion; -} - - -//----------------------------------------------------------------------------- -// Constructor -//----------------------------------------------------------------------------- -CUtlCStringConversion::CUtlCStringConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) : - CUtlCharConversion( nEscapeChar, pDelimiter, nCount, pArray ) -{ - memset( m_pConversion, 0x0, sizeof(m_pConversion) ); - for ( int i = 0; i < nCount; ++i ) - { - m_pConversion[ (unsigned char) pArray[i].m_pReplacementString[0] ] = pArray[i].m_nActualChar; - } -} - -// Finds a conversion for the passed-in string, returns length -char CUtlCStringConversion::FindConversion( const char *pString, int *pLength ) -{ - char c = m_pConversion[ (unsigned char) pString[0] ]; - *pLength = (c != '\0') ? 1 : 0; - return c; -} - - - -//----------------------------------------------------------------------------- -// Constructor -//----------------------------------------------------------------------------- -CUtlCharConversion::CUtlCharConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) -{ - m_nEscapeChar = nEscapeChar; - m_pDelimiter = pDelimiter; - m_nCount = nCount; - m_nDelimiterLength = Q_strlen( pDelimiter ); - m_nMaxConversionLength = 0; - - memset( m_pReplacements, 0, sizeof(m_pReplacements) ); - - for ( int i = 0; i < nCount; ++i ) - { - m_pList[i] = pArray[i].m_nActualChar; - ConversionInfo_t &info = m_pReplacements[ (unsigned char) m_pList[i] ]; - Assert( info.m_pReplacementString == 0 ); - info.m_pReplacementString = pArray[i].m_pReplacementString; - info.m_nLength = Q_strlen( info.m_pReplacementString ); - if ( info.m_nLength > m_nMaxConversionLength ) - { - m_nMaxConversionLength = info.m_nLength; - } - } -} - - -//----------------------------------------------------------------------------- -// Escape character + delimiter -//----------------------------------------------------------------------------- -char CUtlCharConversion::GetEscapeChar() const -{ - return m_nEscapeChar; -} - -const char *CUtlCharConversion::GetDelimiter() const -{ - return m_pDelimiter; -} - -int CUtlCharConversion::GetDelimiterLength() const -{ - return m_nDelimiterLength; -} - - -//----------------------------------------------------------------------------- -// Constructor -//----------------------------------------------------------------------------- -const char *CUtlCharConversion::GetConversionString( char c ) const -{ - return m_pReplacements[ (unsigned char) c ].m_pReplacementString; -} - -int CUtlCharConversion::GetConversionLength( char c ) const -{ - return m_pReplacements[ (unsigned char) c ].m_nLength; -} - -int CUtlCharConversion::MaxConversionLength() const -{ - return m_nMaxConversionLength; -} - - -//----------------------------------------------------------------------------- -// Finds a conversion for the passed-in string, returns length -//----------------------------------------------------------------------------- -char CUtlCharConversion::FindConversion( const char *pString, int *pLength ) -{ - for ( int i = 0; i < m_nCount; ++i ) - { - if ( !Q_strcmp( pString, m_pReplacements[ (unsigned char) m_pList[i] ].m_pReplacementString ) ) - { - *pLength = m_pReplacements[ (unsigned char) m_pList[i] ].m_nLength; - return m_pList[i]; - } - } - - *pLength = 0; - return '\0'; -} - - -//----------------------------------------------------------------------------- -// constructors -//----------------------------------------------------------------------------- -CUtlBuffer::CUtlBuffer( int growSize, int initSize, int nFlags ) : - m_Error(0) -{ - MEM_ALLOC_CREDIT(); - m_Memory.Init( growSize, initSize ); - m_Get = 0; - m_Put = 0; - m_nTab = 0; - m_nOffset = 0; - m_Flags = nFlags; - if ( (initSize != 0) && !IsReadOnly() ) - { - m_nMaxPut = -1; - AddNullTermination(); - } - else - { - m_nMaxPut = 0; - } - SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow ); -} - -CUtlBuffer::CUtlBuffer( const void *pBuffer, int nSize, int nFlags ) : - m_Memory( (unsigned char*)pBuffer, nSize ), m_Error(0) -{ - Assert( nSize != 0 ); - - m_Get = 0; - m_Put = 0; - m_nTab = 0; - m_nOffset = 0; - m_Flags = nFlags; - if ( IsReadOnly() ) - { - m_nMaxPut = nSize; - } - else - { - m_nMaxPut = -1; - AddNullTermination(); - } - SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow ); -} - - -//----------------------------------------------------------------------------- -// Modifies the buffer to be binary or text; Blows away the buffer and the CONTAINS_CRLF value. -//----------------------------------------------------------------------------- -void CUtlBuffer::SetBufferType( bool bIsText, bool bContainsCRLF ) -{ -#ifdef _DEBUG - // If the buffer is empty, there is no opportunity for this stuff to fail - if ( TellMaxPut() != 0 ) - { - if ( IsText() ) - { - if ( bIsText ) - { - Assert( ContainsCRLF() == bContainsCRLF ); - } - else - { - Assert( ContainsCRLF() ); - } - } - else - { - if ( bIsText ) - { - Assert( bContainsCRLF ); - } - } - } -#endif - - if ( bIsText ) - { - m_Flags |= TEXT_BUFFER; - } - else - { - m_Flags &= ~TEXT_BUFFER; - } - if ( bContainsCRLF ) - { - m_Flags |= CONTAINS_CRLF; - } - else - { - m_Flags &= ~CONTAINS_CRLF; - } -} - - -//----------------------------------------------------------------------------- -// Attaches the buffer to external memory.... -//----------------------------------------------------------------------------- -void CUtlBuffer::SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags ) -{ - m_Memory.SetExternalBuffer( (unsigned char*)pMemory, nSize ); - - // Reset all indices; we just changed memory - m_Get = 0; - m_Put = nInitialPut; - m_nTab = 0; - m_Error = 0; - m_nOffset = 0; - m_Flags = nFlags; - m_nMaxPut = -1; - AddNullTermination(); -} - -//----------------------------------------------------------------------------- -// Assumes an external buffer but manages its deletion -//----------------------------------------------------------------------------- -void CUtlBuffer::AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags ) -{ - m_Memory.AssumeMemory( (unsigned char*) pMemory, nSize ); - - // Reset all indices; we just changed memory - m_Get = 0; - m_Put = nInitialPut; - m_nTab = 0; - m_Error = 0; - m_nOffset = 0; - m_Flags = nFlags; - m_nMaxPut = -1; - AddNullTermination(); -} - -//----------------------------------------------------------------------------- -// Makes sure we've got at least this much memory -//----------------------------------------------------------------------------- -void CUtlBuffer::EnsureCapacity( int num ) -{ - MEM_ALLOC_CREDIT(); - // Add one extra for the null termination - num += 1; - if ( m_Memory.IsExternallyAllocated() ) - { - if ( IsGrowable() && ( m_Memory.NumAllocated() < num ) ) - { - m_Memory.ConvertToGrowableMemory( 0 ); - } - else - { - num -= 1; - } - } - - m_Memory.EnsureCapacity( num ); -} - - -//----------------------------------------------------------------------------- -// Base get method from which all others derive -//----------------------------------------------------------------------------- -void CUtlBuffer::Get( void* pMem, int size ) -{ - if ( size > 0 && CheckGet( size ) ) - { - int Index = m_Get - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) ); - - memcpy( pMem, &m_Memory[ Index ], size ); - m_Get += size; - } -} - - -//----------------------------------------------------------------------------- -// This will get at least 1 byte and up to nSize bytes. -// It will return the number of bytes actually read. -//----------------------------------------------------------------------------- -int CUtlBuffer::GetUpTo( void *pMem, int nSize ) -{ - if ( CheckArbitraryPeekGet( 0, nSize ) ) - { - int Index = m_Get - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nSize - 1 ) ); - - memcpy( pMem, &m_Memory[ Index ], nSize ); - m_Get += nSize; - return nSize; - } - return 0; -} - - -//----------------------------------------------------------------------------- -// Eats whitespace -//----------------------------------------------------------------------------- -void CUtlBuffer::EatWhiteSpace() -{ - if ( IsText() && IsValid() ) - { - while ( CheckGet( sizeof(char) ) ) - { - if ( !isspace( *(const unsigned char*)PeekGet() ) ) - break; - m_Get += sizeof(char); - } - } -} - - -//----------------------------------------------------------------------------- -// Eats C++ style comments -//----------------------------------------------------------------------------- -bool CUtlBuffer::EatCPPComment() -{ - if ( IsText() && IsValid() ) - { - // If we don't have a a c++ style comment next, we're done - const char *pPeek = (const char *)PeekGet( 2 * sizeof(char), 0 ); - if ( !pPeek || ( pPeek[0] != '/' ) || ( pPeek[1] != '/' ) ) - return false; - - // Deal with c++ style comments - m_Get += 2; - - // read complete line - for ( char c = GetChar(); IsValid(); c = GetChar() ) - { - if ( c == '\n' ) - break; - } - return true; - } - return false; -} - - -//----------------------------------------------------------------------------- -// Peeks how much whitespace to eat -//----------------------------------------------------------------------------- -int CUtlBuffer::PeekWhiteSpace( int nOffset ) -{ - if ( !IsText() || !IsValid() ) - return 0; - - while ( CheckPeekGet( nOffset, sizeof(char) ) ) - { - if ( !isspace( *(unsigned char*)PeekGet( nOffset ) ) ) - break; - nOffset += sizeof(char); - } - - return nOffset; -} - - -//----------------------------------------------------------------------------- -// Peek size of sting to come, check memory bound -//----------------------------------------------------------------------------- -int CUtlBuffer::PeekStringLength() -{ - if ( !IsValid() ) - return 0; - - // Eat preceeding whitespace - int nOffset = 0; - if ( IsText() ) - { - nOffset = PeekWhiteSpace( nOffset ); - } - - int nStartingOffset = nOffset; - - do - { - int nPeekAmount = 128; - - // NOTE: Add 1 for the terminating zero! - if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) ) - { - if ( nOffset == nStartingOffset ) - return 0; - return nOffset - nStartingOffset + 1; - } - - const char *pTest = (const char *)PeekGet( nOffset ); - - if ( !IsText() ) - { - for ( int i = 0; i < nPeekAmount; ++i ) - { - // The +1 here is so we eat the terminating 0 - if ( pTest[i] == 0 ) - return (i + nOffset - nStartingOffset + 1); - } - } - else - { - for ( int i = 0; i < nPeekAmount; ++i ) - { - // The +1 here is so we eat the terminating 0 - if ( isspace((unsigned char)pTest[i]) || (pTest[i] == 0) ) - return (i + nOffset - nStartingOffset + 1); - } - } - - nOffset += nPeekAmount; - - } while ( true ); -} - - -//----------------------------------------------------------------------------- -// Peek size of line to come, check memory bound -//----------------------------------------------------------------------------- -int CUtlBuffer::PeekLineLength() -{ - if ( !IsValid() ) - return 0; - - int nOffset = 0; - int nStartingOffset = nOffset; - - do - { - int nPeekAmount = 128; - - // NOTE: Add 1 for the terminating zero! - if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) ) - { - if ( nOffset == nStartingOffset ) - return 0; - return nOffset - nStartingOffset + 1; - } - - const char *pTest = (const char *)PeekGet( nOffset ); - - for ( int i = 0; i < nPeekAmount; ++i ) - { - // The +2 here is so we eat the terminating '\n' and 0 - if ( pTest[i] == '\n' || pTest[i] == '\r' ) - return (i + nOffset - nStartingOffset + 2); - // The +1 here is so we eat the terminating 0 - if ( pTest[i] == 0 ) - return (i + nOffset - nStartingOffset + 1); - } - - nOffset += nPeekAmount; - - } while ( true ); -} - - -//----------------------------------------------------------------------------- -// Does the next bytes of the buffer match a pattern? -//----------------------------------------------------------------------------- -bool CUtlBuffer::PeekStringMatch( int nOffset, const char *pString, int nLen ) -{ - if ( !CheckPeekGet( nOffset, nLen ) ) - return false; - return !Q_strncmp( (const char*)PeekGet(nOffset), pString, nLen ); -} - - -//----------------------------------------------------------------------------- -// This version of PeekStringLength converts \" to \\ and " to \, etc. -// It also reads a " at the beginning and end of the string -//----------------------------------------------------------------------------- -int CUtlBuffer::PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize ) -{ - if ( !IsText() || !pConv ) - return PeekStringLength(); - - // Eat preceeding whitespace - int nOffset = 0; - if ( IsText() ) - { - nOffset = PeekWhiteSpace( nOffset ); - } - - if ( !PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) - return 0; - - // Try to read ending ", but don't accept \" - int nActualStart = nOffset; - nOffset += pConv->GetDelimiterLength(); - int nLen = 1; // Starts at 1 for the '\0' termination - - do - { - if ( PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) - break; - - if ( !CheckPeekGet( nOffset, 1 ) ) - break; - - char c = *(const char*)PeekGet( nOffset ); - ++nLen; - ++nOffset; - if ( c == pConv->GetEscapeChar() ) - { - int nLength = pConv->MaxConversionLength(); - if ( !CheckArbitraryPeekGet( nOffset, nLength ) ) - break; - - pConv->FindConversion( (const char*)PeekGet(nOffset), &nLength ); - nOffset += nLength; - } - } while (true); - - return bActualSize ? nLen : nOffset - nActualStart + pConv->GetDelimiterLength() + 1; -} - - -//----------------------------------------------------------------------------- -// Reads a null-terminated string -//----------------------------------------------------------------------------- -void CUtlBuffer::GetString( char* pString, int nMaxChars ) -{ - if (!IsValid()) - { - *pString = 0; - return; - } - - if ( nMaxChars == 0 ) - { - nMaxChars = INT_MAX; - } - - // Remember, this *includes* the null character - // It will be 0, however, if the buffer is empty. - int nLen = PeekStringLength(); - - if ( IsText() ) - { - EatWhiteSpace(); - } - - if ( nLen == 0 ) - { - *pString = 0; - m_Error |= GET_OVERFLOW; - return; - } - - // Strip off the terminating NULL - if ( nLen <= nMaxChars ) - { - Get( pString, nLen - 1 ); - pString[ nLen - 1 ] = 0; - } - else - { - Get( pString, nMaxChars - 1 ); - pString[ nMaxChars - 1 ] = 0; - SeekGet( SEEK_CURRENT, nLen - 1 - nMaxChars ); - } - - // Read the terminating NULL in binary formats - if ( !IsText() ) - { - VerifyEquals( GetChar(), 0 ); - } -} - - -//----------------------------------------------------------------------------- -// Reads up to and including the first \n -//----------------------------------------------------------------------------- -void CUtlBuffer::GetLine( char* pLine, int nMaxChars ) -{ - Assert( IsText() && !ContainsCRLF() ); - - if ( !IsValid() ) - { - *pLine = 0; - return; - } - - if ( nMaxChars == 0 ) - { - nMaxChars = INT_MAX; - } - - // Remember, this *includes* the null character - // It will be 0, however, if the buffer is empty. - int nLen = PeekLineLength(); - if ( nLen == 0 ) - { - *pLine = 0; - m_Error |= GET_OVERFLOW; - return; - } - - // Strip off the terminating NULL - if ( nLen <= nMaxChars ) - { - Get( pLine, nLen - 1 ); - pLine[ nLen - 1 ] = 0; - } - else - { - Get( pLine, nMaxChars - 1 ); - pLine[ nMaxChars - 1 ] = 0; - SeekGet( SEEK_CURRENT, nLen - 1 - nMaxChars ); - } -} - - -//----------------------------------------------------------------------------- -// This version of GetString converts \ to \\ and " to \", etc. -// It also places " at the beginning and end of the string -//----------------------------------------------------------------------------- -char CUtlBuffer::GetDelimitedCharInternal( CUtlCharConversion *pConv ) -{ - char c = GetChar(); - if ( c == pConv->GetEscapeChar() ) - { - int nLength = pConv->MaxConversionLength(); - if ( !CheckArbitraryPeekGet( 0, nLength ) ) - return '\0'; - - c = pConv->FindConversion( (const char *)PeekGet(), &nLength ); - SeekGet( SEEK_CURRENT, nLength ); - } - - return c; -} - -char CUtlBuffer::GetDelimitedChar( CUtlCharConversion *pConv ) -{ - if ( !IsText() || !pConv ) - return GetChar( ); - return GetDelimitedCharInternal( pConv ); -} - -void CUtlBuffer::GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars ) -{ - if ( !IsText() || !pConv ) - { - GetString( pString, nMaxChars ); - return; - } - - if (!IsValid()) - { - *pString = 0; - return; - } - - if ( nMaxChars == 0 ) - { - nMaxChars = INT_MAX; - } - - EatWhiteSpace(); - if ( !PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) - return; - - // Pull off the starting delimiter - SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() ); - - int nRead = 0; - while ( IsValid() ) - { - if ( PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) - { - SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() ); - break; - } - - char c = GetDelimitedCharInternal( pConv ); - - if ( nRead < nMaxChars ) - { - pString[nRead] = c; - ++nRead; - } - } - - if ( nRead >= nMaxChars ) - { - nRead = nMaxChars - 1; - } - pString[nRead] = '\0'; -} - - -//----------------------------------------------------------------------------- -// Checks if a get is ok -//----------------------------------------------------------------------------- -bool CUtlBuffer::CheckGet( int nSize ) -{ - if ( m_Error & GET_OVERFLOW ) - return false; - - if ( TellMaxPut() < m_Get + nSize ) - { - m_Error |= GET_OVERFLOW; - return false; - } - - if ( ( m_Get < m_nOffset ) || ( m_Memory.NumAllocated() < m_Get - m_nOffset + nSize ) ) - { - if ( !OnGetOverflow( nSize ) ) - { - m_Error |= GET_OVERFLOW; - return false; - } - } - - return true; -} - - -//----------------------------------------------------------------------------- -// Checks if a peek get is ok -//----------------------------------------------------------------------------- -bool CUtlBuffer::CheckPeekGet( int nOffset, int nSize ) -{ - if ( m_Error & GET_OVERFLOW ) - return false; - - // Checking for peek can't set the overflow flag - bool bOk = CheckGet( nOffset + nSize ); - m_Error &= ~GET_OVERFLOW; - return bOk; -} - - -//----------------------------------------------------------------------------- -// Call this to peek arbitrarily long into memory. It doesn't fail unless -// it can't read *anything* new -//----------------------------------------------------------------------------- -bool CUtlBuffer::CheckArbitraryPeekGet( int nOffset, int &nIncrement ) -{ - if ( TellGet() + nOffset >= TellMaxPut() ) - { - nIncrement = 0; - return false; - } - - if ( TellGet() + nOffset + nIncrement > TellMaxPut() ) - { - nIncrement = TellMaxPut() - TellGet() - nOffset; - } - - // NOTE: CheckPeekGet could modify TellMaxPut for streaming files - // We have to call TellMaxPut again here - CheckPeekGet( nOffset, nIncrement ); - int nMaxGet = TellMaxPut() - TellGet(); - if ( nMaxGet < nIncrement ) - { - nIncrement = nMaxGet; - } - return (nIncrement != 0); -} - - -//----------------------------------------------------------------------------- -// Peek part of the butt -//----------------------------------------------------------------------------- -const void* CUtlBuffer::PeekGet( int nMaxSize, int nOffset ) -{ - if ( !CheckPeekGet( nOffset, nMaxSize ) ) - return NULL; - - int Index = m_Get + nOffset - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nMaxSize - 1 ) ); - - return &m_Memory[ Index ]; -} - - -//----------------------------------------------------------------------------- -// Change where I'm reading -//----------------------------------------------------------------------------- -void CUtlBuffer::SeekGet( SeekType_t type, int offset ) -{ - switch( type ) - { - case SEEK_HEAD: - m_Get = offset; - break; - - case SEEK_CURRENT: - m_Get += offset; - break; - - case SEEK_TAIL: - m_Get = m_nMaxPut - offset; - break; - } - - if ( m_Get > m_nMaxPut ) - { - m_Error |= GET_OVERFLOW; - } - else - { - m_Error &= ~GET_OVERFLOW; - if ( m_Get < m_nOffset || m_Get >= m_nOffset + Size() ) - { - OnGetOverflow( -1 ); - } - } -} - - -//----------------------------------------------------------------------------- -// Parse... -//----------------------------------------------------------------------------- - -#pragma warning ( disable : 4706 ) - -int CUtlBuffer::VaScanf( const char* pFmt, va_list list ) -{ - Assert( pFmt ); - if ( m_Error || !IsText() ) - return 0; - - int numScanned = 0; - int nLength; - char c; - char* pEnd; - while ( (c = *pFmt++) ) - { - // Stop if we hit the end of the buffer - if ( m_Get >= TellMaxPut() ) - { - m_Error |= GET_OVERFLOW; - break; - } - - switch (c) - { - case ' ': - // eat all whitespace - EatWhiteSpace(); - break; - - case '%': - { - // Conversion character... try to convert baby! - char type = *pFmt++; - if (type == 0) - return numScanned; - - switch(type) - { - case 'c': - { - char* ch = va_arg( list, char * ); - if ( CheckPeekGet( 0, sizeof(char) ) ) - { - *ch = *(const char*)PeekGet(); - ++m_Get; - } - else - { - *ch = 0; - return numScanned; - } - } - break; - - case 'i': - case 'd': - { - int* i = va_arg( list, int * ); - - // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters - nLength = 128; - if ( !CheckArbitraryPeekGet( 0, nLength ) ) - { - *i = 0; - return numScanned; - } - - *i = strtol( (char*)PeekGet(), &pEnd, 10 ); - int nBytesRead = (int)( pEnd - (char*)PeekGet() ); - if ( nBytesRead == 0 ) - return numScanned; - m_Get += nBytesRead; - } - break; - - case 'x': - { - int* i = va_arg( list, int * ); - - // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters - nLength = 128; - if ( !CheckArbitraryPeekGet( 0, nLength ) ) - { - *i = 0; - return numScanned; - } - - *i = strtol( (char*)PeekGet(), &pEnd, 16 ); - int nBytesRead = (int)( pEnd - (char*)PeekGet() ); - if ( nBytesRead == 0 ) - return numScanned; - m_Get += nBytesRead; - } - break; - - case 'u': - { - unsigned int* u = va_arg( list, unsigned int *); - - // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters - nLength = 128; - if ( !CheckArbitraryPeekGet( 0, nLength ) ) - { - *u = 0; - return numScanned; - } - - *u = strtoul( (char*)PeekGet(), &pEnd, 10 ); - int nBytesRead = (int)( pEnd - (char*)PeekGet() ); - if ( nBytesRead == 0 ) - return numScanned; - m_Get += nBytesRead; - } - break; - - case 'f': - { - float* f = va_arg( list, float *); - - // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters - nLength = 128; - if ( !CheckArbitraryPeekGet( 0, nLength ) ) - { - *f = 0.0f; - return numScanned; - } - - *f = (float)strtod( (char*)PeekGet(), &pEnd ); - int nBytesRead = (int)( pEnd - (char*)PeekGet() ); - if ( nBytesRead == 0 ) - return numScanned; - m_Get += nBytesRead; - } - break; - - case 's': - { - char* s = va_arg( list, char * ); - GetString( s ); - } - break; - - default: - { - // unimplemented scanf type - Assert(0); - return numScanned; - } - break; - } - - ++numScanned; - } - break; - - default: - { - // Here we have to match the format string character - // against what's in the buffer or we're done. - if ( !CheckPeekGet( 0, sizeof(char) ) ) - return numScanned; - - if ( c != *(const char*)PeekGet() ) - return numScanned; - - ++m_Get; - } - } - } - return numScanned; -} - -#pragma warning ( default : 4706 ) - -int CUtlBuffer::Scanf( const char* pFmt, ... ) -{ - va_list args; - - va_start( args, pFmt ); - int count = VaScanf( pFmt, args ); - va_end( args ); - - return count; -} - - -//----------------------------------------------------------------------------- -// Advance the get index until after the particular string is found -// Do not eat whitespace before starting. Return false if it failed -//----------------------------------------------------------------------------- -bool CUtlBuffer::GetToken( const char *pToken ) -{ - Assert( pToken ); - - // Look for the token - int nLen = Q_strlen( pToken ); - - int nSizeToCheck = Size() - TellGet() - m_nOffset; - - int nGet = TellGet(); - do - { - int nMaxSize = TellMaxPut() - TellGet(); - if ( nMaxSize < nSizeToCheck ) - { - nSizeToCheck = nMaxSize; - } - if ( nLen > nSizeToCheck ) - break; - - if ( !CheckPeekGet( 0, nSizeToCheck ) ) - break; - - const char *pBufStart = (const char*)PeekGet(); - const char *pFoundEnd = Q_strnistr( pBufStart, pToken, nSizeToCheck ); - if ( pFoundEnd ) - { - size_t nOffset = (size_t)pFoundEnd - (size_t)pBufStart; - SeekGet( CUtlBuffer::SEEK_CURRENT, nOffset + nLen ); - return true; - } - - SeekGet( CUtlBuffer::SEEK_CURRENT, nSizeToCheck - nLen - 1 ); - nSizeToCheck = Size() - (nLen-1); - - } while ( true ); - - SeekGet( CUtlBuffer::SEEK_HEAD, nGet ); - return false; -} - - -//----------------------------------------------------------------------------- -// (For text buffers only) -// Parse a token from the buffer: -// Grab all text that lies between a starting delimiter + ending delimiter -// (skipping whitespace that leads + trails both delimiters). -// Note the delimiter checks are case-insensitive. -// If successful, the get index is advanced and the function returns true, -// otherwise the index is not advanced and the function returns false. -//----------------------------------------------------------------------------- -bool CUtlBuffer::ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen ) -{ - int nCharsToCopy = 0; - int nCurrentGet = 0; - - size_t nEndingDelimLen; - - // Starting delimiter is optional - char emptyBuf = '\0'; - if ( !pStartingDelim ) - { - pStartingDelim = &emptyBuf; - } - - // Ending delimiter is not - Assert( pEndingDelim && pEndingDelim[0] ); - nEndingDelimLen = Q_strlen( pEndingDelim ); - - int nStartGet = TellGet(); - char nCurrChar; - int nTokenStart = -1; - EatWhiteSpace( ); - while ( *pStartingDelim ) - { - nCurrChar = *pStartingDelim++; - if ( !isspace((unsigned char)nCurrChar) ) - { - if ( tolower( GetChar() ) != tolower( nCurrChar ) ) - goto parseFailed; - } - else - { - EatWhiteSpace(); - } - } - - EatWhiteSpace(); - nTokenStart = TellGet(); - if ( !GetToken( pEndingDelim ) ) - goto parseFailed; - - nCurrentGet = TellGet(); - nCharsToCopy = (nCurrentGet - nEndingDelimLen) - nTokenStart; - if ( nCharsToCopy >= nMaxLen ) - { - nCharsToCopy = nMaxLen - 1; - } - - if ( nCharsToCopy > 0 ) - { - SeekGet( CUtlBuffer::SEEK_HEAD, nTokenStart ); - Get( pString, nCharsToCopy ); - if ( !IsValid() ) - goto parseFailed; - - // Eat trailing whitespace - for ( ; nCharsToCopy > 0; --nCharsToCopy ) - { - if ( !isspace( (unsigned char)pString[ nCharsToCopy-1 ] ) ) - break; - } - } - pString[ nCharsToCopy ] = '\0'; - - // Advance the Get index - SeekGet( CUtlBuffer::SEEK_HEAD, nCurrentGet ); - return true; - -parseFailed: - // Revert the get index - SeekGet( SEEK_HEAD, nStartGet ); - pString[0] = '\0'; - return false; -} - - -//----------------------------------------------------------------------------- -// Parses the next token, given a set of character breaks to stop at -//----------------------------------------------------------------------------- -int CUtlBuffer::ParseToken( characterset_t *pBreaks, char *pTokenBuf, int nMaxLen, bool bParseComments ) -{ - Assert( nMaxLen > 0 ); - pTokenBuf[0] = 0; - - // skip whitespace + comments - while ( true ) - { - if ( !IsValid() ) - return -1; - EatWhiteSpace(); - if ( bParseComments ) - { - if ( !EatCPPComment() ) - break; - } - else - { - break; - } - } - - char c = GetChar(); - - // End of buffer - if ( c == 0 ) - return -1; - - // handle quoted strings specially - if ( c == '\"' ) - { - int nLen = 0; - while( IsValid() ) - { - c = GetChar(); - if ( c == '\"' || !c ) - { - pTokenBuf[nLen] = 0; - return nLen; - } - pTokenBuf[nLen] = c; - if ( ++nLen == nMaxLen ) - { - pTokenBuf[nLen-1] = 0; - return nMaxLen; - } - } - - // In this case, we hit the end of the buffer before hitting the end qoute - pTokenBuf[nLen] = 0; - return nLen; - } - - // parse single characters - if ( IN_CHARACTERSET( *pBreaks, c ) ) - { - pTokenBuf[0] = c; - pTokenBuf[1] = 0; - return 1; - } - - // parse a regular word - int nLen = 0; - while ( true ) - { - pTokenBuf[nLen] = c; - if ( ++nLen == nMaxLen ) - { - pTokenBuf[nLen-1] = 0; - return nMaxLen; - } - c = GetChar(); - if ( !IsValid() ) - break; - - if ( IN_CHARACTERSET( *pBreaks, c ) || c == '\"' || c <= ' ' ) - { - SeekGet( SEEK_CURRENT, -1 ); - break; - } - } - - pTokenBuf[nLen] = 0; - return nLen; -} - - - -//----------------------------------------------------------------------------- -// Serialization -//----------------------------------------------------------------------------- -void CUtlBuffer::Put( const void *pMem, int size ) -{ - if ( size && CheckPut( size ) ) - { - int Index = m_Put - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) ); - if( Index >= 0 ) - { - memcpy( &m_Memory[ Index ], pMem, size ); - m_Put += size; - - AddNullTermination(); - } - } -} - - -//----------------------------------------------------------------------------- -// Writes a null-terminated string -//----------------------------------------------------------------------------- -void CUtlBuffer::PutString( const char* pString ) -{ - if (!IsText()) - { - if ( pString ) - { - // Not text? append a null at the end. - size_t nLen = Q_strlen( pString ) + 1; - Put( pString, nLen * sizeof(char) ); - return; - } - else - { - PutTypeBin( 0 ); - } - } - else if (pString) - { - int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab; - if ( nTabCount > 0 ) - { - if ( WasLastCharacterCR() ) - { - PutTabs(); - } - - const char* pEndl = strchr( pString, '\n' ); - while ( pEndl ) - { - size_t nSize = (size_t)pEndl - (size_t)pString + sizeof(char); - Put( pString, nSize ); - pString = pEndl + 1; - if ( *pString ) - { - PutTabs(); - pEndl = strchr( pString, '\n' ); - } - else - { - pEndl = NULL; - } - } - } - size_t nLen = Q_strlen( pString ); - if ( nLen ) - { - Put( pString, nLen * sizeof(char) ); - } - } -} - - -//----------------------------------------------------------------------------- -// This version of PutString converts \ to \\ and " to \", etc. -// It also places " at the beginning and end of the string -//----------------------------------------------------------------------------- -inline void CUtlBuffer::PutDelimitedCharInternal( CUtlCharConversion *pConv, char c ) -{ - int l = pConv->GetConversionLength( c ); - if ( l == 0 ) - { - PutChar( c ); - } - else - { - PutChar( pConv->GetEscapeChar() ); - Put( pConv->GetConversionString( c ), l ); - } -} - -void CUtlBuffer::PutDelimitedChar( CUtlCharConversion *pConv, char c ) -{ - if ( !IsText() || !pConv ) - { - PutChar( c ); - return; - } - - PutDelimitedCharInternal( pConv, c ); -} - -void CUtlBuffer::PutDelimitedString( CUtlCharConversion *pConv, const char *pString ) -{ - if ( !IsText() || !pConv ) - { - PutString( pString ); - return; - } - - if ( WasLastCharacterCR() ) - { - PutTabs(); - } - Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() ); - - int nLen = pString ? Q_strlen( pString ) : 0; - for ( int i = 0; i < nLen; ++i ) - { - PutDelimitedCharInternal( pConv, pString[i] ); - } - - if ( WasLastCharacterCR() ) - { - PutTabs(); - } - Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() ); -} - - -void CUtlBuffer::VaPrintf( const char* pFmt, va_list list ) -{ - char temp[2048]; -#ifdef DBGFLAG_ASSERT - int nLen = -#endif - Q_vsnprintf( temp, sizeof( temp ), pFmt, list ); - Assert( nLen < 2048 ); - PutString( temp ); -} - -void CUtlBuffer::Printf( const char* pFmt, ... ) -{ - va_list args; - - va_start( args, pFmt ); - VaPrintf( pFmt, args ); - va_end( args ); -} - - -//----------------------------------------------------------------------------- -// Calls the overflow functions -//----------------------------------------------------------------------------- -void CUtlBuffer::SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc ) -{ - m_GetOverflowFunc = getFunc; - m_PutOverflowFunc = putFunc; -} - - -//----------------------------------------------------------------------------- -// Calls the overflow functions -//----------------------------------------------------------------------------- -bool CUtlBuffer::OnPutOverflow( int nSize ) -{ - return (this->*m_PutOverflowFunc)( nSize ); -} - -bool CUtlBuffer::OnGetOverflow( int nSize ) -{ - return (this->*m_GetOverflowFunc)( nSize ); -} - - -//----------------------------------------------------------------------------- -// Checks if a put is ok -//----------------------------------------------------------------------------- -bool CUtlBuffer::PutOverflow( int nSize ) -{ - MEM_ALLOC_CREDIT(); - - if ( m_Memory.IsExternallyAllocated() ) - { - if ( !IsGrowable() ) - return false; - - m_Memory.ConvertToGrowableMemory( 0 ); - } - - while( Size() < m_Put - m_nOffset + nSize ) - { - m_Memory.Grow(); - } - - return true; -} - -bool CUtlBuffer::GetOverflow( int nSize ) -{ - return false; -} - - -//----------------------------------------------------------------------------- -// Checks if a put is ok -//----------------------------------------------------------------------------- -bool CUtlBuffer::CheckPut( int nSize ) -{ - if ( ( m_Error & PUT_OVERFLOW ) || IsReadOnly() ) - return false; - - if ( ( m_Put < m_nOffset ) || ( m_Memory.NumAllocated() < m_Put - m_nOffset + nSize ) ) - { - if ( !OnPutOverflow( nSize ) ) - { - m_Error |= PUT_OVERFLOW; - return false; - } - } - return true; -} - -void CUtlBuffer::SeekPut( SeekType_t type, int offset ) -{ - int nNextPut = m_Put; - switch( type ) - { - case SEEK_HEAD: - nNextPut = offset; - break; - - case SEEK_CURRENT: - nNextPut += offset; - break; - - case SEEK_TAIL: - nNextPut = m_nMaxPut - offset; - break; - } - - // Force a write of the data - // FIXME: We could make this more optimal potentially by writing out - // the entire buffer if you seek outside the current range - - // NOTE: This call will write and will also seek the file to nNextPut. - OnPutOverflow( -nNextPut-1 ); - m_Put = nNextPut; - - AddNullTermination(); -} - - -void CUtlBuffer::ActivateByteSwapping( bool bActivate ) -{ - m_Byteswap.ActivateByteSwapping( bActivate ); -} - -void CUtlBuffer::SetBigEndian( bool bigEndian ) -{ - m_Byteswap.SetTargetBigEndian( bigEndian ); -} - -bool CUtlBuffer::IsBigEndian( void ) -{ - return m_Byteswap.IsTargetBigEndian(); -} - - -//----------------------------------------------------------------------------- -// null terminate the buffer -//----------------------------------------------------------------------------- -void CUtlBuffer::AddNullTermination( void ) -{ - if ( m_Put > m_nMaxPut ) - { - if ( !IsReadOnly() && ((m_Error & PUT_OVERFLOW) == 0) ) - { - // Add null termination value - if ( CheckPut( 1 ) ) - { - int Index = m_Put - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) ); - if( Index >= 0 ) - { - m_Memory[ Index ] = 0; - } - } - else - { - // Restore the overflow state, it was valid before... - m_Error &= ~PUT_OVERFLOW; - } - } - m_nMaxPut = m_Put; - } -} - - -//----------------------------------------------------------------------------- -// Converts a buffer from a CRLF buffer to a CR buffer (and back) -// Returns false if no conversion was necessary (and outBuf is left untouched) -// If the conversion occurs, outBuf will be cleared. -//----------------------------------------------------------------------------- -bool CUtlBuffer::ConvertCRLF( CUtlBuffer &outBuf ) -{ - if ( !IsText() || !outBuf.IsText() ) - return false; - - if ( ContainsCRLF() == outBuf.ContainsCRLF() ) - return false; - - int nInCount = TellMaxPut(); - - outBuf.Purge(); - outBuf.EnsureCapacity( nInCount ); - - bool bFromCRLF = ContainsCRLF(); - - // Start reading from the beginning - int nGet = TellGet(); - int nPut = TellPut(); - int nGetDelta = 0; - int nPutDelta = 0; - - const char *pBase = (const char*)Base(); - int nCurrGet = 0; - while ( nCurrGet < nInCount ) - { - const char *pCurr = &pBase[nCurrGet]; - if ( bFromCRLF ) - { - const char *pNext = Q_strnistr( pCurr, "\r\n", nInCount - nCurrGet ); - if ( !pNext ) - { - outBuf.Put( pCurr, nInCount - nCurrGet ); - break; - } - - int nBytes = (size_t)pNext - (size_t)pCurr; - outBuf.Put( pCurr, nBytes ); - outBuf.PutChar( '\n' ); - nCurrGet += nBytes + 2; - if ( nGet >= nCurrGet - 1 ) - { - --nGetDelta; - } - if ( nPut >= nCurrGet - 1 ) - { - --nPutDelta; - } - } - else - { - const char *pNext = Q_strnchr( pCurr, '\n', nInCount - nCurrGet ); - if ( !pNext ) - { - outBuf.Put( pCurr, nInCount - nCurrGet ); - break; - } - - int nBytes = (size_t)pNext - (size_t)pCurr; - outBuf.Put( pCurr, nBytes ); - outBuf.PutChar( '\r' ); - outBuf.PutChar( '\n' ); - nCurrGet += nBytes + 1; - if ( nGet >= nCurrGet ) - { - ++nGetDelta; - } - if ( nPut >= nCurrGet ) - { - ++nPutDelta; - } - } - } - - Assert( nPut + nPutDelta <= outBuf.TellMaxPut() ); - - outBuf.SeekGet( SEEK_HEAD, nGet + nGetDelta ); - outBuf.SeekPut( SEEK_HEAD, nPut + nPutDelta ); - - return true; -} - -//----------------------------------------------------------------------------- -// Fast swap -//----------------------------------------------------------------------------- -void CUtlBuffer::Swap( CUtlBuffer &buf ) -{ - V_swap( m_Get, buf.m_Get ); - V_swap( m_Put, buf.m_Put ); - V_swap( m_nMaxPut, buf.m_nMaxPut ); - V_swap( m_Error, buf.m_Error ); - m_Memory.Swap( buf.m_Memory ); -} - - -//----------------------------------------------------------------------------- -// Fast swap w/ a CUtlMemory. -//----------------------------------------------------------------------------- -void CUtlBuffer::Swap( CUtlMemory &mem ) -{ - m_Get = 0; - m_Put = mem.Count(); - m_nMaxPut = mem.Count(); - m_Error = 0; - m_Memory.Swap( mem ); -} - -//--------------------------------------------------------------------------- -// Implementation of CUtlInplaceBuffer -//--------------------------------------------------------------------------- - -CUtlInplaceBuffer::CUtlInplaceBuffer( int growSize /* = 0 */, int initSize /* = 0 */, int nFlags /* = 0 */ ) : - CUtlBuffer( growSize, initSize, nFlags ) -{ - NULL; -} - -bool CUtlInplaceBuffer::InplaceGetLinePtr( char **ppszInBufferPtr, int *pnLineLength ) -{ - Assert( IsText() && !ContainsCRLF() ); - - int nLineLen = PeekLineLength(); - if ( nLineLen <= 1 ) - { - SeekGet( SEEK_TAIL, 0 ); - return false; - } - - -- nLineLen; // because it accounts for putting a terminating null-character - - char *pszLine = ( char * ) const_cast< void * >( PeekGet() ); - SeekGet( SEEK_CURRENT, nLineLen ); - - // Set the out args - if ( ppszInBufferPtr ) - *ppszInBufferPtr = pszLine; - - if ( pnLineLength ) - *pnLineLength = nLineLen; - - return true; -} - -char * CUtlInplaceBuffer::InplaceGetLinePtr( void ) -{ - char *pszLine = NULL; - int nLineLen = 0; - - if ( InplaceGetLinePtr( &pszLine, &nLineLen ) ) - { - Assert( nLineLen >= 1 ); - - switch ( pszLine[ nLineLen - 1 ] ) - { - case '\n': - case '\r': - pszLine[ nLineLen - 1 ] = 0; - if ( -- nLineLen ) - { - switch ( pszLine[ nLineLen - 1 ] ) - { - case '\n': - case '\r': - pszLine[ nLineLen - 1 ] = 0; - break; - } - } - break; - - default: - Assert( pszLine[ nLineLen ] == 0 ); - break; - } - } - - return pszLine; -} - +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// $Header: $ +// $NoKeywords: $ +// +// Serialization buffer +//===========================================================================// + +#pragma warning (disable : 4514) + +#include "utlbuffer.h" +#include +#include +#include +#include +#include +#include "tier1/strtools.h" +#include "tier1/characterset.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Character conversions for C strings +//----------------------------------------------------------------------------- +class CUtlCStringConversion : public CUtlCharConversion +{ +public: + CUtlCStringConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ); + + // Finds a conversion for the passed-in string, returns length + virtual char FindConversion( const char *pString, int *pLength ); + +private: + char m_pConversion[256]; +}; + + +//----------------------------------------------------------------------------- +// Character conversions for no-escape sequence strings +//----------------------------------------------------------------------------- +class CUtlNoEscConversion : public CUtlCharConversion +{ +public: + CUtlNoEscConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) : + CUtlCharConversion( nEscapeChar, pDelimiter, nCount, pArray ) {} + + // Finds a conversion for the passed-in string, returns length + virtual char FindConversion( const char *pString, int *pLength ) { *pLength = 0; return 0; } +}; + + +//----------------------------------------------------------------------------- +// List of character conversions +//----------------------------------------------------------------------------- +BEGIN_CUSTOM_CHAR_CONVERSION( CUtlCStringConversion, s_StringCharConversion, "\"", '\\' ) + { '\n', "n" }, + { '\t', "t" }, + { '\v', "v" }, + { '\b', "b" }, + { '\r', "r" }, + { '\f', "f" }, + { '\a', "a" }, + { '\\', "\\" }, + { '\?', "\?" }, + { '\'', "\'" }, + { '\"', "\"" }, +END_CUSTOM_CHAR_CONVERSION( CUtlCStringConversion, s_StringCharConversion, "\"", '\\' ) + +CUtlCharConversion *GetCStringCharConversion() +{ + return &s_StringCharConversion; +} + +BEGIN_CUSTOM_CHAR_CONVERSION( CUtlNoEscConversion, s_NoEscConversion, "\"", 0x7F ) + { 0x7F, "" }, +END_CUSTOM_CHAR_CONVERSION( CUtlNoEscConversion, s_NoEscConversion, "\"", 0x7F ) + +CUtlCharConversion *GetNoEscCharConversion() +{ + return &s_NoEscConversion; +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CUtlCStringConversion::CUtlCStringConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) : + CUtlCharConversion( nEscapeChar, pDelimiter, nCount, pArray ) +{ + memset( m_pConversion, 0x0, sizeof(m_pConversion) ); + for ( int i = 0; i < nCount; ++i ) + { + m_pConversion[ (unsigned char) pArray[i].m_pReplacementString[0] ] = pArray[i].m_nActualChar; + } +} + +// Finds a conversion for the passed-in string, returns length +char CUtlCStringConversion::FindConversion( const char *pString, int *pLength ) +{ + char c = m_pConversion[ (unsigned char) pString[0] ]; + *pLength = (c != '\0') ? 1 : 0; + return c; +} + + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CUtlCharConversion::CUtlCharConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) +{ + m_nEscapeChar = nEscapeChar; + m_pDelimiter = pDelimiter; + m_nCount = nCount; + m_nDelimiterLength = Q_strlen( pDelimiter ); + m_nMaxConversionLength = 0; + + memset( m_pReplacements, 0, sizeof(m_pReplacements) ); + + for ( int i = 0; i < nCount; ++i ) + { + m_pList[i] = pArray[i].m_nActualChar; + ConversionInfo_t &info = m_pReplacements[ (unsigned char) m_pList[i] ]; + Assert( info.m_pReplacementString == 0 ); + info.m_pReplacementString = pArray[i].m_pReplacementString; + info.m_nLength = Q_strlen( info.m_pReplacementString ); + if ( info.m_nLength > m_nMaxConversionLength ) + { + m_nMaxConversionLength = info.m_nLength; + } + } +} + + +//----------------------------------------------------------------------------- +// Escape character + delimiter +//----------------------------------------------------------------------------- +char CUtlCharConversion::GetEscapeChar() const +{ + return m_nEscapeChar; +} + +const char *CUtlCharConversion::GetDelimiter() const +{ + return m_pDelimiter; +} + +int CUtlCharConversion::GetDelimiterLength() const +{ + return m_nDelimiterLength; +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +const char *CUtlCharConversion::GetConversionString( char c ) const +{ + return m_pReplacements[ (unsigned char) c ].m_pReplacementString; +} + +int CUtlCharConversion::GetConversionLength( char c ) const +{ + return m_pReplacements[ (unsigned char) c ].m_nLength; +} + +int CUtlCharConversion::MaxConversionLength() const +{ + return m_nMaxConversionLength; +} + + +//----------------------------------------------------------------------------- +// Finds a conversion for the passed-in string, returns length +//----------------------------------------------------------------------------- +char CUtlCharConversion::FindConversion( const char *pString, int *pLength ) +{ + for ( int i = 0; i < m_nCount; ++i ) + { + if ( !Q_strcmp( pString, m_pReplacements[ (unsigned char) m_pList[i] ].m_pReplacementString ) ) + { + *pLength = m_pReplacements[ (unsigned char) m_pList[i] ].m_nLength; + return m_pList[i]; + } + } + + *pLength = 0; + return '\0'; +} + + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- +CUtlBuffer::CUtlBuffer( int growSize, int initSize, int nFlags ) : + m_Error(0) +{ + MEM_ALLOC_CREDIT(); + m_Memory.Init( growSize, initSize ); + m_Get = 0; + m_Put = 0; + m_nTab = 0; + m_nOffset = 0; + m_Flags = nFlags; + if ( (initSize != 0) && !IsReadOnly() ) + { + m_nMaxPut = -1; + AddNullTermination(); + } + else + { + m_nMaxPut = 0; + } + SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow ); +} + +CUtlBuffer::CUtlBuffer( const void *pBuffer, int nSize, int nFlags ) : + m_Memory( (unsigned char*)pBuffer, nSize ), m_Error(0) +{ + Assert( nSize != 0 ); + + m_Get = 0; + m_Put = 0; + m_nTab = 0; + m_nOffset = 0; + m_Flags = nFlags; + if ( IsReadOnly() ) + { + m_nMaxPut = nSize; + } + else + { + m_nMaxPut = -1; + AddNullTermination(); + } + SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow ); +} + + +//----------------------------------------------------------------------------- +// Modifies the buffer to be binary or text; Blows away the buffer and the CONTAINS_CRLF value. +//----------------------------------------------------------------------------- +void CUtlBuffer::SetBufferType( bool bIsText, bool bContainsCRLF ) +{ +#ifdef _DEBUG + // If the buffer is empty, there is no opportunity for this stuff to fail + if ( TellMaxPut() != 0 ) + { + if ( IsText() ) + { + if ( bIsText ) + { + Assert( ContainsCRLF() == bContainsCRLF ); + } + else + { + Assert( ContainsCRLF() ); + } + } + else + { + if ( bIsText ) + { + Assert( bContainsCRLF ); + } + } + } +#endif + + if ( bIsText ) + { + m_Flags |= TEXT_BUFFER; + } + else + { + m_Flags &= ~TEXT_BUFFER; + } + if ( bContainsCRLF ) + { + m_Flags |= CONTAINS_CRLF; + } + else + { + m_Flags &= ~CONTAINS_CRLF; + } +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +void CUtlBuffer::SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags ) +{ + m_Memory.SetExternalBuffer( (unsigned char*)pMemory, nSize ); + + // Reset all indices; we just changed memory + m_Get = 0; + m_Put = nInitialPut; + m_nTab = 0; + m_Error = 0; + m_nOffset = 0; + m_Flags = nFlags; + m_nMaxPut = -1; + AddNullTermination(); +} + +//----------------------------------------------------------------------------- +// Assumes an external buffer but manages its deletion +//----------------------------------------------------------------------------- +void CUtlBuffer::AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags ) +{ + m_Memory.AssumeMemory( (unsigned char*) pMemory, nSize ); + + // Reset all indices; we just changed memory + m_Get = 0; + m_Put = nInitialPut; + m_nTab = 0; + m_Error = 0; + m_nOffset = 0; + m_Flags = nFlags; + m_nMaxPut = -1; + AddNullTermination(); +} + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +void CUtlBuffer::EnsureCapacity( int num ) +{ + MEM_ALLOC_CREDIT(); + // Add one extra for the null termination + num += 1; + if ( m_Memory.IsExternallyAllocated() ) + { + if ( IsGrowable() && ( m_Memory.NumAllocated() < num ) ) + { + m_Memory.ConvertToGrowableMemory( 0 ); + } + else + { + num -= 1; + } + } + + m_Memory.EnsureCapacity( num ); +} + + +//----------------------------------------------------------------------------- +// Base get method from which all others derive +//----------------------------------------------------------------------------- +void CUtlBuffer::Get( void* pMem, int size ) +{ + if ( size > 0 && CheckGet( size ) ) + { + int Index = m_Get - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) ); + + memcpy( pMem, &m_Memory[ Index ], size ); + m_Get += size; + } +} + + +//----------------------------------------------------------------------------- +// This will get at least 1 byte and up to nSize bytes. +// It will return the number of bytes actually read. +//----------------------------------------------------------------------------- +int CUtlBuffer::GetUpTo( void *pMem, int nSize ) +{ + if ( CheckArbitraryPeekGet( 0, nSize ) ) + { + int Index = m_Get - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nSize - 1 ) ); + + memcpy( pMem, &m_Memory[ Index ], nSize ); + m_Get += nSize; + return nSize; + } + return 0; +} + + +//----------------------------------------------------------------------------- +// Eats whitespace +//----------------------------------------------------------------------------- +void CUtlBuffer::EatWhiteSpace() +{ + if ( IsText() && IsValid() ) + { + while ( CheckGet( sizeof(char) ) ) + { + if ( !isspace( *(const unsigned char*)PeekGet() ) ) + break; + m_Get += sizeof(char); + } + } +} + + +//----------------------------------------------------------------------------- +// Eats C++ style comments +//----------------------------------------------------------------------------- +bool CUtlBuffer::EatCPPComment() +{ + if ( IsText() && IsValid() ) + { + // If we don't have a a c++ style comment next, we're done + const char *pPeek = (const char *)PeekGet( 2 * sizeof(char), 0 ); + if ( !pPeek || ( pPeek[0] != '/' ) || ( pPeek[1] != '/' ) ) + return false; + + // Deal with c++ style comments + m_Get += 2; + + // read complete line + for ( char c = GetChar(); IsValid(); c = GetChar() ) + { + if ( c == '\n' ) + break; + } + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Peeks how much whitespace to eat +//----------------------------------------------------------------------------- +int CUtlBuffer::PeekWhiteSpace( int nOffset ) +{ + if ( !IsText() || !IsValid() ) + return 0; + + while ( CheckPeekGet( nOffset, sizeof(char) ) ) + { + if ( !isspace( *(unsigned char*)PeekGet( nOffset ) ) ) + break; + nOffset += sizeof(char); + } + + return nOffset; +} + + +//----------------------------------------------------------------------------- +// Peek size of sting to come, check memory bound +//----------------------------------------------------------------------------- +int CUtlBuffer::PeekStringLength() +{ + if ( !IsValid() ) + return 0; + + // Eat preceeding whitespace + int nOffset = 0; + if ( IsText() ) + { + nOffset = PeekWhiteSpace( nOffset ); + } + + int nStartingOffset = nOffset; + + do + { + int nPeekAmount = 128; + + // NOTE: Add 1 for the terminating zero! + if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) ) + { + if ( nOffset == nStartingOffset ) + return 0; + return nOffset - nStartingOffset + 1; + } + + const char *pTest = (const char *)PeekGet( nOffset ); + + if ( !IsText() ) + { + for ( int i = 0; i < nPeekAmount; ++i ) + { + // The +1 here is so we eat the terminating 0 + if ( pTest[i] == 0 ) + return (i + nOffset - nStartingOffset + 1); + } + } + else + { + for ( int i = 0; i < nPeekAmount; ++i ) + { + // The +1 here is so we eat the terminating 0 + if ( isspace((unsigned char)pTest[i]) || (pTest[i] == 0) ) + return (i + nOffset - nStartingOffset + 1); + } + } + + nOffset += nPeekAmount; + + } while ( true ); +} + + +//----------------------------------------------------------------------------- +// Peek size of line to come, check memory bound +//----------------------------------------------------------------------------- +int CUtlBuffer::PeekLineLength() +{ + if ( !IsValid() ) + return 0; + + int nOffset = 0; + int nStartingOffset = nOffset; + + do + { + int nPeekAmount = 128; + + // NOTE: Add 1 for the terminating zero! + if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) ) + { + if ( nOffset == nStartingOffset ) + return 0; + return nOffset - nStartingOffset + 1; + } + + const char *pTest = (const char *)PeekGet( nOffset ); + + for ( int i = 0; i < nPeekAmount; ++i ) + { + // The +2 here is so we eat the terminating '\n' and 0 + if ( pTest[i] == '\n' || pTest[i] == '\r' ) + return (i + nOffset - nStartingOffset + 2); + // The +1 here is so we eat the terminating 0 + if ( pTest[i] == 0 ) + return (i + nOffset - nStartingOffset + 1); + } + + nOffset += nPeekAmount; + + } while ( true ); +} + + +//----------------------------------------------------------------------------- +// Does the next bytes of the buffer match a pattern? +//----------------------------------------------------------------------------- +bool CUtlBuffer::PeekStringMatch( int nOffset, const char *pString, int nLen ) +{ + if ( !CheckPeekGet( nOffset, nLen ) ) + return false; + return !Q_strncmp( (const char*)PeekGet(nOffset), pString, nLen ); +} + + +//----------------------------------------------------------------------------- +// This version of PeekStringLength converts \" to \\ and " to \, etc. +// It also reads a " at the beginning and end of the string +//----------------------------------------------------------------------------- +int CUtlBuffer::PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize ) +{ + if ( !IsText() || !pConv ) + return PeekStringLength(); + + // Eat preceeding whitespace + int nOffset = 0; + if ( IsText() ) + { + nOffset = PeekWhiteSpace( nOffset ); + } + + if ( !PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) + return 0; + + // Try to read ending ", but don't accept \" + int nActualStart = nOffset; + nOffset += pConv->GetDelimiterLength(); + int nLen = 1; // Starts at 1 for the '\0' termination + + do + { + if ( PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) + break; + + if ( !CheckPeekGet( nOffset, 1 ) ) + break; + + char c = *(const char*)PeekGet( nOffset ); + ++nLen; + ++nOffset; + if ( c == pConv->GetEscapeChar() ) + { + int nLength = pConv->MaxConversionLength(); + if ( !CheckArbitraryPeekGet( nOffset, nLength ) ) + break; + + pConv->FindConversion( (const char*)PeekGet(nOffset), &nLength ); + nOffset += nLength; + } + } while (true); + + return bActualSize ? nLen : nOffset - nActualStart + pConv->GetDelimiterLength() + 1; +} + + +//----------------------------------------------------------------------------- +// Reads a null-terminated string +//----------------------------------------------------------------------------- +void CUtlBuffer::GetString( char* pString, int nMaxChars ) +{ + if (!IsValid()) + { + *pString = 0; + return; + } + + if ( nMaxChars == 0 ) + { + nMaxChars = INT_MAX; + } + + // Remember, this *includes* the null character + // It will be 0, however, if the buffer is empty. + int nLen = PeekStringLength(); + + if ( IsText() ) + { + EatWhiteSpace(); + } + + if ( nLen == 0 ) + { + *pString = 0; + m_Error |= GET_OVERFLOW; + return; + } + + // Strip off the terminating NULL + if ( nLen <= nMaxChars ) + { + Get( pString, nLen - 1 ); + pString[ nLen - 1 ] = 0; + } + else + { + Get( pString, nMaxChars - 1 ); + pString[ nMaxChars - 1 ] = 0; + SeekGet( SEEK_CURRENT, nLen - 1 - nMaxChars ); + } + + // Read the terminating NULL in binary formats + if ( !IsText() ) + { + VerifyEquals( GetChar(), 0 ); + } +} + + +//----------------------------------------------------------------------------- +// Reads up to and including the first \n +//----------------------------------------------------------------------------- +void CUtlBuffer::GetLine( char* pLine, int nMaxChars ) +{ + Assert( IsText() && !ContainsCRLF() ); + + if ( !IsValid() ) + { + *pLine = 0; + return; + } + + if ( nMaxChars == 0 ) + { + nMaxChars = INT_MAX; + } + + // Remember, this *includes* the null character + // It will be 0, however, if the buffer is empty. + int nLen = PeekLineLength(); + if ( nLen == 0 ) + { + *pLine = 0; + m_Error |= GET_OVERFLOW; + return; + } + + // Strip off the terminating NULL + if ( nLen <= nMaxChars ) + { + Get( pLine, nLen - 1 ); + pLine[ nLen - 1 ] = 0; + } + else + { + Get( pLine, nMaxChars - 1 ); + pLine[ nMaxChars - 1 ] = 0; + SeekGet( SEEK_CURRENT, nLen - 1 - nMaxChars ); + } +} + + +//----------------------------------------------------------------------------- +// This version of GetString converts \ to \\ and " to \", etc. +// It also places " at the beginning and end of the string +//----------------------------------------------------------------------------- +char CUtlBuffer::GetDelimitedCharInternal( CUtlCharConversion *pConv ) +{ + char c = GetChar(); + if ( c == pConv->GetEscapeChar() ) + { + int nLength = pConv->MaxConversionLength(); + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + return '\0'; + + c = pConv->FindConversion( (const char *)PeekGet(), &nLength ); + SeekGet( SEEK_CURRENT, nLength ); + } + + return c; +} + +char CUtlBuffer::GetDelimitedChar( CUtlCharConversion *pConv ) +{ + if ( !IsText() || !pConv ) + return GetChar( ); + return GetDelimitedCharInternal( pConv ); +} + +void CUtlBuffer::GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars ) +{ + if ( !IsText() || !pConv ) + { + GetString( pString, nMaxChars ); + return; + } + + if (!IsValid()) + { + *pString = 0; + return; + } + + if ( nMaxChars == 0 ) + { + nMaxChars = INT_MAX; + } + + EatWhiteSpace(); + if ( !PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) + return; + + // Pull off the starting delimiter + SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() ); + + int nRead = 0; + while ( IsValid() ) + { + if ( PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) + { + SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() ); + break; + } + + char c = GetDelimitedCharInternal( pConv ); + + if ( nRead < nMaxChars ) + { + pString[nRead] = c; + ++nRead; + } + } + + if ( nRead >= nMaxChars ) + { + nRead = nMaxChars - 1; + } + pString[nRead] = '\0'; +} + + +//----------------------------------------------------------------------------- +// Checks if a get is ok +//----------------------------------------------------------------------------- +bool CUtlBuffer::CheckGet( int nSize ) +{ + if ( m_Error & GET_OVERFLOW ) + return false; + + if ( TellMaxPut() < m_Get + nSize ) + { + m_Error |= GET_OVERFLOW; + return false; + } + + if ( ( m_Get < m_nOffset ) || ( m_Memory.NumAllocated() < m_Get - m_nOffset + nSize ) ) + { + if ( !OnGetOverflow( nSize ) ) + { + m_Error |= GET_OVERFLOW; + return false; + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Checks if a peek get is ok +//----------------------------------------------------------------------------- +bool CUtlBuffer::CheckPeekGet( int nOffset, int nSize ) +{ + if ( m_Error & GET_OVERFLOW ) + return false; + + // Checking for peek can't set the overflow flag + bool bOk = CheckGet( nOffset + nSize ); + m_Error &= ~GET_OVERFLOW; + return bOk; +} + + +//----------------------------------------------------------------------------- +// Call this to peek arbitrarily long into memory. It doesn't fail unless +// it can't read *anything* new +//----------------------------------------------------------------------------- +bool CUtlBuffer::CheckArbitraryPeekGet( int nOffset, int &nIncrement ) +{ + if ( TellGet() + nOffset >= TellMaxPut() ) + { + nIncrement = 0; + return false; + } + + if ( TellGet() + nOffset + nIncrement > TellMaxPut() ) + { + nIncrement = TellMaxPut() - TellGet() - nOffset; + } + + // NOTE: CheckPeekGet could modify TellMaxPut for streaming files + // We have to call TellMaxPut again here + CheckPeekGet( nOffset, nIncrement ); + int nMaxGet = TellMaxPut() - TellGet(); + if ( nMaxGet < nIncrement ) + { + nIncrement = nMaxGet; + } + return (nIncrement != 0); +} + + +//----------------------------------------------------------------------------- +// Peek part of the butt +//----------------------------------------------------------------------------- +const void* CUtlBuffer::PeekGet( int nMaxSize, int nOffset ) +{ + if ( !CheckPeekGet( nOffset, nMaxSize ) ) + return NULL; + + int Index = m_Get + nOffset - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nMaxSize - 1 ) ); + + return &m_Memory[ Index ]; +} + + +//----------------------------------------------------------------------------- +// Change where I'm reading +//----------------------------------------------------------------------------- +void CUtlBuffer::SeekGet( SeekType_t type, int offset ) +{ + switch( type ) + { + case SEEK_HEAD: + m_Get = offset; + break; + + case SEEK_CURRENT: + m_Get += offset; + break; + + case SEEK_TAIL: + m_Get = m_nMaxPut - offset; + break; + } + + if ( m_Get > m_nMaxPut ) + { + m_Error |= GET_OVERFLOW; + } + else + { + m_Error &= ~GET_OVERFLOW; + if ( m_Get < m_nOffset || m_Get >= m_nOffset + Size() ) + { + OnGetOverflow( -1 ); + } + } +} + + +//----------------------------------------------------------------------------- +// Parse... +//----------------------------------------------------------------------------- + +#pragma warning ( disable : 4706 ) + +int CUtlBuffer::VaScanf( const char* pFmt, va_list list ) +{ + Assert( pFmt ); + if ( m_Error || !IsText() ) + return 0; + + int numScanned = 0; + int nLength; + char c; + char* pEnd; + while ( (c = *pFmt++) ) + { + // Stop if we hit the end of the buffer + if ( m_Get >= TellMaxPut() ) + { + m_Error |= GET_OVERFLOW; + break; + } + + switch (c) + { + case ' ': + // eat all whitespace + EatWhiteSpace(); + break; + + case '%': + { + // Conversion character... try to convert baby! + char type = *pFmt++; + if (type == 0) + return numScanned; + + switch(type) + { + case 'c': + { + char* ch = va_arg( list, char * ); + if ( CheckPeekGet( 0, sizeof(char) ) ) + { + *ch = *(const char*)PeekGet(); + ++m_Get; + } + else + { + *ch = 0; + return numScanned; + } + } + break; + + case 'i': + case 'd': + { + int* i = va_arg( list, int * ); + + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + *i = 0; + return numScanned; + } + + *i = strtol( (char*)PeekGet(), &pEnd, 10 ); + int nBytesRead = (int)( pEnd - (char*)PeekGet() ); + if ( nBytesRead == 0 ) + return numScanned; + m_Get += nBytesRead; + } + break; + + case 'x': + { + int* i = va_arg( list, int * ); + + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + *i = 0; + return numScanned; + } + + *i = strtol( (char*)PeekGet(), &pEnd, 16 ); + int nBytesRead = (int)( pEnd - (char*)PeekGet() ); + if ( nBytesRead == 0 ) + return numScanned; + m_Get += nBytesRead; + } + break; + + case 'u': + { + unsigned int* u = va_arg( list, unsigned int *); + + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + *u = 0; + return numScanned; + } + + *u = strtoul( (char*)PeekGet(), &pEnd, 10 ); + int nBytesRead = (int)( pEnd - (char*)PeekGet() ); + if ( nBytesRead == 0 ) + return numScanned; + m_Get += nBytesRead; + } + break; + + case 'f': + { + float* f = va_arg( list, float *); + + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + *f = 0.0f; + return numScanned; + } + + *f = (float)strtod( (char*)PeekGet(), &pEnd ); + int nBytesRead = (int)( pEnd - (char*)PeekGet() ); + if ( nBytesRead == 0 ) + return numScanned; + m_Get += nBytesRead; + } + break; + + case 's': + { + char* s = va_arg( list, char * ); + GetString( s ); + } + break; + + default: + { + // unimplemented scanf type + Assert(0); + return numScanned; + } + break; + } + + ++numScanned; + } + break; + + default: + { + // Here we have to match the format string character + // against what's in the buffer or we're done. + if ( !CheckPeekGet( 0, sizeof(char) ) ) + return numScanned; + + if ( c != *(const char*)PeekGet() ) + return numScanned; + + ++m_Get; + } + } + } + return numScanned; +} + +#pragma warning ( default : 4706 ) + +int CUtlBuffer::Scanf( const char* pFmt, ... ) +{ + va_list args; + + va_start( args, pFmt ); + int count = VaScanf( pFmt, args ); + va_end( args ); + + return count; +} + + +//----------------------------------------------------------------------------- +// Advance the get index until after the particular string is found +// Do not eat whitespace before starting. Return false if it failed +//----------------------------------------------------------------------------- +bool CUtlBuffer::GetToken( const char *pToken ) +{ + Assert( pToken ); + + // Look for the token + int nLen = Q_strlen( pToken ); + + int nSizeToCheck = Size() - TellGet() - m_nOffset; + + int nGet = TellGet(); + do + { + int nMaxSize = TellMaxPut() - TellGet(); + if ( nMaxSize < nSizeToCheck ) + { + nSizeToCheck = nMaxSize; + } + if ( nLen > nSizeToCheck ) + break; + + if ( !CheckPeekGet( 0, nSizeToCheck ) ) + break; + + const char *pBufStart = (const char*)PeekGet(); + const char *pFoundEnd = Q_strnistr( pBufStart, pToken, nSizeToCheck ); + if ( pFoundEnd ) + { + size_t nOffset = (size_t)pFoundEnd - (size_t)pBufStart; + SeekGet( CUtlBuffer::SEEK_CURRENT, nOffset + nLen ); + return true; + } + + SeekGet( CUtlBuffer::SEEK_CURRENT, nSizeToCheck - nLen - 1 ); + nSizeToCheck = Size() - (nLen-1); + + } while ( true ); + + SeekGet( CUtlBuffer::SEEK_HEAD, nGet ); + return false; +} + + +//----------------------------------------------------------------------------- +// (For text buffers only) +// Parse a token from the buffer: +// Grab all text that lies between a starting delimiter + ending delimiter +// (skipping whitespace that leads + trails both delimiters). +// Note the delimiter checks are case-insensitive. +// If successful, the get index is advanced and the function returns true, +// otherwise the index is not advanced and the function returns false. +//----------------------------------------------------------------------------- +bool CUtlBuffer::ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen ) +{ + int nCharsToCopy = 0; + int nCurrentGet = 0; + + size_t nEndingDelimLen; + + // Starting delimiter is optional + char emptyBuf = '\0'; + if ( !pStartingDelim ) + { + pStartingDelim = &emptyBuf; + } + + // Ending delimiter is not + Assert( pEndingDelim && pEndingDelim[0] ); + nEndingDelimLen = Q_strlen( pEndingDelim ); + + int nStartGet = TellGet(); + char nCurrChar; + int nTokenStart = -1; + EatWhiteSpace( ); + while ( *pStartingDelim ) + { + nCurrChar = *pStartingDelim++; + if ( !isspace((unsigned char)nCurrChar) ) + { + if ( tolower( GetChar() ) != tolower( nCurrChar ) ) + goto parseFailed; + } + else + { + EatWhiteSpace(); + } + } + + EatWhiteSpace(); + nTokenStart = TellGet(); + if ( !GetToken( pEndingDelim ) ) + goto parseFailed; + + nCurrentGet = TellGet(); + nCharsToCopy = (nCurrentGet - nEndingDelimLen) - nTokenStart; + if ( nCharsToCopy >= nMaxLen ) + { + nCharsToCopy = nMaxLen - 1; + } + + if ( nCharsToCopy > 0 ) + { + SeekGet( CUtlBuffer::SEEK_HEAD, nTokenStart ); + Get( pString, nCharsToCopy ); + if ( !IsValid() ) + goto parseFailed; + + // Eat trailing whitespace + for ( ; nCharsToCopy > 0; --nCharsToCopy ) + { + if ( !isspace( (unsigned char)pString[ nCharsToCopy-1 ] ) ) + break; + } + } + pString[ nCharsToCopy ] = '\0'; + + // Advance the Get index + SeekGet( CUtlBuffer::SEEK_HEAD, nCurrentGet ); + return true; + +parseFailed: + // Revert the get index + SeekGet( SEEK_HEAD, nStartGet ); + pString[0] = '\0'; + return false; +} + + +//----------------------------------------------------------------------------- +// Parses the next token, given a set of character breaks to stop at +//----------------------------------------------------------------------------- +int CUtlBuffer::ParseToken( characterset_t *pBreaks, char *pTokenBuf, int nMaxLen, bool bParseComments ) +{ + Assert( nMaxLen > 0 ); + pTokenBuf[0] = 0; + + // skip whitespace + comments + while ( true ) + { + if ( !IsValid() ) + return -1; + EatWhiteSpace(); + if ( bParseComments ) + { + if ( !EatCPPComment() ) + break; + } + else + { + break; + } + } + + char c = GetChar(); + + // End of buffer + if ( c == 0 ) + return -1; + + // handle quoted strings specially + if ( c == '\"' ) + { + int nLen = 0; + while( IsValid() ) + { + c = GetChar(); + if ( c == '\"' || !c ) + { + pTokenBuf[nLen] = 0; + return nLen; + } + pTokenBuf[nLen] = c; + if ( ++nLen == nMaxLen ) + { + pTokenBuf[nLen-1] = 0; + return nMaxLen; + } + } + + // In this case, we hit the end of the buffer before hitting the end qoute + pTokenBuf[nLen] = 0; + return nLen; + } + + // parse single characters + if ( IN_CHARACTERSET( *pBreaks, c ) ) + { + pTokenBuf[0] = c; + pTokenBuf[1] = 0; + return 1; + } + + // parse a regular word + int nLen = 0; + while ( true ) + { + pTokenBuf[nLen] = c; + if ( ++nLen == nMaxLen ) + { + pTokenBuf[nLen-1] = 0; + return nMaxLen; + } + c = GetChar(); + if ( !IsValid() ) + break; + + if ( IN_CHARACTERSET( *pBreaks, c ) || c == '\"' || c <= ' ' ) + { + SeekGet( SEEK_CURRENT, -1 ); + break; + } + } + + pTokenBuf[nLen] = 0; + return nLen; +} + + + +//----------------------------------------------------------------------------- +// Serialization +//----------------------------------------------------------------------------- +void CUtlBuffer::Put( const void *pMem, int size ) +{ + if ( size && CheckPut( size ) ) + { + int Index = m_Put - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) ); + if( Index >= 0 ) + { + memcpy( &m_Memory[ Index ], pMem, size ); + m_Put += size; + + AddNullTermination(); + } + } +} + + +//----------------------------------------------------------------------------- +// Writes a null-terminated string +//----------------------------------------------------------------------------- +void CUtlBuffer::PutString( const char* pString ) +{ + if (!IsText()) + { + if ( pString ) + { + // Not text? append a null at the end. + size_t nLen = Q_strlen( pString ) + 1; + Put( pString, nLen * sizeof(char) ); + return; + } + else + { + PutTypeBin( 0 ); + } + } + else if (pString) + { + int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab; + if ( nTabCount > 0 ) + { + if ( WasLastCharacterCR() ) + { + PutTabs(); + } + + const char* pEndl = strchr( pString, '\n' ); + while ( pEndl ) + { + size_t nSize = (size_t)pEndl - (size_t)pString + sizeof(char); + Put( pString, nSize ); + pString = pEndl + 1; + if ( *pString ) + { + PutTabs(); + pEndl = strchr( pString, '\n' ); + } + else + { + pEndl = NULL; + } + } + } + size_t nLen = Q_strlen( pString ); + if ( nLen ) + { + Put( pString, nLen * sizeof(char) ); + } + } +} + + +//----------------------------------------------------------------------------- +// This version of PutString converts \ to \\ and " to \", etc. +// It also places " at the beginning and end of the string +//----------------------------------------------------------------------------- +inline void CUtlBuffer::PutDelimitedCharInternal( CUtlCharConversion *pConv, char c ) +{ + int l = pConv->GetConversionLength( c ); + if ( l == 0 ) + { + PutChar( c ); + } + else + { + PutChar( pConv->GetEscapeChar() ); + Put( pConv->GetConversionString( c ), l ); + } +} + +void CUtlBuffer::PutDelimitedChar( CUtlCharConversion *pConv, char c ) +{ + if ( !IsText() || !pConv ) + { + PutChar( c ); + return; + } + + PutDelimitedCharInternal( pConv, c ); +} + +void CUtlBuffer::PutDelimitedString( CUtlCharConversion *pConv, const char *pString ) +{ + if ( !IsText() || !pConv ) + { + PutString( pString ); + return; + } + + if ( WasLastCharacterCR() ) + { + PutTabs(); + } + Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() ); + + int nLen = pString ? Q_strlen( pString ) : 0; + for ( int i = 0; i < nLen; ++i ) + { + PutDelimitedCharInternal( pConv, pString[i] ); + } + + if ( WasLastCharacterCR() ) + { + PutTabs(); + } + Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() ); +} + + +void CUtlBuffer::VaPrintf( const char* pFmt, va_list list ) +{ + char temp[2048]; +#ifdef DBGFLAG_ASSERT + int nLen = +#endif + Q_vsnprintf( temp, sizeof( temp ), pFmt, list ); + Assert( nLen < 2048 ); + PutString( temp ); +} + +void CUtlBuffer::Printf( const char* pFmt, ... ) +{ + va_list args; + + va_start( args, pFmt ); + VaPrintf( pFmt, args ); + va_end( args ); +} + + +//----------------------------------------------------------------------------- +// Calls the overflow functions +//----------------------------------------------------------------------------- +void CUtlBuffer::SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc ) +{ + m_GetOverflowFunc = getFunc; + m_PutOverflowFunc = putFunc; +} + + +//----------------------------------------------------------------------------- +// Calls the overflow functions +//----------------------------------------------------------------------------- +bool CUtlBuffer::OnPutOverflow( int nSize ) +{ + return (this->*m_PutOverflowFunc)( nSize ); +} + +bool CUtlBuffer::OnGetOverflow( int nSize ) +{ + return (this->*m_GetOverflowFunc)( nSize ); +} + + +//----------------------------------------------------------------------------- +// Checks if a put is ok +//----------------------------------------------------------------------------- +bool CUtlBuffer::PutOverflow( int nSize ) +{ + MEM_ALLOC_CREDIT(); + + if ( m_Memory.IsExternallyAllocated() ) + { + if ( !IsGrowable() ) + return false; + + m_Memory.ConvertToGrowableMemory( 0 ); + } + + while( Size() < m_Put - m_nOffset + nSize ) + { + m_Memory.Grow(); + } + + return true; +} + +bool CUtlBuffer::GetOverflow( int nSize ) +{ + return false; +} + + +//----------------------------------------------------------------------------- +// Checks if a put is ok +//----------------------------------------------------------------------------- +bool CUtlBuffer::CheckPut( int nSize ) +{ + if ( ( m_Error & PUT_OVERFLOW ) || IsReadOnly() ) + return false; + + if ( ( m_Put < m_nOffset ) || ( m_Memory.NumAllocated() < m_Put - m_nOffset + nSize ) ) + { + if ( !OnPutOverflow( nSize ) ) + { + m_Error |= PUT_OVERFLOW; + return false; + } + } + return true; +} + +void CUtlBuffer::SeekPut( SeekType_t type, int offset ) +{ + int nNextPut = m_Put; + switch( type ) + { + case SEEK_HEAD: + nNextPut = offset; + break; + + case SEEK_CURRENT: + nNextPut += offset; + break; + + case SEEK_TAIL: + nNextPut = m_nMaxPut - offset; + break; + } + + // Force a write of the data + // FIXME: We could make this more optimal potentially by writing out + // the entire buffer if you seek outside the current range + + // NOTE: This call will write and will also seek the file to nNextPut. + OnPutOverflow( -nNextPut-1 ); + m_Put = nNextPut; + + AddNullTermination(); +} + + +void CUtlBuffer::ActivateByteSwapping( bool bActivate ) +{ + m_Byteswap.ActivateByteSwapping( bActivate ); +} + +void CUtlBuffer::SetBigEndian( bool bigEndian ) +{ + m_Byteswap.SetTargetBigEndian( bigEndian ); +} + +bool CUtlBuffer::IsBigEndian( void ) +{ + return m_Byteswap.IsTargetBigEndian(); +} + + +//----------------------------------------------------------------------------- +// null terminate the buffer +//----------------------------------------------------------------------------- +void CUtlBuffer::AddNullTermination( void ) +{ + if ( m_Put > m_nMaxPut ) + { + if ( !IsReadOnly() && ((m_Error & PUT_OVERFLOW) == 0) ) + { + // Add null termination value + if ( CheckPut( 1 ) ) + { + int Index = m_Put - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) ); + if( Index >= 0 ) + { + m_Memory[ Index ] = 0; + } + } + else + { + // Restore the overflow state, it was valid before... + m_Error &= ~PUT_OVERFLOW; + } + } + m_nMaxPut = m_Put; + } +} + + +//----------------------------------------------------------------------------- +// Converts a buffer from a CRLF buffer to a CR buffer (and back) +// Returns false if no conversion was necessary (and outBuf is left untouched) +// If the conversion occurs, outBuf will be cleared. +//----------------------------------------------------------------------------- +bool CUtlBuffer::ConvertCRLF( CUtlBuffer &outBuf ) +{ + if ( !IsText() || !outBuf.IsText() ) + return false; + + if ( ContainsCRLF() == outBuf.ContainsCRLF() ) + return false; + + int nInCount = TellMaxPut(); + + outBuf.Purge(); + outBuf.EnsureCapacity( nInCount ); + + bool bFromCRLF = ContainsCRLF(); + + // Start reading from the beginning + int nGet = TellGet(); + int nPut = TellPut(); + int nGetDelta = 0; + int nPutDelta = 0; + + const char *pBase = (const char*)Base(); + int nCurrGet = 0; + while ( nCurrGet < nInCount ) + { + const char *pCurr = &pBase[nCurrGet]; + if ( bFromCRLF ) + { + const char *pNext = Q_strnistr( pCurr, "\r\n", nInCount - nCurrGet ); + if ( !pNext ) + { + outBuf.Put( pCurr, nInCount - nCurrGet ); + break; + } + + int nBytes = (size_t)pNext - (size_t)pCurr; + outBuf.Put( pCurr, nBytes ); + outBuf.PutChar( '\n' ); + nCurrGet += nBytes + 2; + if ( nGet >= nCurrGet - 1 ) + { + --nGetDelta; + } + if ( nPut >= nCurrGet - 1 ) + { + --nPutDelta; + } + } + else + { + const char *pNext = Q_strnchr( pCurr, '\n', nInCount - nCurrGet ); + if ( !pNext ) + { + outBuf.Put( pCurr, nInCount - nCurrGet ); + break; + } + + int nBytes = (size_t)pNext - (size_t)pCurr; + outBuf.Put( pCurr, nBytes ); + outBuf.PutChar( '\r' ); + outBuf.PutChar( '\n' ); + nCurrGet += nBytes + 1; + if ( nGet >= nCurrGet ) + { + ++nGetDelta; + } + if ( nPut >= nCurrGet ) + { + ++nPutDelta; + } + } + } + + Assert( nPut + nPutDelta <= outBuf.TellMaxPut() ); + + outBuf.SeekGet( SEEK_HEAD, nGet + nGetDelta ); + outBuf.SeekPut( SEEK_HEAD, nPut + nPutDelta ); + + return true; +} + +//----------------------------------------------------------------------------- +// Fast swap +//----------------------------------------------------------------------------- +void CUtlBuffer::Swap( CUtlBuffer &buf ) +{ + V_swap( m_Get, buf.m_Get ); + V_swap( m_Put, buf.m_Put ); + V_swap( m_nMaxPut, buf.m_nMaxPut ); + V_swap( m_Error, buf.m_Error ); + m_Memory.Swap( buf.m_Memory ); +} + + +//----------------------------------------------------------------------------- +// Fast swap w/ a CUtlMemory. +//----------------------------------------------------------------------------- +void CUtlBuffer::Swap( CUtlMemory &mem ) +{ + m_Get = 0; + m_Put = mem.Count(); + m_nMaxPut = mem.Count(); + m_Error = 0; + m_Memory.Swap( mem ); +} + +//--------------------------------------------------------------------------- +// Implementation of CUtlInplaceBuffer +//--------------------------------------------------------------------------- + +CUtlInplaceBuffer::CUtlInplaceBuffer( int growSize /* = 0 */, int initSize /* = 0 */, int nFlags /* = 0 */ ) : + CUtlBuffer( growSize, initSize, nFlags ) +{ + NULL; +} + +bool CUtlInplaceBuffer::InplaceGetLinePtr( char **ppszInBufferPtr, int *pnLineLength ) +{ + Assert( IsText() && !ContainsCRLF() ); + + int nLineLen = PeekLineLength(); + if ( nLineLen <= 1 ) + { + SeekGet( SEEK_TAIL, 0 ); + return false; + } + + -- nLineLen; // because it accounts for putting a terminating null-character + + char *pszLine = ( char * ) const_cast< void * >( PeekGet() ); + SeekGet( SEEK_CURRENT, nLineLen ); + + // Set the out args + if ( ppszInBufferPtr ) + *ppszInBufferPtr = pszLine; + + if ( pnLineLength ) + *pnLineLength = nLineLen; + + return true; +} + +char * CUtlInplaceBuffer::InplaceGetLinePtr( void ) +{ + char *pszLine = NULL; + int nLineLen = 0; + + if ( InplaceGetLinePtr( &pszLine, &nLineLen ) ) + { + Assert( nLineLen >= 1 ); + + switch ( pszLine[ nLineLen - 1 ] ) + { + case '\n': + case '\r': + pszLine[ nLineLen - 1 ] = 0; + if ( -- nLineLen ) + { + switch ( pszLine[ nLineLen - 1 ] ) + { + case '\n': + case '\r': + pszLine[ nLineLen - 1 ] = 0; + break; + } + } + break; + + default: + Assert( pszLine[ nLineLen ] == 0 ); + break; + } + } + + return pszLine; +} + -- cgit v1.2.3