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.
1472 lines
39 KiB
1472 lines
39 KiB
//====== 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 ) ) |
|
{ |
|
*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 ) ) ) |
|
{ |
|
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 ) ) |
|
{ |
|
*(T *)PeekPut() = *src; |
|
} |
|
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 ) ) |
|
{ |
|
*(T *)PeekPut() = src; |
|
} |
|
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 |
|
|
|
|