#ifndef BITBUF_H #define BITBUF_H #ifdef _WIN32 #pragma once #endif #include "mathlib.h" #include "vector.h" #include "basetypes.h" #if _DEBUG #define BITBUF_INLINE inline #else #define BITBUF_INLINE FORCEINLINE #endif class Vector; class QAngle; typedef enum { BITBUFERROR_VALUE_OUT_OF_RANGE = 0, BITBUFERROR_BUFFER_OVERRUN, BITBUFERROR_NUM_ERRORS } BitBufErrorType; typedef void (*BitBufErrorHandler)(BitBufErrorType errorType, const char* pDebugName); #if defined( _DEBUG ) extern void InternalBitBufErrorHandler(BitBufErrorType errorType, const char* pDebugName); #define CallErrorHandler( errorType, pDebugName ) InternalBitBufErrorHandler( errorType, pDebugName ); #else #define CallErrorHandler( errorType, pDebugName ) #endif void SetBitBufErrorHandler(BitBufErrorHandler fn); inline int BitByte(int bits) { return (bits + 7) >> 3; } namespace bitbuf { inline uint32 ZigZagEncode32(int32 n) { return(n << 1) ^ (n >> 31); } inline int32 ZigZagDecode32(uint32 n) { return(n >> 1) ^ -static_cast(n & 1); } inline uint64 ZigZagEncode64(int64 n) { return(n << 1) ^ (n >> 63); } inline int64 ZigZagDecode64(uint64 n) { return(n >> 1) ^ -static_cast(n & 1); } const int kMaxVarintBytes = 10; const int kMaxVarint32Bytes = 5; } class bf_write { public: bf_write(); bf_write(void* pData, int nBytes, int nMaxBits = -1); bf_write(const char* pDebugName, void* pData, int nBytes, int nMaxBits = -1); void StartWriting(void* pData, int nBytes, int iStartBit = 0, int nMaxBits = -1); void Reset(); unsigned char* GetBasePointer() { return (unsigned char*)m_pData; } void SetAssertOnOverflow(bool bAssert); const char* GetDebugName(); void SetDebugName(const char* pDebugName); public: void SeekToBit(int bitPos); public: void WriteOneBit(int nValue); void WriteOneBitNoCheck(int nValue); void WriteOneBitAt(int iBit, int nValue); void WriteUBitLong(unsigned int data, int numbits, bool bCheckRange = true); void WriteSBitLong(int data, int numbits); void WriteBitLong(unsigned int data, int numbits, bool bSigned); bool WriteBits(const void* pIn, int nBits); void WriteUBitVar(unsigned int data); void WriteVarInt32(uint32 data); void WriteVarInt64(uint64 data); void WriteSignedVarInt32(int32 data); void WriteSignedVarInt64(int64 data); int ByteSizeVarInt32(uint32 data); int ByteSizeVarInt64(uint64 data); int ByteSizeSignedVarInt32(int32 data); int ByteSizeSignedVarInt64(int64 data); bool WriteBitsFromBuffer(class bf_read* pIn, int nBits); void WriteBitAngle(float fAngle, int numbits); void WriteBitCoord(const float f); void WriteBitCoordMP(const float f, bool bIntegral, bool bLowPrecision); void WriteBitFloat(float val); void WriteBitVec3Coord(const Vector& fa); void WriteBitNormal(float f); void WriteBitVec3Normal(const Vector& fa); void WriteBitAngles(const QAngle& fa); public: void WriteChar(int val); void WriteByte(int val); void WriteShort(int val); void WriteWord(int val); void WriteLong(long val); void WriteLongLong(int64 val); void WriteFloat(float val); bool WriteBytes(const void* pBuf, int nBytes); bool WriteString(const char* pStr); public: int GetNumBytesWritten() const; int GetNumBitsWritten() const; int GetMaxNumBits(); int GetNumBitsLeft(); int GetNumBytesLeft(); unsigned char* GetData(); const unsigned char* GetData() const; bool CheckForOverflow(int nBits); inline bool IsOverflowed() const { return m_bOverflow; } void SetOverflowFlag(); public: unsigned long* RESTRICT m_pData; int m_nDataBytes; int m_nDataBits; int m_iCurBit; private: bool m_bOverflow; bool m_bAssertOnOverflow; const char* m_pDebugName; }; inline int bf_write::GetNumBytesWritten() const { return BitByte(m_iCurBit); } inline int bf_write::GetNumBitsWritten() const { return m_iCurBit; } inline int bf_write::GetMaxNumBits() { return m_nDataBits; } inline int bf_write::GetNumBitsLeft() { return m_nDataBits - m_iCurBit; } inline int bf_write::GetNumBytesLeft() { return GetNumBitsLeft() >> 3; } inline unsigned char* bf_write::GetData() { return (unsigned char*)m_pData; } inline const unsigned char* bf_write::GetData() const { return (unsigned char*)m_pData; } BITBUF_INLINE bool bf_write::CheckForOverflow(int nBits) { if (m_iCurBit + nBits > m_nDataBits) { SetOverflowFlag(); CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); } return m_bOverflow; } BITBUF_INLINE void bf_write::SetOverflowFlag() { #ifdef DBGFLAG_ASSERT if (m_bAssertOnOverflow) { Assert(false); } #endif m_bOverflow = true; } BITBUF_INLINE void bf_write::WriteOneBitNoCheck(int nValue) { #if __i386__ if (nValue) m_pData[m_iCurBit >> 5] |= 1u << (m_iCurBit & 31); else m_pData[m_iCurBit >> 5] &= ~(1u << (m_iCurBit & 31)); #else extern unsigned long g_LittleBits[32]; if (nValue) m_pData[m_iCurBit >> 5] |= g_LittleBits[m_iCurBit & 31]; else m_pData[m_iCurBit >> 5] &= ~g_LittleBits[m_iCurBit & 31]; #endif ++m_iCurBit; } inline void bf_write::WriteOneBit(int nValue) { if (m_iCurBit >= m_nDataBits) { SetOverflowFlag(); CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); return; } WriteOneBitNoCheck(nValue); } inline void bf_write::WriteOneBitAt(int iBit, int nValue) { if (iBit >= m_nDataBits) { SetOverflowFlag(); CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); return; } #if __i386__ if (nValue) m_pData[iBit >> 5] |= 1u << (iBit & 31); else m_pData[iBit >> 5] &= ~(1u << (iBit & 31)); #else extern unsigned long g_LittleBits[32]; if (nValue) m_pData[iBit >> 5] |= g_LittleBits[iBit & 31]; else m_pData[iBit >> 5] &= ~g_LittleBits[iBit & 31]; #endif } BITBUF_INLINE void bf_write::WriteUBitLong(unsigned int curData, int numbits, bool bCheckRange) RESTRICT { #ifdef _DEBUG if (bCheckRange && numbits < 32) { if (curData >= (unsigned long)(1 << numbits)) { CallErrorHandler(BITBUFERROR_VALUE_OUT_OF_RANGE, GetDebugName()); } } Assert(numbits >= 0 && numbits <= 32); #endif if (GetNumBitsLeft() < numbits) { m_iCurBit = m_nDataBits; SetOverflowFlag(); CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); return; } int iCurBitMasked = m_iCurBit & 31; int iDWord = m_iCurBit >> 5; m_iCurBit += numbits; Assert((iDWord * 4 + sizeof(long)) <= (unsigned int)m_nDataBytes); unsigned long* RESTRICT pOut = &m_pData[iDWord]; curData = (curData << iCurBitMasked) | (curData >> (32 - iCurBitMasked)); unsigned int temp = 1 << (numbits - 1); unsigned int mask1 = (temp * 2 - 1) << iCurBitMasked; unsigned int mask2 = (temp - 1) >> (31 - iCurBitMasked); int i = mask2 & 1; unsigned long dword1 = LoadLittleDWord(pOut, 0); unsigned long dword2 = LoadLittleDWord(pOut, i); dword1 ^= (mask1 & (curData ^ dword1)); dword2 ^= (mask2 & (curData ^ dword2)); StoreLittleDWord(pOut, i, dword2); StoreLittleDWord(pOut, 0, dword1); } BITBUF_INLINE void bf_write::WriteUBitVar(unsigned int data) { int n = (data < 0x10u ? -1 : 0) + (data < 0x100u ? -1 : 0) + (data < 0x1000u ? -1 : 0); WriteUBitLong(data * 4 + n + 3, 6 + n * 4 + 12); if (data >= 0x1000u) { WriteUBitLong(data >> 16, 16); } } BITBUF_INLINE void bf_write::WriteBitFloat(float val) { long intVal; Assert(sizeof(long) == sizeof(float)); Assert(sizeof(float) == 4); intVal = *((long*)&val); WriteUBitLong(intVal, 32); } template class old_bf_write_static : public bf_write { public: inline old_bf_write_static() : bf_write(m_StaticData, SIZE) {} char m_StaticData[SIZE]; }; class bf_read { public: bf_read(); bf_read(const void* pData, int nBytes, int nBits = -1); bf_read(const char* pDebugName, const void* pData, int nBytes, int nBits = -1); void StartReading(const void* pData, int nBytes, int iStartBit = 0, int nBits = -1); void Reset(); void SetAssertOnOverflow(bool bAssert); const char* GetDebugName() const { return m_pDebugName; } void SetDebugName(const char* pName); void ExciseBits(int startbit, int bitstoremove); public: int ReadOneBit(); protected: unsigned int CheckReadUBitLong(int numbits); int ReadOneBitNoCheck(); bool CheckForOverflow(int nBits); public: const unsigned char* GetBasePointer() { return m_pData; } BITBUF_INLINE int TotalBytesAvailable(void) const { return m_nDataBytes; } void ReadBits(void* pOut, int nBits); int ReadBitsClamped_ptr(void* pOut, size_t outSizeBytes, size_t nBits); template int ReadBitsClamped(T(&pOut)[N], size_t nBits) { return ReadBitsClamped_ptr(pOut, N * sizeof(T), nBits); } float ReadBitAngle(int numbits); unsigned int ReadUBitLong(int numbits) RESTRICT; unsigned int ReadUBitLongNoInline(int numbits) RESTRICT; unsigned int PeekUBitLong(int numbits); int ReadSBitLong(int numbits); unsigned int ReadUBitVar(); unsigned int ReadUBitVarInternal(int encodingType); uint32 ReadVarInt32(); uint64 ReadVarInt64(); int32 ReadSignedVarInt32(); int64 ReadSignedVarInt64(); unsigned int ReadBitLong(int numbits, bool bSigned); float ReadBitCoord(); float ReadBitCoordMP(bool bIntegral, bool bLowPrecision); float ReadBitFloat(); float ReadBitNormal(); void ReadBitVec3Coord(Vector& fa); void ReadBitVec3Normal(Vector& fa); void ReadBitAngles(QAngle& fa); unsigned int ReadBitCoordBits(); unsigned int ReadBitCoordMPBits(bool bIntegral, bool bLowPrecision); public: BITBUF_INLINE int ReadChar() { return (char)ReadUBitLong(8); } BITBUF_INLINE int ReadByte() { return ReadUBitLong(8); } BITBUF_INLINE int ReadShort() { return (short)ReadUBitLong(16); } BITBUF_INLINE int ReadWord() { return ReadUBitLong(16); } BITBUF_INLINE long ReadLong() { return ReadUBitLong(32); } int64 ReadLongLong(); float ReadFloat(); bool ReadBytes(void* pOut, int nBytes); bool ReadString(char* pStr, int bufLen, bool bLine = false, int* pOutNumChars = NULL); char* ReadAndAllocateString(bool* pOverflow = 0); int CompareBits(bf_read* RESTRICT other, int bits) RESTRICT; int CompareBitsAt(int offset, bf_read* RESTRICT other, int otherOffset, int bits) RESTRICT; public: int GetNumBytesLeft(); int GetNumBytesRead(); int GetNumBitsLeft(); int GetNumBitsRead() const; inline bool IsOverflowed() const { return m_bOverflow; } inline bool Seek(int iBit); inline bool SeekRelative(int iBitDelta); void SetOverflowFlag(); public: const unsigned char* RESTRICT m_pData; int m_nDataBytes; int m_nDataBits; int m_iCurBit; private: bool m_bOverflow; bool m_bAssertOnOverflow; const char* m_pDebugName; }; inline int bf_read::GetNumBytesRead() { return BitByte(m_iCurBit); } inline int bf_read::GetNumBitsLeft() { return m_nDataBits - m_iCurBit; } inline int bf_read::GetNumBytesLeft() { return GetNumBitsLeft() >> 3; } inline int bf_read::GetNumBitsRead() const { return m_iCurBit; } inline bool bf_read::Seek(int iBit) { if (iBit < 0 || iBit > m_nDataBits) { SetOverflowFlag(); m_iCurBit = m_nDataBits; return false; } else { m_iCurBit = iBit; return true; } } inline bool bf_read::SeekRelative(int iBitDelta) { return Seek(m_iCurBit + iBitDelta); } inline bool bf_read::CheckForOverflow(int nBits) { if (m_iCurBit + nBits > m_nDataBits) { SetOverflowFlag(); CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); } return m_bOverflow; } inline int bf_read::ReadOneBitNoCheck() { #if VALVE_LITTLE_ENDIAN unsigned int value = ((unsigned long* RESTRICT)m_pData)[m_iCurBit >> 5] >> (m_iCurBit & 31); #else unsigned char value = m_pData[m_iCurBit >> 3] >> (m_iCurBit & 7); #endif ++m_iCurBit; return value & 1; } inline int bf_read::ReadOneBit() { if (GetNumBitsLeft() <= 0) { SetOverflowFlag(); CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); return 0; } return ReadOneBitNoCheck(); } inline float bf_read::ReadBitFloat() { union { uint32 u; float f; } c = { ReadUBitLong(32) }; return c.f; } BITBUF_INLINE unsigned int bf_read::ReadUBitVar() { unsigned int sixbits = ReadUBitLong(6); unsigned int encoding = sixbits & 3; if (encoding) { return ReadUBitVarInternal(encoding); } return sixbits >> 2; } BITBUF_INLINE unsigned int bf_read::ReadUBitLong(int numbits) RESTRICT { Assert(numbits > 0 && numbits <= 32); if (GetNumBitsLeft() < numbits) { m_iCurBit = m_nDataBits; SetOverflowFlag(); CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); return 0; } unsigned int iStartBit = m_iCurBit & 31u; int iLastBit = m_iCurBit + numbits - 1; unsigned int iWordOffset1 = m_iCurBit >> 5; unsigned int iWordOffset2 = iLastBit >> 5; m_iCurBit += numbits; #if __i386__ unsigned int bitmask = (2 << (numbits - 1)) - 1; #else extern unsigned long g_ExtraMasks[33]; unsigned int bitmask = g_ExtraMasks[numbits]; #endif unsigned int dw1 = LoadLittleDWord((unsigned long* RESTRICT)m_pData, iWordOffset1) >> iStartBit; unsigned int dw2 = LoadLittleDWord((unsigned long* RESTRICT)m_pData, iWordOffset2) << (32 - iStartBit); return (dw1 | dw2) & bitmask; } BITBUF_INLINE int bf_read::CompareBits(bf_read* RESTRICT other, int numbits) RESTRICT { return (ReadUBitLong(numbits) != other->ReadUBitLong(numbits)); } #endif