//====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
// $NoKeywords: $
//
// Serialization/unserialization buffer
//=============================================================================//
# ifndef UTLBUFFER_H
# define UTLBUFFER_H
# ifdef _WIN32
# pragma once
# endif
# include "unitlib/unitlib.h" // just here for tests - remove before checking in!!!
# 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 ) )
typedef unsigned short ushort ;
template < class A >
static const char * GetFmtStr ( int nRadix = 10 , bool bPrint = true ) { Assert ( 0 ) ; return " " ; }
# if defined( LINUX ) || defined( __clang__ ) || ( defined( _MSC_VER ) && _MSC_VER >= 1900 )
template < > const char * GetFmtStr < short > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %hd " ; }
template < > const char * GetFmtStr < ushort > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %hu " ; }
template < > const char * GetFmtStr < int > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %d " ; }
template < > const char * GetFmtStr < uint > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 | | nRadix = = 16 ) ; return nRadix = = 16 ? " %x " : " %u " ; }
template < > const char * GetFmtStr < int64 > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %lld " ; }
template < > const char * GetFmtStr < float > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %f " ; }
template < > const char * GetFmtStr < double > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return bPrint ? " %.15lf " : " %lf " ; } // force Printf to print DBL_DIG=15 digits of precision for doubles - defaults to FLT_DIG=6
# else
template < > static const char * GetFmtStr < short > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %hd " ; }
template < > static const char * GetFmtStr < ushort > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %hu " ; }
template < > static const char * GetFmtStr < int > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %d " ; }
template < > static const char * GetFmtStr < uint > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 | | nRadix = = 16 ) ; return nRadix = = 16 ? " %x " : " %u " ; }
template < > static const char * GetFmtStr < int64 > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %lld " ; }
template < > static const char * GetFmtStr < float > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return " %f " ; }
template < > static const char * GetFmtStr < double > ( int nRadix , bool bPrint ) { Assert ( nRadix = = 10 ) ; return bPrint ? " %.15lf " : " %lf " ; } // force Printf to print DBL_DIG=15 digits of precision for doubles - defaults to FLT_DIG=6
# endif
//-----------------------------------------------------------------------------
// Command parsing..
//-----------------------------------------------------------------------------
class CUtlBuffer
{
// Brian has on his todo list to revisit this as there are issues in some cases with CUtlVector using operator = instead of copy construtor in InsertMultiple, etc.
// The unsafe case is something like this:
// CUtlVector< CUtlBuffer > vecFoo;
//
// CUtlBuffer buf;
// buf.Put( xxx );
// vecFoo.Insert( buf );
//
// This will cause memory corruption when vecFoo is cleared
//
//private:
// // Disallow copying
// CUtlBuffer( const CUtlBuffer & );// { Assert( 0 ); }
// CUtlBuffer &operator=( const CUtlBuffer & );// { Assert( 0 ); return *this; }
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 ) = delete ;
// UtlBuffer objects should not be copyable; we do a slow copy if you use this but it asserts.
// (REI: I'd like to delete these but we have some python bindings that currently rely on being able to copy these objects)
CUtlBuffer ( const CUtlBuffer & ) ; // = delete;
CUtlBuffer & operator = ( const CUtlBuffer & ) ; // = delete;
# if VALVE_CPP11
// UtlBuffer is non-copyable (same as CUtlMemory), but it is moveable. We would like to declare these with '= default'
// but unfortunately VS2013 isn't fully C++11 compliant, so we have to manually declare these in the boilerplate way.
CUtlBuffer ( CUtlBuffer & & moveFrom ) ; // = default;
CUtlBuffer & operator = ( CUtlBuffer & & moveFrom ) ; // = default;
# endif
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 ) ;
// Access for direct read into buffer
void * AccessForDirectRead ( int nBytes ) ;
// Attaches the buffer to external memory....
void SetExternalBuffer ( void * pMemory , int nSize , int nInitialPut , int nFlags = 0 ) ;
bool IsExternallyAllocated ( ) const ;
void AssumeMemory ( void * pMemory , int nSize , int nInitialPut , int nFlags = 0 ) ;
void * Detach ( ) ;
void * DetachMemory ( ) ;
// 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 ( ) | | IsPS3 ( ) ) )
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 ( ) ;
// Dump the buffer to stdout
void Spew ( ) ;
// 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 ( ) ;
unsigned int GetIntHex ( ) ;
unsigned int GetUnsignedInt ( ) ;
uint64 GetUnsignedInt64 ( ) ;
float GetFloat ( ) ;
double GetDouble ( ) ;
void * GetPtr ( ) ;
void GetString ( char * pString , int nMaxChars ) ;
bool Get ( void * pMem , int size ) ;
void GetLine ( char * pLine , int nMaxChars ) ;
void GetStringManualCharCount ( char * pString , size_t maxLenInChars )
{
GetString ( pString , maxLenInChars ) ;
}
template < size_t maxLenInChars > void GetString ( char ( & pString ) [ maxLenInChars ] )
{
GetString ( pString , maxLenInChars ) ;
}
// 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 PutShort ( short s ) ;
void PutUnsignedShort ( unsigned short us ) ;
void PutInt ( int i ) ;
void PutInt64 ( int64 i ) ;
void PutUnsignedInt ( unsigned int u ) ;
void PutUnsignedInt64 ( uint64 u ) ;
void PutUint64 ( uint64 u ) ;
void PutFloat ( float f ) ;
void PutDouble ( double d ) ;
void PutPtr ( void * ) ; // Writes the pointer, not the pointed to
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 ( ) ;
const void * 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 ) ;
# if !defined( _GAMECONSOLE )
// Swap my internal memory with another buffer,
// and copy all of its other members
void SwapCopy ( CUtlBuffer & other ) ;
# endif
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 ) ;
// NOTE: Pass in nPut here even though it is just a copy of m_Put. This is almost always called immediately
// after modifying m_Put and this lets it stay in a register
void AddNullTermination ( ) ;
void AddNullTermination ( int nPut ) ;
// 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 ) ;
template < typename T > void GetType ( T & dest ) ;
template < typename T > void GetTypeBin ( T & dest ) ;
template < typename T > bool GetTypeText ( T & value , int nRadix = 10 ) ;
template < typename T > void GetObject ( T * src ) ;
template < typename T > void PutType ( T src ) ;
template < typename T > void PutTypeBin ( T src ) ;
template < typename T > void PutObject ( T * src ) ;
// be sure to also update the copy constructor
// and SwapCopy() when adding members.
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( _GAMECONSOLE )
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 ) )
{
memcpy ( dest , PeekGet ( ) , sizeof ( T ) ) ;
}
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 ) )
{
memcpy ( & dest , PeekGet ( ) , sizeof ( T ) ) ;
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 ) ) )
{
uintp pData = ( uintp ) PeekGet ( ) ;
if ( ( IsX360 ( ) | | IsPS3 ( ) ) & & ( 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 < >
inline void CUtlBuffer : : GetTypeBin < double > ( double & dest )
{
if ( CheckGet ( sizeof ( double ) ) )
{
uintp pData = ( uintp ) PeekGet ( ) ;
if ( ( IsX360 ( ) | | IsPS3 ( ) ) & & ( pData & 0x07 ) )
{
// 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 ] ;
( ( unsigned char * ) & dest ) [ 4 ] = ( ( unsigned char * ) pData ) [ 4 ] ;
( ( unsigned char * ) & dest ) [ 5 ] = ( ( unsigned char * ) pData ) [ 5 ] ;
( ( unsigned char * ) & dest ) [ 6 ] = ( ( unsigned char * ) pData ) [ 6 ] ;
( ( unsigned char * ) & dest ) [ 7 ] = ( ( unsigned char * ) pData ) [ 7 ] ;
}
else
{
// aligned read
dest = * ( double * ) pData ;
}
if ( m_Byteswap . IsSwappingBytes ( ) )
{
m_Byteswap . SwapBufferToTargetEndian < double > ( & dest , & dest ) ;
}
m_Get + = sizeof ( double ) ;
}
else
{
dest = 0 ;
}
}
template < class T >
inline T StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
Assert ( 0 ) ;
* ppEnd = pString ;
return 0 ;
}
template < >
inline int8 StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
return ( int8 ) strtol ( pString , ppEnd , nRadix ) ;
}
template < >
inline uint8 StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
return ( uint8 ) strtoul ( pString , ppEnd , nRadix ) ;
}
template < >
inline int16 StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
return ( int16 ) strtol ( pString , ppEnd , nRadix ) ;
}
template < >
inline uint16 StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
return ( uint16 ) strtoul ( pString , ppEnd , nRadix ) ;
}
template < >
inline int32 StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
return ( int32 ) strtol ( pString , ppEnd , nRadix ) ;
}
template < >
inline uint32 StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
return ( uint32 ) strtoul ( pString , ppEnd , nRadix ) ;
}
template < >
inline int64 StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
# if defined(_PS3) || defined(POSIX)
return ( int64 ) strtoll ( pString , ppEnd , nRadix ) ;
# else // !_PS3
return ( int64 ) _strtoi64 ( pString , ppEnd , nRadix ) ;
# endif // _PS3
}
template < >
inline float StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
NOTE_UNUSED ( nRadix ) ;
return ( float ) strtod ( pString , ppEnd ) ;
}
template < >
inline double StringToNumber ( char * pString , char * * ppEnd , int nRadix )
{
NOTE_UNUSED ( nRadix ) ;
return ( double ) strtod ( pString , ppEnd ) ;
}
template < typename T >
inline bool CUtlBuffer : : GetTypeText ( T & value , int nRadix /*= 10*/ )
{
// NOTE: This is not bullet-proof; it assumes numbers are < 128 characters
int nLength = 128 ;
if ( ! CheckArbitraryPeekGet ( 0 , nLength ) )
{
value = 0 ;
return false ;
}
char * pStart = ( char * ) PeekGet ( ) ;
char * pEnd = pStart ;
value = StringToNumber < T > ( pStart , & pEnd , nRadix ) ;
int nBytesRead = ( int ) ( pEnd - pStart ) ;
if ( nBytesRead = = 0 )
return false ;
m_Get + = nBytesRead ;
return true ;
}
template < typename T >
inline void CUtlBuffer : : GetType ( T & dest )
{
if ( ! IsText ( ) )
{
GetTypeBin ( dest ) ;
}
else
{
GetTypeText ( dest ) ;
}
}
inline char CUtlBuffer : : GetChar ( )
{
// LEGACY WARNING: this behaves differently than GetUnsignedChar()
char c ;
GetTypeBin ( c ) ; // always reads as binary
return c ;
}
inline unsigned char CUtlBuffer : : GetUnsignedChar ( )
{
// LEGACY WARNING: this behaves differently than GetChar()
unsigned char c ;
if ( ! IsText ( ) )
{
GetTypeBin ( c ) ;
}
else
{
c = ( unsigned char ) GetUnsignedShort ( ) ;
}
return c ;
}
inline short CUtlBuffer : : GetShort ( )
{
short s ;
GetType ( s ) ;
return s ;
}
inline unsigned short CUtlBuffer : : GetUnsignedShort ( )
{
unsigned short s ;
GetType ( s ) ;
return s ;
}
inline int CUtlBuffer : : GetInt ( )
{
int i ;
GetType ( i ) ;
return i ;
}
inline int64 CUtlBuffer : : GetInt64 ( )
{
int64 i ;
GetType ( i ) ;
return i ;
}
inline unsigned int CUtlBuffer : : GetIntHex ( )
{
uint i ;
if ( ! IsText ( ) )
{
GetTypeBin ( i ) ;
}
else
{
GetTypeText ( i , 16 ) ;
}
return i ;
}
inline unsigned int CUtlBuffer : : GetUnsignedInt ( )
{
unsigned int i ;
GetType ( i ) ;
return i ;
}
inline uint64 CUtlBuffer : : GetUnsignedInt64 ( )
{
uint64 i ;
GetType ( i ) ;
return i ;
}
inline float CUtlBuffer : : GetFloat ( )
{
float f ;
GetType ( f ) ;
return f ;
}
inline double CUtlBuffer : : GetDouble ( )
{
double d ;
GetType ( d ) ;
return d ;
}
inline void * CUtlBuffer : : GetPtr ( )
{
void * p ;
// LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal
# if !defined(X64BITS) && !defined(PLATFORM_64BITS)
p = ( void * ) GetUnsignedInt ( ) ;
# else
p = ( void * ) GetInt64 ( ) ;
# endif
return p ;
}
//-----------------------------------------------------------------------------
// 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 ) )
{
memcpy ( PeekPut ( ) , src , sizeof ( T ) ) ;
}
else
{
m_Byteswap . SwapFieldsToTargetEndian < T > ( ( T * ) PeekPut ( ) , src ) ;
}
m_Put + = sizeof ( T ) ;
AddNullTermination ( m_Put ) ;
}
}
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 ) )
{
memcpy ( PeekPut ( ) , & src , sizeof ( T ) ) ;
}
else
{
m_Byteswap . SwapBufferToTargetEndian < T > ( ( T * ) PeekPut ( ) , & src ) ;
}
m_Put + = sizeof ( T ) ;
AddNullTermination ( m_Put ) ;
}
}
# if defined( _GAMECONSOLE )
template < >
inline void CUtlBuffer : : PutTypeBin < float > ( float src )
{
if ( CheckPut ( sizeof ( src ) ) )
{
if ( m_Byteswap . IsSwappingBytes ( ) )
{
m_Byteswap . SwapBufferToTargetEndian < float > ( & src , & src ) ;
}
//
// Write the data
//
unsigned pData = ( unsigned ) PeekPut ( ) ;
if ( pData & 0x03 )
{
// handle unaligned write
byte * dst = ( byte * ) pData ;
byte * srcPtr = ( byte * ) & src ;
dst [ 0 ] = srcPtr [ 0 ] ;
dst [ 1 ] = srcPtr [ 1 ] ;
dst [ 2 ] = srcPtr [ 2 ] ;
dst [ 3 ] = srcPtr [ 3 ] ;
}
else
{
* ( float * ) pData = src ;
}
m_Put + = sizeof ( float ) ;
AddNullTermination ( m_Put ) ;
}
}
template < >
inline void CUtlBuffer : : PutTypeBin < double > ( double src )
{
if ( CheckPut ( sizeof ( src ) ) )
{
if ( m_Byteswap . IsSwappingBytes ( ) )
{
m_Byteswap . SwapBufferToTargetEndian < double > ( & src , & src ) ;
}
//
// Write the data
//
unsigned pData = ( unsigned ) PeekPut ( ) ;
if ( pData & 0x07 )
{
// handle unaligned write
byte * dst = ( byte * ) pData ;
byte * srcPtr = ( byte * ) & src ;
dst [ 0 ] = srcPtr [ 0 ] ;
dst [ 1 ] = srcPtr [ 1 ] ;
dst [ 2 ] = srcPtr [ 2 ] ;
dst [ 3 ] = srcPtr [ 3 ] ;
dst [ 4 ] = srcPtr [ 4 ] ;
dst [ 5 ] = srcPtr [ 5 ] ;
dst [ 6 ] = srcPtr [ 6 ] ;
dst [ 7 ] = srcPtr [ 7 ] ;
}
else
{
* ( double * ) pData = src ;
}
m_Put + = sizeof ( double ) ;
AddNullTermination ( m_Put ) ;
}
}
# endif
template < typename T >
inline void CUtlBuffer : : PutType ( T src )
{
if ( ! IsText ( ) )
{
PutTypeBin ( src ) ;
}
else
{
Printf ( GetFmtStr < T > ( ) , 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 )
{
if ( ! IsText ( ) )
{
PutTypeBin ( c ) ;
}
else
{
PutUnsignedShort ( c ) ;
}
}
inline void CUtlBuffer : : PutShort ( short s )
{
PutType ( s ) ;
}
inline void CUtlBuffer : : PutUnsignedShort ( unsigned short s )
{
PutType ( s ) ;
}
inline void CUtlBuffer : : PutInt ( int i )
{
PutType ( i ) ;
}
inline void CUtlBuffer : : PutInt64 ( int64 i )
{
PutType ( i ) ;
}
inline void CUtlBuffer : : PutUnsignedInt ( unsigned int u )
{
PutType ( u ) ;
}
inline void CUtlBuffer : : PutUnsignedInt64 ( uint64 i )
{
PutType ( i ) ;
}
inline void CUtlBuffer : : PutUint64 ( uint64 i )
{
PutType ( i ) ;
}
inline void CUtlBuffer : : PutFloat ( float f )
{
PutType ( f ) ;
}
inline void CUtlBuffer : : PutDouble ( double d )
{
PutType ( d ) ;
}
inline void CUtlBuffer : : PutPtr ( void * p )
{
// LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal
if ( ! IsText ( ) )
{
PutTypeBin ( p ) ;
}
else
{
Printf ( " 0x%p " , p ) ;
}
}
//-----------------------------------------------------------------------------
// 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 ( ) ;
}
inline const void * 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 ( m_Put ) ;
}
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 : : AccessForDirectRead ( int nBytes )
{
Assert ( m_Get = = 0 & & m_Put = = 0 & & m_nMaxPut = = 0 ) ;
EnsureCapacity ( nBytes ) ;
m_nMaxPut = nBytes ;
return Base ( ) ;
}
inline void * CUtlBuffer : : Detach ( )
{
void * p = m_Memory . Detach ( ) ;
Clear ( ) ;
return p ;
}
//-----------------------------------------------------------------------------
inline void CUtlBuffer : : Spew ( )
{
SeekGet ( CUtlBuffer : : SEEK_HEAD , 0 ) ;
char pTmpLine [ 1024 ] ;
while ( IsValid ( ) & & GetBytesRemaining ( ) )
{
V_memset ( pTmpLine , 0 , sizeof ( pTmpLine ) ) ;
Get ( pTmpLine , MIN ( ( size_t ) GetBytesRemaining ( ) , sizeof ( pTmpLine ) - 1 ) ) ;
Msg ( _T ( " %s " ) , pTmpLine ) ;
}
}
# if !defined(_GAMECONSOLE)
inline void CUtlBuffer : : SwapCopy ( CUtlBuffer & other )
{
m_Get = other . m_Get ;
m_Put = other . m_Put ;
m_Error = other . m_Error ;
m_Flags = other . m_Flags ;
m_Reserved = other . m_Reserved ;
m_nTab = other . m_nTab ;
m_nMaxPut = other . m_nMaxPut ;
m_nOffset = other . m_nOffset ;
m_GetOverflowFunc = other . m_GetOverflowFunc ;
m_PutOverflowFunc = other . m_PutOverflowFunc ;
m_Byteswap = other . m_Byteswap ;
m_Memory . Swap ( other . m_Memory ) ;
}
# endif
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