ovr_sdk

annotate LibOVR/Src/Net/OVR_BitStream.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
rev   line source
nuclear@0 1 /************************************************************************************
nuclear@0 2
nuclear@0 3 Filename : OVR_BitStream.cpp
nuclear@0 4 Content : A generic serialization toolkit for packing data to a binary stream.
nuclear@0 5 Created : June 10, 2014
nuclear@0 6 Authors : Kevin Jenkins
nuclear@0 7
nuclear@0 8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
nuclear@0 9
nuclear@0 10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
nuclear@0 11 you may not use the Oculus VR Rift SDK except in compliance with the License,
nuclear@0 12 which is provided at the time of installation or download, or which
nuclear@0 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@0 14
nuclear@0 15 You may obtain a copy of the License at
nuclear@0 16
nuclear@0 17 http://www.oculusvr.com/licenses/LICENSE-3.2
nuclear@0 18
nuclear@0 19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
nuclear@0 20 distributed under the License is distributed on an "AS IS" BASIS,
nuclear@0 21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nuclear@0 22 See the License for the specific language governing permissions and
nuclear@0 23 limitations under the License.
nuclear@0 24
nuclear@0 25 ************************************************************************************/
nuclear@0 26
nuclear@0 27 #include "OVR_BitStream.h"
nuclear@0 28
nuclear@0 29 #ifdef OVR_OS_WIN32
nuclear@0 30 #include <WinSock2.h>
nuclear@0 31 #else
nuclear@0 32 #include <arpa/inet.h>
nuclear@0 33 #endif
nuclear@0 34
nuclear@0 35 namespace OVR { namespace Net {
nuclear@0 36
nuclear@0 37
nuclear@0 38 //-----------------------------------------------------------------------------
nuclear@0 39 // BitStream
nuclear@0 40
nuclear@0 41 BitStream::BitStream()
nuclear@0 42 {
nuclear@0 43 numberOfBitsUsed = 0;
nuclear@0 44 //numberOfBitsAllocated = 32 * 8;
nuclear@0 45 numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE * 8;
nuclear@0 46 readOffset = 0;
nuclear@0 47 //data = ( unsigned char* ) OVR_ALLOC( 32);
nuclear@0 48 data = ( unsigned char* ) stackData;
nuclear@0 49
nuclear@0 50 #ifdef _DEBUG
nuclear@0 51 // OVR_ASSERT( data );
nuclear@0 52 #endif
nuclear@0 53 //memset(data, 0, 32);
nuclear@0 54 copyData = true;
nuclear@0 55 }
nuclear@0 56
nuclear@0 57 BitStream::BitStream( const unsigned int initialBytesToAllocate )
nuclear@0 58 {
nuclear@0 59 numberOfBitsUsed = 0;
nuclear@0 60 readOffset = 0;
nuclear@0 61 if (initialBytesToAllocate <= BITSTREAM_STACK_ALLOCATION_SIZE)
nuclear@0 62 {
nuclear@0 63 data = ( unsigned char* ) stackData;
nuclear@0 64 numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE * 8;
nuclear@0 65 }
nuclear@0 66 else
nuclear@0 67 {
nuclear@0 68 data = ( unsigned char* ) OVR_ALLOC( (size_t) initialBytesToAllocate);
nuclear@0 69 numberOfBitsAllocated = initialBytesToAllocate << 3;
nuclear@0 70 }
nuclear@0 71 #ifdef _DEBUG
nuclear@0 72 OVR_ASSERT( data );
nuclear@0 73 #endif
nuclear@0 74 // memset(data, 0, initialBytesToAllocate);
nuclear@0 75 copyData = true;
nuclear@0 76 }
nuclear@0 77
nuclear@0 78 BitStream::BitStream( char* _data, const unsigned int lengthInBytes, bool _copyData )
nuclear@0 79 {
nuclear@0 80 numberOfBitsUsed = lengthInBytes << 3;
nuclear@0 81 readOffset = 0;
nuclear@0 82 copyData = _copyData;
nuclear@0 83 numberOfBitsAllocated = lengthInBytes << 3;
nuclear@0 84
nuclear@0 85 if ( copyData )
nuclear@0 86 {
nuclear@0 87 if ( lengthInBytes > 0 )
nuclear@0 88 {
nuclear@0 89 if (lengthInBytes < BITSTREAM_STACK_ALLOCATION_SIZE)
nuclear@0 90 {
nuclear@0 91 data = ( unsigned char* ) stackData;
nuclear@0 92 numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE << 3;
nuclear@0 93 }
nuclear@0 94 else
nuclear@0 95 {
nuclear@0 96 data = ( unsigned char* ) OVR_ALLOC( (size_t) lengthInBytes);
nuclear@0 97 }
nuclear@0 98 #ifdef _DEBUG
nuclear@0 99 OVR_ASSERT( data );
nuclear@0 100 #endif
nuclear@0 101 memcpy( data, _data, (size_t) lengthInBytes );
nuclear@0 102 }
nuclear@0 103 else
nuclear@0 104 data = 0;
nuclear@0 105 }
nuclear@0 106 else
nuclear@0 107 data = ( unsigned char* ) _data;
nuclear@0 108 }
nuclear@0 109
nuclear@0 110 // Use this if you pass a pointer copy to the constructor (_copyData==false) and want to overallocate to prevent reallocation
nuclear@0 111 void BitStream::SetNumberOfBitsAllocated( const BitSize_t lengthInBits )
nuclear@0 112 {
nuclear@0 113 #ifdef _DEBUG
nuclear@0 114 OVR_ASSERT( lengthInBits >= ( BitSize_t ) numberOfBitsAllocated );
nuclear@0 115 #endif
nuclear@0 116 numberOfBitsAllocated = lengthInBits;
nuclear@0 117 }
nuclear@0 118
nuclear@0 119 BitStream::~BitStream()
nuclear@0 120 {
nuclear@0 121 if ( copyData && numberOfBitsAllocated > (BITSTREAM_STACK_ALLOCATION_SIZE << 3))
nuclear@0 122 OVR_FREE( data ); // Use realloc and free so we are more efficient than delete and new for resizing
nuclear@0 123 }
nuclear@0 124
nuclear@0 125 void BitStream::Reset( void )
nuclear@0 126 {
nuclear@0 127 // Note: Do NOT reallocate memory because BitStream is used
nuclear@0 128 // in places to serialize/deserialize a buffer. Reallocation
nuclear@0 129 // is a dangerous operation (may result in leaks).
nuclear@0 130
nuclear@0 131 if ( numberOfBitsUsed > 0 )
nuclear@0 132 {
nuclear@0 133 // memset(data, 0, BITS_TO_BYTES(numberOfBitsUsed));
nuclear@0 134 }
nuclear@0 135
nuclear@0 136 // Don't free memory here for speed efficiency
nuclear@0 137 //free(data); // Use realloc and free so we are more efficient than delete and new for resizing
nuclear@0 138 numberOfBitsUsed = 0;
nuclear@0 139
nuclear@0 140 //numberOfBitsAllocated=8;
nuclear@0 141 readOffset = 0;
nuclear@0 142
nuclear@0 143 //data=(unsigned char*)OVR_ALLOC(1, _FILE_AND_LINE_);
nuclear@0 144 // if (numberOfBitsAllocated>0)
nuclear@0 145 // memset(data, 0, BITS_TO_BYTES(numberOfBitsAllocated));
nuclear@0 146 }
nuclear@0 147
nuclear@0 148 // Write an array or casted stream
nuclear@0 149 void BitStream::Write( const char* inputByteArray, const unsigned int numberOfBytes )
nuclear@0 150 {
nuclear@0 151 if (numberOfBytes==0)
nuclear@0 152 return;
nuclear@0 153
nuclear@0 154 // Optimization:
nuclear@0 155 if ((numberOfBitsUsed & 7) == 0)
nuclear@0 156 {
nuclear@0 157 AddBitsAndReallocate( BYTES_TO_BITS(numberOfBytes) );
nuclear@0 158 memcpy(data+BITS_TO_BYTES(numberOfBitsUsed), inputByteArray, (size_t) numberOfBytes);
nuclear@0 159 numberOfBitsUsed+=BYTES_TO_BITS(numberOfBytes);
nuclear@0 160 }
nuclear@0 161 else
nuclear@0 162 {
nuclear@0 163 WriteBits( ( unsigned char* ) inputByteArray, numberOfBytes * 8, true );
nuclear@0 164 }
nuclear@0 165
nuclear@0 166 }
nuclear@0 167 void BitStream::Write( BitStream *bitStream)
nuclear@0 168 {
nuclear@0 169 Write(bitStream, bitStream->GetNumberOfBitsUsed()-bitStream->GetReadOffset());
nuclear@0 170 }
nuclear@0 171 void BitStream::Write( BitStream *bitStream, BitSize_t numberOfBits )
nuclear@0 172 {
nuclear@0 173 AddBitsAndReallocate( numberOfBits );
nuclear@0 174 BitSize_t numberOfBitsMod8;
nuclear@0 175
nuclear@0 176 if ((bitStream->GetReadOffset()&7)==0 && (numberOfBitsUsed&7)==0)
nuclear@0 177 {
nuclear@0 178 int readOffsetBytes=bitStream->GetReadOffset()/8;
nuclear@0 179 int numBytes=numberOfBits/8;
nuclear@0 180 memcpy(data + (numberOfBitsUsed >> 3), bitStream->GetData()+readOffsetBytes, numBytes);
nuclear@0 181 numberOfBits-=BYTES_TO_BITS(numBytes);
nuclear@0 182 bitStream->SetReadOffset(BYTES_TO_BITS(numBytes+readOffsetBytes));
nuclear@0 183 numberOfBitsUsed+=BYTES_TO_BITS(numBytes);
nuclear@0 184 }
nuclear@0 185
nuclear@0 186 while (numberOfBits-->0 && bitStream->readOffset + 1 <= bitStream->numberOfBitsUsed)
nuclear@0 187 {
nuclear@0 188 numberOfBitsMod8 = numberOfBitsUsed & 7;
nuclear@0 189 if ( numberOfBitsMod8 == 0 )
nuclear@0 190 {
nuclear@0 191 // New byte
nuclear@0 192 if (bitStream->data[ bitStream->readOffset >> 3 ] & ( 0x80 >> ( bitStream->readOffset & 7 ) ) )
nuclear@0 193 {
nuclear@0 194 // Write 1
nuclear@0 195 data[ numberOfBitsUsed >> 3 ] = 0x80;
nuclear@0 196 }
nuclear@0 197 else
nuclear@0 198 {
nuclear@0 199 // Write 0
nuclear@0 200 data[ numberOfBitsUsed >> 3 ] = 0;
nuclear@0 201 }
nuclear@0 202
nuclear@0 203 }
nuclear@0 204 else
nuclear@0 205 {
nuclear@0 206 // Existing byte
nuclear@0 207 if (bitStream->data[ bitStream->readOffset >> 3 ] & ( 0x80 >> ( bitStream->readOffset & 7 ) ) )
nuclear@0 208 data[ numberOfBitsUsed >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1
nuclear@0 209 // else 0, do nothing
nuclear@0 210 }
nuclear@0 211
nuclear@0 212 bitStream->readOffset++;
nuclear@0 213 numberOfBitsUsed++;
nuclear@0 214 }
nuclear@0 215 }
nuclear@0 216 void BitStream::Write( BitStream &bitStream, BitSize_t numberOfBits )
nuclear@0 217 {
nuclear@0 218 Write(&bitStream, numberOfBits);
nuclear@0 219 }
nuclear@0 220 void BitStream::Write( BitStream &bitStream )
nuclear@0 221 {
nuclear@0 222 Write(&bitStream);
nuclear@0 223 }
nuclear@0 224 bool BitStream::Read( BitStream *bitStream, BitSize_t numberOfBits )
nuclear@0 225 {
nuclear@0 226 if (GetNumberOfUnreadBits() < numberOfBits)
nuclear@0 227 return false;
nuclear@0 228 bitStream->Write(this, numberOfBits);
nuclear@0 229 return true;
nuclear@0 230 }
nuclear@0 231 bool BitStream::Read( BitStream *bitStream )
nuclear@0 232 {
nuclear@0 233 bitStream->Write(this);
nuclear@0 234 return true;
nuclear@0 235 }
nuclear@0 236 bool BitStream::Read( BitStream &bitStream, BitSize_t numberOfBits )
nuclear@0 237 {
nuclear@0 238 if (GetNumberOfUnreadBits() < numberOfBits)
nuclear@0 239 return false;
nuclear@0 240 bitStream.Write(this, numberOfBits);
nuclear@0 241 return true;
nuclear@0 242 }
nuclear@0 243 bool BitStream::Read( BitStream &bitStream )
nuclear@0 244 {
nuclear@0 245 bitStream.Write(this);
nuclear@0 246 return true;
nuclear@0 247 }
nuclear@0 248
nuclear@0 249 // Read an array or casted stream
nuclear@0 250 bool BitStream::Read( char* outByteArray, const unsigned int numberOfBytes )
nuclear@0 251 {
nuclear@0 252 // Optimization:
nuclear@0 253 if ((readOffset & 7) == 0)
nuclear@0 254 {
nuclear@0 255 if ( readOffset + ( numberOfBytes << 3 ) > numberOfBitsUsed )
nuclear@0 256 return false;
nuclear@0 257
nuclear@0 258 // Write the data
nuclear@0 259 memcpy( outByteArray, data + ( readOffset >> 3 ), (size_t) numberOfBytes );
nuclear@0 260
nuclear@0 261 readOffset += numberOfBytes << 3;
nuclear@0 262 return true;
nuclear@0 263 }
nuclear@0 264 else
nuclear@0 265 {
nuclear@0 266 return ReadBits( ( unsigned char* ) outByteArray, numberOfBytes * 8 );
nuclear@0 267 }
nuclear@0 268 }
nuclear@0 269
nuclear@0 270 // Sets the read pointer back to the beginning of your data.
nuclear@0 271 void BitStream::ResetReadPointer( void )
nuclear@0 272 {
nuclear@0 273 readOffset = 0;
nuclear@0 274 }
nuclear@0 275
nuclear@0 276 // Sets the write pointer back to the beginning of your data.
nuclear@0 277 void BitStream::ResetWritePointer( void )
nuclear@0 278 {
nuclear@0 279 numberOfBitsUsed = 0;
nuclear@0 280 }
nuclear@0 281
nuclear@0 282 // Write a 0
nuclear@0 283 void BitStream::Write0( void )
nuclear@0 284 {
nuclear@0 285 AddBitsAndReallocate( 1 );
nuclear@0 286
nuclear@0 287 // New bytes need to be zeroed
nuclear@0 288 if ( ( numberOfBitsUsed & 7 ) == 0 )
nuclear@0 289 data[ numberOfBitsUsed >> 3 ] = 0;
nuclear@0 290
nuclear@0 291 numberOfBitsUsed++;
nuclear@0 292 }
nuclear@0 293
nuclear@0 294 // Write a 1
nuclear@0 295 void BitStream::Write1( void )
nuclear@0 296 {
nuclear@0 297 AddBitsAndReallocate( 1 );
nuclear@0 298
nuclear@0 299 BitSize_t numberOfBitsMod8 = numberOfBitsUsed & 7;
nuclear@0 300
nuclear@0 301 if ( numberOfBitsMod8 == 0 )
nuclear@0 302 data[ numberOfBitsUsed >> 3 ] = 0x80;
nuclear@0 303 else
nuclear@0 304 data[ numberOfBitsUsed >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1
nuclear@0 305
nuclear@0 306 numberOfBitsUsed++;
nuclear@0 307 }
nuclear@0 308
nuclear@0 309 // Returns true if the next data read is a 1, false if it is a 0
nuclear@0 310 bool BitStream::ReadBit( void )
nuclear@0 311 {
nuclear@0 312 bool result = ( data[ readOffset >> 3 ] & ( 0x80 >> ( readOffset & 7 ) ) ) !=0;
nuclear@0 313 readOffset++;
nuclear@0 314 return result;
nuclear@0 315 }
nuclear@0 316
nuclear@0 317 // Align the bitstream to the byte boundary and then write the specified number of bits.
nuclear@0 318 // This is faster than WriteBits but wastes the bits to do the alignment and requires you to call
nuclear@0 319 // SetReadToByteAlignment at the corresponding read position
nuclear@0 320 void BitStream::WriteAlignedBytes( const unsigned char* inByteArray, const unsigned int numberOfBytesToWrite )
nuclear@0 321 {
nuclear@0 322 AlignWriteToByteBoundary();
nuclear@0 323 Write((const char*) inByteArray, numberOfBytesToWrite);
nuclear@0 324 }
nuclear@0 325 void BitStream::EndianSwapBytes( int byteOffset, int length )
nuclear@0 326 {
nuclear@0 327 if (DoEndianSwap())
nuclear@0 328 {
nuclear@0 329 ReverseBytesInPlace(data+byteOffset, length);
nuclear@0 330 }
nuclear@0 331 }
nuclear@0 332 /// Aligns the bitstream, writes inputLength, and writes input. Won't write beyond maxBytesToWrite
nuclear@0 333 void BitStream::WriteAlignedBytesSafe( const char *inByteArray, const unsigned int inputLength, const unsigned int maxBytesToWrite )
nuclear@0 334 {
nuclear@0 335 if (inByteArray==0 || inputLength==0)
nuclear@0 336 {
nuclear@0 337 WriteCompressed((unsigned int)0);
nuclear@0 338 return;
nuclear@0 339 }
nuclear@0 340 WriteCompressed(inputLength);
nuclear@0 341 WriteAlignedBytes((const unsigned char*) inByteArray, inputLength < maxBytesToWrite ? inputLength : maxBytesToWrite);
nuclear@0 342 }
nuclear@0 343
nuclear@0 344 // Read bits, starting at the next aligned bits. Note that the modulus 8 starting offset of the
nuclear@0 345 // sequence must be the same as was used with WriteBits. This will be a problem with packet coalescence
nuclear@0 346 // unless you byte align the coalesced packets.
nuclear@0 347 bool BitStream::ReadAlignedBytes( unsigned char* inOutByteArray, const unsigned int numberOfBytesToRead )
nuclear@0 348 {
nuclear@0 349 #ifdef _DEBUG
nuclear@0 350 OVR_ASSERT( numberOfBytesToRead > 0 );
nuclear@0 351 #endif
nuclear@0 352
nuclear@0 353 if ( numberOfBytesToRead <= 0 )
nuclear@0 354 return false;
nuclear@0 355
nuclear@0 356 // Byte align
nuclear@0 357 AlignReadToByteBoundary();
nuclear@0 358
nuclear@0 359 if ( readOffset + ( numberOfBytesToRead << 3 ) > numberOfBitsUsed )
nuclear@0 360 return false;
nuclear@0 361
nuclear@0 362 // Write the data
nuclear@0 363 memcpy( inOutByteArray, data + ( readOffset >> 3 ), (size_t) numberOfBytesToRead );
nuclear@0 364
nuclear@0 365 readOffset += numberOfBytesToRead << 3;
nuclear@0 366
nuclear@0 367 return true;
nuclear@0 368 }
nuclear@0 369 bool BitStream::ReadAlignedBytesSafe( char *inOutByteArray, int &inputLength, const int maxBytesToRead )
nuclear@0 370 {
nuclear@0 371 return ReadAlignedBytesSafe(inOutByteArray,(unsigned int&) inputLength,(unsigned int)maxBytesToRead);
nuclear@0 372 }
nuclear@0 373 bool BitStream::ReadAlignedBytesSafe( char *inOutByteArray, unsigned int &inputLength, const unsigned int maxBytesToRead )
nuclear@0 374 {
nuclear@0 375 if (ReadCompressed(inputLength)==false)
nuclear@0 376 return false;
nuclear@0 377 if (inputLength > maxBytesToRead)
nuclear@0 378 inputLength=maxBytesToRead;
nuclear@0 379 if (inputLength==0)
nuclear@0 380 return true;
nuclear@0 381 return ReadAlignedBytes((unsigned char*) inOutByteArray, inputLength);
nuclear@0 382 }
nuclear@0 383 bool BitStream::ReadAlignedBytesSafeAlloc( char **outByteArray, int &inputLength, const unsigned int maxBytesToRead )
nuclear@0 384 {
nuclear@0 385 return ReadAlignedBytesSafeAlloc(outByteArray,(unsigned int&) inputLength, maxBytesToRead);
nuclear@0 386 }
nuclear@0 387 bool BitStream::ReadAlignedBytesSafeAlloc( char ** outByteArray, unsigned int &inputLength, const unsigned int maxBytesToRead )
nuclear@0 388 {
nuclear@0 389 OVR_FREE(*outByteArray);
nuclear@0 390 *outByteArray=0;
nuclear@0 391 if (ReadCompressed(inputLength)==false)
nuclear@0 392 return false;
nuclear@0 393 if (inputLength > maxBytesToRead)
nuclear@0 394 inputLength=maxBytesToRead;
nuclear@0 395 if (inputLength==0)
nuclear@0 396 return true;
nuclear@0 397 *outByteArray = (char*) OVR_ALLOC( (size_t) inputLength);
nuclear@0 398 return ReadAlignedBytes((unsigned char*) *outByteArray, inputLength);
nuclear@0 399 }
nuclear@0 400
nuclear@0 401 // Write numberToWrite bits from the input source
nuclear@0 402 void BitStream::WriteBits( const unsigned char* inByteArray, BitSize_t numberOfBitsToWrite, const bool rightAlignedBits )
nuclear@0 403 {
nuclear@0 404 // if (numberOfBitsToWrite<=0)
nuclear@0 405 // return;
nuclear@0 406
nuclear@0 407 AddBitsAndReallocate( numberOfBitsToWrite );
nuclear@0 408
nuclear@0 409 const BitSize_t numberOfBitsUsedMod8 = numberOfBitsUsed & 7;
nuclear@0 410
nuclear@0 411 // If currently aligned and numberOfBits is a multiple of 8, just memcpy for speed
nuclear@0 412 if (numberOfBitsUsedMod8==0 && (numberOfBitsToWrite&7)==0)
nuclear@0 413 {
nuclear@0 414 memcpy( data + ( numberOfBitsUsed >> 3 ), inByteArray, numberOfBitsToWrite>>3);
nuclear@0 415 numberOfBitsUsed+=numberOfBitsToWrite;
nuclear@0 416 return;
nuclear@0 417 }
nuclear@0 418
nuclear@0 419 unsigned char dataByte;
nuclear@0 420 const unsigned char* inputPtr=inByteArray;
nuclear@0 421
nuclear@0 422 // Faster to put the while at the top surprisingly enough
nuclear@0 423 while ( numberOfBitsToWrite > 0 )
nuclear@0 424 //do
nuclear@0 425 {
nuclear@0 426 dataByte = *( inputPtr++ );
nuclear@0 427
nuclear@0 428 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 429 dataByte <<= 8 - numberOfBitsToWrite; // shift left to get the bits on the left, as in our internal representation
nuclear@0 430
nuclear@0 431 // Writing to a new byte each time
nuclear@0 432 if ( numberOfBitsUsedMod8 == 0 )
nuclear@0 433 * ( data + ( numberOfBitsUsed >> 3 ) ) = dataByte;
nuclear@0 434 else
nuclear@0 435 {
nuclear@0 436 // Copy over the new data.
nuclear@0 437 *( data + ( numberOfBitsUsed >> 3 ) ) |= dataByte >> ( numberOfBitsUsedMod8 ); // First half
nuclear@0 438
nuclear@0 439 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 440 {
nuclear@0 441 *( data + ( numberOfBitsUsed >> 3 ) + 1 ) = (unsigned char) ( dataByte << ( 8 - ( numberOfBitsUsedMod8 ) ) ); // Second half (overlaps byte boundary)
nuclear@0 442 }
nuclear@0 443 }
nuclear@0 444
nuclear@0 445 if ( numberOfBitsToWrite >= 8 )
nuclear@0 446 {
nuclear@0 447 numberOfBitsUsed += 8;
nuclear@0 448 numberOfBitsToWrite -= 8;
nuclear@0 449 }
nuclear@0 450 else
nuclear@0 451 {
nuclear@0 452 numberOfBitsUsed += numberOfBitsToWrite;
nuclear@0 453 numberOfBitsToWrite=0;
nuclear@0 454 }
nuclear@0 455 }
nuclear@0 456 // } while(numberOfBitsToWrite>0);
nuclear@0 457 }
nuclear@0 458
nuclear@0 459 // Set the stream to some initial data. For internal use
nuclear@0 460 void BitStream::SetData( unsigned char *inByteArray )
nuclear@0 461 {
nuclear@0 462 data=inByteArray;
nuclear@0 463 copyData=false;
nuclear@0 464 }
nuclear@0 465
nuclear@0 466 // Assume the input source points to a native type, compress and write it
nuclear@0 467 void BitStream::WriteCompressed( const unsigned char* inByteArray,
nuclear@0 468 const unsigned int size, const bool unsignedData )
nuclear@0 469 {
nuclear@0 470 BitSize_t currentByte = ( size >> 3 ) - 1; // PCs
nuclear@0 471
nuclear@0 472 unsigned char byteMatch;
nuclear@0 473
nuclear@0 474 if ( unsignedData )
nuclear@0 475 {
nuclear@0 476 byteMatch = 0;
nuclear@0 477 }
nuclear@0 478
nuclear@0 479 else
nuclear@0 480 {
nuclear@0 481 byteMatch = 0xFF;
nuclear@0 482 }
nuclear@0 483
nuclear@0 484 // Write upper bytes with a single 1
nuclear@0 485 // 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 486 while ( currentByte > 0 )
nuclear@0 487 {
nuclear@0 488 if ( inByteArray[ currentByte ] == byteMatch ) // If high byte is byteMatch (0 of 0xff) then it would have the same value shifted
nuclear@0 489 {
nuclear@0 490 bool b = true;
nuclear@0 491 Write( b );
nuclear@0 492 }
nuclear@0 493 else
nuclear@0 494 {
nuclear@0 495 // Write the remainder of the data after writing 0
nuclear@0 496 bool b = false;
nuclear@0 497 Write( b );
nuclear@0 498
nuclear@0 499 WriteBits( inByteArray, ( currentByte + 1 ) << 3, true );
nuclear@0 500 // currentByte--;
nuclear@0 501
nuclear@0 502
nuclear@0 503 return ;
nuclear@0 504 }
nuclear@0 505
nuclear@0 506 currentByte--;
nuclear@0 507 }
nuclear@0 508
nuclear@0 509 // 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 510 if ( ( unsignedData && ( ( *( inByteArray + currentByte ) ) & 0xF0 ) == 0x00 ) ||
nuclear@0 511 ( unsignedData == false && ( ( *( inByteArray + currentByte ) ) & 0xF0 ) == 0xF0 ) )
nuclear@0 512 {
nuclear@0 513 bool b = true;
nuclear@0 514 Write( b );
nuclear@0 515 WriteBits( inByteArray + currentByte, 4, true );
nuclear@0 516 }
nuclear@0 517
nuclear@0 518 else
nuclear@0 519 {
nuclear@0 520 bool b = false;
nuclear@0 521 Write( b );
nuclear@0 522 WriteBits( inByteArray + currentByte, 8, true );
nuclear@0 523 }
nuclear@0 524 }
nuclear@0 525
nuclear@0 526 // Read numberOfBitsToRead bits to the output source
nuclear@0 527 // alignBitsToRight should be set to true to convert internal bitstream data to userdata
nuclear@0 528 // It should be false if you used WriteBits with rightAlignedBits false
nuclear@0 529 bool BitStream::ReadBits( unsigned char *inOutByteArray, BitSize_t numberOfBitsToRead, const bool alignBitsToRight )
nuclear@0 530 {
nuclear@0 531 #ifdef _DEBUG
nuclear@0 532 // OVR_ASSERT( numberOfBitsToRead > 0 );
nuclear@0 533 #endif
nuclear@0 534 if (numberOfBitsToRead<=0)
nuclear@0 535 return false;
nuclear@0 536
nuclear@0 537 if ( readOffset + numberOfBitsToRead > numberOfBitsUsed )
nuclear@0 538 return false;
nuclear@0 539
nuclear@0 540
nuclear@0 541 const BitSize_t readOffsetMod8 = readOffset & 7;
nuclear@0 542
nuclear@0 543 // If currently aligned and numberOfBits is a multiple of 8, just memcpy for speed
nuclear@0 544 if (readOffsetMod8==0 && (numberOfBitsToRead&7)==0)
nuclear@0 545 {
nuclear@0 546 memcpy( inOutByteArray, data + ( readOffset >> 3 ), numberOfBitsToRead>>3);
nuclear@0 547 readOffset+=numberOfBitsToRead;
nuclear@0 548 return true;
nuclear@0 549 }
nuclear@0 550
nuclear@0 551
nuclear@0 552
nuclear@0 553 BitSize_t offset = 0;
nuclear@0 554
nuclear@0 555 memset( inOutByteArray, 0, (size_t) BITS_TO_BYTES( numberOfBitsToRead ) );
nuclear@0 556
nuclear@0 557 while ( numberOfBitsToRead > 0 )
nuclear@0 558 {
nuclear@0 559 *( inOutByteArray + offset ) |= *( data + ( readOffset >> 3 ) ) << ( readOffsetMod8 ); // First half
nuclear@0 560
nuclear@0 561 if ( readOffsetMod8 > 0 && numberOfBitsToRead > 8 - ( readOffsetMod8 ) ) // If we have a second half, we didn't read enough bytes in the first half
nuclear@0 562 *( inOutByteArray + offset ) |= *( data + ( readOffset >> 3 ) + 1 ) >> ( 8 - ( readOffsetMod8 ) ); // Second half (overlaps byte boundary)
nuclear@0 563
nuclear@0 564 if (numberOfBitsToRead>=8)
nuclear@0 565 {
nuclear@0 566 numberOfBitsToRead -= 8;
nuclear@0 567 readOffset += 8;
nuclear@0 568 offset++;
nuclear@0 569 }
nuclear@0 570 else
nuclear@0 571 {
nuclear@0 572 int neg = (int) numberOfBitsToRead - 8;
nuclear@0 573
nuclear@0 574 if ( neg < 0 ) // Reading a partial byte for the last byte, shift right so the data is aligned on the right
nuclear@0 575 {
nuclear@0 576
nuclear@0 577 if ( alignBitsToRight )
nuclear@0 578 * ( inOutByteArray + offset ) >>= -neg;
nuclear@0 579
nuclear@0 580 readOffset += 8 + neg;
nuclear@0 581 }
nuclear@0 582 else
nuclear@0 583 readOffset += 8;
nuclear@0 584
nuclear@0 585 offset++;
nuclear@0 586
nuclear@0 587 numberOfBitsToRead=0;
nuclear@0 588 }
nuclear@0 589 }
nuclear@0 590
nuclear@0 591 return true;
nuclear@0 592 }
nuclear@0 593
nuclear@0 594 // Assume the input source points to a compressed native type. Decompress and read it
nuclear@0 595 bool BitStream::ReadCompressed( unsigned char* inOutByteArray,
nuclear@0 596 const unsigned int size, const bool unsignedData )
nuclear@0 597 {
nuclear@0 598 unsigned int currentByte = ( size >> 3 ) - 1;
nuclear@0 599
nuclear@0 600
nuclear@0 601 unsigned char byteMatch, halfByteMatch;
nuclear@0 602
nuclear@0 603 if ( unsignedData )
nuclear@0 604 {
nuclear@0 605 byteMatch = 0;
nuclear@0 606 halfByteMatch = 0;
nuclear@0 607 }
nuclear@0 608
nuclear@0 609 else
nuclear@0 610 {
nuclear@0 611 byteMatch = 0xFF;
nuclear@0 612 halfByteMatch = 0xF0;
nuclear@0 613 }
nuclear@0 614
nuclear@0 615 // Upper bytes are specified with a single 1 if they match byteMatch
nuclear@0 616 // 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 617 while ( currentByte > 0 )
nuclear@0 618 {
nuclear@0 619 // If we read a 1 then the data is byteMatch.
nuclear@0 620
nuclear@0 621 bool b;
nuclear@0 622
nuclear@0 623 if ( Read( b ) == false )
nuclear@0 624 return false;
nuclear@0 625
nuclear@0 626 if ( b ) // Check that bit
nuclear@0 627 {
nuclear@0 628 inOutByteArray[ currentByte ] = byteMatch;
nuclear@0 629 currentByte--;
nuclear@0 630 }
nuclear@0 631 else
nuclear@0 632 {
nuclear@0 633 // Read the rest of the bytes
nuclear@0 634
nuclear@0 635 if ( ReadBits( inOutByteArray, ( currentByte + 1 ) << 3 ) == false )
nuclear@0 636 return false;
nuclear@0 637
nuclear@0 638 return true;
nuclear@0 639 }
nuclear@0 640 }
nuclear@0 641
nuclear@0 642 // 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 643 // Otherwise we read a 0 and the 8 bytes
nuclear@0 644 //OVR_ASSERT(readOffset+1 <=numberOfBitsUsed); // If this assert is hit the stream wasn't long enough to read from
nuclear@0 645 if ( readOffset + 1 > numberOfBitsUsed )
nuclear@0 646 return false;
nuclear@0 647
nuclear@0 648 bool b=false;
nuclear@0 649
nuclear@0 650 if ( Read( b ) == false )
nuclear@0 651 return false;
nuclear@0 652
nuclear@0 653 if ( b ) // Check that bit
nuclear@0 654 {
nuclear@0 655
nuclear@0 656 if ( ReadBits( inOutByteArray + currentByte, 4 ) == false )
nuclear@0 657 return false;
nuclear@0 658
nuclear@0 659 inOutByteArray[ currentByte ] |= halfByteMatch; // We have to set the high 4 bits since these are set to 0 by ReadBits
nuclear@0 660 }
nuclear@0 661 else
nuclear@0 662 {
nuclear@0 663 if ( ReadBits( inOutByteArray + currentByte, 8 ) == false )
nuclear@0 664 return false;
nuclear@0 665 }
nuclear@0 666
nuclear@0 667 return true;
nuclear@0 668 }
nuclear@0 669
nuclear@0 670 // Reallocates (if necessary) in preparation of writing numberOfBitsToWrite
nuclear@0 671 void BitStream::AddBitsAndReallocate( const BitSize_t numberOfBitsToWrite )
nuclear@0 672 {
nuclear@0 673 BitSize_t newNumberOfBitsAllocated = numberOfBitsToWrite + numberOfBitsUsed;
nuclear@0 674
nuclear@0 675 if ( numberOfBitsToWrite + numberOfBitsUsed > 0 && ( ( numberOfBitsAllocated - 1 ) >> 3 ) < ( ( newNumberOfBitsAllocated - 1 ) >> 3 ) ) // If we need to allocate 1 or more new bytes
nuclear@0 676 {
nuclear@0 677 #ifdef _DEBUG
nuclear@0 678 // If this assert hits then we need to specify true for the third parameter in the constructor
nuclear@0 679 // It needs to reallocate to hold all the data and can't do it unless we allocated to begin with
nuclear@0 680 // Often hits if you call Write or Serialize on a read-only bitstream
nuclear@0 681 OVR_ASSERT( copyData == true );
nuclear@0 682 #endif
nuclear@0 683
nuclear@0 684 // Less memory efficient but saves on news and deletes
nuclear@0 685 /// Cap to 1 meg buffer to save on huge allocations
nuclear@0 686 newNumberOfBitsAllocated = ( numberOfBitsToWrite + numberOfBitsUsed ) * 2;
nuclear@0 687 if (newNumberOfBitsAllocated - ( numberOfBitsToWrite + numberOfBitsUsed ) > 1048576 )
nuclear@0 688 newNumberOfBitsAllocated = numberOfBitsToWrite + numberOfBitsUsed + 1048576;
nuclear@0 689
nuclear@0 690 // BitSize_t newByteOffset = BITS_TO_BYTES( numberOfBitsAllocated );
nuclear@0 691 // Use realloc and free so we are more efficient than delete and new for resizing
nuclear@0 692 BitSize_t amountToAllocate = BITS_TO_BYTES( newNumberOfBitsAllocated );
nuclear@0 693 if (data==(unsigned char*)stackData)
nuclear@0 694 {
nuclear@0 695 if (amountToAllocate > BITSTREAM_STACK_ALLOCATION_SIZE)
nuclear@0 696 {
nuclear@0 697 data = ( unsigned char* ) OVR_ALLOC( (size_t) amountToAllocate);
nuclear@0 698 OVR_ASSERT(data);
nuclear@0 699 if (data)
nuclear@0 700 {
nuclear@0 701 // need to copy the stack data over to our new memory area too
nuclear@0 702 memcpy ((void *)data, (void *)stackData, (size_t) BITS_TO_BYTES( numberOfBitsAllocated ));
nuclear@0 703 }
nuclear@0 704 }
nuclear@0 705 }
nuclear@0 706 else
nuclear@0 707 {
nuclear@0 708 data = ( unsigned char* ) OVR_REALLOC( data, (size_t) amountToAllocate);
nuclear@0 709 }
nuclear@0 710
nuclear@0 711 #ifdef _DEBUG
nuclear@0 712 OVR_ASSERT( data ); // Make sure realloc succeeded
nuclear@0 713 #endif
nuclear@0 714 // memset(data+newByteOffset, 0, ((newNumberOfBitsAllocated-1)>>3) - ((numberOfBitsAllocated-1)>>3)); // Set the new data block to 0
nuclear@0 715 }
nuclear@0 716
nuclear@0 717 if ( newNumberOfBitsAllocated > numberOfBitsAllocated )
nuclear@0 718 numberOfBitsAllocated = newNumberOfBitsAllocated;
nuclear@0 719 }
nuclear@0 720 BitSize_t BitStream::GetNumberOfBitsAllocated(void) const
nuclear@0 721 {
nuclear@0 722 return numberOfBitsAllocated;
nuclear@0 723 }
nuclear@0 724 void BitStream::PadWithZeroToByteLength( unsigned int bytes )
nuclear@0 725 {
nuclear@0 726 if (GetNumberOfBytesUsed() < bytes)
nuclear@0 727 {
nuclear@0 728 AlignWriteToByteBoundary();
nuclear@0 729 unsigned int numToWrite = bytes - GetNumberOfBytesUsed();
nuclear@0 730 AddBitsAndReallocate( BYTES_TO_BITS(numToWrite) );
nuclear@0 731 memset(data+BITS_TO_BYTES(numberOfBitsUsed), 0, (size_t) numToWrite);
nuclear@0 732 numberOfBitsUsed+=BYTES_TO_BITS(numToWrite);
nuclear@0 733 }
nuclear@0 734 }
nuclear@0 735
nuclear@0 736 /*
nuclear@0 737 // Julius Goryavsky's version of Harley's algorithm.
nuclear@0 738 // 17 elementary ops plus an indexed load, if the machine
nuclear@0 739 // has "and not."
nuclear@0 740
nuclear@0 741 int nlz10b(unsigned x) {
nuclear@0 742
nuclear@0 743 static char table[64] =
nuclear@0 744 {32,20,19, u, u,18, u, 7, 10,17, u, u,14, u, 6, u,
nuclear@0 745 u, 9, u,16, u, u, 1,26, u,13, u, u,24, 5, u, u,
nuclear@0 746 u,21, u, 8,11, u,15, u, u, u, u, 2,27, 0,25, u,
nuclear@0 747 22, u,12, u, u, 3,28, u, 23, u, 4,29, u, u,30,31};
nuclear@0 748
nuclear@0 749 x = x | (x >> 1); // Propagate leftmost
nuclear@0 750 x = x | (x >> 2); // 1-bit to the right.
nuclear@0 751 x = x | (x >> 4);
nuclear@0 752 x = x | (x >> 8);
nuclear@0 753 x = x & ~(x >> 16);
nuclear@0 754 x = x*0xFD7049FF; // Activate this line or the following 3.
nuclear@0 755 // x = (x << 9) - x; // Multiply by 511.
nuclear@0 756 // x = (x << 11) - x; // Multiply by 2047.
nuclear@0 757 // x = (x << 14) - x; // Multiply by 16383.
nuclear@0 758 return table[x >> 26];
nuclear@0 759 }
nuclear@0 760 */
nuclear@0 761 int BitStream::NumberOfLeadingZeroes( int8_t x ) {return NumberOfLeadingZeroes((uint8_t)x);}
nuclear@0 762 int BitStream::NumberOfLeadingZeroes( uint8_t x )
nuclear@0 763 {
nuclear@0 764 uint8_t y;
nuclear@0 765 int n;
nuclear@0 766
nuclear@0 767 n = 8;
nuclear@0 768 y = x >> 4; if (y != 0) {n = n - 4; x = y;}
nuclear@0 769 y = x >> 2; if (y != 0) {n = n - 2; x = y;}
nuclear@0 770 y = x >> 1; if (y != 0) return n - 2;
nuclear@0 771 return (int)(n - x);
nuclear@0 772 }
nuclear@0 773 int BitStream::NumberOfLeadingZeroes( int16_t x ) {return NumberOfLeadingZeroes((uint16_t)x);}
nuclear@0 774 int BitStream::NumberOfLeadingZeroes( uint16_t x )
nuclear@0 775 {
nuclear@0 776 uint16_t y;
nuclear@0 777 int n;
nuclear@0 778
nuclear@0 779 n = 16;
nuclear@0 780 y = x >> 8; if (y != 0) {n = n - 8; x = y;}
nuclear@0 781 y = x >> 4; if (y != 0) {n = n - 4; x = y;}
nuclear@0 782 y = x >> 2; if (y != 0) {n = n - 2; x = y;}
nuclear@0 783 y = x >> 1; if (y != 0) return n - 2;
nuclear@0 784 return (int)(n - x);
nuclear@0 785 }
nuclear@0 786 int BitStream::NumberOfLeadingZeroes( int32_t x ) {return NumberOfLeadingZeroes((uint32_t)x);}
nuclear@0 787 int BitStream::NumberOfLeadingZeroes( uint32_t x )
nuclear@0 788 {
nuclear@0 789 uint32_t y;
nuclear@0 790 int n;
nuclear@0 791
nuclear@0 792 n = 32;
nuclear@0 793 y = x >>16; if (y != 0) {n = n -16; x = y;}
nuclear@0 794 y = x >> 8; if (y != 0) {n = n - 8; x = y;}
nuclear@0 795 y = x >> 4; if (y != 0) {n = n - 4; x = y;}
nuclear@0 796 y = x >> 2; if (y != 0) {n = n - 2; x = y;}
nuclear@0 797 y = x >> 1; if (y != 0) return n - 2;
nuclear@0 798 return (int)(n - x);
nuclear@0 799 }
nuclear@0 800 int BitStream::NumberOfLeadingZeroes( int64_t x ) {return NumberOfLeadingZeroes((uint64_t)x);}
nuclear@0 801 int BitStream::NumberOfLeadingZeroes( uint64_t x )
nuclear@0 802 {
nuclear@0 803 uint64_t y;
nuclear@0 804 int n;
nuclear@0 805
nuclear@0 806 n = 64;
nuclear@0 807 y = x >>32; if (y != 0) {n = n -32; x = y;}
nuclear@0 808 y = x >>16; if (y != 0) {n = n -16; x = y;}
nuclear@0 809 y = x >> 8; if (y != 0) {n = n - 8; x = y;}
nuclear@0 810 y = x >> 4; if (y != 0) {n = n - 4; x = y;}
nuclear@0 811 y = x >> 2; if (y != 0) {n = n - 2; x = y;}
nuclear@0 812 y = x >> 1; if (y != 0) return n - 2;
nuclear@0 813 return (int)(n - x);
nuclear@0 814 }
nuclear@0 815
nuclear@0 816 // Should hit if reads didn't match writes
nuclear@0 817 void BitStream::AssertStreamEmpty( void )
nuclear@0 818 {
nuclear@0 819 OVR_ASSERT( readOffset == numberOfBitsUsed );
nuclear@0 820 }
nuclear@0 821 void BitStream::PrintBits( char *out ) const
nuclear@0 822 {
nuclear@0 823 if ( numberOfBitsUsed <= 0 )
nuclear@0 824 {
nuclear@0 825 OVR_strcpy(out, 128, "No bits\n" );
nuclear@0 826 return;
nuclear@0 827 }
nuclear@0 828
nuclear@0 829 unsigned int strIndex=0;
nuclear@0 830 for ( BitSize_t counter = 0; counter < BITS_TO_BYTES( numberOfBitsUsed ) && strIndex < 2000 ; counter++ )
nuclear@0 831 {
nuclear@0 832 BitSize_t stop;
nuclear@0 833
nuclear@0 834 if ( counter == ( numberOfBitsUsed - 1 ) >> 3 )
nuclear@0 835 stop = 8 - ( ( ( numberOfBitsUsed - 1 ) & 7 ) + 1 );
nuclear@0 836 else
nuclear@0 837 stop = 0;
nuclear@0 838
nuclear@0 839 for ( BitSize_t counter2 = 7; counter2 >= stop; counter2-- )
nuclear@0 840 {
nuclear@0 841 if ( ( data[ counter ] >> counter2 ) & 1 )
nuclear@0 842 out[strIndex++]='1';
nuclear@0 843 else
nuclear@0 844 out[strIndex++]='0';
nuclear@0 845
nuclear@0 846 if (counter2==0)
nuclear@0 847 break;
nuclear@0 848 }
nuclear@0 849
nuclear@0 850 out[strIndex++]=' ';
nuclear@0 851 }
nuclear@0 852
nuclear@0 853 out[strIndex++]='\n';
nuclear@0 854
nuclear@0 855 out[strIndex++]=0;
nuclear@0 856 }
nuclear@0 857 void BitStream::PrintBits( void ) const
nuclear@0 858 {
nuclear@0 859 char out[2048];
nuclear@0 860 PrintBits(out);
nuclear@0 861 printf("%s", out);
nuclear@0 862 }
nuclear@0 863 void BitStream::PrintHex( char *out ) const
nuclear@0 864 {
nuclear@0 865 BitSize_t i;
nuclear@0 866 for ( i=0; i < GetNumberOfBytesUsed(); i++)
nuclear@0 867 {
nuclear@0 868 OVR_sprintf(out+i*3, 128, "%02x ", data[i]);
nuclear@0 869 }
nuclear@0 870 }
nuclear@0 871 void BitStream::PrintHex( void ) const
nuclear@0 872 {
nuclear@0 873 char out[2048];
nuclear@0 874 PrintHex(out);
nuclear@0 875 printf("%s", out);
nuclear@0 876 }
nuclear@0 877
nuclear@0 878 // Exposes the data for you to look at, like PrintBits does.
nuclear@0 879 // Data will point to the stream. Returns the length in bits of the stream.
nuclear@0 880 BitSize_t BitStream::CopyData( unsigned char** _data ) const
nuclear@0 881 {
nuclear@0 882 #ifdef _DEBUG
nuclear@0 883 OVR_ASSERT( numberOfBitsUsed > 0 );
nuclear@0 884 #endif
nuclear@0 885
nuclear@0 886 *_data = (unsigned char*) OVR_ALLOC( (size_t) BITS_TO_BYTES( numberOfBitsUsed ));
nuclear@0 887 memcpy( *_data, data, sizeof(unsigned char) * (size_t) ( BITS_TO_BYTES( numberOfBitsUsed ) ) );
nuclear@0 888 return numberOfBitsUsed;
nuclear@0 889 }
nuclear@0 890
nuclear@0 891 // Ignore data we don't intend to read
nuclear@0 892 void BitStream::IgnoreBits( const BitSize_t numberOfBits )
nuclear@0 893 {
nuclear@0 894 readOffset += numberOfBits;
nuclear@0 895 }
nuclear@0 896
nuclear@0 897 void BitStream::IgnoreBytes( const unsigned int numberOfBytes )
nuclear@0 898 {
nuclear@0 899 IgnoreBits(BYTES_TO_BITS(numberOfBytes));
nuclear@0 900 }
nuclear@0 901
nuclear@0 902 // Move the write pointer to a position on the array. Dangerous if you don't know what you are doing!
nuclear@0 903 // Doesn't work with non-aligned data!
nuclear@0 904 void BitStream::SetWriteOffset( const BitSize_t offset )
nuclear@0 905 {
nuclear@0 906 numberOfBitsUsed = offset;
nuclear@0 907 }
nuclear@0 908
nuclear@0 909 /*
nuclear@0 910 BitSize_t BitStream::GetWriteOffset( void ) const
nuclear@0 911 {
nuclear@0 912 return numberOfBitsUsed;
nuclear@0 913 }
nuclear@0 914
nuclear@0 915 // Returns the length in bits of the stream
nuclear@0 916 BitSize_t BitStream::GetNumberOfBitsUsed( void ) const
nuclear@0 917 {
nuclear@0 918 return GetWriteOffset();
nuclear@0 919 }
nuclear@0 920
nuclear@0 921 // Returns the length in bytes of the stream
nuclear@0 922 BitSize_t BitStream::GetNumberOfBytesUsed( void ) const
nuclear@0 923 {
nuclear@0 924 return BITS_TO_BYTES( numberOfBitsUsed );
nuclear@0 925 }
nuclear@0 926
nuclear@0 927 // Returns the number of bits into the stream that we have read
nuclear@0 928 BitSize_t BitStream::GetReadOffset( void ) const
nuclear@0 929 {
nuclear@0 930 return readOffset;
nuclear@0 931 }
nuclear@0 932
nuclear@0 933
nuclear@0 934 // Sets the read bit index
nuclear@0 935 void BitStream::SetReadOffset( const BitSize_t newReadOffset )
nuclear@0 936 {
nuclear@0 937 readOffset=newReadOffset;
nuclear@0 938 }
nuclear@0 939
nuclear@0 940 // Returns the number of bits left in the stream that haven't been read
nuclear@0 941 BitSize_t BitStream::GetNumberOfUnreadBits( void ) const
nuclear@0 942 {
nuclear@0 943 return numberOfBitsUsed - readOffset;
nuclear@0 944 }
nuclear@0 945 // Exposes the internal data
nuclear@0 946 unsigned char* BitStream::GetData( void ) const
nuclear@0 947 {
nuclear@0 948 return data;
nuclear@0 949 }
nuclear@0 950
nuclear@0 951 */
nuclear@0 952 // 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 953 void BitStream::AssertCopyData( void )
nuclear@0 954 {
nuclear@0 955 if ( copyData == false )
nuclear@0 956 {
nuclear@0 957 copyData = true;
nuclear@0 958
nuclear@0 959 if ( numberOfBitsAllocated > 0 )
nuclear@0 960 {
nuclear@0 961 unsigned char * newdata = ( unsigned char* ) OVR_ALLOC( (size_t) BITS_TO_BYTES( numberOfBitsAllocated ));
nuclear@0 962 #ifdef _DEBUG
nuclear@0 963
nuclear@0 964 OVR_ASSERT( data );
nuclear@0 965 #endif
nuclear@0 966
nuclear@0 967 memcpy( newdata, data, (size_t) BITS_TO_BYTES( numberOfBitsAllocated ) );
nuclear@0 968 data = newdata;
nuclear@0 969 }
nuclear@0 970
nuclear@0 971 else
nuclear@0 972 data = 0;
nuclear@0 973 }
nuclear@0 974 }
nuclear@0 975 bool BitStream::IsNetworkOrderInternal(void)
nuclear@0 976 {
nuclear@0 977 #if defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3)
nuclear@0 978 return true;
nuclear@0 979 #elif defined(SN_TARGET_PSP2)
nuclear@0 980 return false;
nuclear@0 981 #else
nuclear@0 982 static unsigned long htonlValue = htonl(12345);
nuclear@0 983 return htonlValue == 12345;
nuclear@0 984 #endif
nuclear@0 985 }
nuclear@0 986 void BitStream::ReverseBytes(unsigned char *inByteArray, unsigned char *inOutByteArray, const unsigned int length)
nuclear@0 987 {
nuclear@0 988 for (BitSize_t i=0; i < length; i++)
nuclear@0 989 inOutByteArray[i]=inByteArray[length-i-1];
nuclear@0 990 }
nuclear@0 991 void BitStream::ReverseBytesInPlace(unsigned char *inOutData,const unsigned int length)
nuclear@0 992 {
nuclear@0 993 unsigned char temp;
nuclear@0 994 BitSize_t i;
nuclear@0 995 for (i=0; i < (length>>1); i++)
nuclear@0 996 {
nuclear@0 997 temp = inOutData[i];
nuclear@0 998 inOutData[i]=inOutData[length-i-1];
nuclear@0 999 inOutData[length-i-1]=temp;
nuclear@0 1000 }
nuclear@0 1001 }
nuclear@0 1002
nuclear@0 1003 void BitStream::WriteAlignedVar8(const char *inByteArray)
nuclear@0 1004 {
nuclear@0 1005 OVR_ASSERT((numberOfBitsUsed&7)==0);
nuclear@0 1006 AddBitsAndReallocate(1*8);
nuclear@0 1007 data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[0];
nuclear@0 1008 numberOfBitsUsed+=1*8;
nuclear@0 1009 }
nuclear@0 1010 bool BitStream::ReadAlignedVar8(char *inOutByteArray)
nuclear@0 1011 {
nuclear@0 1012 OVR_ASSERT((readOffset&7)==0);
nuclear@0 1013 if ( readOffset + 1*8 > numberOfBitsUsed )
nuclear@0 1014 return false;
nuclear@0 1015
nuclear@0 1016 inOutByteArray[0] = data[( readOffset >> 3 ) + 0];
nuclear@0 1017 readOffset+=1*8;
nuclear@0 1018 return true;
nuclear@0 1019 }
nuclear@0 1020 void BitStream::WriteAlignedVar16(const char *inByteArray)
nuclear@0 1021 {
nuclear@0 1022 OVR_ASSERT((numberOfBitsUsed&7)==0);
nuclear@0 1023 AddBitsAndReallocate(2*8);
nuclear@0 1024 #ifndef __BITSTREAM_NATIVE_END
nuclear@0 1025 if (DoEndianSwap())
nuclear@0 1026 {
nuclear@0 1027 data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[1];
nuclear@0 1028 data[( numberOfBitsUsed >> 3 ) + 1] = inByteArray[0];
nuclear@0 1029 }
nuclear@0 1030 else
nuclear@0 1031 #endif
nuclear@0 1032 {
nuclear@0 1033 data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[0];
nuclear@0 1034 data[( numberOfBitsUsed >> 3 ) + 1] = inByteArray[1];
nuclear@0 1035 }
nuclear@0 1036
nuclear@0 1037 numberOfBitsUsed+=2*8;
nuclear@0 1038 }
nuclear@0 1039 bool BitStream::ReadAlignedVar16(char *inOutByteArray)
nuclear@0 1040 {
nuclear@0 1041 OVR_ASSERT((readOffset&7)==0);
nuclear@0 1042 if ( readOffset + 2*8 > numberOfBitsUsed )
nuclear@0 1043 return false;
nuclear@0 1044 #ifndef __BITSTREAM_NATIVE_END
nuclear@0 1045 if (DoEndianSwap())
nuclear@0 1046 {
nuclear@0 1047 inOutByteArray[0] = data[( readOffset >> 3 ) + 1];
nuclear@0 1048 inOutByteArray[1] = data[( readOffset >> 3 ) + 0];
nuclear@0 1049 }
nuclear@0 1050 else
nuclear@0 1051 #endif
nuclear@0 1052 {
nuclear@0 1053 inOutByteArray[0] = data[( readOffset >> 3 ) + 0];
nuclear@0 1054 inOutByteArray[1] = data[( readOffset >> 3 ) + 1];
nuclear@0 1055 }
nuclear@0 1056
nuclear@0 1057 readOffset+=2*8;
nuclear@0 1058 return true;
nuclear@0 1059 }
nuclear@0 1060 void BitStream::WriteAlignedVar32(const char *inByteArray)
nuclear@0 1061 {
nuclear@0 1062 OVR_ASSERT((numberOfBitsUsed&7)==0);
nuclear@0 1063 AddBitsAndReallocate(4*8);
nuclear@0 1064 #ifndef __BITSTREAM_NATIVE_END
nuclear@0 1065 if (DoEndianSwap())
nuclear@0 1066 {
nuclear@0 1067 data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[3];
nuclear@0 1068 data[( numberOfBitsUsed >> 3 ) + 1] = inByteArray[2];
nuclear@0 1069 data[( numberOfBitsUsed >> 3 ) + 2] = inByteArray[1];
nuclear@0 1070 data[( numberOfBitsUsed >> 3 ) + 3] = inByteArray[0];
nuclear@0 1071 }
nuclear@0 1072 else
nuclear@0 1073 #endif
nuclear@0 1074 {
nuclear@0 1075 data[( numberOfBitsUsed >> 3 ) + 0] = inByteArray[0];
nuclear@0 1076 data[( numberOfBitsUsed >> 3 ) + 1] = inByteArray[1];
nuclear@0 1077 data[( numberOfBitsUsed >> 3 ) + 2] = inByteArray[2];
nuclear@0 1078 data[( numberOfBitsUsed >> 3 ) + 3] = inByteArray[3];
nuclear@0 1079 }
nuclear@0 1080
nuclear@0 1081 numberOfBitsUsed+=4*8;
nuclear@0 1082 }
nuclear@0 1083 bool BitStream::ReadAlignedVar32(char *inOutByteArray)
nuclear@0 1084 {
nuclear@0 1085 OVR_ASSERT((readOffset&7)==0);
nuclear@0 1086 if ( readOffset + 4*8 > numberOfBitsUsed )
nuclear@0 1087 return false;
nuclear@0 1088 #ifndef __BITSTREAM_NATIVE_END
nuclear@0 1089 if (DoEndianSwap())
nuclear@0 1090 {
nuclear@0 1091 inOutByteArray[0] = data[( readOffset >> 3 ) + 3];
nuclear@0 1092 inOutByteArray[1] = data[( readOffset >> 3 ) + 2];
nuclear@0 1093 inOutByteArray[2] = data[( readOffset >> 3 ) + 1];
nuclear@0 1094 inOutByteArray[3] = data[( readOffset >> 3 ) + 0];
nuclear@0 1095 }
nuclear@0 1096 else
nuclear@0 1097 #endif
nuclear@0 1098 {
nuclear@0 1099 inOutByteArray[0] = data[( readOffset >> 3 ) + 0];
nuclear@0 1100 inOutByteArray[1] = data[( readOffset >> 3 ) + 1];
nuclear@0 1101 inOutByteArray[2] = data[( readOffset >> 3 ) + 2];
nuclear@0 1102 inOutByteArray[3] = data[( readOffset >> 3 ) + 3];
nuclear@0 1103 }
nuclear@0 1104
nuclear@0 1105 readOffset+=4*8;
nuclear@0 1106 return true;
nuclear@0 1107 }
nuclear@0 1108 bool BitStream::ReadFloat16( float &outFloat, float floatMin, float floatMax )
nuclear@0 1109 {
nuclear@0 1110 uint16_t percentile;
nuclear@0 1111 if (Read(percentile))
nuclear@0 1112 {
nuclear@0 1113 OVR_ASSERT(floatMax>floatMin);
nuclear@0 1114 outFloat = floatMin + ((float) percentile / 65535.0f) * (floatMax-floatMin);
nuclear@0 1115 if (outFloat<floatMin)
nuclear@0 1116 outFloat=floatMin;
nuclear@0 1117 else if (outFloat>floatMax)
nuclear@0 1118 outFloat=floatMax;
nuclear@0 1119 return true;
nuclear@0 1120 }
nuclear@0 1121 return false;
nuclear@0 1122 }
nuclear@0 1123 bool BitStream::SerializeFloat16(bool writeToBitstream, float &inOutFloat, float floatMin, float floatMax)
nuclear@0 1124 {
nuclear@0 1125 if (writeToBitstream)
nuclear@0 1126 WriteFloat16(inOutFloat, floatMin, floatMax);
nuclear@0 1127 else
nuclear@0 1128 return ReadFloat16(inOutFloat, floatMin, floatMax);
nuclear@0 1129 return true;
nuclear@0 1130 }
nuclear@0 1131 void BitStream::WriteFloat16( float inOutFloat, float floatMin, float floatMax )
nuclear@0 1132 {
nuclear@0 1133 OVR_ASSERT(floatMax>floatMin);
nuclear@0 1134 if (inOutFloat>floatMax+.001)
nuclear@0 1135 {
nuclear@0 1136 OVR_ASSERT(inOutFloat<=floatMax+.001);
nuclear@0 1137 }
nuclear@0 1138 if (inOutFloat<floatMin-.001)
nuclear@0 1139 {
nuclear@0 1140 OVR_ASSERT(inOutFloat>=floatMin-.001);
nuclear@0 1141 }
nuclear@0 1142 float percentile=65535.0f * (inOutFloat-floatMin)/(floatMax-floatMin);
nuclear@0 1143 if (percentile<0.0)
nuclear@0 1144 percentile=0.0;
nuclear@0 1145 if (percentile>65535.0f)
nuclear@0 1146 percentile=65535.0f;
nuclear@0 1147 Write((uint16_t)percentile);
nuclear@0 1148 }
nuclear@0 1149
nuclear@0 1150
nuclear@0 1151 }} // OVR::Net