diff options
Diffstat (limited to 'mp/src/public/tier1/bitbuf.h')
| -rw-r--r-- | mp/src/public/tier1/bitbuf.h | 809 |
1 files changed, 809 insertions, 0 deletions
diff --git a/mp/src/public/tier1/bitbuf.h b/mp/src/public/tier1/bitbuf.h new file mode 100644 index 00000000..b47d80d5 --- /dev/null +++ b/mp/src/public/tier1/bitbuf.h @@ -0,0 +1,809 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// NOTE: bf_read is guaranteed to return zeros if it overflows.
+
+#ifndef BITBUF_H
+#define BITBUF_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "mathlib/mathlib.h"
+#include "mathlib/vector.h"
+#include "basetypes.h"
+#include "tier0/dbg.h"
+
+
+#if _DEBUG
+#define BITBUF_INLINE inline
+#else
+#define BITBUF_INLINE FORCEINLINE
+#endif
+
+//-----------------------------------------------------------------------------
+// Forward declarations.
+//-----------------------------------------------------------------------------
+
+class Vector;
+class QAngle;
+
+//-----------------------------------------------------------------------------
+// You can define a handler function that will be called in case of
+// out-of-range values and overruns here.
+//
+// NOTE: the handler is only called in debug mode.
+//
+// Call SetBitBufErrorHandler to install a handler.
+//-----------------------------------------------------------------------------
+
+typedef enum
+{
+ BITBUFERROR_VALUE_OUT_OF_RANGE=0, // Tried to write a value with too few bits.
+ BITBUFERROR_BUFFER_OVERRUN, // Was about to overrun a buffer.
+
+ 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
+
+
+// Use this to install the error handler. Call with NULL to uninstall your error handler.
+void SetBitBufErrorHandler( BitBufErrorHandler fn );
+
+
+//-----------------------------------------------------------------------------
+// Helpers.
+//-----------------------------------------------------------------------------
+
+inline int BitByte( int bits )
+{
+ // return PAD_NUMBER( bits, 8 ) >> 3;
+ return (bits + 7) >> 3;
+}
+
+//-----------------------------------------------------------------------------
+// namespaced helpers
+//-----------------------------------------------------------------------------
+namespace bitbuf
+{
+ // ZigZag Transform: Encodes signed integers so that they can be
+ // effectively used with varint encoding.
+ //
+ // varint operates on unsigned integers, encoding smaller numbers into
+ // fewer bytes. If you try to use it on a signed integer, it will treat
+ // this number as a very large unsigned integer, which means that even
+ // small signed numbers like -1 will take the maximum number of bytes
+ // (10) to encode. ZigZagEncode() maps signed integers to unsigned
+ // in such a way that those with a small absolute value will have smaller
+ // encoded values, making them appropriate for encoding using varint.
+ //
+ // int32 -> uint32
+ // -------------------------
+ // 0 -> 0
+ // -1 -> 1
+ // 1 -> 2
+ // -2 -> 3
+ // ... -> ...
+ // 2147483647 -> 4294967294
+ // -2147483648 -> 4294967295
+ //
+ // >> encode >>
+ // << decode <<
+
+ inline uint32 ZigZagEncode32(int32 n)
+ {
+ // Note: the right-shift must be arithmetic
+ return(n << 1) ^ (n >> 31);
+ }
+
+ inline int32 ZigZagDecode32(uint32 n)
+ {
+ return(n >> 1) ^ -static_cast<int32>(n & 1);
+ }
+
+ inline uint64 ZigZagEncode64(int64 n)
+ {
+ // Note: the right-shift must be arithmetic
+ 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;
+}
+
+//-----------------------------------------------------------------------------
+// Used for serialization
+//-----------------------------------------------------------------------------
+
+class bf_write
+{
+public:
+ bf_write();
+
+ // nMaxBits can be used as the number of bits in the buffer.
+ // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8.
+ bf_write( void *pData, int nBytes, int nMaxBits = -1 );
+ bf_write( const char *pDebugName, void *pData, int nBytes, int nMaxBits = -1 );
+
+ // Start writing to the specified buffer.
+ // nMaxBits can be used as the number of bits in the buffer.
+ // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8.
+ void StartWriting( void *pData, int nBytes, int iStartBit = 0, int nMaxBits = -1 );
+
+ // Restart buffer writing.
+ void Reset();
+
+ // Get the base pointer.
+ unsigned char* GetBasePointer() { return (unsigned char*) m_pData; }
+
+ // Enable or disable assertion on overflow. 99% of the time, it's a bug that we need to catch,
+ // but there may be the occasional buffer that is allowed to overflow gracefully.
+ void SetAssertOnOverflow( bool bAssert );
+
+ // This can be set to assign a name that gets output if the buffer overflows.
+ const char* GetDebugName();
+ void SetDebugName( const char *pDebugName );
+
+
+// Seek to a specific position.
+public:
+
+ void SeekToBit( int bitPos );
+
+
+// Bit functions.
+public:
+
+ void WriteOneBit(int nValue);
+ void WriteOneBitNoCheck(int nValue);
+ void WriteOneBitAt( int iBit, int nValue );
+
+ // Write signed or unsigned. Range is only checked in debug.
+ void WriteUBitLong( unsigned int data, int numbits, bool bCheckRange=true );
+ void WriteSBitLong( int data, int numbits );
+
+ // Tell it whether or not the data is unsigned. If it's signed,
+ // cast to unsigned before passing in (it will cast back inside).
+ void WriteBitLong(unsigned int data, int numbits, bool bSigned);
+
+ // Write a list of bits in.
+ bool WriteBits(const void *pIn, int nBits);
+
+ // writes an unsigned integer with variable bit length
+ void WriteUBitVar( unsigned int data );
+
+ // writes a varint encoded integer
+ 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 );
+
+ // Copy the bits straight out of pIn. This seeks pIn forward by nBits.
+ // Returns an error if this buffer or the read buffer overflows.
+ 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 );
+
+
+// Byte functions.
+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 );
+
+ // Returns false if it overflows the buffer.
+ bool WriteString(const char *pStr);
+
+
+// Status.
+public:
+
+ // How many bytes are filled in?
+ int GetNumBytesWritten() const;
+ int GetNumBitsWritten() const;
+ int GetMaxNumBits();
+ int GetNumBitsLeft();
+ int GetNumBytesLeft();
+ unsigned char* GetData();
+ const unsigned char* GetData() const;
+
+ // Has the buffer overflowed?
+ bool CheckForOverflow(int nBits);
+ inline bool IsOverflowed() const {return m_bOverflow;}
+
+ void SetOverflowFlag();
+
+
+public:
+ // The current buffer.
+ unsigned long* RESTRICT m_pData;
+ int m_nDataBytes;
+ int m_nDataBits;
+
+ // Where we are in the buffer.
+ int m_iCurBit;
+
+private:
+
+ // Errors?
+ bool m_bOverflow;
+
+ bool m_bAssertOnOverflow;
+ const char *m_pDebugName;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inlined methods
+//-----------------------------------------------------------------------------
+
+// How many bytes are filled in?
+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
+ // Make sure it doesn't overflow.
+ 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;
+
+ // Mask in a dword.
+ Assert( (iDWord*4 + sizeof(long)) <= (unsigned int)m_nDataBytes );
+ unsigned long * RESTRICT pOut = &m_pData[iDWord];
+
+ // Rotate data into dword alignment
+ curData = (curData << iCurBitMasked) | (curData >> (32 - iCurBitMasked));
+
+ // Calculate bitmasks for first and second word
+ unsigned int temp = 1 << (numbits-1);
+ unsigned int mask1 = (temp*2-1) << iCurBitMasked;
+ unsigned int mask2 = (temp-1) >> (31 - iCurBitMasked);
+
+ // Only look beyond current word if necessary (avoid access violation)
+ int i = mask2 & 1;
+ unsigned long dword1 = LoadLittleDWord( pOut, 0 );
+ unsigned long dword2 = LoadLittleDWord( pOut, i );
+
+ // Drop bits into place
+ dword1 ^= ( mask1 & ( curData ^ dword1 ) );
+ dword2 ^= ( mask2 & ( curData ^ dword2 ) );
+
+ // Note reversed order of writes so that dword1 wins if mask2 == 0 && i == 0
+ StoreLittleDWord( pOut, i, dword2 );
+ StoreLittleDWord( pOut, 0, dword1 );
+}
+
+// writes an unsigned integer with variable bit length
+BITBUF_INLINE void bf_write::WriteUBitVar( unsigned int data )
+{
+ /* Reference:
+ if ( data < 0x10u )
+ WriteUBitLong( 0, 2 ), WriteUBitLong( data, 4 );
+ else if ( data < 0x100u )
+ WriteUBitLong( 1, 2 ), WriteUBitLong( data, 8 );
+ else if ( data < 0x1000u )
+ WriteUBitLong( 2, 2 ), WriteUBitLong( data, 12 );
+ else
+ WriteUBitLong( 3, 2 ), WriteUBitLong( data, 32 );
+ */
+ // a < b ? -1 : 0 translates into a CMP, SBB instruction pair
+ // with no flow control. should also be branchless on consoles.
+ 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 );
+ }
+}
+
+// write raw IEEE float bits in little endian form
+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 );
+}
+
+//-----------------------------------------------------------------------------
+// This is useful if you just want a buffer to write into on the stack.
+//-----------------------------------------------------------------------------
+
+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];
+};
+
+
+
+//-----------------------------------------------------------------------------
+// Used for unserialization
+//-----------------------------------------------------------------------------
+
+class bf_read
+{
+public:
+ bf_read();
+
+ // nMaxBits can be used as the number of bits in the buffer.
+ // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8.
+ bf_read( const void *pData, int nBytes, int nBits = -1 );
+ bf_read( const char *pDebugName, const void *pData, int nBytes, int nBits = -1 );
+
+ // Start reading from the specified buffer.
+ // pData's start address must be dword-aligned.
+ // nMaxBits can be used as the number of bits in the buffer.
+ // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8.
+ void StartReading( const void *pData, int nBytes, int iStartBit = 0, int nBits = -1 );
+
+ // Restart buffer reading.
+ void Reset();
+
+ // Enable or disable assertion on overflow. 99% of the time, it's a bug that we need to catch,
+ // but there may be the occasional buffer that is allowed to overflow gracefully.
+ void SetAssertOnOverflow( bool bAssert );
+
+ // This can be set to assign a name that gets output if the buffer overflows.
+ const char* GetDebugName() const { return m_pDebugName; }
+ void SetDebugName( const char *pName );
+
+ void ExciseBits( int startbit, int bitstoremove );
+
+
+// Bit functions.
+public:
+
+ // Returns 0 or 1.
+ int ReadOneBit();
+
+
+protected:
+
+ unsigned int CheckReadUBitLong(int numbits); // For debugging.
+ int ReadOneBitNoCheck(); // Faster version, doesn't check bounds and is inlined.
+ bool CheckForOverflow(int nBits);
+
+
+public:
+
+ // Get the base pointer.
+ const unsigned char* GetBasePointer() { return m_pData; }
+
+ BITBUF_INLINE int TotalBytesAvailable( void ) const
+ {
+ return m_nDataBytes;
+ }
+
+ // Read a list of bits in.
+ void ReadBits(void *pOut, int nBits);
+ // Read a list of bits in, but don't overrun the destination buffer.
+ // Returns the number of bits read into the buffer. The remaining
+ // bits are skipped over.
+ int ReadBitsClamped_ptr(void *pOut, size_t outSizeBytes, size_t nBits);
+ // Helper 'safe' template function that infers the size of the destination
+ // array. This version of the function should be preferred.
+ // Usage: char databuffer[100];
+ // ReadBitsClamped( dataBuffer, msg->m_nLength );
+ 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 );
+
+ // reads an unsigned integer with variable bit length
+ unsigned int ReadUBitVar();
+ unsigned int ReadUBitVarInternal( int encodingType );
+
+ // reads a varint encoded integer
+ uint32 ReadVarInt32();
+ uint64 ReadVarInt64();
+ int32 ReadSignedVarInt32();
+ int64 ReadSignedVarInt64();
+
+ // You can read signed or unsigned data with this, just cast to
+ // a signed int if necessary.
+ 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 );
+
+ // Faster for comparisons but do not fully decode float values
+ unsigned int ReadBitCoordBits();
+ unsigned int ReadBitCoordMPBits( bool bIntegral, bool bLowPrecision );
+
+// Byte functions (these still read data in bit-by-bit).
+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);
+
+ // Returns false if bufLen isn't large enough to hold the
+ // string in the buffer.
+ //
+ // Always reads to the end of the string (so you can read the
+ // next piece of data waiting).
+ //
+ // If bLine is true, it stops when it reaches a '\n' or a null-terminator.
+ //
+ // pStr is always null-terminated (unless bufLen is 0).
+ //
+ // pOutNumChars is set to the number of characters left in pStr when the routine is
+ // complete (this will never exceed bufLen-1).
+ //
+ bool ReadString( char *pStr, int bufLen, bool bLine=false, int *pOutNumChars=NULL );
+
+ // Reads a string and allocates memory for it. If the string in the buffer
+ // is > 2048 bytes, then pOverflow is set to true (if it's not NULL).
+ char* ReadAndAllocateString( bool *pOverflow = 0 );
+
+ // Returns nonzero if any bits differ
+ int CompareBits( bf_read * RESTRICT other, int bits ) RESTRICT;
+ int CompareBitsAt( int offset, bf_read * RESTRICT other, int otherOffset, int bits ) RESTRICT;
+
+// Status.
+public:
+ int GetNumBytesLeft();
+ int GetNumBytesRead();
+ int GetNumBitsLeft();
+ int GetNumBitsRead() const;
+
+ // Has the buffer overflowed?
+ inline bool IsOverflowed() const {return m_bOverflow;}
+
+ inline bool Seek(int iBit); // Seek to a specific bit.
+ inline bool SeekRelative(int iBitDelta); // Seek to an offset from the current position.
+
+ // Called when the buffer is overflowed.
+ void SetOverflowFlag();
+
+
+public:
+
+ // The current buffer.
+ const unsigned char* RESTRICT m_pData;
+ int m_nDataBytes;
+ int m_nDataBits;
+
+ // Where we are in the buffer.
+ int m_iCurBit;
+
+
+private:
+ // Errors?
+ bool m_bOverflow;
+
+ // For debugging..
+ bool m_bAssertOnOverflow;
+
+ const char *m_pDebugName;
+};
+
+//-----------------------------------------------------------------------------
+// Inlines.
+//-----------------------------------------------------------------------------
+
+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;
+ }
+}
+
+// Seek to an offset from the current position.
+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()
+{
+ // six bits: low 2 bits for encoding + first 4 bits of value
+ unsigned int sixbits = ReadUBitLong(6);
+ unsigned int encoding = sixbits & 3;
+ if ( encoding )
+ {
+ // this function will seek back four bits and read the full value
+ 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
+
+
+
|