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
|