//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ // // The copyright to the contents herein is the property of Valve, L.L.C. // The contents may be used and/or copied only with the written permission of // Valve, L.L.C., or in accordance with the terms and conditions stipulated in // the agreement/contract under which the contents have been supplied. // // $Header: $ // $NoKeywords: $ // // Serialization/unserialization buffer //============================================================================= #ifndef UTLBUFFER_H #define UTLBUFFER_H #include "osconfig.h" #include "utlmemory.h" #include //----------------------------------------------------------------------------- // Command parsing.. //----------------------------------------------------------------------------- class CUtlBuffer { public: enum SeekType_t { SEEK_HEAD = 0, SEEK_CURRENT, SEEK_TAIL }; CUtlBuffer(int growSize = 0, int initSize = 0, bool text = false); CUtlBuffer(void const* pBuffer, int size, bool text = false); // 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 numElements, bool text = false); // 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 reaced char GetChar(); unsigned char GetUnsignedChar(); short GetShort(); unsigned short GetUnsignedShort(); int GetInt(); int GetIntHex(); unsigned int GetUnsignedInt(); float GetFloat(); double GetDouble(); void GetString(char* pString, int nMaxLen = 0); void Get(void* pMem, int size); // Just like scanf, but doesn't work in binary mode int Scanf(char const* pFmt, ...); int VaScanf(char const* pFmt, va_list list); // Eats white space, advances Get index void EatWhiteSpace(); // 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 PutUnsignedInt(unsigned int u); void PutFloat(float f); void PutDouble(double d); void PutString(char const* pString); void Put(void const* pMem, int size); // Just like printf, writes a terminating zero in binary mode void Printf(char const* pFmt, ...); void VaPrintf(char const* pFmt, va_list list); // What am I writing (put)/reading (get)? void* PeekPut(int offset = 0); void const* PeekGet(int offset = 0) const; // Where am I writing (put)/reading (get)? int TellPut() const; int TellGet() 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 void const* Base() const; void* Base(); // memory allocation size, does *not* reflect size written or read, // use TellPut or TellGet for that int Size() const; // Am I a text buffer? inline bool IsText() const { return (m_Flags & TEXT_BUFFER) != 0; } // Am I valid? (overflow or underflow error), Once invalid it stays invalid inline bool IsValid() const { return m_Error == 0; } private: // error flags enum { PUT_OVERFLOW = 0x1, GET_OVERFLOW = 0x2, }; // flags enum { TEXT_BUFFER = 0x1, }; // Checks if a get/put is ok bool CheckPut(int size); bool CheckGet(int size); CUtlMemory m_Memory; int m_Get; int m_Put; unsigned char m_Error; unsigned char m_Flags; }; //----------------------------------------------------------------------------- // Where am I reading? //----------------------------------------------------------------------------- inline int CUtlBuffer::TellGet() const { return m_Get; } //----------------------------------------------------------------------------- // What am I reading? //----------------------------------------------------------------------------- inline void const* CUtlBuffer::PeekGet(int offset) const { return &m_Memory[m_Get + offset]; } //----------------------------------------------------------------------------- // Unserialization //----------------------------------------------------------------------------- #define GET_TYPE( _type, _val, _fmt ) \ if (!IsText()) \ { \ if (CheckGet( sizeof(_type) )) \ { \ _val = *(_type *)PeekGet(); \ m_Get += sizeof(_type); \ } \ else \ { \ _val = 0; \ } \ } \ else \ { \ _val = 0; \ Scanf( _fmt, &_val ); \ } inline char CUtlBuffer::GetChar() { char c; GET_TYPE(char, c, "%c"); return c; } inline unsigned char CUtlBuffer::GetUnsignedChar() { unsigned char c; GET_TYPE(unsigned char, c, "%u"); return c; } inline short CUtlBuffer::GetShort() { short s; GET_TYPE(short, s, "%d"); return s; } inline unsigned short CUtlBuffer::GetUnsignedShort() { unsigned short s; GET_TYPE(unsigned short, s, "%u"); return s; } inline int CUtlBuffer::GetInt() { int i; GET_TYPE(int, i, "%d"); return i; } inline int CUtlBuffer::GetIntHex() { int i; GET_TYPE(int, i, "%x"); return i; } inline unsigned int CUtlBuffer::GetUnsignedInt() { unsigned int u; GET_TYPE(unsigned int, u, "%u"); return u; } inline float CUtlBuffer::GetFloat() { float f; GET_TYPE(float, f, "%f"); return f; } inline double CUtlBuffer::GetDouble() { double d; GET_TYPE(double, d, "%f"); return d; } //----------------------------------------------------------------------------- // Where am I writing? //----------------------------------------------------------------------------- inline int CUtlBuffer::TellPut() const { return m_Put; } //----------------------------------------------------------------------------- // What am I reading? //----------------------------------------------------------------------------- inline void* CUtlBuffer::PeekPut(int offset) { return &m_Memory[m_Put + offset]; } //----------------------------------------------------------------------------- // Various put methods //----------------------------------------------------------------------------- #define PUT_TYPE( _type, _val, _fmt ) \ if (!IsText()) \ { \ if (CheckPut( sizeof(_type) )) \ { \ *(_type *)PeekPut() = _val; \ m_Put += sizeof(_type); \ } \ } \ else \ { \ Printf( _fmt, _val ); \ } inline void CUtlBuffer::PutChar(char c) { PUT_TYPE(char, c, "%c"); } inline void CUtlBuffer::PutUnsignedChar(unsigned char c) { PUT_TYPE(unsigned char, c, "%u"); } inline void CUtlBuffer::PutShort(short s) { PUT_TYPE(short, s, "%d"); } inline void CUtlBuffer::PutUnsignedShort(unsigned short s) { PUT_TYPE(unsigned short, s, "%u"); } inline void CUtlBuffer::PutInt(int i) { PUT_TYPE(int, i, "%d"); } inline void CUtlBuffer::PutUnsignedInt(unsigned int u) { PUT_TYPE(unsigned int, u, "%u"); } inline void CUtlBuffer::PutFloat(float f) { PUT_TYPE(float, f, "%f"); } inline void CUtlBuffer::PutDouble(double d) { PUT_TYPE(double, d, "%f"); } //----------------------------------------------------------------------------- // Buffer base and size //----------------------------------------------------------------------------- inline void const* CUtlBuffer::Base() const { return m_Memory.Base(); } inline void* CUtlBuffer::Base() { return m_Memory.Base(); } inline int CUtlBuffer::Size() const { return m_Memory.NumAllocated(); } #endif // UTLBUFFER_H