diff options
Diffstat (limited to 'NorthstarDLL/bitbuf.h')
-rw-r--r-- | NorthstarDLL/bitbuf.h | 2296 |
1 files changed, 1148 insertions, 1148 deletions
diff --git a/NorthstarDLL/bitbuf.h b/NorthstarDLL/bitbuf.h index 95288e29..8e8e216f 100644 --- a/NorthstarDLL/bitbuf.h +++ b/NorthstarDLL/bitbuf.h @@ -1,1148 +1,1148 @@ -#pragma once
-
-#define INLINE inline
-
-#define BITS_PER_INT 32
-
-INLINE int GetBitForBitnum(int bitNum)
-{
- static int bitsForBitnum[] = {
- (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), (1 << 8), (1 << 9), (1 << 10),
- (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15), (1 << 16), (1 << 17), (1 << 18), (1 << 19), (1 << 20), (1 << 21),
- (1 << 22), (1 << 23), (1 << 24), (1 << 25), (1 << 26), (1 << 27), (1 << 28), (1 << 29), (1 << 30), (1 << 31),
- };
-
- return bitsForBitnum[(bitNum) & (BITS_PER_INT - 1)];
-}
-
-#undef BITS_PER_INT
-
-using u8 = uint8_t;
-using u16 = uint16_t;
-using u32 = uint32_t;
-using u64 = uint64_t;
-using uptr = uintptr_t;
-
-using i8 = int8_t;
-using i16 = int16_t;
-using i32 = int32_t;
-using i64 = int64_t;
-using iptr = intptr_t;
-
-// Endianess, don't use on PPC64 nor ARM64BE
-#define LittleDWord(val) (val)
-
-static INLINE void StoreLittleDWord(u32* base, size_t dwordIndex, u32 dword)
-{
- base[dwordIndex] = LittleDWord(dword);
-}
-
-static INLINE u32 LoadLittleDWord(u32* base, size_t dwordIndex)
-{
- return LittleDWord(base[dwordIndex]);
-}
-
-#include <algorithm>
-
-static inline const u32 s_nMaskTable[33] = {
- 0,
- (1 << 1) - 1,
- (1 << 2) - 1,
- (1 << 3) - 1,
- (1 << 4) - 1,
- (1 << 5) - 1,
- (1 << 6) - 1,
- (1 << 7) - 1,
- (1 << 8) - 1,
- (1 << 9) - 1,
- (1 << 10) - 1,
- (1 << 11) - 1,
- (1 << 12) - 1,
- (1 << 13) - 1,
- (1 << 14) - 1,
- (1 << 15) - 1,
- (1 << 16) - 1,
- (1 << 17) - 1,
- (1 << 18) - 1,
- (1 << 19) - 1,
- (1 << 20) - 1,
- (1 << 21) - 1,
- (1 << 22) - 1,
- (1 << 23) - 1,
- (1 << 24) - 1,
- (1 << 25) - 1,
- (1 << 26) - 1,
- (1 << 27) - 1,
- (1 << 28) - 1,
- (1 << 29) - 1,
- (1 << 30) - 1,
- 0x7fffffff,
- 0xffffffff,
-};
-
-enum EBitCoordType
-{
- kCW_None,
- kCW_LowPrecision,
- kCW_Integral
-};
-
-class BitBufferBase
-{
- protected:
- INLINE void SetName(const char* name)
- {
- m_BufferName = name;
- }
-
- public:
- INLINE bool IsOverflowed()
- {
- return m_Overflow;
- }
- INLINE void SetOverflowed()
- {
- m_Overflow = true;
- }
-
- INLINE const char* GetName()
- {
- return m_BufferName;
- }
-
- private:
- const char* m_BufferName = "";
-
- protected:
- u8 m_Overflow = false;
-};
-
-class BFRead : public BitBufferBase
-{
- public:
- BFRead() = default;
-
- INLINE BFRead(uptr data, size_t byteLength, size_t startPos = 0, const char* bufferName = 0)
- {
- StartReading(data, byteLength, startPos);
-
- if (bufferName)
- SetName(bufferName);
- }
-
- public:
- INLINE void StartReading(uptr data, size_t byteLength, size_t startPos = 0)
- {
- m_Data = reinterpret_cast<u32 const*>(data);
- m_DataIn = m_Data;
-
- m_DataBytes = byteLength;
- m_DataBits = byteLength << 3;
-
- m_DataEnd = reinterpret_cast<u32 const*>(reinterpret_cast<u8 const*>(m_Data) + m_DataBytes);
-
- Seek(startPos);
- }
-
- INLINE void GrabNextDWord(bool overflow = false)
- {
- if (m_Data == m_DataEnd)
- {
- m_CachedBitsLeft = 1;
- m_CachedBufWord = 0;
-
- m_DataIn++;
-
- if (overflow)
- SetOverflowed();
- }
- else
- {
- if (m_DataIn > m_DataEnd)
- {
- SetOverflowed();
- m_CachedBufWord = 0;
- }
- else
- {
- m_CachedBufWord = LittleDWord(*(m_DataIn++));
- }
- }
- }
-
- INLINE void FetchNext()
- {
- m_CachedBitsLeft = 32;
- GrabNextDWord(false);
- }
-
- INLINE i32 ReadOneBit()
- {
- i32 ret = m_CachedBufWord & 1;
-
- if (--m_CachedBitsLeft == 0)
- FetchNext();
- else
- m_CachedBufWord >>= 1;
-
- return ret;
- }
-
- INLINE u32 ReadUBitLong(i32 numBits)
- {
- if (m_CachedBitsLeft >= numBits)
- {
- u32 ret = m_CachedBufWord & s_nMaskTable[numBits];
-
- m_CachedBitsLeft -= numBits;
-
- if (m_CachedBitsLeft)
- m_CachedBufWord >>= numBits;
- else
- FetchNext();
-
- return ret;
- }
- else
- {
- // need to merge words
- u32 ret = m_CachedBufWord;
- numBits -= m_CachedBitsLeft;
-
- GrabNextDWord(true);
-
- if (IsOverflowed())
- return 0;
-
- ret |= ((m_CachedBufWord & s_nMaskTable[numBits]) << m_CachedBitsLeft);
-
- m_CachedBitsLeft = 32 - numBits;
- m_CachedBufWord >>= numBits;
-
- return ret;
- }
- }
-
- INLINE i32 ReadSBitLong(int numBits)
- {
- i32 ret = ReadUBitLong(numBits);
- return (ret << (32 - numBits)) >> (32 - numBits);
- }
-
- INLINE u32 ReadUBitVar()
- {
- u32 ret = ReadUBitLong(6);
-
- switch (ret & (16 | 32))
- {
- case 16:
- ret = (ret & 15) | (ReadUBitLong(4) << 4);
- // Assert(ret >= 16);
- break;
- case 32:
- ret = (ret & 15) | (ReadUBitLong(8) << 4);
- // Assert(ret >= 256);
- break;
- case 48:
- ret = (ret & 15) | (ReadUBitLong(32 - 4) << 4);
- // Assert(ret >= 4096);
- break;
- }
-
- return ret;
- }
-
- INLINE u32 PeekUBitLong(i32 numBits)
- {
- i32 nSaveBA = m_CachedBitsLeft;
- i32 nSaveW = m_CachedBufWord;
- u32 const* pSaveP = m_DataIn;
- u32 nRet = ReadUBitLong(numBits);
-
- m_CachedBitsLeft = nSaveBA;
- m_CachedBufWord = nSaveW;
- m_DataIn = pSaveP;
-
- return nRet;
- }
-
- INLINE float ReadBitFloat()
- {
- u32 value = ReadUBitLong(32);
- return *reinterpret_cast<float*>(&value);
- }
-
- /*INLINE float ReadBitCoord() {
- i32 intval = 0, fractval = 0, signbit = 0;
- float value = 0.0;
-
- // Read the required integer and fraction flags
- intval = ReadOneBit();
- fractval = ReadOneBit();
-
- // If we got either parse them, otherwise it's a zero.
- if (intval || fractval) {
- // Read the sign bit
- signbit = ReadOneBit();
-
- // If there's an integer, read it in
- if (intval) {
- // Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
- intval = ReadUBitLong(COORD_INTEGER_BITS) + 1;
- }
-
- // If there's a fraction, read it in
- if (fractval) {
- fractval = ReadUBitLong(COORD_FRACTIONAL_BITS);
- }
-
- // Calculate the correct floating point value
- value = intval + ((float)fractval * COORD_RESOLUTION);
-
- // Fixup the sign if negative.
- if (signbit)
- value = -value;
- }
-
- return value;
- }
-
- INLINE float ReadBitCoordMP() {
- i32 intval = 0, fractval = 0, signbit = 0;
- float value = 0.0;
-
- bool inBounds = ReadOneBit() ? true : false;
-
- // Read the required integer and fraction flags
- intval = ReadOneBit();
-
- // If we got either parse them, otherwise it's a zero.
- if (intval) {
- // Read the sign bit
- signbit = ReadOneBit();
-
- // If there's an integer, read it in
- // Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
- if (inBounds)
- value = ReadUBitLong(COORD_INTEGER_BITS_MP) + 1;
- else
- value = ReadUBitLong(COORD_INTEGER_BITS) + 1;
- }
-
- // Fixup the sign if negative.
- if (signbit)
- value = -value;
-
- return value;
- }
-
- INLINE float ReadBitCellCoord(int bits, EBitCoordType coordType) {
- bool bIntegral = (coordType == kCW_Integral);
- bool bLowPrecision = (coordType == kCW_LowPrecision);
-
- int intval = 0, fractval = 0;
- float value = 0.0;
-
- if (bIntegral)
- value = ReadUBitLong(bits);
- else {
- intval = ReadUBitLong(bits);
-
- // If there's a fraction, read it in
- fractval = ReadUBitLong(bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS);
-
- // Calculate the correct floating point value
- value = intval + ((float)fractval * (bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION));
- }
-
- return value;
- }
-
- INLINE float ReadBitNormal() {
- // Read the sign bit
- i32 signbit = ReadOneBit();
-
- // Read the fractional part
- u32 fractval = ReadUBitLong(NORMAL_FRACTIONAL_BITS);
-
- // Calculate the correct floating point value
- float value = (float)fractval * NORMAL_RESOLUTION;
-
- // Fixup the sign if negative.
- if (signbit)
- value = -value;
-
- return value;
- }
-
- INLINE void ReadBitVec3Coord(Vector& fa) {
- i32 xflag, yflag, zflag;
-
- // This vector must be initialized! Otherwise, If any of the flags aren't set,
- // the corresponding component will not be read and will be stack garbage.
- fa.Init(0, 0, 0);
-
- xflag = ReadOneBit();
- yflag = ReadOneBit();
- zflag = ReadOneBit();
-
- if (xflag)
- fa[0] = ReadBitCoord();
- if (yflag)
- fa[1] = ReadBitCoord();
- if (zflag)
- fa[2] = ReadBitCoord();
- }
-
- INLINE void ReadBitVec3Normal(Vector& fa) {
- i32 xflag = ReadOneBit();
- i32 yflag = ReadOneBit();
-
- if (xflag)
- fa[0] = ReadBitNormal();
- else
- fa[0] = 0.0f;
-
- if (yflag)
- fa[1] = ReadBitNormal();
- else
- fa[1] = 0.0f;
-
- // The first two imply the third (but not its sign)
- i32 znegative = ReadOneBit();
-
- float fafafbfb = fa[0] * fa[0] + fa[1] * fa[1];
- if (fafafbfb < 1.0f)
- fa[2] = sqrt(1.0f - fafafbfb);
- else
- fa[2] = 0.0f;
-
- if (znegative)
- fa[2] = -fa[2];
- }
-
- INLINE void ReadBitAngles(QAngle& fa) {
- Vector tmp;
- ReadBitVec3Coord(tmp);
- fa.Init(tmp.x, tmp.y, tmp.z);
- }*/
-
- INLINE float ReadBitAngle(int numBits)
- {
- float shift = (float)(GetBitForBitnum(numBits));
-
- i32 i = ReadUBitLong(numBits);
- float fReturn = (float)i * (360.0 / shift);
-
- return fReturn;
- }
-
- INLINE i32 ReadChar()
- {
- return ReadSBitLong(sizeof(char) << 3);
- }
- INLINE u32 ReadByte()
- {
- return ReadUBitLong(sizeof(unsigned char) << 3);
- }
-
- INLINE i32 ReadShort()
- {
- return ReadSBitLong(sizeof(short) << 3);
- }
- INLINE u32 ReadWord()
- {
- return ReadUBitLong(sizeof(unsigned short) << 3);
- }
-
- INLINE i32 ReadLong()
- {
- return (i32)(ReadUBitLong(sizeof(i32) << 3));
- }
- INLINE float ReadFloat()
- {
- u32 temp = ReadUBitLong(sizeof(float) << 3);
- return *reinterpret_cast<float*>(&temp);
- }
-
- INLINE u32 ReadVarInt32()
- {
- constexpr int kMaxVarint32Bytes = 5;
-
- u32 result = 0;
- int count = 0;
- u32 b;
-
- do
- {
- if (count == kMaxVarint32Bytes)
- return result;
-
- b = ReadUBitLong(8);
- result |= (b & 0x7F) << (7 * count);
- ++count;
- } while (b & 0x80);
-
- return result;
- }
-
- INLINE u64 ReadVarInt64()
- {
- constexpr int kMaxVarintBytes = 10;
-
- u64 result = 0;
- int count = 0;
- u64 b;
-
- do
- {
- if (count == kMaxVarintBytes)
- return result;
-
- b = ReadUBitLong(8);
- result |= static_cast<u64>(b & 0x7F) << (7 * count);
- ++count;
- } while (b & 0x80);
-
- return result;
- }
-
- INLINE void ReadBits(uptr outData, u32 bitLength)
- {
- u8* out = reinterpret_cast<u8*>(outData);
- int bitsLeft = bitLength;
-
- // align output to dword boundary
- while (((uptr)out & 3) != 0 && bitsLeft >= 8)
- {
- *out = (unsigned char)ReadUBitLong(8);
- ++out;
- bitsLeft -= 8;
- }
-
- // read dwords
- while (bitsLeft >= 32)
- {
- *((u32*)out) = ReadUBitLong(32);
- out += sizeof(u32);
- bitsLeft -= 32;
- }
-
- // read remaining bytes
- while (bitsLeft >= 8)
- {
- *out = ReadUBitLong(8);
- ++out;
- bitsLeft -= 8;
- }
-
- // read remaining bits
- if (bitsLeft)
- *out = ReadUBitLong(bitsLeft);
- }
-
- INLINE bool ReadBytes(uptr outData, u32 byteLength)
- {
- ReadBits(outData, byteLength << 3);
- return !IsOverflowed();
- }
-
- INLINE bool ReadString(char* str, i32 maxLength, bool stopAtLineTermination = false, i32* outNumChars = 0)
- {
- bool tooSmall = false;
- int iChar = 0;
-
- while (1)
- {
- char val = ReadChar();
-
- if (val == 0)
- break;
- else if (stopAtLineTermination && val == '\n')
- break;
-
- if (iChar < (maxLength - 1))
- {
- str[iChar] = val;
- ++iChar;
- }
- else
- {
- tooSmall = true;
- }
- }
-
- // Make sure it's null-terminated.
- // Assert(iChar < maxLength);
- str[iChar] = 0;
-
- if (outNumChars)
- *outNumChars = iChar;
-
- return !IsOverflowed() && !tooSmall;
- }
-
- INLINE char* ReadAndAllocateString(bool* hasOverflowed = 0)
- {
- char str[2048];
-
- int chars = 0;
- bool overflowed = !ReadString(str, sizeof(str), false, &chars);
-
- if (hasOverflowed)
- *hasOverflowed = overflowed;
-
- // Now copy into the output and return it;
- char* ret = new char[chars + 1];
- for (u32 i = 0; i <= chars; i++)
- ret[i] = str[i];
-
- return ret;
- }
-
- INLINE i64 ReadLongLong()
- {
- i64 retval;
- u32* longs = (u32*)&retval;
-
- // Read the two DWORDs according to network endian
- const short endianIndex = 0x0100;
- u8* idx = (u8*)&endianIndex;
-
- longs[*idx++] = ReadUBitLong(sizeof(i32) << 3);
- longs[*idx] = ReadUBitLong(sizeof(i32) << 3);
-
- return retval;
- }
-
- INLINE bool Seek(size_t startPos)
- {
- bool bSucc = true;
-
- if (startPos < 0 || startPos > m_DataBits)
- {
- SetOverflowed();
- bSucc = false;
- startPos = m_DataBits;
- }
-
- // non-multiple-of-4 bytes at head of buffer. We put the "round off"
- // at the head to make reading and detecting the end efficient.
- int nHead = m_DataBytes & 3;
-
- int posBytes = startPos / 8;
- if ((m_DataBytes < 4) || (nHead && (posBytes < nHead)))
- {
- // partial first dword
- u8 const* partial = (u8 const*)m_Data;
-
- if (m_Data)
- {
- m_CachedBufWord = *(partial++);
- if (nHead > 1)
- m_CachedBufWord |= (*partial++) << 8;
- if (nHead > 2)
- m_CachedBufWord |= (*partial++) << 16;
- }
-
- m_DataIn = (u32 const*)partial;
-
- m_CachedBufWord >>= (startPos & 31);
- m_CachedBitsLeft = (nHead << 3) - (startPos & 31);
- }
- else
- {
- int adjustedPos = startPos - (nHead << 3);
-
- m_DataIn = reinterpret_cast<u32 const*>(reinterpret_cast<u8 const*>(m_Data) + ((adjustedPos / 32) << 2) + nHead);
-
- if (m_Data)
- {
- m_CachedBitsLeft = 32;
- GrabNextDWord();
- }
- else
- {
- m_CachedBufWord = 0;
- m_CachedBitsLeft = 1;
- }
-
- m_CachedBufWord >>= (adjustedPos & 31);
- m_CachedBitsLeft = std::min(m_CachedBitsLeft, u32(32 - (adjustedPos & 31))); // in case grabnextdword overflowed
- }
-
- return bSucc;
- }
-
- INLINE size_t GetNumBitsRead()
- {
- if (!m_Data)
- return 0;
-
- size_t nCurOfs = size_t(((iptr(m_DataIn) - iptr(m_Data)) / 4) - 1);
- nCurOfs *= 32;
- nCurOfs += (32 - m_CachedBitsLeft);
-
- size_t nAdjust = 8 * (m_DataBytes & 3);
- return std::min(nCurOfs + nAdjust, m_DataBits);
- }
-
- INLINE bool SeekRelative(size_t offset)
- {
- return Seek(GetNumBitsRead() + offset);
- }
-
- INLINE size_t TotalBytesAvailable()
- {
- return m_DataBytes;
- }
-
- INLINE size_t GetNumBitsLeft()
- {
- return m_DataBits - GetNumBitsRead();
- }
- INLINE size_t GetNumBytesLeft()
- {
- return GetNumBitsLeft() >> 3;
- }
-
- private:
- size_t m_DataBits; // 0x0010
- size_t m_DataBytes; // 0x0018
-
- u32 m_CachedBufWord; // 0x0020
- u32 m_CachedBitsLeft; // 0x0024
-
- const u32* m_DataIn; // 0x0028
- const u32* m_DataEnd; // 0x0030
- const u32* m_Data; // 0x0038
-};
-
-class BFWrite : public BitBufferBase
-{
- public:
- BFWrite() = default;
-
- INLINE BFWrite(uptr data, size_t byteLength, const char* bufferName = 0)
- {
- StartWriting(data, byteLength);
-
- if (bufferName)
- SetName(bufferName);
- }
-
- public:
- INLINE void StartWriting(uptr data, size_t byteLength)
- {
- m_Data = reinterpret_cast<u32*>(data);
- m_DataOut = m_Data;
-
- m_DataBytes = byteLength;
- m_DataBits = byteLength << 3;
-
- m_DataEnd = reinterpret_cast<u32*>(reinterpret_cast<u8*>(m_Data) + m_DataBytes);
- }
-
- INLINE int GetNumBitsLeft()
- {
- return m_OutBitsLeft + (32 * (m_DataEnd - m_DataOut - 1));
- }
-
- INLINE void Reset()
- {
- m_Overflow = false;
- m_OutBufWord = 0;
- m_OutBitsLeft = 32;
- m_DataOut = m_Data;
- }
-
- INLINE void TempFlush()
- {
- if (m_OutBitsLeft != 32)
- {
- if (m_DataOut == m_DataEnd)
- SetOverflowed();
- else
- StoreLittleDWord(m_DataOut, 0, LoadLittleDWord(m_DataOut, 0) & ~s_nMaskTable[32 - m_OutBitsLeft] | m_OutBufWord);
- }
-
- m_Flushed = true;
- }
-
- INLINE u8* GetBasePointer()
- {
- TempFlush();
- return reinterpret_cast<u8*>(m_Data);
- }
-
- INLINE u8* GetData()
- {
- return GetBasePointer();
- }
-
- INLINE void Finish()
- {
- if (m_OutBitsLeft != 32)
- {
- if (m_DataOut == m_DataEnd)
- SetOverflowed();
-
- StoreLittleDWord(m_DataOut, 0, m_OutBufWord);
- }
- }
-
- INLINE void FlushNoCheck()
- {
- StoreLittleDWord(m_DataOut++, 0, m_OutBufWord);
-
- m_OutBitsLeft = 32;
- m_OutBufWord = 0;
- }
-
- INLINE void Flush()
- {
- if (m_DataOut == m_DataEnd)
- SetOverflowed();
- else
- StoreLittleDWord(m_DataOut++, 0, m_OutBufWord);
-
- m_OutBitsLeft = 32;
- m_OutBufWord = 0;
- }
-
- INLINE void WriteOneBitNoCheck(i32 value)
- {
- m_OutBufWord |= (value & 1) << (32 - m_OutBitsLeft);
-
- if (--m_OutBitsLeft == 0)
- FlushNoCheck();
- }
-
- INLINE void WriteOneBit(i32 value)
- {
- m_OutBufWord |= (value & 1) << (32 - m_OutBitsLeft);
-
- if (--m_OutBitsLeft == 0)
- Flush();
- }
-
- INLINE void WriteUBitLong(u32 data, i32 numBits, bool checkRange = true)
- {
- if (numBits <= m_OutBitsLeft)
- {
- if (checkRange)
- m_OutBufWord |= (data) << (32 - m_OutBitsLeft);
- else
- m_OutBufWord |= (data & s_nMaskTable[numBits]) << (32 - m_OutBitsLeft);
-
- m_OutBitsLeft -= numBits;
-
- if (m_OutBitsLeft == 0)
- Flush();
- }
- else
- {
- // split dwords case
- i32 overflowBits = (numBits - m_OutBitsLeft);
- m_OutBufWord |= (data & s_nMaskTable[m_OutBitsLeft]) << (32 - m_OutBitsLeft);
- Flush();
- m_OutBufWord = (data >> (numBits - overflowBits));
- m_OutBitsLeft = 32 - overflowBits;
- }
- }
-
- INLINE void WriteSBitLong(i32 data, i32 numBits)
- {
- WriteUBitLong((u32)data, numBits, false);
- }
-
- INLINE void WriteUBitVar(u32 n)
- {
- if (n < 16)
- WriteUBitLong(n, 6);
- else if (n < 256)
- WriteUBitLong((n & 15) | 16 | ((n & (128 | 64 | 32 | 16)) << 2), 10);
- else if (n < 4096)
- WriteUBitLong((n & 15) | 32 | ((n & (2048 | 1024 | 512 | 256 | 128 | 64 | 32 | 16)) << 2), 14);
- else
- {
- WriteUBitLong((n & 15) | 48, 6);
- WriteUBitLong((n >> 4), 32 - 4);
- }
- }
-
- INLINE void WriteBitFloat(float value)
- {
- auto temp = &value;
- WriteUBitLong(*reinterpret_cast<u32*>(temp), 32);
- }
-
- INLINE void WriteFloat(float value)
- {
- auto temp = &value;
- WriteUBitLong(*reinterpret_cast<u32*>(temp), 32);
- }
-
- INLINE bool WriteBits(const uptr data, i32 numBits)
- {
- u8* out = (u8*)data;
- i32 numBitsLeft = numBits;
-
- // Bounds checking..
- if ((GetNumBitsWritten() + numBits) > m_DataBits)
- {
- SetOverflowed();
- return false;
- }
-
- // !! speed!! need fast paths
- // write remaining bytes
- while (numBitsLeft >= 8)
- {
- WriteUBitLong(*out, 8, false);
- ++out;
- numBitsLeft -= 8;
- }
-
- // write remaining bits
- if (numBitsLeft)
- WriteUBitLong(*out, numBitsLeft, false);
-
- return !IsOverflowed();
- }
-
- INLINE bool WriteBytes(const uptr data, i32 numBytes)
- {
- return WriteBits(data, numBytes << 3);
- }
-
- INLINE i32 GetNumBitsWritten()
- {
- return (32 - m_OutBitsLeft) + (32 * (m_DataOut - m_Data));
- }
-
- INLINE i32 GetNumBytesWritten()
- {
- return (GetNumBitsWritten() + 7) >> 3;
- }
-
- INLINE void WriteChar(i32 val)
- {
- WriteSBitLong(val, sizeof(char) << 3);
- }
-
- INLINE void WriteByte(i32 val)
- {
- WriteUBitLong(val, sizeof(unsigned char) << 3, false);
- }
-
- INLINE void WriteShort(i32 val)
- {
- WriteSBitLong(val, sizeof(short) << 3);
- }
-
- INLINE void WriteWord(i32 val)
- {
- WriteUBitLong(val, sizeof(unsigned short) << 3);
- }
-
- INLINE bool WriteString(const char* str)
- {
- if (str)
- while (*str)
- WriteChar(*(str++));
-
- WriteChar(0);
-
- return !IsOverflowed();
- }
-
- INLINE void WriteLongLong(i64 val)
- {
- u32* pLongs = (u32*)&val;
-
- // Insert the two DWORDS according to network endian
- const short endianIndex = 0x0100;
- u8* idx = (u8*)&endianIndex;
-
- WriteUBitLong(pLongs[*idx++], sizeof(i32) << 3);
- WriteUBitLong(pLongs[*idx], sizeof(i32) << 3);
- }
-
- /*INLINE void WriteBitCoord(const float f) {
- i32 signbit = (f <= -COORD_RESOLUTION);
- i32 intval = (i32)abs(f);
- i32 fractval = abs((i32)(f * COORD_DENOMINATOR)) & (COORD_DENOMINATOR - 1);
-
- // Send the bit flags that indicate whether we have an integer part and/or a fraction part.
- WriteOneBit(intval);
- WriteOneBit(fractval);
-
- if (intval || fractval) {
- // Send the sign bit
- WriteOneBit(signbit);
-
- // Send the integer if we have one.
- if (intval) {
- // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
- intval--;
- WriteUBitLong((u32)intval, COORD_INTEGER_BITS);
- }
-
- // Send the fraction if we have one
- if (fractval) {
- WriteUBitLong((u32)fractval, COORD_FRACTIONAL_BITS);
- }
- }
- }
-
- INLINE void WriteBitCoordMP(const float f) {
- i32 signbit = (f <= -COORD_RESOLUTION);
- i32 intval = (i32)abs(f);
- i32 fractval = (abs((i32)(f * COORD_DENOMINATOR)) & (COORD_DENOMINATOR - 1));
-
- bool bInBounds = intval < (1 << COORD_INTEGER_BITS_MP);
-
- WriteOneBit(bInBounds);
-
- // Send the sign bit
- WriteOneBit(intval);
-
- if (intval) {
- WriteOneBit(signbit);
-
- // Send the integer if we have one.
- // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
- intval--;
-
- if (bInBounds)
- WriteUBitLong((u32)intval, COORD_INTEGER_BITS_MP);
- else
- WriteUBitLong((u32)intval, COORD_INTEGER_BITS);
- }
- }
-
- INLINE void WriteBitCellCoord(const float f, int bits, EBitCoordType coordType) {
- bool bIntegral = (coordType == kCW_Integral);
- bool bLowPrecision = (coordType == kCW_LowPrecision);
-
- i32 intval = (i32)abs(f);
- i32 fractval = bLowPrecision ? (abs((i32)(f * COORD_DENOMINATOR_LOWPRECISION)) & (COORD_DENOMINATOR_LOWPRECISION - 1)) :
- (abs((i32)(f * COORD_DENOMINATOR)) & (COORD_DENOMINATOR - 1));
-
- if (bIntegral)
- WriteUBitLong((u32)intval, bits);
- else {
- WriteUBitLong((u32)intval, bits);
- WriteUBitLong((u32)fractval, bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS);
- }
- }*/
-
- INLINE void SeekToBit(int bit)
- {
- TempFlush();
-
- m_DataOut = m_Data + (bit / 32);
- m_OutBufWord = LoadLittleDWord(m_DataOut, 0);
- m_OutBitsLeft = 32 - (bit & 31);
- }
-
- /*INLINE void WriteBitVec3Coord(const Vector& fa) {
- i32 xflag, yflag, zflag;
-
- xflag = (fa[0] >= COORD_RESOLUTION) || (fa[0] <= -COORD_RESOLUTION);
- yflag = (fa[1] >= COORD_RESOLUTION) || (fa[1] <= -COORD_RESOLUTION);
- zflag = (fa[2] >= COORD_RESOLUTION) || (fa[2] <= -COORD_RESOLUTION);
-
- WriteOneBit(xflag);
- WriteOneBit(yflag);
- WriteOneBit(zflag);
-
- if (xflag)
- WriteBitCoord(fa[0]);
- if (yflag)
- WriteBitCoord(fa[1]);
- if (zflag)
- WriteBitCoord(fa[2]);
- }
-
- INLINE void WriteBitNormal(float f) {
- i32 signbit = (f <= -NORMAL_RESOLUTION);
-
- // NOTE: Since +/-1 are valid values for a normal, I'm going to encode that as all ones
- u32 fractval = abs((i32)(f * NORMAL_DENOMINATOR));
-
- // clamp..
- if (fractval > NORMAL_DENOMINATOR)
- fractval = NORMAL_DENOMINATOR;
-
- // Send the sign bit
- WriteOneBit(signbit);
-
- // Send the fractional component
- WriteUBitLong(fractval, NORMAL_FRACTIONAL_BITS);
- }
-
- INLINE void WriteBitVec3Normal(const Vector& fa) {
- i32 xflag, yflag;
-
- xflag = (fa[0] >= NORMAL_RESOLUTION) || (fa[0] <= -NORMAL_RESOLUTION);
- yflag = (fa[1] >= NORMAL_RESOLUTION) || (fa[1] <= -NORMAL_RESOLUTION);
-
- WriteOneBit(xflag);
- WriteOneBit(yflag);
-
- if (xflag)
- WriteBitNormal(fa[0]);
- if (yflag)
- WriteBitNormal(fa[1]);
-
- // Write z sign bit
- i32 signbit = (fa[2] <= -NORMAL_RESOLUTION);
- WriteOneBit(signbit);
- }*/
-
- INLINE void WriteBitAngle(float angle, int numBits)
- {
- u32 shift = GetBitForBitnum(numBits);
- u32 mask = shift - 1;
-
- i32 d = (i32)((angle / 360.0) * shift);
- d &= mask;
-
- WriteUBitLong((u32)d, numBits);
- }
-
- INLINE bool WriteBitsFromBuffer(BFRead* in, int numBits)
- {
- while (numBits > 32)
- {
- WriteUBitLong(in->ReadUBitLong(32), 32);
- numBits -= 32;
- }
-
- WriteUBitLong(in->ReadUBitLong(numBits), numBits);
- return !IsOverflowed() && !in->IsOverflowed();
- }
-
- /*INLINE void WriteBitAngles(const QAngle& fa) {
- // FIXME:
- Vector tmp(fa.x, fa.y, fa.z);
- WriteBitVec3Coord(tmp);
- }*/
-
- private:
- size_t m_DataBits = 0;
- size_t m_DataBytes = 0;
-
- u32 m_OutBufWord = 0;
- u32 m_OutBitsLeft = 32;
-
- u32* m_DataOut = nullptr;
- u32* m_DataEnd = nullptr;
- u32* m_Data = nullptr;
-
- bool m_Flushed = false; // :flushed:
-};
-
-#undef INLINE
+#pragma once + +#define INLINE inline + +#define BITS_PER_INT 32 + +INLINE int GetBitForBitnum(int bitNum) +{ + static int bitsForBitnum[] = { + (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), (1 << 8), (1 << 9), (1 << 10), + (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15), (1 << 16), (1 << 17), (1 << 18), (1 << 19), (1 << 20), (1 << 21), + (1 << 22), (1 << 23), (1 << 24), (1 << 25), (1 << 26), (1 << 27), (1 << 28), (1 << 29), (1 << 30), (1 << 31), + }; + + return bitsForBitnum[(bitNum) & (BITS_PER_INT - 1)]; +} + +#undef BITS_PER_INT + +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; +using u64 = uint64_t; +using uptr = uintptr_t; + +using i8 = int8_t; +using i16 = int16_t; +using i32 = int32_t; +using i64 = int64_t; +using iptr = intptr_t; + +// Endianess, don't use on PPC64 nor ARM64BE +#define LittleDWord(val) (val) + +static INLINE void StoreLittleDWord(u32* base, size_t dwordIndex, u32 dword) +{ + base[dwordIndex] = LittleDWord(dword); +} + +static INLINE u32 LoadLittleDWord(u32* base, size_t dwordIndex) +{ + return LittleDWord(base[dwordIndex]); +} + +#include <algorithm> + +static inline const u32 s_nMaskTable[33] = { + 0, + (1 << 1) - 1, + (1 << 2) - 1, + (1 << 3) - 1, + (1 << 4) - 1, + (1 << 5) - 1, + (1 << 6) - 1, + (1 << 7) - 1, + (1 << 8) - 1, + (1 << 9) - 1, + (1 << 10) - 1, + (1 << 11) - 1, + (1 << 12) - 1, + (1 << 13) - 1, + (1 << 14) - 1, + (1 << 15) - 1, + (1 << 16) - 1, + (1 << 17) - 1, + (1 << 18) - 1, + (1 << 19) - 1, + (1 << 20) - 1, + (1 << 21) - 1, + (1 << 22) - 1, + (1 << 23) - 1, + (1 << 24) - 1, + (1 << 25) - 1, + (1 << 26) - 1, + (1 << 27) - 1, + (1 << 28) - 1, + (1 << 29) - 1, + (1 << 30) - 1, + 0x7fffffff, + 0xffffffff, +}; + +enum EBitCoordType +{ + kCW_None, + kCW_LowPrecision, + kCW_Integral +}; + +class BitBufferBase +{ + protected: + INLINE void SetName(const char* name) + { + m_BufferName = name; + } + + public: + INLINE bool IsOverflowed() + { + return m_Overflow; + } + INLINE void SetOverflowed() + { + m_Overflow = true; + } + + INLINE const char* GetName() + { + return m_BufferName; + } + + private: + const char* m_BufferName = ""; + + protected: + u8 m_Overflow = false; +}; + +class BFRead : public BitBufferBase +{ + public: + BFRead() = default; + + INLINE BFRead(uptr data, size_t byteLength, size_t startPos = 0, const char* bufferName = 0) + { + StartReading(data, byteLength, startPos); + + if (bufferName) + SetName(bufferName); + } + + public: + INLINE void StartReading(uptr data, size_t byteLength, size_t startPos = 0) + { + m_Data = reinterpret_cast<u32 const*>(data); + m_DataIn = m_Data; + + m_DataBytes = byteLength; + m_DataBits = byteLength << 3; + + m_DataEnd = reinterpret_cast<u32 const*>(reinterpret_cast<u8 const*>(m_Data) + m_DataBytes); + + Seek(startPos); + } + + INLINE void GrabNextDWord(bool overflow = false) + { + if (m_Data == m_DataEnd) + { + m_CachedBitsLeft = 1; + m_CachedBufWord = 0; + + m_DataIn++; + + if (overflow) + SetOverflowed(); + } + else + { + if (m_DataIn > m_DataEnd) + { + SetOverflowed(); + m_CachedBufWord = 0; + } + else + { + m_CachedBufWord = LittleDWord(*(m_DataIn++)); + } + } + } + + INLINE void FetchNext() + { + m_CachedBitsLeft = 32; + GrabNextDWord(false); + } + + INLINE i32 ReadOneBit() + { + i32 ret = m_CachedBufWord & 1; + + if (--m_CachedBitsLeft == 0) + FetchNext(); + else + m_CachedBufWord >>= 1; + + return ret; + } + + INLINE u32 ReadUBitLong(i32 numBits) + { + if (m_CachedBitsLeft >= numBits) + { + u32 ret = m_CachedBufWord & s_nMaskTable[numBits]; + + m_CachedBitsLeft -= numBits; + + if (m_CachedBitsLeft) + m_CachedBufWord >>= numBits; + else + FetchNext(); + + return ret; + } + else + { + // need to merge words + u32 ret = m_CachedBufWord; + numBits -= m_CachedBitsLeft; + + GrabNextDWord(true); + + if (IsOverflowed()) + return 0; + + ret |= ((m_CachedBufWord & s_nMaskTable[numBits]) << m_CachedBitsLeft); + + m_CachedBitsLeft = 32 - numBits; + m_CachedBufWord >>= numBits; + + return ret; + } + } + + INLINE i32 ReadSBitLong(int numBits) + { + i32 ret = ReadUBitLong(numBits); + return (ret << (32 - numBits)) >> (32 - numBits); + } + + INLINE u32 ReadUBitVar() + { + u32 ret = ReadUBitLong(6); + + switch (ret & (16 | 32)) + { + case 16: + ret = (ret & 15) | (ReadUBitLong(4) << 4); + // Assert(ret >= 16); + break; + case 32: + ret = (ret & 15) | (ReadUBitLong(8) << 4); + // Assert(ret >= 256); + break; + case 48: + ret = (ret & 15) | (ReadUBitLong(32 - 4) << 4); + // Assert(ret >= 4096); + break; + } + + return ret; + } + + INLINE u32 PeekUBitLong(i32 numBits) + { + i32 nSaveBA = m_CachedBitsLeft; + i32 nSaveW = m_CachedBufWord; + u32 const* pSaveP = m_DataIn; + u32 nRet = ReadUBitLong(numBits); + + m_CachedBitsLeft = nSaveBA; + m_CachedBufWord = nSaveW; + m_DataIn = pSaveP; + + return nRet; + } + + INLINE float ReadBitFloat() + { + u32 value = ReadUBitLong(32); + return *reinterpret_cast<float*>(&value); + } + + /*INLINE float ReadBitCoord() { + i32 intval = 0, fractval = 0, signbit = 0; + float value = 0.0; + + // Read the required integer and fraction flags + intval = ReadOneBit(); + fractval = ReadOneBit(); + + // If we got either parse them, otherwise it's a zero. + if (intval || fractval) { + // Read the sign bit + signbit = ReadOneBit(); + + // If there's an integer, read it in + if (intval) { + // Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE] + intval = ReadUBitLong(COORD_INTEGER_BITS) + 1; + } + + // If there's a fraction, read it in + if (fractval) { + fractval = ReadUBitLong(COORD_FRACTIONAL_BITS); + } + + // Calculate the correct floating point value + value = intval + ((float)fractval * COORD_RESOLUTION); + + // Fixup the sign if negative. + if (signbit) + value = -value; + } + + return value; + } + + INLINE float ReadBitCoordMP() { + i32 intval = 0, fractval = 0, signbit = 0; + float value = 0.0; + + bool inBounds = ReadOneBit() ? true : false; + + // Read the required integer and fraction flags + intval = ReadOneBit(); + + // If we got either parse them, otherwise it's a zero. + if (intval) { + // Read the sign bit + signbit = ReadOneBit(); + + // If there's an integer, read it in + // Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE] + if (inBounds) + value = ReadUBitLong(COORD_INTEGER_BITS_MP) + 1; + else + value = ReadUBitLong(COORD_INTEGER_BITS) + 1; + } + + // Fixup the sign if negative. + if (signbit) + value = -value; + + return value; + } + + INLINE float ReadBitCellCoord(int bits, EBitCoordType coordType) { + bool bIntegral = (coordType == kCW_Integral); + bool bLowPrecision = (coordType == kCW_LowPrecision); + + int intval = 0, fractval = 0; + float value = 0.0; + + if (bIntegral) + value = ReadUBitLong(bits); + else { + intval = ReadUBitLong(bits); + + // If there's a fraction, read it in + fractval = ReadUBitLong(bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS); + + // Calculate the correct floating point value + value = intval + ((float)fractval * (bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION)); + } + + return value; + } + + INLINE float ReadBitNormal() { + // Read the sign bit + i32 signbit = ReadOneBit(); + + // Read the fractional part + u32 fractval = ReadUBitLong(NORMAL_FRACTIONAL_BITS); + + // Calculate the correct floating point value + float value = (float)fractval * NORMAL_RESOLUTION; + + // Fixup the sign if negative. + if (signbit) + value = -value; + + return value; + } + + INLINE void ReadBitVec3Coord(Vector& fa) { + i32 xflag, yflag, zflag; + + // This vector must be initialized! Otherwise, If any of the flags aren't set, + // the corresponding component will not be read and will be stack garbage. + fa.Init(0, 0, 0); + + xflag = ReadOneBit(); + yflag = ReadOneBit(); + zflag = ReadOneBit(); + + if (xflag) + fa[0] = ReadBitCoord(); + if (yflag) + fa[1] = ReadBitCoord(); + if (zflag) + fa[2] = ReadBitCoord(); + } + + INLINE void ReadBitVec3Normal(Vector& fa) { + i32 xflag = ReadOneBit(); + i32 yflag = ReadOneBit(); + + if (xflag) + fa[0] = ReadBitNormal(); + else + fa[0] = 0.0f; + + if (yflag) + fa[1] = ReadBitNormal(); + else + fa[1] = 0.0f; + + // The first two imply the third (but not its sign) + i32 znegative = ReadOneBit(); + + float fafafbfb = fa[0] * fa[0] + fa[1] * fa[1]; + if (fafafbfb < 1.0f) + fa[2] = sqrt(1.0f - fafafbfb); + else + fa[2] = 0.0f; + + if (znegative) + fa[2] = -fa[2]; + } + + INLINE void ReadBitAngles(QAngle& fa) { + Vector tmp; + ReadBitVec3Coord(tmp); + fa.Init(tmp.x, tmp.y, tmp.z); + }*/ + + INLINE float ReadBitAngle(int numBits) + { + float shift = (float)(GetBitForBitnum(numBits)); + + i32 i = ReadUBitLong(numBits); + float fReturn = (float)i * (360.0 / shift); + + return fReturn; + } + + INLINE i32 ReadChar() + { + return ReadSBitLong(sizeof(char) << 3); + } + INLINE u32 ReadByte() + { + return ReadUBitLong(sizeof(unsigned char) << 3); + } + + INLINE i32 ReadShort() + { + return ReadSBitLong(sizeof(short) << 3); + } + INLINE u32 ReadWord() + { + return ReadUBitLong(sizeof(unsigned short) << 3); + } + + INLINE i32 ReadLong() + { + return (i32)(ReadUBitLong(sizeof(i32) << 3)); + } + INLINE float ReadFloat() + { + u32 temp = ReadUBitLong(sizeof(float) << 3); + return *reinterpret_cast<float*>(&temp); + } + + INLINE u32 ReadVarInt32() + { + constexpr int kMaxVarint32Bytes = 5; + + u32 result = 0; + int count = 0; + u32 b; + + do + { + if (count == kMaxVarint32Bytes) + return result; + + b = ReadUBitLong(8); + result |= (b & 0x7F) << (7 * count); + ++count; + } while (b & 0x80); + + return result; + } + + INLINE u64 ReadVarInt64() + { + constexpr int kMaxVarintBytes = 10; + + u64 result = 0; + int count = 0; + u64 b; + + do + { + if (count == kMaxVarintBytes) + return result; + + b = ReadUBitLong(8); + result |= static_cast<u64>(b & 0x7F) << (7 * count); + ++count; + } while (b & 0x80); + + return result; + } + + INLINE void ReadBits(uptr outData, u32 bitLength) + { + u8* out = reinterpret_cast<u8*>(outData); + int bitsLeft = bitLength; + + // align output to dword boundary + while (((uptr)out & 3) != 0 && bitsLeft >= 8) + { + *out = (unsigned char)ReadUBitLong(8); + ++out; + bitsLeft -= 8; + } + + // read dwords + while (bitsLeft >= 32) + { + *((u32*)out) = ReadUBitLong(32); + out += sizeof(u32); + bitsLeft -= 32; + } + + // read remaining bytes + while (bitsLeft >= 8) + { + *out = ReadUBitLong(8); + ++out; + bitsLeft -= 8; + } + + // read remaining bits + if (bitsLeft) + *out = ReadUBitLong(bitsLeft); + } + + INLINE bool ReadBytes(uptr outData, u32 byteLength) + { + ReadBits(outData, byteLength << 3); + return !IsOverflowed(); + } + + INLINE bool ReadString(char* str, i32 maxLength, bool stopAtLineTermination = false, i32* outNumChars = 0) + { + bool tooSmall = false; + int iChar = 0; + + while (1) + { + char val = ReadChar(); + + if (val == 0) + break; + else if (stopAtLineTermination && val == '\n') + break; + + if (iChar < (maxLength - 1)) + { + str[iChar] = val; + ++iChar; + } + else + { + tooSmall = true; + } + } + + // Make sure it's null-terminated. + // Assert(iChar < maxLength); + str[iChar] = 0; + + if (outNumChars) + *outNumChars = iChar; + + return !IsOverflowed() && !tooSmall; + } + + INLINE char* ReadAndAllocateString(bool* hasOverflowed = 0) + { + char str[2048]; + + int chars = 0; + bool overflowed = !ReadString(str, sizeof(str), false, &chars); + + if (hasOverflowed) + *hasOverflowed = overflowed; + + // Now copy into the output and return it; + char* ret = new char[chars + 1]; + for (u32 i = 0; i <= chars; i++) + ret[i] = str[i]; + + return ret; + } + + INLINE i64 ReadLongLong() + { + i64 retval; + u32* longs = (u32*)&retval; + + // Read the two DWORDs according to network endian + const short endianIndex = 0x0100; + u8* idx = (u8*)&endianIndex; + + longs[*idx++] = ReadUBitLong(sizeof(i32) << 3); + longs[*idx] = ReadUBitLong(sizeof(i32) << 3); + + return retval; + } + + INLINE bool Seek(size_t startPos) + { + bool bSucc = true; + + if (startPos < 0 || startPos > m_DataBits) + { + SetOverflowed(); + bSucc = false; + startPos = m_DataBits; + } + + // non-multiple-of-4 bytes at head of buffer. We put the "round off" + // at the head to make reading and detecting the end efficient. + int nHead = m_DataBytes & 3; + + int posBytes = startPos / 8; + if ((m_DataBytes < 4) || (nHead && (posBytes < nHead))) + { + // partial first dword + u8 const* partial = (u8 const*)m_Data; + + if (m_Data) + { + m_CachedBufWord = *(partial++); + if (nHead > 1) + m_CachedBufWord |= (*partial++) << 8; + if (nHead > 2) + m_CachedBufWord |= (*partial++) << 16; + } + + m_DataIn = (u32 const*)partial; + + m_CachedBufWord >>= (startPos & 31); + m_CachedBitsLeft = (nHead << 3) - (startPos & 31); + } + else + { + int adjustedPos = startPos - (nHead << 3); + + m_DataIn = reinterpret_cast<u32 const*>(reinterpret_cast<u8 const*>(m_Data) + ((adjustedPos / 32) << 2) + nHead); + + if (m_Data) + { + m_CachedBitsLeft = 32; + GrabNextDWord(); + } + else + { + m_CachedBufWord = 0; + m_CachedBitsLeft = 1; + } + + m_CachedBufWord >>= (adjustedPos & 31); + m_CachedBitsLeft = std::min(m_CachedBitsLeft, u32(32 - (adjustedPos & 31))); // in case grabnextdword overflowed + } + + return bSucc; + } + + INLINE size_t GetNumBitsRead() + { + if (!m_Data) + return 0; + + size_t nCurOfs = size_t(((iptr(m_DataIn) - iptr(m_Data)) / 4) - 1); + nCurOfs *= 32; + nCurOfs += (32 - m_CachedBitsLeft); + + size_t nAdjust = 8 * (m_DataBytes & 3); + return std::min(nCurOfs + nAdjust, m_DataBits); + } + + INLINE bool SeekRelative(size_t offset) + { + return Seek(GetNumBitsRead() + offset); + } + + INLINE size_t TotalBytesAvailable() + { + return m_DataBytes; + } + + INLINE size_t GetNumBitsLeft() + { + return m_DataBits - GetNumBitsRead(); + } + INLINE size_t GetNumBytesLeft() + { + return GetNumBitsLeft() >> 3; + } + + private: + size_t m_DataBits; // 0x0010 + size_t m_DataBytes; // 0x0018 + + u32 m_CachedBufWord; // 0x0020 + u32 m_CachedBitsLeft; // 0x0024 + + const u32* m_DataIn; // 0x0028 + const u32* m_DataEnd; // 0x0030 + const u32* m_Data; // 0x0038 +}; + +class BFWrite : public BitBufferBase +{ + public: + BFWrite() = default; + + INLINE BFWrite(uptr data, size_t byteLength, const char* bufferName = 0) + { + StartWriting(data, byteLength); + + if (bufferName) + SetName(bufferName); + } + + public: + INLINE void StartWriting(uptr data, size_t byteLength) + { + m_Data = reinterpret_cast<u32*>(data); + m_DataOut = m_Data; + + m_DataBytes = byteLength; + m_DataBits = byteLength << 3; + + m_DataEnd = reinterpret_cast<u32*>(reinterpret_cast<u8*>(m_Data) + m_DataBytes); + } + + INLINE int GetNumBitsLeft() + { + return m_OutBitsLeft + (32 * (m_DataEnd - m_DataOut - 1)); + } + + INLINE void Reset() + { + m_Overflow = false; + m_OutBufWord = 0; + m_OutBitsLeft = 32; + m_DataOut = m_Data; + } + + INLINE void TempFlush() + { + if (m_OutBitsLeft != 32) + { + if (m_DataOut == m_DataEnd) + SetOverflowed(); + else + StoreLittleDWord(m_DataOut, 0, LoadLittleDWord(m_DataOut, 0) & ~s_nMaskTable[32 - m_OutBitsLeft] | m_OutBufWord); + } + + m_Flushed = true; + } + + INLINE u8* GetBasePointer() + { + TempFlush(); + return reinterpret_cast<u8*>(m_Data); + } + + INLINE u8* GetData() + { + return GetBasePointer(); + } + + INLINE void Finish() + { + if (m_OutBitsLeft != 32) + { + if (m_DataOut == m_DataEnd) + SetOverflowed(); + + StoreLittleDWord(m_DataOut, 0, m_OutBufWord); + } + } + + INLINE void FlushNoCheck() + { + StoreLittleDWord(m_DataOut++, 0, m_OutBufWord); + + m_OutBitsLeft = 32; + m_OutBufWord = 0; + } + + INLINE void Flush() + { + if (m_DataOut == m_DataEnd) + SetOverflowed(); + else + StoreLittleDWord(m_DataOut++, 0, m_OutBufWord); + + m_OutBitsLeft = 32; + m_OutBufWord = 0; + } + + INLINE void WriteOneBitNoCheck(i32 value) + { + m_OutBufWord |= (value & 1) << (32 - m_OutBitsLeft); + + if (--m_OutBitsLeft == 0) + FlushNoCheck(); + } + + INLINE void WriteOneBit(i32 value) + { + m_OutBufWord |= (value & 1) << (32 - m_OutBitsLeft); + + if (--m_OutBitsLeft == 0) + Flush(); + } + + INLINE void WriteUBitLong(u32 data, i32 numBits, bool checkRange = true) + { + if (numBits <= m_OutBitsLeft) + { + if (checkRange) + m_OutBufWord |= (data) << (32 - m_OutBitsLeft); + else + m_OutBufWord |= (data & s_nMaskTable[numBits]) << (32 - m_OutBitsLeft); + + m_OutBitsLeft -= numBits; + + if (m_OutBitsLeft == 0) + Flush(); + } + else + { + // split dwords case + i32 overflowBits = (numBits - m_OutBitsLeft); + m_OutBufWord |= (data & s_nMaskTable[m_OutBitsLeft]) << (32 - m_OutBitsLeft); + Flush(); + m_OutBufWord = (data >> (numBits - overflowBits)); + m_OutBitsLeft = 32 - overflowBits; + } + } + + INLINE void WriteSBitLong(i32 data, i32 numBits) + { + WriteUBitLong((u32)data, numBits, false); + } + + INLINE void WriteUBitVar(u32 n) + { + if (n < 16) + WriteUBitLong(n, 6); + else if (n < 256) + WriteUBitLong((n & 15) | 16 | ((n & (128 | 64 | 32 | 16)) << 2), 10); + else if (n < 4096) + WriteUBitLong((n & 15) | 32 | ((n & (2048 | 1024 | 512 | 256 | 128 | 64 | 32 | 16)) << 2), 14); + else + { + WriteUBitLong((n & 15) | 48, 6); + WriteUBitLong((n >> 4), 32 - 4); + } + } + + INLINE void WriteBitFloat(float value) + { + auto temp = &value; + WriteUBitLong(*reinterpret_cast<u32*>(temp), 32); + } + + INLINE void WriteFloat(float value) + { + auto temp = &value; + WriteUBitLong(*reinterpret_cast<u32*>(temp), 32); + } + + INLINE bool WriteBits(const uptr data, i32 numBits) + { + u8* out = (u8*)data; + i32 numBitsLeft = numBits; + + // Bounds checking.. + if ((GetNumBitsWritten() + numBits) > m_DataBits) + { + SetOverflowed(); + return false; + } + + // !! speed!! need fast paths + // write remaining bytes + while (numBitsLeft >= 8) + { + WriteUBitLong(*out, 8, false); + ++out; + numBitsLeft -= 8; + } + + // write remaining bits + if (numBitsLeft) + WriteUBitLong(*out, numBitsLeft, false); + + return !IsOverflowed(); + } + + INLINE bool WriteBytes(const uptr data, i32 numBytes) + { + return WriteBits(data, numBytes << 3); + } + + INLINE i32 GetNumBitsWritten() + { + return (32 - m_OutBitsLeft) + (32 * (m_DataOut - m_Data)); + } + + INLINE i32 GetNumBytesWritten() + { + return (GetNumBitsWritten() + 7) >> 3; + } + + INLINE void WriteChar(i32 val) + { + WriteSBitLong(val, sizeof(char) << 3); + } + + INLINE void WriteByte(i32 val) + { + WriteUBitLong(val, sizeof(unsigned char) << 3, false); + } + + INLINE void WriteShort(i32 val) + { + WriteSBitLong(val, sizeof(short) << 3); + } + + INLINE void WriteWord(i32 val) + { + WriteUBitLong(val, sizeof(unsigned short) << 3); + } + + INLINE bool WriteString(const char* str) + { + if (str) + while (*str) + WriteChar(*(str++)); + + WriteChar(0); + + return !IsOverflowed(); + } + + INLINE void WriteLongLong(i64 val) + { + u32* pLongs = (u32*)&val; + + // Insert the two DWORDS according to network endian + const short endianIndex = 0x0100; + u8* idx = (u8*)&endianIndex; + + WriteUBitLong(pLongs[*idx++], sizeof(i32) << 3); + WriteUBitLong(pLongs[*idx], sizeof(i32) << 3); + } + + /*INLINE void WriteBitCoord(const float f) { + i32 signbit = (f <= -COORD_RESOLUTION); + i32 intval = (i32)abs(f); + i32 fractval = abs((i32)(f * COORD_DENOMINATOR)) & (COORD_DENOMINATOR - 1); + + // Send the bit flags that indicate whether we have an integer part and/or a fraction part. + WriteOneBit(intval); + WriteOneBit(fractval); + + if (intval || fractval) { + // Send the sign bit + WriteOneBit(signbit); + + // Send the integer if we have one. + if (intval) { + // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1] + intval--; + WriteUBitLong((u32)intval, COORD_INTEGER_BITS); + } + + // Send the fraction if we have one + if (fractval) { + WriteUBitLong((u32)fractval, COORD_FRACTIONAL_BITS); + } + } + } + + INLINE void WriteBitCoordMP(const float f) { + i32 signbit = (f <= -COORD_RESOLUTION); + i32 intval = (i32)abs(f); + i32 fractval = (abs((i32)(f * COORD_DENOMINATOR)) & (COORD_DENOMINATOR - 1)); + + bool bInBounds = intval < (1 << COORD_INTEGER_BITS_MP); + + WriteOneBit(bInBounds); + + // Send the sign bit + WriteOneBit(intval); + + if (intval) { + WriteOneBit(signbit); + + // Send the integer if we have one. + // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1] + intval--; + + if (bInBounds) + WriteUBitLong((u32)intval, COORD_INTEGER_BITS_MP); + else + WriteUBitLong((u32)intval, COORD_INTEGER_BITS); + } + } + + INLINE void WriteBitCellCoord(const float f, int bits, EBitCoordType coordType) { + bool bIntegral = (coordType == kCW_Integral); + bool bLowPrecision = (coordType == kCW_LowPrecision); + + i32 intval = (i32)abs(f); + i32 fractval = bLowPrecision ? (abs((i32)(f * COORD_DENOMINATOR_LOWPRECISION)) & (COORD_DENOMINATOR_LOWPRECISION - 1)) : + (abs((i32)(f * COORD_DENOMINATOR)) & (COORD_DENOMINATOR - 1)); + + if (bIntegral) + WriteUBitLong((u32)intval, bits); + else { + WriteUBitLong((u32)intval, bits); + WriteUBitLong((u32)fractval, bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS); + } + }*/ + + INLINE void SeekToBit(int bit) + { + TempFlush(); + + m_DataOut = m_Data + (bit / 32); + m_OutBufWord = LoadLittleDWord(m_DataOut, 0); + m_OutBitsLeft = 32 - (bit & 31); + } + + /*INLINE void WriteBitVec3Coord(const Vector& fa) { + i32 xflag, yflag, zflag; + + xflag = (fa[0] >= COORD_RESOLUTION) || (fa[0] <= -COORD_RESOLUTION); + yflag = (fa[1] >= COORD_RESOLUTION) || (fa[1] <= -COORD_RESOLUTION); + zflag = (fa[2] >= COORD_RESOLUTION) || (fa[2] <= -COORD_RESOLUTION); + + WriteOneBit(xflag); + WriteOneBit(yflag); + WriteOneBit(zflag); + + if (xflag) + WriteBitCoord(fa[0]); + if (yflag) + WriteBitCoord(fa[1]); + if (zflag) + WriteBitCoord(fa[2]); + } + + INLINE void WriteBitNormal(float f) { + i32 signbit = (f <= -NORMAL_RESOLUTION); + + // NOTE: Since +/-1 are valid values for a normal, I'm going to encode that as all ones + u32 fractval = abs((i32)(f * NORMAL_DENOMINATOR)); + + // clamp.. + if (fractval > NORMAL_DENOMINATOR) + fractval = NORMAL_DENOMINATOR; + + // Send the sign bit + WriteOneBit(signbit); + + // Send the fractional component + WriteUBitLong(fractval, NORMAL_FRACTIONAL_BITS); + } + + INLINE void WriteBitVec3Normal(const Vector& fa) { + i32 xflag, yflag; + + xflag = (fa[0] >= NORMAL_RESOLUTION) || (fa[0] <= -NORMAL_RESOLUTION); + yflag = (fa[1] >= NORMAL_RESOLUTION) || (fa[1] <= -NORMAL_RESOLUTION); + + WriteOneBit(xflag); + WriteOneBit(yflag); + + if (xflag) + WriteBitNormal(fa[0]); + if (yflag) + WriteBitNormal(fa[1]); + + // Write z sign bit + i32 signbit = (fa[2] <= -NORMAL_RESOLUTION); + WriteOneBit(signbit); + }*/ + + INLINE void WriteBitAngle(float angle, int numBits) + { + u32 shift = GetBitForBitnum(numBits); + u32 mask = shift - 1; + + i32 d = (i32)((angle / 360.0) * shift); + d &= mask; + + WriteUBitLong((u32)d, numBits); + } + + INLINE bool WriteBitsFromBuffer(BFRead* in, int numBits) + { + while (numBits > 32) + { + WriteUBitLong(in->ReadUBitLong(32), 32); + numBits -= 32; + } + + WriteUBitLong(in->ReadUBitLong(numBits), numBits); + return !IsOverflowed() && !in->IsOverflowed(); + } + + /*INLINE void WriteBitAngles(const QAngle& fa) { + // FIXME: + Vector tmp(fa.x, fa.y, fa.z); + WriteBitVec3Coord(tmp); + }*/ + + private: + size_t m_DataBits = 0; + size_t m_DataBytes = 0; + + u32 m_OutBufWord = 0; + u32 m_OutBitsLeft = 32; + + u32* m_DataOut = nullptr; + u32* m_DataEnd = nullptr; + u32* m_Data = nullptr; + + bool m_Flushed = false; // :flushed: +}; + +#undef INLINE |