mirror of
https://github.com/0TheSpy/Seaside.git
synced 2025-01-11 11:33:01 +08:00
625 lines
14 KiB
C++
625 lines
14 KiB
C++
#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
|
|
|