aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/Net/OVR_BitStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/Net/OVR_BitStream.cpp')
-rw-r--r--LibOVR/Src/Net/OVR_BitStream.cpp1151
1 files changed, 1151 insertions, 0 deletions
diff --git a/LibOVR/Src/Net/OVR_BitStream.cpp b/LibOVR/Src/Net/OVR_BitStream.cpp
new file mode 100644
index 0000000..b565f22
--- /dev/null
+++ b/LibOVR/Src/Net/OVR_BitStream.cpp
@@ -0,0 +1,1151 @@
+/************************************************************************************
+
+Filename : OVR_BitStream.cpp
+Content : A generic serialization toolkit for packing data to a binary stream.
+Created : June 10, 2014
+Authors : Kevin Jenkins
+
+Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.2
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#include "OVR_BitStream.h"
+
+#ifdef OVR_OS_WIN32
+#include <WinSock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+namespace OVR { namespace Net {
+
+
+//-----------------------------------------------------------------------------
+// BitStream
+
+BitStream::BitStream()
+{
+ numberOfBitsUsed = 0;
+ //numberOfBitsAllocated = 32 * 8;
+ numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE * 8;
+ readOffset = 0;
+ //data = ( unsigned char* ) OVR_ALLOC( 32);
+ data = ( unsigned char* ) stackData;
+
+#ifdef _DEBUG
+ // OVR_ASSERT( data );
+#endif
+ //memset(data, 0, 32);
+ copyData = true;
+}
+
+BitStream::BitStream( const unsigned int initialBytesToAllocate )
+{
+ numberOfBitsUsed = 0;
+ readOffset = 0;
+ if (initialBytesToAllocate <= BITSTREAM_STACK_ALLOCATION_SIZE)
+ {
+ data = ( unsigned char* ) stackData;
+ numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE * 8;
+ }
+ else
+ {
+ data = ( unsigned char* ) OVR_ALLOC( (size_t) initialBytesToAllocate);
+ numberOfBitsAllocated = initialBytesToAllocate << 3;
+ }
+#ifdef _DEBUG
+ OVR_ASSERT( data );
+#endif
+ // memset(data, 0, initialBytesToAllocate);
+ copyData = true;
+}
+
+BitStream::BitStream( char* _data, const unsigned int lengthInBytes, bool _copyData )
+{
+ numberOfBitsUsed = lengthInBytes << 3;
+ readOffset = 0;
+ copyData = _copyData;
+ numberOfBitsAllocated = lengthInBytes << 3;
+
+ if ( copyData )
+ {
+ if ( lengthInBytes > 0 )
+ {
+ if (lengthInBytes < BITSTREAM_STACK_ALLOCATION_SIZE)
+ {
+ data = ( unsigned char* ) stackData;
+ numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE << 3;
+ }
+ else
+ {
+ data = ( unsigned char* ) OVR_ALLOC( (size_t) lengthInBytes);
+ }
+#ifdef _DEBUG
+ OVR_ASSERT( data );
+#endif
+ memcpy( data, _data, (size_t) lengthInBytes );
+ }
+ else
+ data = 0;
+ }
+ else
+ data = ( unsigned char* ) _data;
+}
+
+// Use this if you pass a pointer copy to the constructor (_copyData==false) and want to overallocate to prevent reallocation
+void BitStream::SetNumberOfBitsAllocated( const BitSize_t lengthInBits )
+{
+#ifdef _DEBUG
+ OVR_ASSERT( lengthInBits >= ( BitSize_t ) numberOfBitsAllocated );
+#endif
+ numberOfBitsAllocated = lengthInBits;
+}
+
+BitStream::~BitStream()
+{
+ if ( copyData && numberOfBitsAllocated > (BITSTREAM_STACK_ALLOCATION_SIZE << 3))
+ OVR_FREE( data ); // Use realloc and free so we are more efficient than delete and new for resizing
+}
+
+void BitStream::Reset( void )
+{
+ // Note: Do NOT reallocate memory because BitStream is used
+ // in places to serialize/deserialize a buffer. Reallocation
+ // is a dangerous operation (may result in leaks).
+
+ if ( numberOfBitsUsed > 0 )
+ {
+ // memset(data, 0, BITS_TO_BYTES(numberOfBitsUsed));
+ }
+
+ // Don't free memory here for speed efficiency
+ //free(data); // Use realloc and free so we are more efficient than delete and new for resizing
+ numberOfBitsUsed = 0;
+
+ //numberOfBitsAllocated=8;
+ readOffset = 0;
+
+ //data=(unsigned char*)OVR_ALLOC(1, _FILE_AND_LINE_);
+ // if (numberOfBitsAllocated>0)
+ // memset(data, 0, BITS_TO_BYTES(numberOfBitsAllocated));
+}
+
+// Write an array or casted stream
+void BitStream::Write( const char* inputByteArray, const unsigned int numberOfBytes )
+{
+ if (numberOfBytes==0)
+ return;
+
+ // Optimization:
+ if ((numberOfBitsUsed & 7) == 0)
+ {
+ AddBitsAndReallocate( BYTES_TO_BITS(numberOfBytes) );
+ memcpy(data+BITS_TO_BYTES(numberOfBitsUsed), inputByteArray, (size_t) numberOfBytes);
+ numberOfBitsUsed+=BYTES_TO_BITS(numberOfBytes);
+ }
+ else
+ {
+ WriteBits( ( unsigned char* ) inputByteArray, numberOfBytes * 8, true );
+ }
+
+}
+void BitStream::Write( BitStream *bitStream)
+{
+ Write(bitStream, bitStream->GetNumberOfBitsUsed()-bitStream->GetReadOffset());
+}
+void BitStream::Write( BitStream *bitStream, BitSize_t numberOfBits )
+{
+ AddBitsAndReallocate( numberOfBits );
+ BitSize_t numberOfBitsMod8;
+
+ if ((bitStream->GetReadOffset()&7)==0 && (numberOfBitsUsed&7)==0)
+ {
+ int readOffsetBytes=bitStream->GetReadOffset()/8;
+ int numBytes=numberOfBits/8;
+ memcpy(data + (numberOfBitsUsed >> 3), bitStream->GetData()+readOffsetBytes, numBytes);
+ numberOfBits-=BYTES_TO_BITS(numBytes);
+ bitStream->SetReadOffset(BYTES_TO_BITS(numBytes+readOffsetBytes));
+ numberOfBitsUsed+=BYTES_TO_BITS(numBytes);
+ }
+
+ while (numberOfBits-->0 && bitStream->readOffset + 1 <= bitStream->numberOfBitsUsed)
+ {
+ numberOfBitsMod8 = numberOfBitsUsed & 7;
+ if ( numberOfBitsMod8 == 0 )
+ {
+ // New byte
+ if (bitStream->data[ bitStream->readOffset >> 3 ] & ( 0x80 >> ( bitStream->readOffset & 7 ) ) )
+ {
+ // Write 1
+ data[ numberOfBitsUsed >> 3 ] = 0x80;
+ }
+ else
+ {
+ // Write 0
+ data[ numberOfBitsUsed >> 3 ] = 0;
+ }
+
+ }
+ else
+ {
+ // Existing byte
+ if (bitStream->data[ bitStream->readOffset >> 3 ] & ( 0x80 >> ( bitStream->readOffset & 7 ) ) )
+ data[ numberOfBitsUsed >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1
+ // else 0, do nothing
+ }
+
+ bitStream->readOffset++;
+ numberOfBitsUsed++;
+ }
+}
+void BitStream::Write( BitStream &bitStream, BitSize_t numberOfBits )
+{
+ Write(&bitStream, numberOfBits);
+}
+void BitStream::Write( BitStream &bitStream )
+{
+ Write(&bitStream);
+}
+bool BitStream::Read( BitStream *bitStream, BitSize_t numberOfBits )
+{
+ if (GetNumberOfUnreadBits() < numberOfBits)
+ return false;
+ bitStream->Write(this, numberOfBits);
+ return true;
+}
+bool BitStream::Read( BitStream *bitStream )
+{
+ bitStream->Write(this);
+ return true;
+}
+bool BitStream::Read( BitStream &bitStream, BitSize_t numberOfBits )
+{
+ if (GetNumberOfUnreadBits() < numberOfBits)
+ return false;
+ bitStream.Write(this, numberOfBits);
+ return true;
+}
+bool BitStream::Read( BitStream &bitStream )
+{
+ bitStream.Write(this);
+ return true;
+}
+
+// Read an array or casted stream
+bool BitStream::Read( char* outByteArray, const unsigned int numberOfBytes )
+{
+ // Optimization:
+ if ((readOffset & 7) == 0)
+ {
+ if ( readOffset + ( numberOfBytes << 3 ) > numberOfBitsUsed )
+ return false;
+
+ // Write the data
+ memcpy( outByteArray, data + ( readOffset >> 3 ), (size_t) numberOfBytes );
+
+ readOffset += numberOfBytes << 3;
+ return true;
+ }
+ else
+ {
+ return ReadBits( ( unsigned char* ) outByteArray, numberOfBytes * 8 );
+ }
+}
+
+// Sets the read pointer back to the beginning of your data.
+void BitStream::ResetReadPointer( void )
+{
+ readOffset = 0;
+}
+
+// Sets the write pointer back to the beginning of your data.
+void BitStream::ResetWritePointer( void )
+{
+ numberOfBitsUsed = 0;
+}
+
+// Write a 0
+void BitStream::Write0( void )
+{
+ AddBitsAndReallocate( 1 );
+
+ // New bytes need to be zeroed
+ if ( ( numberOfBitsUsed & 7 ) == 0 )
+ data[ numberOfBitsUsed >> 3 ] = 0;
+
+ numberOfBitsUsed++;
+}
+
+// Write a 1
+void BitStream::Write1( void )
+{
+ AddBitsAndReallocate( 1 );
+
+ BitSize_t numberOfBitsMod8 = numberOfBitsUsed & 7;
+
+ if ( numberOfBitsMod8 == 0 )
+ data[ numberOfBitsUsed >> 3 ] = 0x80;
+ else
+ data[ numberOfBitsUsed >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1
+
+ numberOfBitsUsed++;
+}
+
+// Returns true if the next data read is a 1, false if it is a 0
+bool BitStream::ReadBit( void )
+{
+ bool result = ( data[ readOffset >> 3 ] & ( 0x80 >> ( readOffset & 7 ) ) ) !=0;
+ readOffset++;
+ return result;
+}
+
+// Align the bitstream to the byte boundary and then write the specified number of bits.
+// This is faster than WriteBits but wastes the bits to do the alignment and requires you to call
+// SetReadToByteAlignment at the corresponding read position
+void BitStream::WriteAlignedBytes( const unsigned char* inByteArray, const unsigned int numberOfBytesToWrite )
+{
+ AlignWriteToByteBoundary();
+ Write((const char*) inByteArray, numberOfBytesToWrite);
+}
+void BitStream::EndianSwapBytes( int byteOffset, int length )
+{
+ if (DoEndianSwap())
+ {
+ ReverseBytesInPlace(data+byteOffset, length);
+ }
+}
+/// Aligns the bitstream, writes inputLength, and writes input. Won't write beyond maxBytesToWrite
+void BitStream::WriteAlignedBytesSafe( const char *inByteArray, const unsigned int inputLength, const unsigned int maxBytesToWrite )
+{
+ if (inByteArray==0 || inputLength==0)
+ {
+ WriteCompressed((unsigned int)0);
+ return;
+ }
+ WriteCompressed(inputLength);
+ WriteAlignedBytes((const unsigned char*) inByteArray, inputLength < maxBytesToWrite ? inputLength : maxBytesToWrite);
+}
+
+// Read bits, starting at the next aligned bits. Note that the modulus 8 starting offset of the
+// sequence must be the same as was used with WriteBits. This will be a problem with packet coalescence
+// unless you byte align the coalesced packets.
+bool BitStream::ReadAlignedBytes( unsigned char* inOutByteArray, const unsigned int numberOfBytesToRead )
+{
+#ifdef _DEBUG
+ OVR_ASSERT( numberOfBytesToRead > 0 );
+#endif
+
+ if ( numberOfBytesToRead <= 0 )
+ return false;
+
+ // Byte align
+ AlignReadToByteBoundary();
+
+ if ( readOffset + ( numberOfBytesToRead << 3 ) > numberOfBitsUsed )
+ return false;
+
+ // Write the data
+ memcpy( inOutByteArray, data + ( readOffset >> 3 ), (size_t) numberOfBytesToRead );
+
+ readOffset += numberOfBytesToRead << 3;
+
+ return true;
+}
+bool BitStream::ReadAlignedBytesSafe( char *inOutByteArray, int &inputLength, const int maxBytesToRead )
+{
+ return ReadAlignedBytesSafe(inOutByteArray,(unsigned int&) inputLength,(unsigned int)maxBytesToRead);
+}
+bool BitStream::ReadAlignedBytesSafe( char *inOutByteArray, unsigned int &inputLength, const unsigned int maxBytesToRead )
+{
+ if (ReadCompressed(inputLength)==false)
+ return false;
+ if (inputLength > maxBytesToRead)
+ inputLength=maxBytesToRead;
+ if (inputLength==0)
+ return true;
+ return ReadAlignedBytes((unsigned char*) inOutByteArray, inputLength);
+}
+bool BitStream::ReadAlignedBytesSafeAlloc( char **outByteArray, int &inputLength, const unsigned int maxBytesToRead )
+{
+ return ReadAlignedBytesSafeAlloc(outByteArray,(unsigned int&) inputLength, maxBytesToRead);
+}
+bool BitStream::ReadAlignedBytesSafeAlloc( char ** outByteArray, unsigned int &inputLength, const unsigned int maxBytesToRead )
+{
+ OVR_FREE(*outByteArray);
+ *outByteArray=0;
+ if (ReadCompressed(inputLength)==false)
+ return false;
+ if (inputLength > maxBytesToRead)
+ inputLength=maxBytesToRead;
+ if (inputLength==0)
+ return true;
+ *outByteArray = (char*) OVR_ALLOC( (size_t) inputLength);
+ return ReadAlignedBytes((unsigned char*) *outByteArray, inputLength);
+}
+
+// Write numberToWrite bits from the input source
+void BitStream::WriteBits( const unsigned char* inByteArray, BitSize_t numberOfBitsToWrite, const bool rightAlignedBits )
+{
+// if (numberOfBitsToWrite<=0)
+// return;
+
+ AddBitsAndReallocate( numberOfBitsToWrite );
+
+ const BitSize_t numberOfBitsUsedMod8 = numberOfBitsUsed & 7;
+
+ // If currently aligned and numberOfBits is a multiple of 8, just memcpy for speed
+ if (numberOfBitsUsedMod8==0 && (numberOfBitsToWrite&7)==0)
+ {
+ memcpy( data + ( numberOfBitsUsed >> 3 ), inByteArray, numberOfBitsToWrite>>3);
+ numberOfBitsUsed+=numberOfBitsToWrite;
+ return;
+ }
+
+ unsigned char dataByte;
+ const unsigned char* inputPtr=inByteArray;
+
+ // Faster to put the while at the top surprisingly enough
+ while ( numberOfBitsToWrite > 0 )
+ //do
+ {
+ dataByte = *( inputPtr++ );
+
+ if ( numberOfBitsToWrite < 8 && rightAlignedBits ) // rightAlignedBits means in the case of a partial byte, the bits are aligned from the right (bit 0) rather than the left (as in the normal internal representation)
+ dataByte <<= 8 - numberOfBitsToWrite; // shift left to get the bits on the left, as in our internal representation
+
+ // Writing to a new byte each time
+ if ( numberOfBitsUsedMod8 == 0 )
+ * ( data + ( numberOfBitsUsed >> 3 ) ) = dataByte;
+ else
+ {
+ // Copy over the new data.
+ *( data + ( numberOfBitsUsed >> 3 ) ) |= dataByte >> ( numberOfBitsUsedMod8 ); // First half
+
+ if ( 8 - ( numberOfBitsUsedMod8 ) < 8 && 8 - ( numberOfBitsUsedMod8 ) < numberOfBitsToWrite ) // If we didn't write it all out in the first half (8 - (numberOfBitsUsed%8) is the number we wrote in the first half)
+ {
+ *( data + ( numberOfBitsUsed >> 3 ) + 1 ) = (unsigned char) ( dataByte << ( 8 - ( numberOfBitsUsedMod8 ) ) ); // Second half (overlaps byte boundary)
+ }
+ }
+
+ if ( numberOfBitsToWrite >= 8 )
+ {
+ numberOfBitsUsed += 8;
+ numberOfBitsToWrite -= 8;
+ }
+ else
+ {
+ numberOfBitsUsed += numberOfBitsToWrite;
+ numberOfBitsToWrite=0;
+ }
+ }
+ // } while(numberOfBitsToWrite>0);
+}
+
+// Set the stream to some initial data. For internal use
+void BitStream::SetData( unsigned char *inByteArray )
+{
+ data=inByteArray;
+ copyData=false;
+}
+
+// Assume the input source points to a native type, compress and write it
+void BitStream::WriteCompressed( const unsigned char* inByteArray,
+ const unsigned int size, const bool unsignedData )
+{
+ BitSize_t currentByte = ( size >> 3 ) - 1; // PCs
+
+ unsigned char byteMatch;
+
+ if ( unsignedData )
+ {
+ byteMatch = 0;
+ }
+
+ else
+ {
+ byteMatch = 0xFF;
+ }
+
+ // Write upper bytes with a single 1
+ // From high byte to low byte, if high byte is a byteMatch then write a 1 bit. Otherwise write a 0 bit and then write the remaining bytes
+ while ( currentByte > 0 )
+ {
+ if ( inByteArray[ currentByte ] == byteMatch ) // If high byte is byteMatch (0 of 0xff) then it would have the same value shifted
+ {
+ bool b = true;
+ Write( b );
+ }
+ else
+ {
+ // Write the remainder of the data after writing 0
+ bool b = false;
+ Write( b );
+
+ WriteBits( inByteArray, ( currentByte + 1 ) << 3, true );
+ // currentByte--;
+
+
+ return ;
+ }
+
+ currentByte--;
+ }
+
+ // If the upper half of the last byte is a 0 (positive) or 16 (negative) then write a 1 and the remaining 4 bits. Otherwise write a 0 and the 8 bites.
+ if ( ( unsignedData && ( ( *( inByteArray + currentByte ) ) & 0xF0 ) == 0x00 ) ||
+ ( unsignedData == false && ( ( *( inByteArray + currentByte ) ) & 0xF0 ) == 0xF0 ) )
+ {
+ bool b = true;
+ Write( b );
+ WriteBits( inByteArray + currentByte, 4, true );
+ }
+
+ else
+ {
+ bool b = false;
+ Write( b );
+ WriteBits( inByteArray + currentByte, 8, true );
+ }
+}
+
+// Read numberOfBitsToRead bits to the output source
+// alignBitsToRight should be set to true to convert internal bitstream data to userdata
+// It should be false if you used WriteBits with rightAlignedBits false
+bool BitStream::ReadBits( unsigned char *inOutByteArray, BitSize_t numberOfBitsToRead, const bool alignBitsToRight )
+{
+#ifdef _DEBUG
+ // OVR_ASSERT( numberOfBitsToRead > 0 );
+#endif
+ if (numberOfBitsToRead<=0)
+ return false;
+
+ if ( readOffset + numberOfBitsToRead > numberOfBitsUsed )
+ return false;
+
+
+ const BitSize_t readOffsetMod8 = readOffset & 7;
+
+ // If currently aligned and numberOfBits is a multiple of 8, just memcpy for speed
+ if (readOffsetMod8==0 && (numberOfBitsToRead&7)==0)
+ {
+ memcpy( inOutByteArray, data + ( readOffset >> 3 ), numberOfBitsToRead>>3);
+ readOffset+=numberOfBitsToRead;
+ return true;
+ }
+
+
+
+ BitSize_t offset = 0;
+
+ memset( inOutByteArray, 0, (size_t) BITS_TO_BYTES( numberOfBitsToRead ) );
+
+ while ( numberOfBitsToRead > 0 )
+ {
+ *( inOutByteArray + offset ) |= *( data + ( readOffset >> 3 ) ) << ( readOffsetMod8 ); // First half
+
+ if ( readOffsetMod8 > 0 && numberOfBitsToRead > 8 - ( readOffsetMod8 ) ) // If we have a second half, we didn't read enough bytes in the first half
+ *( inOutByteArray + offset ) |= *( data + ( readOffset >> 3 ) + 1 ) >> ( 8 - ( readOffsetMod8 ) ); // Second half (overlaps byte boundary)
+
+ if (numberOfBitsToRead>=8)
+ {
+ numberOfBitsToRead -= 8;
+ readOffset += 8;
+ offset++;
+ }
+ else
+ {
+ int neg = (int) numberOfBitsToRead - 8;
+
+ if ( neg < 0 ) // Reading a partial byte for the last byte, shift right so the data is aligned on the right
+ {
+
+ if ( alignBitsToRight )
+ * ( inOutByteArray + offset ) >>= -neg;
+
+ readOffset += 8 + neg;
+ }
+ else
+ readOffset += 8;
+
+ offset++;
+
+ numberOfBitsToRead=0;
+ }
+ }
+
+ return true;
+}
+
+// Assume the input source points to a compressed native type. Decompress and read it
+bool BitStream::ReadCompressed( unsigned char* inOutByteArray,
+ const unsigned int size, const bool unsignedData )
+{
+ unsigned int currentByte = ( size >> 3 ) - 1;
+
+
+ unsigned char byteMatch, halfByteMatch;
+
+ if ( unsignedData )
+ {
+ byteMatch = 0;
+ halfByteMatch = 0;
+ }
+
+ else
+ {
+ byteMatch = 0xFF;
+ halfByteMatch = 0xF0;
+ }
+
+ // Upper bytes are specified with a single 1 if they match byteMatch
+ // From high byte to low byte, if high byte is a byteMatch then write a 1 bit. Otherwise write a 0 bit and then write the remaining bytes
+ while ( currentByte > 0 )
+ {
+ // If we read a 1 then the data is byteMatch.
+
+ bool b;
+
+ if ( Read( b ) == false )
+ return false;
+
+ if ( b ) // Check that bit
+ {
+ inOutByteArray[ currentByte ] = byteMatch;
+ currentByte--;
+ }
+ else
+ {
+ // Read the rest of the bytes
+
+ if ( ReadBits( inOutByteArray, ( currentByte + 1 ) << 3 ) == false )
+ return false;
+
+ return true;
+ }
+ }
+
+ // All but the first bytes are byteMatch. If the upper half of the last byte is a 0 (positive) or 16 (negative) then what we read will be a 1 and the remaining 4 bits.
+ // Otherwise we read a 0 and the 8 bytes
+ //OVR_ASSERT(readOffset+1 <=numberOfBitsUsed); // If this assert is hit the stream wasn't long enough to read from
+ if ( readOffset + 1 > numberOfBitsUsed )
+ return false;
+
+ bool b=false;
+
+ if ( Read( b ) == false )
+ return false;
+
+ if ( b ) // Check that bit
+ {
+
+ if ( ReadBits( inOutByteArray + currentByte, 4 ) == false )
+ return false;
+
+ inOutByteArray[ currentByte ] |= halfByteMatch; // We have to set the high 4 bits since these are set to 0 by ReadBits
+ }
+ else
+ {
+ if ( ReadBits( inOutByteArray + currentByte, 8 ) == false )
+ return false;
+ }
+
+ return true;
+}
+
+// Reallocates (if necessary) in preparation of writing numberOfBitsToWrite
+void BitStream::AddBitsAndReallocate( const BitSize_t numberOfBitsToWrite )
+{
+ BitSize_t newNumberOfBitsAllocated = numberOfBitsToWrite + numberOfBitsUsed;
+
+ if ( numberOfBitsToWrite + numberOfBitsUsed > 0 && ( ( numberOfBitsAllocated - 1 ) >> 3 ) < ( ( newNumberOfBitsAllocated - 1 ) >> 3 ) ) // If we need to allocate 1 or more new bytes
+ {
+#ifdef _DEBUG
+ // If this assert hits then we need to specify true for the third parameter in the constructor
+ // It needs to reallocate to hold all the data and can't do it unless we allocated to begin with
+ // Often hits if you call Write or Serialize on a read-only bitstream
+ OVR_ASSERT( copyData == true );
+#endif
+
+ // Less memory efficient but saves on news and deletes
+ /// Cap to 1 meg buffer to save on huge allocations
+ newNumberOfBitsAllocated = ( numberOfBitsToWrite + numberOfBitsUsed ) * 2;
+ if (newNumberOfBitsAllocated - ( numberOfBitsToWrite + numberOfBitsUsed ) > 1048576 )
+ newNumberOfBitsAllocated = numberOfBitsToWrite + numberOfBitsUsed + 1048576;
+
+ // BitSize_t newByteOffset = BITS_TO_BYTES( numberOfBitsAllocated );
+ // Use realloc and free so we are more efficient than delete and new for resizing
+ BitSize_t amountToAllocate = BITS_TO_BYTES( newNumberOfBitsAllocated );
+ if (data==(unsigned char*)stackData)
+ {
+ if (amountToAllocate > BITSTREAM_STACK_ALLOCATION_SIZE)
+ {
+ data = ( unsigned char* ) OVR_ALLOC( (size_t) amountToAllocate);
+ OVR_ASSERT(data);
+ if (data)
+ {
+ // need to copy the stack data over to our new memory area too
+ memcpy ((void *)data, (void *)stackData, (size_t) BITS_TO_BYTES( numberOfBitsAllocated ));
+ }
+ }
+ }
+ else
+ {
+ data = ( unsigned char* ) OVR_REALLOC( data, (size_t) amountToAllocate);
+ }
+
+#ifdef _DEBUG
+ OVR_ASSERT( data ); // Make sure realloc succeeded
+#endif
+ // memset(data+newByteOffset, 0, ((newNumberOfBitsAllocated-1)>>3) - ((numberOfBitsAllocated-1)>>3)); // Set the new data block to 0
+ }
+
+ if ( newNumberOfBitsAllocated > numberOfBitsAllocated )
+ numberOfBitsAllocated = newNumberOfBitsAllocated;
+}
+BitSize_t BitStream::GetNumberOfBitsAllocated(void) const
+{
+ return numberOfBitsAllocated;
+}
+void BitStream::PadWithZeroToByteLength( unsigned int bytes )
+{
+ if (GetNumberOfBytesUsed() < bytes)
+ {
+ AlignWriteToByteBoundary();
+ unsigned int numToWrite = bytes - GetNumberOfBytesUsed();
+ AddBitsAndReallocate( BYTES_TO_BITS(numToWrite) );
+ memset(data+BITS_TO_BYTES(numberOfBitsUsed), 0, (size_t) numToWrite);
+ numberOfBitsUsed+=BYTES_TO_BITS(numToWrite);
+ }
+}
+
+/*
+// Julius Goryavsky's version of Harley's algorithm.
+// 17 elementary ops plus an indexed load, if the machine
+// has "and not."
+
+int nlz10b(unsigned x) {
+
+ static char table[64] =
+ {32,20,19, u, u,18, u, 7, 10,17, u, u,14, u, 6, u,
+ u, 9, u,16, u, u, 1,26, u,13, u, u,24, 5, u, u,
+ u,21, u, 8,11, u,15, u, u, u, u, 2,27, 0,25, u,
+ 22, u,12, u, u, 3,28, u, 23, u, 4,29, u, u,30,31};
+
+ x = x | (x >> 1); // Propagate leftmost
+ x = x | (x >> 2); // 1-bit to the right.
+ x = x | (x >> 4);
+ x = x | (x >> 8);
+ x = x & ~(x >> 16);
+ x = x*0xFD7049FF; // Activate this line or the following 3.
+// x = (x << 9) - x; // Multiply by 511.
+// x = (x << 11) - x; // Multiply by 2047.
+// x = (x << 14) - x; // Multiply by 16383.
+ return table[x >> 26];
+}
+*/
+int BitStream::NumberOfLeadingZeroes( int8_t x ) {return NumberOfLeadingZeroes((uint8_t)x);}
+int BitStream::NumberOfLeadingZeroes( uint8_t x )
+{
+ uint8_t y;
+ int n;
+
+ n = 8;
+ y = x >> 4; if (y != 0) {n = n - 4; x = y;}
+ y = x >> 2; if (y != 0) {n = n - 2; x = y;}
+ y = x >> 1; if (y != 0) return n - 2;
+ return (int)(n - x);
+}
+int BitStream::NumberOfLeadingZeroes( int16_t x ) {return NumberOfLeadingZeroes((uint16_t)x);}
+int BitStream::NumberOfLeadingZeroes( uint16_t x )
+{
+ uint16_t y;
+ int n;
+
+ n = 16;
+ y = x >> 8; if (y != 0) {n = n - 8; x = y;}
+ y = x >> 4; if (y != 0) {n = n - 4; x = y;}
+ y = x >> 2; if (y != 0) {n = n - 2; x = y;}
+ y = x >> 1; if (y != 0) return n - 2;
+ return (int)(n - x);
+}
+int BitStream::NumberOfLeadingZeroes( int32_t x ) {return NumberOfLeadingZeroes((uint32_t)x);}
+int BitStream::NumberOfLeadingZeroes( uint32_t x )
+{
+ uint32_t y;
+ int n;
+
+ n = 32;
+ y = x >>16; if (y != 0) {n = n -16; x = y;}
+ y = x >> 8; if (y != 0) {n = n - 8; x = y;}
+ y = x >> 4; if (y != 0) {n = n - 4; x = y;}
+ y = x >> 2; if (y != 0) {n = n - 2; x = y;}
+ y = x >> 1; if (y != 0) return n - 2;
+ return (int)(n - x);
+}
+int BitStream::NumberOfLeadingZeroes( int64_t x ) {return NumberOfLeadingZeroes((uint64_t)x);}
+int BitStream::NumberOfLeadingZeroes( uint64_t x )
+{
+ uint64_t y;
+ int n;
+
+ n = 64;
+ y = x >>32; if (y != 0) {n = n -32; x = y;}
+ y = x >>16; if (y != 0) {n = n -16; x = y;}
+ y = x >> 8; if (y != 0) {n = n - 8; x = y;}
+ y = x >> 4; if (y != 0) {n = n - 4; x = y;}
+ y = x >> 2; if (y != 0) {n = n - 2; x = y;}
+ y = x >> 1; if (y != 0) return n - 2;
+ return (int)(n - x);
+}
+
+// Should hit if reads didn't match writes
+void BitStream::AssertStreamEmpty( void )
+{
+ OVR_ASSERT( readOffset == numberOfBitsUsed );
+}
+void BitStream::PrintBits( char *out ) const
+{
+ if ( numberOfBitsUsed <= 0 )
+ {
+ OVR_strcpy(out, 128, "No bits\n" );
+ return;
+ }
+
+ unsigned int strIndex=0;
+ for ( BitSize_t counter = 0; counter < BITS_TO_BYTES( numberOfBitsUsed ) && strIndex < 2000 ; counter++ )
+ {
+ BitSize_t stop;
+
+ if ( counter == ( numberOfBitsUsed - 1 ) >> 3 )
+ stop = 8 - ( ( ( numberOfBitsUsed - 1 ) & 7 ) + 1 );
+ else
+ stop = 0;
+
+ for ( BitSize_t counter2 = 7; counter2 >= stop; counter2-- )
+ {
+ if ( ( data[ counter ] >> counter2 ) & 1 )
+ out[strIndex++]='1';
+ else
+ out[strIndex++]='0';
+
+ if (counter2==0)
+ break;
+ }
+
+ out[strIndex++]=' ';
+ }
+
+ out[strIndex++]='\n';
+
+ out[strIndex++]=0;
+}
+void BitStream::PrintBits( void ) const
+{
+ char out[2048];
+ PrintBits(out);
+ printf("%s", out);
+}
+void BitStream::PrintHex( char *out ) const
+{
+ BitSize_t i;
+ for ( i=0; i < GetNumberOfBytesUsed(); i++)
+ {
+ OVR_sprintf(out+i*3, 128, "%02x ", data[i]);
+ }
+}
+void BitStream::PrintHex( void ) const
+{
+ char out[2048];
+ PrintHex(out);
+ printf("%s", out);
+}
+
+// Exposes the data for you to look at, like PrintBits does.
+// Data will point to the stream. Returns the length in bits of the stream.
+BitSize_t BitStream::CopyData( unsigned char** _data ) const
+{
+#ifdef _DEBUG
+ OVR_ASSERT( numberOfBitsUsed > 0 );
+#endif
+
+ *_data = (unsigned char*) OVR_ALLOC( (size_t) BITS_TO_BYTES( numberOfBitsUsed ));
+ memcpy( *_data, data, sizeof(unsigned char) * (size_t) ( BITS_TO_BYTES( numberOfBitsUsed ) ) );
+ return numberOfBitsUsed;
+}
+
+// Ignore data we don't intend to read
+void BitStream::IgnoreBits( const BitSize_t numberOfBits )
+{
+ readOffset += numberOfBits;
+}
+
+void BitStream::IgnoreBytes( const unsigned int numberOfBytes )
+{
+ IgnoreBits(BYTES_TO_BITS(numberOfBytes));
+}
+
+// Move the write pointer to a position on the array. Dangerous if you don't know what you are doing!
+// Doesn't work with non-aligned data!
+void BitStream::SetWriteOffset( const BitSize_t offset )
+{
+ numberOfBitsUsed = offset;
+}
+
+/*
+BitSize_t BitStream::GetWriteOffset( void ) const
+{
+return numberOfBitsUsed;
+}
+
+// Returns the length in bits of the stream
+BitSize_t BitStream::GetNumberOfBitsUsed( void ) const
+{
+return GetWriteOffset();
+}
+
+// Returns the length in bytes of the stream
+BitSize_t BitStream::GetNumberOfBytesUsed( void ) const
+{
+return BITS_TO_BYTES( numberOfBitsUsed );
+}
+
+// Returns the number of bits into the stream that we have read
+BitSize_t BitStream::GetReadOffset( void ) const
+{
+return readOffset;
+}
+
+
+// Sets the read bit index
+void BitStream::SetReadOffset( const BitSize_t newReadOffset )
+{
+readOffset=newReadOffset;
+}
+
+// Returns the number of bits left in the stream that haven't been read
+BitSize_t BitStream::GetNumberOfUnreadBits( void ) const
+{
+return numberOfBitsUsed - readOffset;
+}
+// Exposes the internal data
+unsigned char* BitStream::GetData( void ) const
+{
+return data;
+}
+
+*/
+// If we used the constructor version with copy data off, this makes sure it is set to on and the data pointed to is copied.
+void BitStream::AssertCopyData( void )
+{
+ if ( copyData == false )
+ {
+ copyData = true;
+
+ if ( numberOfBitsAllocated > 0 )
+ {
+ unsigned char * newdata = ( unsigned char* ) OVR_ALLOC( (size_t) BITS_TO_BYTES( numberOfBitsAllocated ));
+#ifdef _DEBUG
+
+ OVR_ASSERT( data );
+#endif
+
+ memcpy( newdata, data, (size_t) BITS_TO_BYTES( numberOfBitsAllocated ) );
+ data = newdata;
+ }
+
+ else
+ data = 0;
+ }
+}
+bool BitStream::IsNetworkOrderInternal(void)
+{
+#if defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3)
+ return true;
+#elif defined(SN_TARGET_PSP2)
+ return false;
+#else
+ static unsigned long htonlValue = htonl(12345);
+ return htonlValue == 12345;
+#endif
+}
+void BitStream::ReverseBytes(unsigned char *inByteArray, unsigned char *inOutByteArray, const unsigned int length)
+{
+ for (BitSize_t i=0; i < length; i++)
+ inOutByteArray[i]=inByteArray[length-i-1];
+}
+void BitStream::ReverseBytesInPlace(unsigned char *inOutData,const unsigned int length)
+{
+ unsigned char temp;
+ BitSize_t i;
+ for (i=0; i < (length>>1); i++)
+ {
+ temp = inOutData[i];
+ inOutData[i]=inOutData[length-i-1];
+ inOutData[length-i-1]=temp;
+ }
+}
+
+void BitStream::WriteAlignedVar8(const char *inByteArray)
+{
+ OVR_ASSERT((numberOfBitsUsed&7)==0);
+ AddBitsAndReallocate(1*8);
+ data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[0];
+ numberOfBitsUsed+=1*8;
+}
+bool BitStream::ReadAlignedVar8(char *inOutByteArray)
+{
+ OVR_ASSERT((readOffset&7)==0);
+ if ( readOffset + 1*8 > numberOfBitsUsed )
+ return false;
+
+ inOutByteArray[0] = data[( readOffset >> 3 ) + 0];
+ readOffset+=1*8;
+ return true;
+}
+void BitStream::WriteAlignedVar16(const char *inByteArray)
+{
+ OVR_ASSERT((numberOfBitsUsed&7)==0);
+ AddBitsAndReallocate(2*8);
+#ifndef __BITSTREAM_NATIVE_END
+ if (DoEndianSwap())
+ {
+ data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[1];
+ data[( numberOfBitsUsed >> 3 ) + 1] = inByteArray[0];
+ }
+ else
+#endif
+ {
+ data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[0];
+ data[( numberOfBitsUsed >> 3 ) + 1] = inByteArray[1];
+ }
+
+ numberOfBitsUsed+=2*8;
+}
+bool BitStream::ReadAlignedVar16(char *inOutByteArray)
+{
+ OVR_ASSERT((readOffset&7)==0);
+ if ( readOffset + 2*8 > numberOfBitsUsed )
+ return false;
+#ifndef __BITSTREAM_NATIVE_END
+ if (DoEndianSwap())
+ {
+ inOutByteArray[0] = data[( readOffset >> 3 ) + 1];
+ inOutByteArray[1] = data[( readOffset >> 3 ) + 0];
+ }
+ else
+#endif
+ {
+ inOutByteArray[0] = data[( readOffset >> 3 ) + 0];
+ inOutByteArray[1] = data[( readOffset >> 3 ) + 1];
+ }
+
+ readOffset+=2*8;
+ return true;
+}
+void BitStream::WriteAlignedVar32(const char *inByteArray)
+{
+ OVR_ASSERT((numberOfBitsUsed&7)==0);
+ AddBitsAndReallocate(4*8);
+#ifndef __BITSTREAM_NATIVE_END
+ if (DoEndianSwap())
+ {
+ data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[3];
+ data[( numberOfBitsUsed >> 3 ) + 1] = inByteArray[2];
+ data[( numberOfBitsUsed >> 3 ) + 2] = inByteArray[1];
+ data[( numberOfBitsUsed >> 3 ) + 3] = inByteArray[0];
+ }
+ else
+#endif
+ {
+ data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[0];
+ data[( numberOfBitsUsed >> 3 ) + 1] = inByteArray[1];
+ data[( numberOfBitsUsed >> 3 ) + 2] = inByteArray[2];
+ data[( numberOfBitsUsed >> 3 ) + 3] = inByteArray[3];
+ }
+
+ numberOfBitsUsed+=4*8;
+}
+bool BitStream::ReadAlignedVar32(char *inOutByteArray)
+{
+ OVR_ASSERT((readOffset&7)==0);
+ if ( readOffset + 4*8 > numberOfBitsUsed )
+ return false;
+#ifndef __BITSTREAM_NATIVE_END
+ if (DoEndianSwap())
+ {
+ inOutByteArray[0] = data[( readOffset >> 3 ) + 3];
+ inOutByteArray[1] = data[( readOffset >> 3 ) + 2];
+ inOutByteArray[2] = data[( readOffset >> 3 ) + 1];
+ inOutByteArray[3] = data[( readOffset >> 3 ) + 0];
+ }
+ else
+#endif
+ {
+ inOutByteArray[0] = data[( readOffset >> 3 ) + 0];
+ inOutByteArray[1] = data[( readOffset >> 3 ) + 1];
+ inOutByteArray[2] = data[( readOffset >> 3 ) + 2];
+ inOutByteArray[3] = data[( readOffset >> 3 ) + 3];
+ }
+
+ readOffset+=4*8;
+ return true;
+}
+bool BitStream::ReadFloat16( float &outFloat, float floatMin, float floatMax )
+{
+ uint16_t percentile;
+ if (Read(percentile))
+ {
+ OVR_ASSERT(floatMax>floatMin);
+ outFloat = floatMin + ((float) percentile / 65535.0f) * (floatMax-floatMin);
+ if (outFloat<floatMin)
+ outFloat=floatMin;
+ else if (outFloat>floatMax)
+ outFloat=floatMax;
+ return true;
+ }
+ return false;
+}
+bool BitStream::SerializeFloat16(bool writeToBitstream, float &inOutFloat, float floatMin, float floatMax)
+{
+ if (writeToBitstream)
+ WriteFloat16(inOutFloat, floatMin, floatMax);
+ else
+ return ReadFloat16(inOutFloat, floatMin, floatMax);
+ return true;
+}
+void BitStream::WriteFloat16( float inOutFloat, float floatMin, float floatMax )
+{
+ OVR_ASSERT(floatMax>floatMin);
+ if (inOutFloat>floatMax+.001)
+ {
+ OVR_ASSERT(inOutFloat<=floatMax+.001);
+ }
+ if (inOutFloat<floatMin-.001)
+ {
+ OVR_ASSERT(inOutFloat>=floatMin-.001);
+ }
+ float percentile=65535.0f * (inOutFloat-floatMin)/(floatMax-floatMin);
+ if (percentile<0.0)
+ percentile=0.0;
+ if (percentile>65535.0f)
+ percentile=65535.0f;
+ Write((uint16_t)percentile);
+}
+
+
+}} // OVR::Net