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