Seaside/SpyCustom/sdk/bitbuf.h

625 lines
14 KiB
C
Raw Normal View History

2021-06-16 18:45:17 +03:00
#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<int32>(n & 1);
}
inline uint64 ZigZagEncode64(int64 n)
{
return(n << 1) ^ (n >> 63);
}
inline int64 ZigZagDecode64(uint64 n)
{
return(n >> 1) ^ -static_cast<int64>(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<int SIZE>
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 <typename T, size_t N>
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