Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1094 lines
28 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
// Serialization/unserialization buffer
//=============================================================================//
#ifndef UTLBUFFER_H
#define UTLBUFFER_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlmemory.h"
#include "tier1/byteswap.h"
#include <stdarg.h>
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
struct characterset_t;
//-----------------------------------------------------------------------------
// Description of character conversions for string output
// Here's an example of how to use the macros to define a character conversion
// BEGIN_CHAR_CONVERSION( CStringConversion, '\\' )
// { '\n', "n" },
// { '\t', "t" }
// END_CHAR_CONVERSION( CStringConversion, '\\' )
//-----------------------------------------------------------------------------
class CUtlCharConversion
{
public:
struct ConversionArray_t
{
char m_nActualChar;
const char *m_pReplacementString;
};
CUtlCharConversion( 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;
// Finds a conversion for the passed-in string, returns length
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[256];
ConversionInfo_t m_pReplacements[256];
};
#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 );
//-----------------------------------------------------------------------------
// Character conversions for C strings
//-----------------------------------------------------------------------------
CUtlCharConversion *GetCStringCharConversion();
//-----------------------------------------------------------------------------
// Character conversions for quoted strings, with no escape sequences
//-----------------------------------------------------------------------------
CUtlCharConversion *GetNoEscCharConversion();
//-----------------------------------------------------------------------------
// Macro to set overflow functions easily
//-----------------------------------------------------------------------------
#define SetUtlBufferOverflowFuncs( _get, _put ) \
SetOverflowFuncs( static_cast <UtlBufferOverflowFunc_t>( _get ), static_cast <UtlBufferOverflowFunc_t>( _put ) )
//-----------------------------------------------------------------------------
// Command parsing..
//-----------------------------------------------------------------------------
class CUtlBuffer
{
public:
enum SeekType_t
{
SEEK_HEAD = 0,
SEEK_CURRENT,
SEEK_TAIL
};
// flags
enum BufferFlags_t
{
TEXT_BUFFER = 0x1, // Describes how get + put work (as strings, or binary)
EXTERNAL_GROWABLE = 0x2, // This is used w/ external buffers and causes the utlbuf to switch to reallocatable memory if an overflow happens when Putting.
CONTAINS_CRLF = 0x4, // For text buffers only, does this contain \n or \n\r?
READ_ONLY = 0x8, // For external buffers; prevents null termination from happening.
AUTO_TABS_DISABLED = 0x10, // Used to disable/enable push/pop tabs
};
// Overflow functions when a get or put overflows
typedef bool (CUtlBuffer::*UtlBufferOverflowFunc_t)( int nSize );
// Constructors for growable + external buffers for serialization/unserialization
CUtlBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 );
CUtlBuffer( const void* pBuffer, int size, int nFlags = 0 );
// This one isn't actually defined so that we catch contructors that are trying to pass a bool in as the third param.
CUtlBuffer( const void *pBuffer, int size, bool crap );
unsigned char GetFlags() const;
// NOTE: This will assert if you attempt to recast it in a way that
// is not compatible. The only valid conversion is binary-> text w/CRLF
void SetBufferType( bool bIsText, bool bContainsCRLF );
// Makes sure we've got at least this much memory
void EnsureCapacity( int num );
// Attaches the buffer to external memory....
void SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags = 0 );
bool IsExternallyAllocated() const;
// Takes ownership of the passed memory, including freeing it when this buffer is destroyed.
void AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags = 0 );
// copies data from another buffer
void CopyBuffer( const CUtlBuffer &buffer );
void CopyBuffer( const void *pubData, int cubData );
void Swap( CUtlBuffer &buf );
void Swap( CUtlMemory<uint8> &mem );
FORCEINLINE void ActivateByteSwappingIfBigEndian( void )
{
if ( IsX360() )
ActivateByteSwapping( true );
}
// Controls endian-ness of binary utlbufs - default matches the current platform
void ActivateByteSwapping( bool bActivate );
void SetBigEndian( bool bigEndian );
bool IsBigEndian( void );
// Resets the buffer; but doesn't free memory
void Clear();
// Clears out the buffer; frees memory
void Purge();
// Read stuff out.
// Binary mode: it'll just read the bits directly in, and characters will be
// read for strings until a null character is reached.
// Text mode: it'll parse the file, turning text #s into real numbers.
// GetString will read a string until a space is reached
char GetChar( );
unsigned char GetUnsignedChar( );
short GetShort( );
unsigned short GetUnsignedShort( );
int GetInt( );
int64 GetInt64( );
int GetIntHex( );
unsigned int GetUnsignedInt( );
float GetFloat( );
double GetDouble( );
template <size_t maxLenInChars> void GetString( char( &pString )[maxLenInChars] )
{
GetStringInternal( pString, maxLenInChars );
}
void GetStringManualCharCount( char *pString, size_t maxLenInChars )
{
GetStringInternal( pString, maxLenInChars );
}
void Get( void* pMem, int size );
void GetLine( char* pLine, int nMaxChars = 0 );
// Used for getting objects that have a byteswap datadesc defined
template <typename T> void GetObjects( T *dest, int count = 1 );
// This will get at least 1 byte and up to nSize bytes.
// It will return the number of bytes actually read.
int GetUpTo( void *pMem, int nSize );
// This version of GetString converts \" to \\ and " to \, etc.
// It also reads a " at the beginning and end of the string
void GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars = 0 );
char GetDelimitedChar( CUtlCharConversion *pConv );
// This will return the # of characters of the string about to be read out
// NOTE: The count will *include* the terminating 0!!
// In binary mode, it's the number of characters until the next 0
// In text mode, it's the number of characters until the next space.
int PeekStringLength();
// This version of PeekStringLength converts \" to \\ and " to \, etc.
// It also reads a " at the beginning and end of the string
// NOTE: The count will *include* the terminating 0!!
// In binary mode, it's the number of characters until the next 0
// In text mode, it's the number of characters between "s (checking for \")
// Specifying false for bActualSize will return the pre-translated number of characters
// including the delimiters and the escape characters. So, \n counts as 2 characters when bActualSize == false
// and only 1 character when bActualSize == true
int PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize = true );
// Just like scanf, but doesn't work in binary mode
int Scanf( SCANF_FORMAT_STRING const char* pFmt, ... );
int VaScanf( const char* pFmt, va_list list );
// Eats white space, advances Get index
void EatWhiteSpace();
// Eats C++ style comments
bool EatCPPComment();
// (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).
// If successful, the get index is advanced and the function returns true,
// otherwise the index is not advanced and the function returns false.
bool ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen );
// Advance the get index until after the particular string is found
// Do not eat whitespace before starting. Return false if it failed
// String test is case-insensitive.
bool GetToken( const char *pToken );
// Parses the next token, given a set of character breaks to stop at
// Returns the length of the token parsed in bytes (-1 if none parsed)
int ParseToken( characterset_t *pBreaks, char *pTokenBuf, int nMaxLen, bool bParseComments = true );
// Write stuff in
// Binary mode: it'll just write the bits directly in, and strings will be
// written with a null terminating character
// Text mode: it'll convert the numbers to text versions
// PutString will not write a terminating character
void PutChar( char c );
void PutUnsignedChar( unsigned char uc );
void PutUint64( uint64 ub );
void PutInt16( int16 s16 );
void PutShort( short s );
void PutUnsignedShort( unsigned short us );
void PutInt( int i );
void PutInt64( int64 i );
void PutUnsignedInt( unsigned int u );
void PutFloat( float f );
void PutDouble( double d );
void PutString( const char* pString );
void Put( const void* pMem, int size );
// Used for putting objects that have a byteswap datadesc defined
template <typename T> void PutObjects( T *src, int count = 1 );
// This version of PutString converts \ to \\ and " to \", etc.
// It also places " at the beginning and end of the string
void PutDelimitedString( CUtlCharConversion *pConv, const char *pString );
void PutDelimitedChar( CUtlCharConversion *pConv, char c );
// Just like printf, writes a terminating zero in binary mode
void Printf( PRINTF_FORMAT_STRING const char* pFmt, ... ) FMTFUNCTION( 2, 3 );
void VaPrintf( const char* pFmt, va_list list );
// What am I writing (put)/reading (get)?
void* PeekPut( int offset = 0 );
const void* PeekGet( int offset = 0 ) const;
const void* PeekGet( int nMaxSize, int nOffset );
// Where am I writing (put)/reading (get)?
int TellPut( ) const;
int TellGet( ) const;
// What's the most I've ever written?
int TellMaxPut( ) const;
// How many bytes remain to be read?
// NOTE: This is not accurate for streaming text files; it overshoots
int GetBytesRemaining() const;
// Change where I'm writing (put)/reading (get)
void SeekPut( SeekType_t type, int offset );
void SeekGet( SeekType_t type, int offset );
// Buffer base
const void* Base() const;
void* Base();
// Returns the base as a const char*, only valid in text mode.
const char *String() const;
// memory allocation size, does *not* reflect size written or read,
// use TellPut or TellGet for that
int Size() const;
// Am I a text buffer?
bool IsText() const;
// Can I grow if I'm externally allocated?
bool IsGrowable() const;
// Am I valid? (overflow or underflow error), Once invalid it stays invalid
bool IsValid() const;
// Do I contain carriage return/linefeeds?
bool ContainsCRLF() const;
// Am I read-only
bool IsReadOnly() const;
// 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 ConvertCRLF( CUtlBuffer &outBuf );
// Push/pop pretty-printing tabs
void PushTab();
void PopTab();
// Temporarily disables pretty print
void EnableTabs( bool bEnable );
protected:
// error flags
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:
// Checks if a get/put is ok
bool CheckPut( int size );
bool CheckGet( int size );
void AddNullTermination( );
// Methods to help with pretty-printing
bool WasLastCharacterCR();
void PutTabs();
// Help with delimited stuff
char GetDelimitedCharInternal( CUtlCharConversion *pConv );
void PutDelimitedCharInternal( CUtlCharConversion *pConv, char c );
// Default overflow funcs
bool PutOverflow( int nSize );
bool GetOverflow( int nSize );
// Does the next bytes of the buffer match a pattern?
bool PeekStringMatch( int nOffset, const char *pString, int nLen );
// Peek size of line to come, check memory bound
int PeekLineLength();
// How much whitespace should I skip?
int PeekWhiteSpace( int nOffset );
// Checks if a peek get is ok
bool CheckPeekGet( int nOffset, int nSize );
// Call this to peek arbitrarily long into memory. It doesn't fail unless
// it can't read *anything* new
bool CheckArbitraryPeekGet( int nOffset, int &nIncrement );
void GetStringInternal( char *pString, size_t maxLenInChars );
template <typename T> void GetType( T& dest, const char *pszFmt );
template <typename T> void GetTypeBin( T& dest );
template <typename T> void GetObject( T *src );
template <typename T> void PutType( T src, const char *pszFmt );
template <typename T> void PutTypeBin( T src );
template <typename T> void PutObject( T *src );
CUtlMemory<unsigned char> m_Memory;
int m_Get;
int m_Put;
unsigned char m_Error;
unsigned char m_Flags;
unsigned char m_Reserved;
#if defined( _X360 )
unsigned char pad;
#endif
int m_nTab;
int m_nMaxPut;
int m_nOffset;
UtlBufferOverflowFunc_t m_GetOverflowFunc;
UtlBufferOverflowFunc_t m_PutOverflowFunc;
CByteswap m_Byteswap;
};
// Stream style output operators for CUtlBuffer
inline CUtlBuffer &operator<<( CUtlBuffer &b, char v )
{
b.PutChar( v );
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned char v )
{
b.PutUnsignedChar( v );
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, short v )
{
b.PutShort( v );
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned short v )
{
b.PutUnsignedShort( v );
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, int v )
{
b.PutInt( v );
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned int v )
{
b.PutUnsignedInt( v );
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, float v )
{
b.PutFloat( v );
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, double v )
{
b.PutDouble( v );
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, const char *pv )
{
b.PutString( pv );
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, const Vector &v )
{
b << v.x << " " << v.y << " " << v.z;
return b;
}
inline CUtlBuffer &operator<<( CUtlBuffer &b, const Vector2D &v )
{
b << v.x << " " << v.y;
return b;
}
class CUtlInplaceBuffer : public CUtlBuffer
{
public:
CUtlInplaceBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 );
//
// Routines returning buffer-inplace-pointers
//
public:
//
// Upon success, determines the line length, fills out the pointer to the
// beginning of the line and the line length, advances the "get" pointer
// offset by the line length and returns "true".
//
// If end of file is reached or upon error returns "false".
//
// Note: the returned length of the line is at least one character because the
// trailing newline characters are also included as part of the line.
//
// Note: the pointer returned points into the local memory of this buffer, in
// case the buffer gets relocated or destroyed the pointer becomes invalid.
//
// e.g.: -------------
//
// char *pszLine;
// int nLineLen;
// while ( pUtlInplaceBuffer->InplaceGetLinePtr( &pszLine, &nLineLen ) )
// {
// ...
// }
//
// -------------
//
// @param ppszInBufferPtr on return points into this buffer at start of line
// @param pnLineLength on return holds num bytes accessible via (*ppszInBufferPtr)
//
// @returns true if line was successfully read
// false when EOF is reached or error occurs
//
bool InplaceGetLinePtr( /* out */ char **ppszInBufferPtr, /* out */ int *pnLineLength );
//
// Determines the line length, advances the "get" pointer offset by the line length,
// replaces the newline character with null-terminator and returns the initial pointer
// to now null-terminated line.
//
// If end of file is reached or upon error returns NULL.
//
// Note: the pointer returned points into the local memory of this buffer, in
// case the buffer gets relocated or destroyed the pointer becomes invalid.
//
// e.g.: -------------
//
// while ( char *pszLine = pUtlInplaceBuffer->InplaceGetLinePtr() )
// {
// ...
// }
//
// -------------
//
// @returns ptr-to-zero-terminated-line if line was successfully read and buffer modified
// NULL when EOF is reached or error occurs
//
char * InplaceGetLinePtr( void );
};
//-----------------------------------------------------------------------------
// Where am I reading?
//-----------------------------------------------------------------------------
inline int CUtlBuffer::TellGet( ) const
{
return m_Get;
}
//-----------------------------------------------------------------------------
// How many bytes remain to be read?
//-----------------------------------------------------------------------------
inline int CUtlBuffer::GetBytesRemaining() const
{
return m_nMaxPut - TellGet();
}
//-----------------------------------------------------------------------------
// What am I reading?
//-----------------------------------------------------------------------------
inline const void* CUtlBuffer::PeekGet( int offset ) const
{
return &m_Memory[ m_Get + offset - m_nOffset ];
}
//-----------------------------------------------------------------------------
// Unserialization
//-----------------------------------------------------------------------------
template <typename T>
inline void CUtlBuffer::GetObject( T *dest )
{
if ( CheckGet( sizeof(T) ) )
{
if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
{
*dest = *(T *)PeekGet();
}
else
{
m_Byteswap.SwapFieldsToTargetEndian<T>( dest, (T*)PeekGet() );
}
m_Get += sizeof(T);
}
else
{
Q_memset( dest, 0, sizeof(T) );
}
}
template <typename T>
inline void CUtlBuffer::GetObjects( T *dest, int count )
{
for ( int i = 0; i < count; ++i, ++dest )
{
GetObject<T>( dest );
}
}
template <typename T>
inline void CUtlBuffer::GetTypeBin( T &dest )
{
if ( CheckGet( sizeof(T) ) )
{
if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
{
dest = *(T *)PeekGet();
}
else
{
m_Byteswap.SwapBufferToTargetEndian<T>( &dest, (T*)PeekGet() );
}
m_Get += sizeof(T);
}
else
{
dest = 0;
}
}
template <>
inline void CUtlBuffer::GetTypeBin< float >( float &dest )
{
if ( CheckGet( sizeof( float ) ) )
{
uintptr_t pData = (uintptr_t)PeekGet();
if ( IsX360() && ( pData & 0x03 ) )
{
// handle unaligned read
((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0];
((unsigned char*)&dest)[1] = ((unsigned char*)pData)[1];
((unsigned char*)&dest)[2] = ((unsigned char*)pData)[2];
((unsigned char*)&dest)[3] = ((unsigned char*)pData)[3];
}
else
{
// aligned read
dest = *(float *)pData;
}
if ( m_Byteswap.IsSwappingBytes() )
{
m_Byteswap.SwapBufferToTargetEndian< float >( &dest, &dest );
}
m_Get += sizeof( float );
}
else
{
dest = 0;
}
}
template <typename T>
inline void CUtlBuffer::GetType( T &dest, const char *pszFmt )
{
if (!IsText())
{
GetTypeBin( dest );
}
else
{
dest = 0;
Scanf( pszFmt, &dest );
}
}
inline char CUtlBuffer::GetChar( )
{
char c;
GetType( c, "%c" );
return c;
}
inline unsigned char CUtlBuffer::GetUnsignedChar( )
{
unsigned char c;
GetType( c, "%u" );
return c;
}
inline short CUtlBuffer::GetShort( )
{
short s;
GetType( s, "%d" );
return s;
}
inline unsigned short CUtlBuffer::GetUnsignedShort( )
{
unsigned short s;
GetType( s, "%u" );
return s;
}
inline int CUtlBuffer::GetInt( )
{
int i;
GetType( i, "%d" );
return i;
}
inline int64 CUtlBuffer::GetInt64( )
{
int64 i;
GetType( i, "%lld" );
return i;
}
inline int CUtlBuffer::GetIntHex( )
{
int i;
GetType( i, "%x" );
return i;
}
inline unsigned int CUtlBuffer::GetUnsignedInt( )
{
unsigned int u;
GetType( u, "%u" );
return u;
}
inline float CUtlBuffer::GetFloat( )
{
float f;
GetType( f, "%f" );
return f;
}
inline double CUtlBuffer::GetDouble( )
{
double d;
GetType( d, "%f" );
return d;
}
//-----------------------------------------------------------------------------
// Where am I writing?
//-----------------------------------------------------------------------------
inline unsigned char CUtlBuffer::GetFlags() const
{
return m_Flags;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
inline bool CUtlBuffer::IsExternallyAllocated() const
{
return m_Memory.IsExternallyAllocated();
}
//-----------------------------------------------------------------------------
// Where am I writing?
//-----------------------------------------------------------------------------
inline int CUtlBuffer::TellPut( ) const
{
return m_Put;
}
//-----------------------------------------------------------------------------
// What's the most I've ever written?
//-----------------------------------------------------------------------------
inline int CUtlBuffer::TellMaxPut( ) const
{
return m_nMaxPut;
}
//-----------------------------------------------------------------------------
// What am I reading?
//-----------------------------------------------------------------------------
inline void* CUtlBuffer::PeekPut( int offset )
{
return &m_Memory[m_Put + offset - m_nOffset];
}
//-----------------------------------------------------------------------------
// Various put methods
//-----------------------------------------------------------------------------
template <typename T>
inline void CUtlBuffer::PutObject( T *src )
{
if ( CheckPut( sizeof(T) ) )
{
if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
{
*(T *)PeekPut() = *src;
}
else
{
m_Byteswap.SwapFieldsToTargetEndian<T>( (T*)PeekPut(), src );
}
m_Put += sizeof(T);
AddNullTermination();
}
}
template <typename T>
inline void CUtlBuffer::PutObjects( T *src, int count )
{
for ( int i = 0; i < count; ++i, ++src )
{
PutObject<T>( src );
}
}
template <typename T>
inline void CUtlBuffer::PutTypeBin( T src )
{
if ( CheckPut( sizeof(T) ) )
{
if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) )
{
*(T *)PeekPut() = src;
}
else
{
m_Byteswap.SwapBufferToTargetEndian<T>( (T*)PeekPut(), &src );
}
m_Put += sizeof(T);
AddNullTermination();
}
}
template <typename T>
inline void CUtlBuffer::PutType( T src, const char *pszFmt )
{
if (!IsText())
{
PutTypeBin( src );
}
else
{
Printf( pszFmt, src );
}
}
//-----------------------------------------------------------------------------
// Methods to help with pretty-printing
//-----------------------------------------------------------------------------
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; )
{
PutTypeBin<char>( '\t' );
}
}
//-----------------------------------------------------------------------------
// Push/pop pretty-printing tabs
//-----------------------------------------------------------------------------
inline void CUtlBuffer::PushTab( )
{
++m_nTab;
}
inline void CUtlBuffer::PopTab()
{
if ( --m_nTab < 0 )
{
m_nTab = 0;
}
}
//-----------------------------------------------------------------------------
// Temporarily disables pretty print
//-----------------------------------------------------------------------------
inline void CUtlBuffer::EnableTabs( bool bEnable )
{
if ( bEnable )
{
m_Flags &= ~AUTO_TABS_DISABLED;
}
else
{
m_Flags |= AUTO_TABS_DISABLED;
}
}
inline void CUtlBuffer::PutChar( char c )
{
if ( WasLastCharacterCR() )
{
PutTabs();
}
PutTypeBin( c );
}
inline void CUtlBuffer::PutUnsignedChar( unsigned char c )
{
PutType( c, "%u" );
}
inline void CUtlBuffer::PutUint64( uint64 ub )
{
PutType( ub, "%llu" );
}
inline void CUtlBuffer::PutInt16( int16 s16 )
{
PutType( s16, "%d" );
}
inline void CUtlBuffer::PutShort( short s )
{
PutType( s, "%d" );
}
inline void CUtlBuffer::PutUnsignedShort( unsigned short s )
{
PutType( s, "%u" );
}
inline void CUtlBuffer::PutInt( int i )
{
PutType( i, "%d" );
}
inline void CUtlBuffer::PutInt64( int64 i )
{
PutType( i, "%llu" );
}
inline void CUtlBuffer::PutUnsignedInt( unsigned int u )
{
PutType( u, "%u" );
}
inline void CUtlBuffer::PutFloat( float f )
{
PutType( f, "%f" );
}
inline void CUtlBuffer::PutDouble( double d )
{
PutType( d, "%f" );
}
//-----------------------------------------------------------------------------
// Am I a text buffer?
//-----------------------------------------------------------------------------
inline bool CUtlBuffer::IsText() const
{
return (m_Flags & TEXT_BUFFER) != 0;
}
//-----------------------------------------------------------------------------
// Can I grow if I'm externally allocated?
//-----------------------------------------------------------------------------
inline bool CUtlBuffer::IsGrowable() const
{
return (m_Flags & EXTERNAL_GROWABLE) != 0;
}
//-----------------------------------------------------------------------------
// Am I valid? (overflow or underflow error), Once invalid it stays invalid
//-----------------------------------------------------------------------------
inline bool CUtlBuffer::IsValid() const
{
return m_Error == 0;
}
//-----------------------------------------------------------------------------
// Do I contain carriage return/linefeeds?
//-----------------------------------------------------------------------------
inline bool CUtlBuffer::ContainsCRLF() const
{
return IsText() && ((m_Flags & CONTAINS_CRLF) != 0);
}
//-----------------------------------------------------------------------------
// Am I read-only
//-----------------------------------------------------------------------------
inline bool CUtlBuffer::IsReadOnly() const
{
return (m_Flags & READ_ONLY) != 0;
}
//-----------------------------------------------------------------------------
// Buffer base and size
//-----------------------------------------------------------------------------
inline const void* CUtlBuffer::Base() const
{
return m_Memory.Base();
}
inline void* CUtlBuffer::Base()
{
return m_Memory.Base();
}
// Returns the base as a const char*, only valid in text mode.
inline const char *CUtlBuffer::String() const
{
Assert( IsText() );
return reinterpret_cast<const char*>( m_Memory.Base() );
}
inline int CUtlBuffer::Size() const
{
return m_Memory.NumAllocated();
}
//-----------------------------------------------------------------------------
// Clears out the buffer; frees memory
//-----------------------------------------------------------------------------
inline void CUtlBuffer::Clear()
{
m_Get = 0;
m_Put = 0;
m_Error = 0;
m_nOffset = 0;
m_nMaxPut = -1;
AddNullTermination();
}
inline void CUtlBuffer::Purge()
{
m_Get = 0;
m_Put = 0;
m_nOffset = 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 );
}
}
#endif // UTLBUFFER_H