#ifndef UTLBUFFER_H
#define UTLBUFFER_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlmemory.h"
#include <stdarg.h>
BEGIN_TIER1_NAMESPACE
class CUtlCharConversion
{
public:
struct ConversionArray_t
{
char m_nActualChar;
const char *m_pReplacementString;
};
CUtlCharConversion( const char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray );
char GetEscapeChar() const;
const char *GetDelimiter() const;
int GetDelimiterLength() const;
const char *GetConversionString( char c ) const;
int GetConversionLength( char c ) const;
int MaxConversionLength() const;
virtual char FindConversion( const char *pString, int *pLength );
protected:
struct ConversionInfo_t
{
int m_nLength;
const char *m_pReplacementString;
};
char m_nEscapeChar;
const char *m_pDelimiter;
int m_nDelimiterLength;
int m_nCount;
int m_nMaxConversionLength;
char m_pList[255];
ConversionInfo_t m_pReplacements[255];
};
#define BEGIN_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \
static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = {
#define END_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \
}; \
CUtlCharConversion _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name );
#define BEGIN_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \
static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = {
#define END_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \
}; \
_className _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name );
CUtlCharConversion *GetCStringCharConversion();
CUtlCharConversion *GetNoEscCharConversion();
#define SetUtlBufferOverflowFuncs( _get, _put ) \
SetOverflowFuncs( static_cast <UtlBufferOverflowFunc_t>( _get ), static_cast <UtlBufferOverflowFunc_t>( _put ) )
class CUtlBuffer
{
public:
enum SeekType_t
{
SEEK_HEAD = 0,
SEEK_CURRENT,
SEEK_TAIL
};
enum BufferFlags_t
{
TEXT_BUFFER = 0x1, EXTERNAL_GROWABLE = 0x2, CONTAINS_CRLF = 0x4, READ_ONLY = 0x8, AUTO_TABS_DISABLED = 0x10, LITTLE_ENDIAN_BUFFER = 0x20, BIG_ENDIAN_BUFFER = 0x40, };
typedef bool (CUtlBuffer::*UtlBufferOverflowFunc_t)( int nSize );
CUtlBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 );
CUtlBuffer( const void* pBuffer, int size, int nFlags = 0 );
unsigned char GetFlags() const;
void SetBufferType( bool bIsText, bool bContainsCRLF );
void EnsureCapacity( int num );
void SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags = 0 );
void SetReadOnlyBuffer( void *pMemory, int nSize );
void Clear();
void Purge();
void Swap( CUtlBuffer &buf );
void TakeOwnershipOfMemory( CUtlMemory<uint8> &mem );
void ReleaseToMemory( CUtlMemory<uint8> &mem, int *punCurrentPut );
void * DetachAndClear();
void CopyBuffer( const CUtlBuffer &buffer );
void CopyBuffer( const void *pubData, int cubData );
char GetChar();
uint8 GetUint8();
short GetShort();
unsigned short GetUnsignedShort();
int GetInt();
int GetIntHex();
unsigned int GetUnsignedInt();
int16 GetInt16();
uint64 GetUnsignedInt64();
int64 GetInt64();
float GetFloat();
double GetDouble();
bool GetString( char *pString, int nMaxLen );
bool GetLine( char *pString, int nMaxLen );
const char* GetStringFast(); bool Get( void* pMem, int size );
int GetUpTo( void *pMem, int nSize );
void GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars );
char GetDelimitedChar( CUtlCharConversion *pConv );
int PeekStringLength();
int PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize = true );
int Scanf( SCANF_FORMAT_STRING const char* pFmt, ... );
int VaScanf( const char* pFmt, va_list list );
void EatWhiteSpace();
void EatWhiteSpaceNoOverflow();
bool EatCPPComment();
bool ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen );
bool GetToken( const char *pToken );
void PutChar( char c );
void PutUint8( uint8 ub );
void PutShort( short s );
void PutUnsignedShort( unsigned short us );
void PutInt( int i );
void PutUnsignedInt( unsigned int u );
void PutInt16( int16 s16 );
void PutUnsignedInt64( uint64 u64 );
void PutInt64( int64 u64 );
void PutFloat( float f );
void PutDouble( double d );
void PutString( const char* pString );
void PutStringWithoutNull( const char* pString );
void Put( const void* pMem, int size );
void PutDelimitedString( CUtlCharConversion *pConv, const char *pString );
void PutDelimitedChar( CUtlCharConversion *pConv, char c );
void Printf( PRINTF_FORMAT_STRING const char* pFmt, ... ) FMTFUNCTION( 2, 3 );
void VaPrintf( const char* pFmt, va_list list );
void* PeekPut( int offset = 0 );
const void* PeekGet( ) const;
const void* PeekGet( int offset ) const;
const void* PeekGet( int nMaxSize, int nOffset );
void *ReservePut( int nBytes );
int GetBytesRemaining() const;
int TellPut() const;
int TellGet() const;
void SeekPut( SeekType_t type, int offset );
bool SeekGet( SeekType_t type, int offset );
const void* Base() const;
void* Base();
const char *String() const;
int Size() const; int SizeAllocated() const;
bool IsText() const;
bool IsExternallyAllocated() const;
bool IsGrowable() const;
bool IsValid() const;
bool ContainsCRLF() const;
bool IsReadOnly() const;
bool ConvertCRLF( CUtlBuffer &outBuf );
void PushTab();
void PopTab();
void EnableTabs( bool bEnable );
void SecureZero() { SecureZeroMemory( m_Memory.Base(), m_Memory.Count() ); }
protected:
enum
{
PUT_OVERFLOW = 0x1,
GET_OVERFLOW = 0x2,
MAX_ERROR_FLAG = GET_OVERFLOW,
};
void SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc );
bool OnPutOverflow( int nSize );
bool OnGetOverflow( int nSize );
protected:
bool CheckPut( int size );
bool CheckGet( int size );
void AddNullTermination( );
bool WasLastCharacterCR();
void PutTabs();
char GetDelimitedCharInternal( CUtlCharConversion *pConv );
void PutDelimitedCharInternal( CUtlCharConversion *pConv, char c );
bool PutOverflow( int nSize );
bool GetOverflow( int nSize );
bool PeekStringMatch( int nOffset, const char *pString, int nLen );
int PeekWhiteSpace( int nOffset );
bool CheckPeekGet( int nOffset, int nSize );
bool CheckArbitraryPeekGet( int nOffset, int &nIncrement );
CUtlMemory<uint8> m_Memory;
int m_Get;
int m_Put;
int m_nMaxPut;
uint16 m_nTab;
uint8 m_Error;
uint8 m_Flags;
UtlBufferOverflowFunc_t m_GetOverflowFunc;
UtlBufferOverflowFunc_t m_PutOverflowFunc;
private:
int TellMaxPut() const;
CUtlBuffer(const CUtlBuffer& rhs);
const CUtlBuffer& operator=(const CUtlBuffer& rhs);
};
inline int CUtlBuffer::TellGet() const
{
return m_Get;
}
inline int CUtlBuffer::GetBytesRemaining() const
{
return m_nMaxPut - TellGet();
}
inline const void* CUtlBuffer::PeekGet( int offset ) const
{
return &m_Memory[ m_Get + offset ];
}
inline const void* CUtlBuffer::PeekGet() const
{
return &m_Memory[ m_Get ];
}
inline void *CUtlBuffer::ReservePut( int nBytes )
{
return CheckPut( nBytes ) ? PeekPut() : NULL;
}
#if defined(__arm__) || defined(__arm64__)
#define COPY_TYPE( _type, _val ) V_memcpy( &_val, PeekGet(), sizeof( _type ) )
#else
#define COPY_TYPE( _type, _val ) _val = *(_type *)PeekGet()
#endif
#define GET_TYPE( _type, _val, _fmt ) \
if ( !IsText() ) \
{ \
if (CheckGet( sizeof(_type) )) \
{ \
if ( (sizeof(_type)>1) && (m_Flags & CUtlBuffer::LITTLE_ENDIAN_BUFFER ) ) \
{ \
if( sizeof(_type) == 2 ) \
{ \
_val = LittleWord( (uint16)*(_type *)PeekGet() ); \
} \
else if ( sizeof(_type) == 4 ) \
{ \
_val = LittleDWord( (uint32)*(_type *)PeekGet() ); \
} \
else if ( sizeof(_type) == 8 ) \
{ \
_val = LittleQWord( (uint64)*(_type *)PeekGet() ); \
} \
else \
{ \
Assert( !"Type not supported" ); \
} \
} \
else if ( (sizeof(_type)>1) && (m_Flags & CUtlBuffer::BIG_ENDIAN_BUFFER ) ) \
{ \
if( sizeof(_type) == 2 ) \
{ \
_val = BigWord( (uint16)*(_type *)PeekGet() ); \
} \
else if ( sizeof(_type) == 4 ) \
{ \
_val = BigDWord( (uint32)*(_type *)PeekGet() ); \
} \
else if ( sizeof(_type) == 8 ) \
{ \
_val = BigQWord( (uint64)*(_type *)PeekGet() ); \
} \
else \
{ \
Assert( !"Type not supported" ); \
} \
} \
else \
{ \
COPY_TYPE( _type, _val ); \
} \
m_Get += sizeof(_type); \
} \
else \
{ \
_val = 0; \
} \
} \
else \
{ \
_val = 0; \
Scanf( _fmt, &_val ); \
}
inline unsigned char CUtlBuffer::GetFlags() const
{
return m_Flags;
}
inline int CUtlBuffer::TellPut() const
{
return m_Put;
}
inline int CUtlBuffer::TellMaxPut( ) const
{
return m_nMaxPut;
}
inline void* CUtlBuffer::PeekPut( int offset )
{
return &m_Memory[m_Put + offset];
}
#define PUT_BIN_DATA( _type, _val ) \
if ( CheckPut( sizeof(_type) ) ) \
{ \
if ( (sizeof(_type)>1) && (m_Flags & CUtlBuffer::LITTLE_ENDIAN_BUFFER ) ) \
{ \
if( sizeof(_type) == 2 ) \
{ \
*(_type *)PeekPut() = (_type)LittleWord( (uint16)_val ); \
} \
else if ( sizeof(_type) == 4 ) \
{ \
*(_type *)PeekPut() = (_type)LittleDWord( (uint32)_val ); \
} \
else if ( sizeof(_type) == 8 ) \
{ \
*(_type *)PeekPut() = (_type)LittleQWord( (uint64)_val ); \
} \
else \
{ \
Assert( !"Type not supported" ); \
} \
} \
else if ( (sizeof(_type)>1) && (m_Flags & CUtlBuffer::BIG_ENDIAN_BUFFER ) ) \
{ \
if( sizeof(_type) == 2 ) \
{ \
*(_type *)PeekPut() = (_type)BigWord( (uint16)_val ); \
} \
else if ( sizeof(_type) == 4 ) \
{ \
*(_type *)PeekPut() = (_type)BigDWord( (uint32)_val ); \
} \
else if ( sizeof(_type) == 8 ) \
{ \
*(_type *)PeekPut() = (_type)BigQWord( (uint64)_val ); \
} \
else \
{ \
Assert( !"Type not supported" ); \
} \
} \
else \
{ \
*(_type *)PeekPut() = _val; \
} \
m_Put += sizeof(_type); \
AddNullTermination(); \
} \
#define PUT_TYPE( _type, _val ) \
if (!IsText()) \
{ \
PUT_BIN_DATA( _type, _val ); \
} \
else \
{ \
PutString( CNumStr( _val ) ); \
}
inline bool CUtlBuffer::WasLastCharacterCR()
{
if ( !IsText() || (TellPut() == 0) )
return false;
return ( *( const char * )PeekPut( -1 ) == '\n' );
}
inline void CUtlBuffer::PutTabs()
{
int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab;
for (int i = nTabCount; --i >= 0; )
{
PUT_BIN_DATA( char, '\t' );
}
}
inline void CUtlBuffer::PushTab( )
{
++m_nTab;
}
inline void CUtlBuffer::PopTab()
{
if ( m_nTab )
{
m_nTab--;
}
}
inline void CUtlBuffer::EnableTabs( bool bEnable )
{
if ( bEnable )
{
m_Flags &= ~AUTO_TABS_DISABLED;
}
else
{
m_Flags |= AUTO_TABS_DISABLED;
}
}
inline bool CUtlBuffer::IsText() const
{
return (m_Flags & TEXT_BUFFER) != 0;
}
inline bool CUtlBuffer::IsGrowable() const
{
return (m_Flags & EXTERNAL_GROWABLE) != 0;
}
inline bool CUtlBuffer::IsExternallyAllocated() const
{
return m_Memory.IsExternallyAllocated();
}
inline bool CUtlBuffer::IsValid() const
{
return m_Error == 0;
}
inline bool CUtlBuffer::ContainsCRLF() const
{
return IsText() && ((m_Flags & CONTAINS_CRLF) != 0);
}
inline bool CUtlBuffer::IsReadOnly() const
{
return (m_Flags & READ_ONLY) != 0;
}
inline const void* CUtlBuffer::Base() const
{
return m_Memory.Base();
}
inline void* CUtlBuffer::Base()
{
return m_Memory.Base();
}
inline const char *CUtlBuffer::String() const
{
Assert( IsText() );
const char *pchReturn = reinterpret_cast<const char*>( m_Memory.Base() );
if ( pchReturn )
return pchReturn;
else
return "";
}
inline int CUtlBuffer::Size() const {
return m_Memory.NumAllocated();
}
inline int CUtlBuffer::SizeAllocated() const
{
return m_Memory.NumAllocated();
}
inline void CUtlBuffer::Clear()
{
m_Get = 0;
m_Put = 0;
m_Error = 0;
m_nMaxPut = -1;
AddNullTermination();
}
inline void CUtlBuffer::Purge()
{
m_Get = 0;
m_Put = 0;
m_nMaxPut = 0;
m_Error = 0;
m_Memory.Purge();
}
inline void CUtlBuffer::CopyBuffer( const CUtlBuffer &buffer )
{
CopyBuffer( buffer.Base(), buffer.TellPut() );
}
inline void CUtlBuffer::CopyBuffer( const void *pubData, int cubData )
{
Clear();
if ( cubData )
{
Put( pubData, cubData );
}
}
class CAutoWipeBuffer : public CUtlBuffer
{
public:
CAutoWipeBuffer() {}
explicit CAutoWipeBuffer( int cbInit ) : CUtlBuffer( 0, cbInit, 0 ) {}
~CAutoWipeBuffer() { Purge(); }
void Clear()
{
SecureZeroMemory( Base(), SizeAllocated() );
CUtlBuffer::Clear();
}
void Purge()
{
Clear();
CUtlBuffer::Purge();
}
};
END_TIER1_NAMESPACE
#endif