ovr_sdk

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