C#版BitStream 1.0

根据C++版的改编,刚刚改完,估计使用会有问题,对于uint8处理的不好

关于使用:

1 BitStream bs = new BitStream( );

2             bs.WriteInt32( 123 );

3 

4             int a = bs.ReadInt32( );

非常简单

BitStream.cs

   1 public class BitStream

   2     {

   3 #if __BITSTREAM_BIG_END

   4 // Set up the read/write routines to produce Big-End network streams.

   5 private const int B16_1 = 0;

   6 private const int B16_0 = 1;

   7 

   8 private const int B32_3 = 0;

   9 private const int B32_2 = 1;

  10 private const int B32_1 = 2;

  11 private const int B32_0 = 3;

  12 

  13 private const int B64_7 = 0;

  14 private const int B64_6 = 1;

  15 private const int B64_5 = 2;

  16 private const int B64_4 = 3;

  17 private const int B64_3 = 4;

  18 private const int B64_2 = 5;

  19 private const int B64_1 = 6;

  20 private const int B64_0 = 7;

  21 

  22 #else

  23 // Default to producing Little-End network streams.

  24         private const int B16_1 = 1;

  25         private const int B16_0 = 0;

  26 

  27         private const int B32_3 = 3;

  28         private const int B32_2 = 2;

  29         private const int B32_1 = 1;

  30         private const int B32_0 = 0;

  31 

  32         private const int B64_7 = 7;

  33         private const int B64_6 = 6;

  34         private const int B64_5 = 5;

  35         private const int B64_4 = 4;

  36         private const int B64_3 = 3;

  37         private const int B64_2 = 2;

  38         private const int B64_1 = 1;

  39         private const int B64_0 = 0;

  40 #endif

  41         public const int BITSTREAM_STACK_ALLOCATION_SIZE = 2048;

  42 

  43         /// Default Constructor

  44         public static int BITS_TO_BYTES(int x)

  45         {

  46             return (((x) + 7) >> 3);

  47         }

  48 

  49         public static int BYTES_TO_BITS(int x)

  50         {

  51             return (x << 3);

  52         }

  53 

  54         /**

  55      * @brief Packets encoding and decoding facilities 

  56      * 

  57      * Helper class to encode and decode packets. 

  58      * 

  59      */

  60 

  61         /**

  62          * Default Constructor 

  63          */

  64 

  65         public BitStream()

  66         {

  67             numberOfBitsUsed = 0;

  68             //numberOfBitsAllocated = 32 * 8;

  69             numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE*8;

  70             readOffset = 0;

  71             //data = ( unsigned char* ) malloc( 32 );

  72             data = stackData;

  73             copyData = true;

  74         }

  75 

  76         /**

  77          * Preallocate some memory for the construction of the packet 

  78          * @param initialBytesToAllocate the amount of byte to pre-allocate. 

  79          */

  80 

  81         public BitStream(int initialBytesToAllocate)

  82         {

  83             numberOfBitsUsed = 0;

  84             readOffset = 0;

  85             if (initialBytesToAllocate <= BITSTREAM_STACK_ALLOCATION_SIZE)

  86             {

  87                 data = stackData;

  88                 numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE*8;

  89             }

  90             else

  91             {

  92                 data = new Byte[initialBytesToAllocate];

  93                 numberOfBitsAllocated = initialBytesToAllocate << 3;

  94             }

  95             copyData = true;

  96         }

  97 

  98         /**

  99          * Initialize the BitStream object using data from the network. 

 100          * Set _copyData to true if you want to make an internal copy of

 101          * the data you are passing. You can then Write and do all other

 102          * operations Set it to false if you want to just use a pointer to

 103          * the data you are passing, in order to save memory and speed.

 104          * You should only then do read operations.

 105          * @param _data An array of bytes.

 106          * @param lengthInBytes Size of the @em _data.

 107          * @param _copyData Does a copy of the input data.  

 108          */

 109 

 110         public BitStream(Byte[] _data, int lengthInBytes, bool _copyData)

 111         {

 112             numberOfBitsUsed = lengthInBytes << 3;

 113             readOffset = 0;

 114             copyData = _copyData;

 115             numberOfBitsAllocated = lengthInBytes << 3;

 116 

 117             if (copyData)

 118             {

 119                 if (lengthInBytes > 0)

 120                 {

 121                     if (lengthInBytes < BITSTREAM_STACK_ALLOCATION_SIZE)

 122                     {

 123                         data = stackData;

 124                         numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE << 3;

 125                     }

 126                     else

 127                     {

 128                         data = new Byte[lengthInBytes];

 129                     }

 130                     _data.CopyTo(data, 0);

 131                 }

 132                 else

 133                     data = null;

 134             }

 135             else

 136             {

 137                 data = _data;

 138                 numberOfBitsUsed = 0;

 139             }

 140         }

 141 

 142         //

 143         public BitStream(Byte[] _data, int lengthInBytes, int datasize)

 144         {

 145             numberOfBitsUsed = datasize << 3;

 146             readOffset = 0;

 147             numberOfBitsAllocated = lengthInBytes << 3;

 148             data = _data;

 149             copyData = false;

 150         }

 151 

 152         /**

 153          * Destructor 

 154          */

 155         //~BitStream(){}

 156         /**

 157          * Reset the bitstream for reuse

 158          */

 159 

 160         private void Reset()

 161         {

 162             if (numberOfBitsUsed > 0)

 163             {

 164                 //  memset(data, 0, BITS_TO_BYTES(numberOfBitsUsed));

 165             }

 166             // Don't free memory here for speed efficiency

 167             //free(data);  // Use realloc and free so we are more efficient than delete and new for resizing

 168             numberOfBitsUsed = 0;

 169             //numberOfBitsAllocated=8;

 170             readOffset = 0;

 171         }

 172 

 173         public void SetBuffer(Byte[] _data, int lengthInBytes, int datasize)

 174         {

 175             numberOfBitsUsed = datasize << 3;

 176             readOffset = 0;

 177             numberOfBitsAllocated = lengthInBytes << 3;

 178             data = _data;

 179             copyData = false;

 180         }

 181 

 182         public void ClearBuffer()

 183         {

 184             numberOfBitsUsed = 0;

 185             readOffset = 0;

 186             numberOfBitsAllocated = 0;

 187             data = null;

 188         }

 189 

 190         /**

 191          * Write the native types to the end of the buffer

 192          * without any compression mecanism. 

 193          * @param input The data 

 194          */

 195 

 196         public void WriteBool(bool input)

 197         {

 198             if (input)

 199                 WriteInt8(1);

 200             else

 201                 WriteInt8(0);

 202         }

 203 

 204         /**

 205          * Write the native types to the end of the buffer

 206          * without any compression mecanism. 

 207          * @param input The data 

 208          */

 209 

 210         public void WriteUInt8(Byte input)

 211         {

 212             WriteBits(BitConverter.GetBytes(input), sizeof (Byte)*8, true);

 213         }

 214 

 215         //

 216 

 217         /**

 218          * Write the native types to the end of the buffer

 219          * without any compression mecanism. 

 220          * @param input The data 

 221          */

 222 

 223         public void WriteInt8(SByte input)

 224         {

 225             WriteBits(BitConverter.GetBytes(input), sizeof (SByte)*8, true);

 226         }

 227 

 228         /**

 229          * Write the native types to the end of the buffer

 230          * without any compression mecanism. 

 231          * @param input The data 

 232          */

 233 

 234         public void WriteUInt16(UInt16 input)

 235         {

 236             var uint16w = new Byte[2];

 237             uint16w[B16_1] = (Byte) ((Byte) (input >> 8) & (0xff));

 238             uint16w[B16_0] = (Byte) (input & (0xff));

 239 

 240             WriteBits(uint16w, sizeof (UInt16)*8, true);

 241         }

 242 

 243         /**

 244          * Write the native types to the end of the buffer

 245          * without any compression mecanism. 

 246          * @param input The data 

 247          */

 248 

 249         public void WriteInt16(Int16 input)

 250         {

 251             var int16w = new Byte[2];

 252             int16w[B16_1] = (Byte) ((Byte) (input >> 8) & (0xff));

 253             int16w[B16_0] = (Byte) (input & (0xff));

 254 

 255             WriteBits(int16w, sizeof (Int16)*8, true);

 256         }

 257 

 258         /**

 259          * Write the native types to the end of the buffer

 260          * without any compression mecanism. 

 261          * @param input The data 

 262          */

 263 

 264         public void WriteUInt32(UInt32 input)

 265         {

 266             var uint32w = new Byte[4];

 267             uint32w[B32_3] = (Byte) ((Byte) (input >> 24) & (0x000000ff));

 268             uint32w[B32_2] = (Byte) ((Byte) (input >> 16) & (0x000000ff));

 269             uint32w[B32_1] = (Byte) ((Byte) (input >> 8) & (0x000000ff));

 270             uint32w[B32_0] = (Byte) ((input) & (0x000000ff));

 271 

 272             WriteBits(uint32w, sizeof (UInt32)*8, true);

 273         }

 274 

 275         /**

 276          * Write the native types to the end of the buffer

 277          * without any compression mecanism. 

 278          * @param input The data 

 279          */

 280 

 281         public void WriteInt32(int input)

 282         {

 283             var int32w = new Byte[4];

 284             int32w[B32_3] = (Byte) ((Byte) (input >> 24) & (0x000000ff));

 285             int32w[B32_2] = (Byte) ((Byte) (input >> 16) & (0x000000ff));

 286             int32w[B32_1] = (Byte) ((Byte) (input >> 8) & (0x000000ff));

 287             int32w[B32_0] = (Byte) ((input) & (0x000000ff));

 288 

 289             WriteBits(int32w, sizeof (int)*8, true);

 290         }

 291 

 292 //#if HAS_INT64

 293         /**

 294          * Write the native types to the end of the buffer

 295          * without any compression mecanism. 

 296          * @param input The data 

 297          */

 298 

 299         public void WriteUInt64(UInt64 input)

 300         {

 301             var uint64w = new Byte[8];

 302             uint64w[B64_7] = (Byte) ((input >> 56) & 0xff);

 303             uint64w[B64_6] = (Byte) ((input >> 48) & 0xff);

 304             uint64w[B64_5] = (Byte) ((input >> 40) & 0xff);

 305             uint64w[B64_4] = (Byte) ((input >> 32) & 0xff);

 306             uint64w[B64_3] = (Byte) ((input >> 24) & 0xff);

 307             uint64w[B64_2] = (Byte) ((input >> 16) & 0xff);

 308             uint64w[B64_1] = (Byte) ((input >> 8) & 0xff);

 309             uint64w[B64_0] = (Byte) (input & 0xff);

 310 

 311             WriteBits(uint64w, sizeof (UInt64)*8, true);

 312         }

 313 

 314         /**

 315          * Write the native types to the end of the buffer

 316          * without any compression mecanism. 

 317          * @param input The data 

 318          */

 319 

 320         public void WriteInt64(Int64 input)

 321         {

 322             var int64w = new Byte[8];

 323             int64w[B64_7] = (Byte) ((input >> 56) & 0xff);

 324             int64w[B64_6] = (Byte) ((input >> 48) & 0xff);

 325             int64w[B64_5] = (Byte) ((input >> 40) & 0xff);

 326             int64w[B64_4] = (Byte) ((input >> 32) & 0xff);

 327             int64w[B64_3] = (Byte) ((input >> 24) & 0xff);

 328             int64w[B64_2] = (Byte) ((input >> 16) & 0xff);

 329             int64w[B64_1] = (Byte) ((input >> 8) & 0xff);

 330             int64w[B64_0] = (Byte) (input & 0xff);

 331 

 332             WriteBits(int64w, sizeof (Int64)*8, true);

 333         }

 334 

 335 //#endif

 336 

 337         /**

 338          * Write the native types to the end of the buffer

 339          * without any compression mecanism. 

 340          * @param input The data 

 341          */

 342 

 343         public void WriteFloat(float input)

 344         {

 345             WriteBits(BitConverter.GetBytes(input), sizeof (float)*8, true);

 346         }

 347 

 348         /**

 349          * Write the native types to the end of the buffer

 350          * without any compression mechanism. 

 351          * @param input The data 

 352          */

 353 

 354         public void WriteDouble(double input)

 355         {

 356             WriteBits(BitConverter.GetBytes(input), sizeof (double)*8, true);

 357         }

 358 

 359         /**

 360          * Write an array or casted stream. It is supposed to

 361          * be raw data. It is also not possible to deal with endian problem 

 362          * @param input a byte buffer 

 363          * @param numberOfBytes the size of the byte buffer 

 364          */

 365 

 366         public void WriteBytes(Byte[] input, int numberOfBytes)

 367         {

 368             WriteBits(input, numberOfBytes*8, true);

 369         }

 370 

 371         /**

 372                  * write multi bytes string

 373                  * @param input

 374                  */

 375 

 376         public void WriteStr(string input)

 377         {

 378             var len = (short) input.Length;

 379             WriteUInt16((ushort) len);

 380             if (len > 0)

 381             {

 382                 WriteBytes(Encoding.Default.GetBytes(input), len);

 383             }

 384         }

 385 

 386         /// **

 387         //         * write standard string

 388         //         * @param input

 389         //         */

 390         //    public void WriteStr(

 391         //     const std::

 392         //     string 

 393         //&

 394         //     input 

 395         //){}

 396         /**

 397         * Copy from another bitstream

 398         * @bitStream the bitstream to copy from

 399         */

 400         public void WriteBS(BitStream bitStream)

 401         {

 402             WriteBits(bitStream.GetData(), bitStream.GetWriteOffset(), false);

 403         }

 404 

 405         /**

 406          * Write the native types with simple compression.

 407          * Best used with  negatives and positives close to 0

 408          * @param input The data.

 409          */

 410 

 411         public void WriteCompUInt8(Byte input)

 412         {

 413             WriteCompressed(BitConverter.GetBytes(input), sizeof (Byte)*8, true);

 414         }

 415 

 416         /**

 417          * Write the native types with simple compression.

 418          * Best used with  negatives and positives close to 0

 419          * @param input The data.

 420          */

 421 

 422         public void WriteCompInt8(SByte input)

 423         {

 424             WriteCompressed(BitConverter.GetBytes(input), sizeof (SByte)*8, false);

 425         }

 426 

 427         /**

 428          * Write the native types with simple compression.

 429          * Best used with  negatives and positives close to 0

 430          * @param input The data.

 431          */

 432 

 433         public void WriteCompUInt16(UInt16 input)

 434         {

 435             var uint16wc = new Byte[2];

 436             uint16wc[B16_1] = (byte) ((Byte) (input >> 8) & (0xff));

 437             uint16wc[B16_0] = (byte) (input & (0xff));

 438 

 439             WriteCompressed(uint16wc, sizeof (UInt16)*8, true);

 440         }

 441 

 442         /**

 443          * Write the native types with simple compression.

 444          * Best used with  negatives and positives close to 0

 445          * @param input The data.

 446          */

 447 

 448         public void WriteCompInt16(Int16 input)

 449         {

 450             var int16wc = new Byte[2];

 451             int16wc[B16_1] = (Byte) ((input >> 8) & (0xff));

 452             int16wc[B16_0] = (Byte) (input & (0xff));

 453 

 454             WriteCompressed(int16wc, sizeof (Int16)*8, false);

 455         }

 456 

 457         /**

 458          * Write the native types with simple compression.

 459          * Best used with  negatives and positives close to 0

 460          * @param input The data.

 461          */

 462 

 463         public void WriteCompUInt32(UInt32 input)

 464         {

 465             var uint32wc = new Byte[4];

 466             uint32wc[B32_3] = (Byte) ((input >> 24) & (0x000000ff));

 467             uint32wc[B32_2] = (Byte) ((input >> 16) & (0x000000ff));

 468             uint32wc[B32_1] = (Byte) ((input >> 8) & (0x000000ff));

 469             uint32wc[B32_0] = (Byte) ((input) & (0x000000ff));

 470 

 471             WriteCompressed(uint32wc, sizeof (UInt32)*8, true);

 472         }

 473 

 474         /**

 475          * Write the native types with simple compression.

 476          * Best used with  negatives and positives close to 0

 477          * @param input The data.

 478          */

 479 

 480         public void WriteCompInt32(int input)

 481         {

 482             var int32wc = new Byte[4];

 483             int32wc[B32_3] = (Byte) ((input >> 24) & (0x000000ff));

 484             int32wc[B32_2] = (Byte) ((input >> 16) & (0x000000ff));

 485             int32wc[B32_1] = (Byte) ((input >> 8) & (0x000000ff));

 486             int32wc[B32_0] = (Byte) ((input) & (0x000000ff));

 487 

 488             WriteCompressed(int32wc, sizeof (int)*8, false);

 489         }

 490 

 491 //#ifdef HAS_INT64

 492         /**

 493          * Write the native types with simple compression.

 494          * Best used with  negatives and positives close to 0

 495          * @param input The data.

 496          */

 497 

 498         public void WriteCompUInt64(UInt64 input)

 499         {

 500             var uint64wc = new Byte[8];

 501             uint64wc[B64_7] = (Byte) ((input >> 56) & 0xff);

 502             uint64wc[B64_6] = (Byte) ((input >> 48) & 0xff);

 503             uint64wc[B64_5] = (Byte) ((input >> 40) & 0xff);

 504             uint64wc[B64_4] = (Byte) ((input >> 32) & 0xff);

 505             uint64wc[B64_3] = (Byte) ((input >> 24) & 0xff);

 506             uint64wc[B64_2] = (Byte) ((input >> 16) & 0xff);

 507             uint64wc[B64_1] = (Byte) ((input >> 8) & 0xff);

 508             uint64wc[B64_0] = (Byte) (input & 0xff);

 509 

 510             WriteCompressed(uint64wc, sizeof (UInt64)*8, true);

 511         }

 512 

 513         /**

 514          * Write the native types with simple compression.

 515          * Best used with  negatives and positives close to 0

 516          * @param input The data.

 517          */

 518 

 519         public void WriteCompInt64(Int64 input)

 520         {

 521             var int64wc = new Byte[8];

 522             int64wc[B64_7] = (Byte) ((input >> 56) & 0xff);

 523             int64wc[B64_6] = (Byte) ((input >> 48) & 0xff);

 524             int64wc[B64_5] = (Byte) ((input >> 40) & 0xff);

 525             int64wc[B64_4] = (Byte) ((input >> 32) & 0xff);

 526             int64wc[B64_3] = (Byte) ((input >> 24) & 0xff);

 527             int64wc[B64_2] = (Byte) ((input >> 16) & 0xff);

 528             int64wc[B64_1] = (Byte) ((input >> 8) & 0xff);

 529             int64wc[B64_0] = (Byte) (input & 0xff);

 530 

 531             WriteCompressed(int64wc, sizeof (Int64)*8, false);

 532         }

 533 

 534 //#endif

 535         /**

 536          * Write the native types with simple compression.

 537          * Best used with  negatives and positives close to 0

 538          * @param input The data.

 539          */

 540 

 541         public void WriteCompFloat(float input)

 542         {

 543             WriteFloat(input);

 544         }

 545 

 546         /**

 547          * Write the native types with simple compression.

 548          * Best used with  negatives and positives close to 0

 549          * @param input The data.

 550          */

 551 

 552         public void WriteCompDouble(double input)

 553         {

 554             WriteDouble(input);

 555         }

 556 

 557         /**

 558          * Read the native types from the front of the buffer

 559          * @param output The readed value. 

 560          * @return true on success false otherwise. The result of a reading 

 561          * can only be wrong in the case we reach the end of the BitStream 

 562          * with some missing bits. 

 563          */

 564 

 565         public bool ReadBool()

 566         {

 567             if (readOffset + 1 > numberOfBitsUsed)

 568                 return false;

 569 

 570             //if (ReadBit()) // Check that bit

 571             if ((data[readOffset >> 3] & (0x80 >> (readOffset++%8))) != 0) // Is it faster to just write it out here?

 572                 return true;

 573 

 574             return false;

 575         }

 576 

 577         /**

 578          * Read the native types from the front of the buffer

 579          * @param output The readed value. 

 580          * @return true on success false otherwise. The result of a reading 

 581          * can only be wrong in the case we reach the end of the BitStream 

 582          * with some missing bits. 

 583          */

 584 

 585         public SByte ReadUInt8()

 586         {

 587             var x = new Byte[sizeof (SByte)];

 588             if (ReadBits(ref x, sizeof (SByte)*8))

 589             {

 590                 return (SByte) BitConverter.ToChar(x, 0);

 591             }

 592             return 0;

 593         }

 594 

 595         /**

 596          * Read the native types from the front of the buffer

 597          * @param output The readed value. 

 598          * @return true on success false otherwise. The result of a reading 

 599          * can only be wrong in the case we reach the end of the BitStream 

 600          * with some missing bits. 

 601          */

 602 

 603         public Byte ReadInt8()

 604         {

 605             var x = new Byte[sizeof (Byte)];

 606             if (ReadBits(ref x, sizeof (Byte)*8))

 607             {

 608                 return (Byte) BitConverter.ToChar(x, 0);

 609                 ;

 610             }

 611             return 0;

 612         }

 613 

 614         /**

 615          * Read the native types from the front of the buffer

 616          * @param output The readed value. 

 617          * @return true on success false otherwise. The result of a reading 

 618          * can only be wrong in the case we reach the end of the BitStream 

 619          * with some missing bits. 

 620          */

 621 

 622         public UInt16 ReadUInt16()

 623         {

 624             var uint16r = new Byte[2];

 625             if (ReadBits(ref uint16r, sizeof (UInt16)*8) != true)

 626                 return 0;

 627             return (ushort) ((uint16r[B16_1] << 8) | uint16r[B16_0]);

 628         }

 629 

 630         /**

 631          * Read the native types from the front of the buffer

 632          * @param output The readed value. 

 633          * @return true on success false otherwise. The result of a reading 

 634          * can only be wrong in the case we reach the end of the BitStream 

 635          * with some missing bits. 

 636          */

 637 

 638         public short ReadInt16()

 639         {

 640             var int16r = new Byte[2];

 641             if (ReadBits(ref int16r, sizeof (short)*8) != true)

 642                 return 0;

 643 

 644             return (short) ((int16r[B16_1] << 8) | int16r[B16_0]);

 645         }

 646 

 647         /**

 648          * Read the native types from the front of the buffer

 649          * @param output The readed value. 

 650          * @return true on success false otherwise. The result of a reading 

 651          * can only be wrong in the case we reach the end of the BitStream 

 652          * with some missing bits. 

 653          */

 654 

 655         public UInt32 ReadUInt32()

 656         {

 657             var uint32r = new Byte[4];

 658             if (ReadBits(ref uint32r, sizeof (UInt32)*8) != true)

 659                 return 0;

 660             return (((UInt32) uint32r[B32_3]) << 24) |

 661                    (((UInt32) uint32r[B32_2]) << 16) |

 662                    (((UInt32) uint32r[B32_1]) << 8) |

 663                    uint32r[B32_0];

 664         }

 665 

 666         /**

 667          * Read the native types from the front of the buffer

 668          * @param output The readed value. 

 669          * @return true on success false otherwise. The result of a reading 

 670          * can only be wrong in the case we reach the end of the BitStream 

 671          * with some missing bits. 

 672          */

 673 

 674         public int ReadInt32()

 675         {

 676             var int32r = new Byte[4];

 677             if (ReadBits(ref int32r, sizeof (int)*8) != true)

 678                 return 0;

 679             return (int32r[B32_3] << 24) |

 680                    (int32r[B32_2] << 16) |

 681                    (int32r[B32_1] << 8) |

 682                    int32r[B32_0];

 683         }

 684 

 685 

 686 //#ifdef HAS_INT64

 687         /**

 688          * Read the native types from the front of the buffer

 689          * @param output The readed value. 

 690          * @return true on success false otherwise. The result of a reading 

 691          * can only be wrong in the case we reach the end of the BitStream 

 692          * with some missing bits. 

 693          */

 694 

 695         public UInt64 ReadUInt64()

 696         {

 697             var uint64r = new Byte[8];

 698             if (ReadBits(ref uint64r, sizeof (UInt64)*8) != true)

 699                 return 0;

 700             return (((UInt64) uint64r[B64_7]) << 56) | (((UInt64) uint64r[B64_6]) << 48) |

 701                    (((UInt64) uint64r[B64_5]) << 40) | (((UInt64) uint64r[B64_4]) << 32) |

 702                    (((UInt64) uint64r[B64_3]) << 24) | (((UInt64) uint64r[B64_2]) << 16) |

 703                    (((UInt64) uint64r[B64_1]) << 8) | uint64r[B64_0];

 704         }

 705 

 706         /**

 707          * Read the native types from the front of the buffer

 708          * @param output The readed value. 

 709          * @return true on success false otherwise. The result of a reading 

 710          * can only be wrong in the case we reach the end of the BitStream 

 711          * with some missing bits. 

 712          */

 713 

 714         public Int64 ReadInt64()

 715         {

 716             var int64r = new Byte[8];

 717             if (ReadBits(ref int64r, sizeof (Int64)*8) != true)

 718                 return 0;

 719             return (Int64) ((((UInt64) int64r[B64_7]) << 56) | (((UInt64) int64r[B64_6]) << 48) |

 720                             (((UInt64) int64r[B64_5]) << 40) | (((UInt64) int64r[B64_4]) << 32) |

 721                             (((UInt64) int64r[B64_3]) << 24) | (((UInt64) int64r[B64_2]) << 16) |

 722                             (((UInt64) int64r[B64_1]) << 8) | int64r[B64_0]);

 723         }

 724 

 725 //#endif

 726         /**

 727          * Read the native types from the front of the buffer

 728          * @param output The readed value. 

 729          * @return true on success false otherwise. The result of a reading 

 730          * can only be wrong in the case we reach the end of the BitStream 

 731          * with some missing bits. 

 732          */

 733 

 734         public float ReadFloat()

 735         {

 736             uint val = ReadUInt32();

 737             return BitConverter.ToSingle(BitConverter.GetBytes(val), 0);

 738         }

 739 

 740         /**

 741          * Read the native types from the front of the buffer

 742          * @param output The readed value. 

 743          * @return true on success false otherwise. The result of a reading 

 744          * can only be wrong in the case we reach the end of the BitStream 

 745          * with some missing bits. 

 746          */

 747 

 748         public double ReadDouble()

 749         {

 750             UInt64 val = ReadUInt64();

 751             return BitConverter.ToDouble(BitConverter.GetBytes(val), 0);

 752         }

 753 

 754         /**

 755          * Read an array or casted stream of byte. The array

 756          * is raw data. There is no automatic conversion on

 757          * big endian arch

 758          * @param output The result byte array. It should be larger than @em numberOfBytes. 

 759          * @param numberOfBytes The number of byte to read

 760          * @return true on success false if there is some missing bytes. 

 761          */

 762 

 763         public bool ReadBytes(ref Byte[] output, int numberOfBytes)

 764         {

 765             return ReadBits(ref output, numberOfBytes*8);

 766         }

 767 

 768         /**

 769                  * Read standard string

 770                  * @return

 771                  */

 772 

 773         public string ReadStr()

 774         {

 775             string strs;

 776             ushort len = ReadUInt16();

 777             if (len > 0)

 778             {

 779                 var str = new Byte[len + 1];

 780                 if (ReadBytes(ref str, len))

 781                 {

 782                     str[len] = 10;

 783                     strs = Encoding.Default.GetString(str);

 784                     return strs;

 785                 }

 786             }

 787             return string.Empty;

 788         }

 789 

 790         /**

 791          * Read the types you wrote with WriteCompressed

 792          * @param output The read value

 793          * @return true on success, false on not enough data to read

 794          */

 795 

 796         public SByte ReadCompUInt8()

 797         {

 798             var uint8rc = new Byte[sizeof (Byte)];

 799 

 800             if (ReadCompressed(ref uint8rc, sizeof (Byte)*8, true))

 801             {

 802                 return (SByte) uint8rc[0];

 803             }

 804             return 0;

 805         }

 806 

 807         /**

 808          * Read the types you wrote with WriteCompressed

 809          * @param output The read value

 810          * @return true on success, false on not enough data to read

 811          */

 812 

 813         public Byte ReadCompInt8()

 814         {

 815             var uint8rc = new Byte[sizeof (Byte)];

 816 

 817             if (ReadCompressed(ref uint8rc, sizeof (Byte)*8, true))

 818             {

 819                 return uint8rc[0];

 820             }

 821             return 0;

 822         }

 823 

 824         /**

 825          * Read the types you wrote with WriteCompressed

 826          * @param output The read value

 827          * @return true on success, false on not enough data to read

 828          */

 829 

 830         public UInt16 ReadCompUInt16()

 831         {

 832             var uint16rc = new Byte[2];

 833             if (ReadCompressed(ref uint16rc, sizeof (UInt16)*8, true) != true)

 834                 return 0;

 835             return (ushort) ((uint16rc[B16_1] << 8) |

 836                              uint16rc[B16_0]);

 837         }

 838 

 839         /**

 840          * Read the types you wrote with WriteCompressed

 841          * @param output The read value

 842          * @return true on success, false on not enough data to read

 843          */

 844 

 845         public short ReadCompInt16()

 846         {

 847             var int16rc = new byte[2];

 848             if (ReadCompressed(ref int16rc, sizeof (short)*8, false) != true) return 0;

 849             return (short) ((int16rc[B16_1] << 8) | int16rc[B16_0]);

 850         }

 851 

 852         /**

 853          * Read the types you wrote with WriteCompressed

 854          * @param output The read value

 855          * @return true on success, false on not enough data to read

 856          */

 857 

 858         public UInt32 ReadCompUInt32()

 859         {

 860             var uint32rc = new Byte[4];

 861             if (ReadCompressed(ref uint32rc, sizeof (UInt32)*8, true) != true)

 862                 return 0;

 863             return (((UInt32) uint32rc[B32_3]) << 24) |

 864                    (((UInt32) uint32rc[B32_2]) << 16) |

 865                    (((UInt32) uint32rc[B32_1]) << 8) |

 866                    uint32rc[B32_0];

 867         }

 868 

 869         /**

 870          * Read the types you wrote with WriteCompressed

 871          * @param output The read value

 872          * @return true on success, false on not enough data to read

 873          */

 874 

 875         public int ReadCompInt32()

 876         {

 877             var int32rc = new Byte[4];

 878             if (ReadCompressed(ref int32rc, sizeof (int)*8, false) != true)

 879                 return 0;

 880             return (int) ((((UInt32) int32rc[B32_3]) << 24) |

 881                           (((UInt32) int32rc[B32_2]) << 16) |

 882                           (((UInt32) int32rc[B32_1]) << 8) |

 883                           int32rc[B32_0]);

 884         }

 885 

 886 //#ifdef HAS_INT64

 887         /**

 888          * Read the types you wrote with WriteCompressed

 889          * @param output The read value

 890          * @return true on success, false on not enough data to read

 891          */

 892 

 893         public UInt64 ReadCompUInt64()

 894         {

 895             var uint64rc = new Byte[8];

 896             if (ReadCompressed(ref uint64rc, sizeof (UInt64)*8, true) != true)

 897                 return 0;

 898             return (((UInt64) uint64rc[B64_7]) << 56) | (((UInt64) uint64rc[B64_6]) << 48) |

 899                    (((UInt64) uint64rc[B64_5]) << 40) | (((UInt64) uint64rc[B64_4]) << 32) |

 900                    (((UInt64) uint64rc[B64_3]) << 24) | (((UInt64) uint64rc[B64_2]) << 16) |

 901                    (((UInt64) uint64rc[B64_1]) << 8) | uint64rc[B64_0];

 902         }

 903 

 904         /**

 905          * Read the types you wrote with WriteCompressed

 906          * @param output The read value

 907          * @return true on success, false on not enough data to read

 908          */

 909 

 910         public Int64 ReadCompInt64()

 911         {

 912             var int64rc = new Byte[8];

 913             if (ReadCompressed(ref int64rc, sizeof (Int64)*8, false) != true)

 914                 return 0;

 915             return (Int64) ((((UInt64) int64rc[B64_7]) << 56) | (((UInt64) int64rc[B64_6]) << 48) |

 916                             (((UInt64) int64rc[B64_5]) << 40) | (((UInt64) int64rc[B64_4]) << 32) |

 917                             (((UInt64) int64rc[B64_3]) << 24) | (((UInt64) int64rc[B64_2]) << 16) |

 918                             (((UInt64) int64rc[B64_1]) << 8) | int64rc[B64_0]);

 919         }

 920 

 921 //#endif

 922         /**

 923          * Read the types you wrote with WriteCompressed

 924          * @param output The read value

 925          * @return true on success, false on not enough data to read

 926          */

 927 

 928         public float ReadCompFloat()

 929         {

 930             return ReadFloat();

 931         }

 932 

 933         /**

 934          * Read the types you wrote with WriteCompressed

 935          * @param output The read value

 936          * @return true on success, false on not enough data to read

 937          */

 938 

 939         public double ReadCompDouble()

 940         {

 941             return ReadDouble();

 942         }

 943 

 944         /**

 945         * Read a normalized 3D vector, using (at most) 4 bytes + 3 bits instead of 12 bytes.  Will further compress y or z axis aligned vectors.

 946         * Accurate to 1/32767.5.

 947         * @param x x

 948         * @param y y

 949         * @param z z

 950         */

 951 

 952 

 953         /**

 954          * This is good to call when you are done with the stream to make

 955          * sure you didn't leave any data left over void

 956          */

 957 

 958         public void AssertStreamEmpty()

 959         {

 960             if (readOffset == numberOfBitsUsed)

 961                 throw new Exception();

 962         }

 963 

 964         // * print to the standard output the state of the stream bit by bit 

 965         // */

 966 

 967         //public void PrintBits()

 968         //{

 969 

 970         //}

 971         /// **

 972         /// **

 973         // * Ignore data we don't intend to read

 974         // * @param numberOfBits The number of bits to ignore

 975         // */

 976         public void IgnoreBits(int numberOfBits)

 977         {

 978             readOffset += numberOfBits;

 979         }

 980 

 981         /**

 982          * Move the write pointer to a position on the array.  

 983          * @param offset the offset from the start of the array. 

 984          * @attention 

 985          * Dangerous if you don't know what you are doing!

 986          *

 987          */

 988 

 989         public void SetWriteOffset(int offset)

 990         {

 991             numberOfBitsUsed = offset;

 992         }

 993 

 994         /**

 995          * Returns the length in bits of the stream

 996          */

 997 

 998         public int GetWriteOffset()

 999         {

1000             return numberOfBitsUsed;

1001         }

1002 

1003         /**

1004          * Returns the length in bytes of the stream

1005          */

1006 

1007         public int GetNumberOfBytesUsed()

1008         {

1009             return BITS_TO_BYTES(numberOfBitsUsed);

1010         }

1011 

1012         public int GetNumberOfBytesRead()

1013         {

1014             return BITS_TO_BYTES(readOffset);

1015         }

1016 

1017         /**

1018                  * Move the read pointer to a position on the array.

1019                  * @param offset

1020                  */

1021 

1022         public void SetReadOffset(int offset)

1023         {

1024             readOffset = offset;

1025         }

1026 

1027         public void SetByteReadOffSet(int offset)

1028         {

1029             readOffset = BYTES_TO_BITS(offset);

1030         }

1031 

1032         /**

1033          * Returns the number of bits into the stream that we have read

1034          */

1035 

1036         public int GetReadOffset()

1037         {

1038             return readOffset;

1039         }

1040 

1041 

1042         /**

1043          * Returns the number of bits left in the stream that haven't been read

1044          */

1045 

1046         public int GetNumberOfUnreadBits()

1047         {

1048             return numberOfBitsUsed - readOffset;

1049         }

1050 

1051         /**

1052          * Makes a copy of the internal data for you Data will point to

1053          * the stream. Returns the length in bits of the stream. Partial

1054          * bytes are left aligned 

1055          * @param _data the resulting byte copy of the internal state. 

1056          */

1057 

1058         public int CopyData(Byte[] _data)

1059         {

1060             _data = new Byte[BITS_TO_BYTES(numberOfBitsUsed)];

1061             data.CopyTo(_data, 0);

1062             return numberOfBitsUsed;

1063         }

1064 

1065         /**

1066          * Set the stream to some initial data.  For internal use

1067          * Partial bytes are left aligned

1068          * @param input The data

1069          * @param numberOfBits the number of bits set in the data buffer 

1070          */

1071 

1072         public void SetData(Byte[] input, int numberOfBits)

1073         {

1074             if (numberOfBits <= 0)

1075                 return;

1076             AddBitsAndReallocate(numberOfBits);

1077             input.CopyTo(data, 0);

1078             numberOfBitsUsed = numberOfBits;

1079         }

1080 

1081         /**

1082          * Exposes the internal data.

1083          * Partial bytes are left aligned.

1084          * @return A pointer to the internal state 

1085          */

1086 

1087         public Byte[] GetData()

1088         {

1089             return data;

1090         }

1091 

1092         /**

1093          * Write numberToWrite bits from the input source Right aligned

1094          * data means in the case of a partial byte, the bits are aligned

1095          * from the right (bit 0) rather than the left (as in the normal

1096          * internal representation) You would set this to true when

1097          * writing user data, and false when copying bitstream data, such

1098          * as writing one bitstream to another

1099          * @param input The data 

1100          * @param numberOfBitsToWrite The number of bits to write 

1101          * @param rightAlignedBits if true data will be right aligned 

1102          */

1103 

1104         public void WriteBits(Byte[] input, int numberOfBitsToWrite, bool rightAlignedBits = true)

1105         {

1106             AddBitsAndReallocate(numberOfBitsToWrite);

1107             int offset = 0;

1108             Byte dataByte;

1109             int numberOfBitsUsedMod8;

1110 

1111             numberOfBitsUsedMod8 = numberOfBitsUsed%8;

1112 

1113             // Faster to put the while at the top surprisingly enough

1114             while (numberOfBitsToWrite > 0)

1115                 //do

1116             {

1117                 dataByte = input[offset]; //*( input + offset );

1118 

1119                 if (numberOfBitsToWrite < 8 && rightAlignedBits)

1120                     // 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)

1121                     dataByte <<= 8 - numberOfBitsToWrite;

1122                 // shift left to get the bits on the left, as in our internal representation

1123 

1124                 // Writing to a new byte each time

1125                 if (numberOfBitsUsedMod8 == 0)

1126                     data[numberOfBitsUsed >> 3] = dataByte; //*( data + ( numberOfBitsUsed >> 3 ) ) = dataByte;

1127                 else

1128                 {

1129                     // Copy over the new data.

1130                     data[numberOfBitsUsed >> 3] |= (Byte) (dataByte >> (numberOfBitsUsedMod8));

1131                     //*( data + ( numberOfBitsUsed >> 3 ) ) |= dataByte >> ( numberOfBitsUsedMod8 ); // First half

1132 

1133                     if (8 - (numberOfBitsUsedMod8) < 8 && 8 - (numberOfBitsUsedMod8) < numberOfBitsToWrite)

1134                         // If we didn't write it all out in the first half (8 - (numberOfBitsUsed%8) is the number we wrote in the first half)

1135                     {

1136                         //*( data + ( numberOfBitsUsed >> 3 ) + 1 ) = (unsigned char) ( dataByte << ( 8 - ( numberOfBitsUsedMod8 ) ) ); // Second half (overlaps byte boundary)

1137                         data[(numberOfBitsUsed >> 3) + 1] = (Byte) (dataByte << (8 - (numberOfBitsUsedMod8)));

1138                     }

1139                 }

1140 

1141                 if (numberOfBitsToWrite >= 8)

1142                     numberOfBitsUsed += 8;

1143                 else

1144                     numberOfBitsUsed += numberOfBitsToWrite;

1145 

1146                 numberOfBitsToWrite -= 8;

1147 

1148                 offset++;

1149             }

1150         }

1151 

1152         /**

1153          * Align the bitstream to the byte boundary and then write the

1154          * specified number of bits.  This is faster than WriteBits but

1155          * wastes the bits to do the alignment and requires you to call

1156          * ReadAlignedBits at the corresponding read position.

1157          * @param input The data

1158          * @param numberOfBytesToWrite The size of data. 

1159          */

1160 

1161         public void WriteAlignedBytes(Byte[] input, int numberOfBytesToWrite)

1162         {

1163             AlignWriteToByteBoundary();

1164             // Allocate enough memory to hold everything

1165             AddBitsAndReallocate(numberOfBytesToWrite << 3);

1166 

1167             // Write the data

1168             //memcpy( data + ( numberOfBitsUsed >> 3 ), input, numberOfBytesToWrite );

1169             input.CopyTo(data, (numberOfBitsUsed >> 3));

1170             numberOfBitsUsed += numberOfBytesToWrite << 3;

1171         }

1172 

1173         /**

1174          * Read bits, starting at the next aligned bits. Note that the

1175          * modulus 8 starting offset of the sequence must be the same as

1176          * was used with WriteBits. This will be a problem with packet

1177          * coalescence unless you byte align the coalesced packets.

1178          * @param output The byte array larger than @em numberOfBytesToRead

1179          * @param numberOfBytesToRead The number of byte to read from the internal state 

1180          * @return true if there is enough byte. 

1181          */

1182 

1183         public bool ReadAlignedBytes(out Byte[] output, int numberOfBytesToRead)

1184         {

1185             if (numberOfBytesToRead <= 0)

1186             {

1187                 output = null;

1188                 return false;

1189             }

1190             // Byte align

1191             AlignReadToByteBoundary();

1192             if (readOffset + (numberOfBytesToRead << 3) > numberOfBitsUsed)

1193             {

1194                 output = null;

1195                 return false;

1196             }

1197 

1198             // Write the data

1199             //memcpy( output, data + ( readOffset >> 3 ), numberOfBytesToRead );

1200             output = new byte[] {};

1201             Array.Copy(data, readOffset >> 3, output, 0, numberOfBytesToRead);

1202             readOffset += numberOfBytesToRead << 3;

1203             return true;

1204         }

1205 

1206         /**

1207          * Align the next write and/or read to a byte boundary.  This can

1208          * be used to 'waste' bits to byte align for efficiency reasons It

1209          * can also be used to force coalesced bitstreams to start on byte

1210          * boundaries so so WriteAlignedBits and ReadAlignedBits both

1211          * calculate the same offset when aligning.

1212          */

1213 

1214         public void AlignWriteToByteBoundary()

1215         {

1216             if (numberOfBitsUsed > 0)

1217                 numberOfBitsUsed += 8 - ((numberOfBitsUsed - 1)%8 + 1);

1218         }

1219 

1220         /**

1221          * Align the next write and/or read to a byte boundary.  This can

1222          * be used to 'waste' bits to byte align for efficiency reasons It

1223          * can also be used to force coalesced bitstreams to start on byte

1224          * boundaries so so WriteAlignedBits and ReadAlignedBits both

1225          * calculate the same offset when aligning.

1226          */

1227 

1228         public void AlignReadToByteBoundary()

1229         {

1230             if (readOffset > 0)

1231                 readOffset += 8 - ((readOffset - 1)%8 + 1);

1232         }

1233 

1234         /**

1235          * Read numberOfBitsToRead bits to the output source

1236          * alignBitsToRight should be set to true to convert internal

1237          * bitstream data to userdata It should be false if you used

1238          * WriteBits with rightAlignedBits false

1239          * @param output The resulting bits array 

1240          * @param numberOfBitsToRead The number of bits to read 

1241          * @param alignsBitsToRight if true bits will be right aligned. 

1242          * @return true if there is enough bits to read 

1243          */

1244 

1245         public bool ReadBits(ref Byte[] output, int numberOfBitsToRead, bool alignBitsToRight = true)

1246         {

1247             if (readOffset + numberOfBitsToRead > numberOfBitsUsed)

1248             {

1249                 output = null;

1250                 return false;

1251             }

1252 

1253             int readOffsetMod8;

1254             int offset = 0;

1255             //memset( output, 0, BITS_TO_BYTES( numberOfBitsToRead ) );

1256             readOffsetMod8 = readOffset%8;

1257 

1258             // do

1259             // Faster to put the while at the top surprisingly enough

1260             while (numberOfBitsToRead > 0)

1261             {

1262                 //*( output + offset ) |= *( data + ( readOffset >> 3 ) ) << ( readOffsetMod8 ); // First half

1263                 output[offset] |= (Byte) (data[readOffset >> 3] << (readOffsetMod8));

1264                 if (readOffsetMod8 > 0 && numberOfBitsToRead > 8 - (readOffsetMod8))

1265                     // If we have a second half, we didn't read enough bytes in the first half

1266                     //*(output + offset) |= *(data + (readOffset >> 3) + 1) >> (8 - (readOffsetMod8));

1267                     output[offset] |= (Byte) (data[(readOffset >> 3) + 1] >> (8 - (readOffsetMod8)));

1268                 // Second half (overlaps byte boundary)

1269 

1270                 numberOfBitsToRead -= 8;

1271 

1272                 if (numberOfBitsToRead < 0)

1273                     // Reading a partial byte for the last byte, shift right so the data is aligned on the right

1274                 {

1275                     if (alignBitsToRight)

1276                         output[offset] >>= -numberOfBitsToRead;

1277                     //*(output + offset) >>= -numberOfBitsToRead;

1278 

1279                     readOffset += 8 + numberOfBitsToRead;

1280                 }

1281                 else

1282                     readOffset += 8;

1283 

1284                 offset++;

1285             }

1286             return true;

1287         }

1288 

1289         /**

1290          * --- Low level functions --- 

1291          * These are for when you want to deal

1292          * with bits and don't care about type checking 

1293          * Write a 0  

1294          */

1295 

1296         public void Write0()

1297         {

1298             AddBitsAndReallocate(1);

1299 

1300             // New bytes need to be zeroed

1301 

1302             if ((numberOfBitsUsed%8) == 0)

1303                 data[numberOfBitsUsed >> 3] = 0;

1304 

1305             numberOfBitsUsed++;

1306         }

1307 

1308         /**

1309          * --- Low level functions --- 

1310          * These are for when you want to deal

1311          * with bits and don't care about type checking 

1312          * Write a 1 

1313          */

1314 

1315         public void Write1()

1316         {

1317             AddBitsAndReallocate(1);

1318 

1319             int numberOfBitsMod8 = numberOfBitsUsed%8;

1320 

1321             if (numberOfBitsMod8 == 0)

1322                 data[numberOfBitsUsed >> 3] = 0x80;

1323             else

1324                 data[numberOfBitsUsed >> 3] |= (Byte) (0x80 >> (numberOfBitsMod8));

1325             //data[ numberOfBitsUsed >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1

1326 

1327             numberOfBitsUsed++;

1328         }

1329 

1330         /**

1331          * --- Low level functions --- 

1332          * These are for when you want to deal

1333          * with bits and don't care about type checking 

1334          * Reads 1 bit and returns true if that bit is 1 and false if it is 0

1335          */

1336 

1337         public bool ReadBit()

1338         {

1339             return (data[readOffset >> 3] & (0x80 >> (readOffset++%8))) == 1;

1340         }

1341 

1342         /**

1343          * If we used the constructor version with copy data off, this

1344          * makes sure it is set to on and the data pointed to is copied.

1345          */

1346 

1347         public void AssertCopyData()

1348         {

1349             if (copyData == false)

1350             {

1351                 copyData = true;

1352 

1353                 if (numberOfBitsAllocated > 0)

1354                 {

1355                     var newdata = new Byte[BITS_TO_BYTES(numberOfBitsAllocated)];

1356                     data.CopyTo(newdata, 0);

1357                     data = newdata;

1358                 }

1359                 else

1360                     data = null;

1361             }

1362         }

1363 

1364         /**

1365          * Use this if you pass a pointer copy to the constructor

1366          * (_copyData==false) and want to overallocate to prevent

1367          * reallocation

1368          */

1369 

1370         public void SetNumberOfBitsAllocated(int lengthInBits)

1371         {

1372             numberOfBitsAllocated = lengthInBits;

1373         }

1374 

1375 

1376         /**

1377          * Assume the input source points to a native type, compress and write it.

1378          */

1379 

1380         public void WriteCompressed(Byte[] input, int size, bool unsignedData)

1381         {

1382             int currentByte = (size >> 3) - 1; // PCs

1383 

1384             Byte byteMatch;

1385 

1386             if (unsignedData)

1387             {

1388                 byteMatch = 0;

1389             }

1390 

1391             else

1392             {

1393                 byteMatch = 0xFF;

1394             }

1395 

1396             // Write upper bytes with a single 1

1397             // 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

1398             while (currentByte > 0)

1399             {

1400                 if (input[currentByte] == byteMatch)

1401                     // If high byte is byteMatch (0 of 0xff) then it would have the same value shifted

1402                 {

1403                     bool b = true;

1404                     WriteBool(b);

1405                 }

1406                 else

1407                 {

1408                     // Write the remainder of the data after writing 0

1409                     bool b = false;

1410                     WriteBool(b);

1411 

1412                     WriteBits(input, (currentByte + 1) << 3, true);

1413                     //  currentByte--;

1414 

1415 

1416                     return;

1417                 }

1418 

1419                 currentByte--;

1420             }

1421 

1422             // 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.

1423             if ((unsignedData && (((input[currentByte])) & 0xF0) == 0x00) ||

1424                 (unsignedData == false && (((input[currentByte])) & 0xF0) == 0xF0))

1425             {

1426                 bool b = true;

1427                 WriteBool(b);

1428                 var bs = new byte[4];

1429                 Array.Copy(input, currentByte, bs, 0, 4);

1430                 WriteBits(bs, 4, true);

1431             }

1432 

1433             else

1434             {

1435                 bool b = false;

1436                 WriteBool(b);

1437                 var bs = new byte[9];

1438                 Array.Copy(input, currentByte, bs, 0, 9);

1439                 WriteBits(bs, 8, true);

1440             }

1441         }

1442 

1443         /**

1444          * Assume the input source points to a compressed native type.

1445          * Decompress and read it.

1446          */

1447 

1448         public bool ReadCompressed(ref Byte[] output, int size, bool unsignedData)

1449         {

1450             int currentByte = (size >> 3) - 1;

1451 

1452 

1453             Byte byteMatch, halfByteMatch;

1454 

1455             if (unsignedData)

1456             {

1457                 byteMatch = 0;

1458                 halfByteMatch = 0;

1459             }

1460 

1461             else

1462             {

1463                 byteMatch = 0xFF;

1464                 halfByteMatch = 0xF0;

1465             }

1466 

1467             // Upper bytes are specified with a single 1 if they match byteMatch

1468             // 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

1469             while (currentByte > 0)

1470             {

1471                 // If we read a 1 then the data is byteMatch.

1472 

1473                 bool b = ReadBool();

1474 

1475                 if (b) // Check that bit

1476                 {

1477                     output[currentByte] = byteMatch;

1478                     currentByte--;

1479                 }

1480                 else

1481                 {

1482                     // Read the rest of the bytes

1483 

1484                     if (ReadBits(ref output, (currentByte + 1) << 3) == false)

1485                         return false;

1486 

1487                     return true;

1488                 }

1489             }

1490             return false;

1491         }

1492 

1493         /**

1494          * Reallocates (if necessary) in preparation of writing

1495          * numberOfBitsToWrite 

1496          */

1497 

1498         public void AddBitsAndReallocate(int numberOfBitsToWrite)

1499         {

1500             if (numberOfBitsToWrite <= 0)

1501                 return;

1502 

1503             int newNumberOfBitsAllocated = numberOfBitsToWrite + numberOfBitsUsed;

1504 

1505             if (numberOfBitsToWrite + numberOfBitsUsed > 0 &&

1506                 ((numberOfBitsAllocated - 1) >> 3) < ((newNumberOfBitsAllocated - 1) >> 3))

1507                 // If we need to allocate 1 or more new bytes

1508             {

1509                 // Less memory efficient but saves on news and deletes

1510                 newNumberOfBitsAllocated = (numberOfBitsToWrite + numberOfBitsUsed)*2;

1511 //        int newByteOffset = BITS_TO_BYTES( numberOfBitsAllocated );

1512                 // Use realloc and free so we are more efficient than delete and new for resizing

1513                 int amountToAllocate = BITS_TO_BYTES(newNumberOfBitsAllocated);

1514                 if (data == stackData)

1515                 {

1516                     if (amountToAllocate > BITSTREAM_STACK_ALLOCATION_SIZE)

1517                     {

1518                         data = new byte[amountToAllocate];

1519 

1520                         // need to copy the stack data over to our new memory area too

1521                         stackData.CopyTo(data, 0);

1522                     }

1523                 }

1524                 else

1525                 {

1526                     data = data.Concat(new Byte[amountToAllocate - data.Length]).ToArray();

1527                     //data = ( unsigned char* ) realloc( data, amountToAllocate );

1528                 }

1529                 //  memset(data+newByteOffset, 0,  ((newNumberOfBitsAllocated-1)>>3) - ((numberOfBitsAllocated-1)>>3)); // Set the new data block to 0

1530             }

1531 

1532             if (newNumberOfBitsAllocated > numberOfBitsAllocated)

1533                 numberOfBitsAllocated = newNumberOfBitsAllocated;

1534         }

1535 

1536         /**

1537          * Number of bits currently used 

1538          */

1539         private int numberOfBitsUsed;

1540         /**

1541          * Number of bits currently allocated 

1542          */

1543 

1544         private

1545             int numberOfBitsAllocated;

1546 

1547         /**

1548          * Current readOffset 

1549          */

1550 

1551         private

1552             int readOffset;

1553 

1554         /**

1555          * array of byte storing the data.  Points to stackData or if is bigger than that then is allocated

1556          */

1557 

1558         private

1559             Byte[] data;

1560 

1561         /**

1562          * true if the internal buffer is copy of the data passed to the

1563          * constructor

1564          */

1565 

1566         private

1567             bool copyData;

1568 

1569         private Byte[] stackData = new Byte[BITSTREAM_STACK_ALLOCATION_SIZE];

1570     }

 

const 

你可能感兴趣的:(Stream)