根据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 static readonly int B16_1 = 0; 6 private static readonly int B16_0 = 1; 7 8 private static readonly int B32_3 = 0; 9 private static readonly int B32_2 = 1; 10 private static readonly int B32_1 = 2; 11 private static readonly int B32_0 = 3; 12 13 private static readonly int B64_7 = 0; 14 private static readonly int B64_6 = 1; 15 private static readonly int B64_5 = 2; 16 private static readonly int B64_4 = 3; 17 private static readonly int B64_3 = 4; 18 private static readonly int B64_2 = 5; 19 private static readonly int B64_1 = 6; 20 private static readonly int B64_0 = 7; 21 22 #else 23 // Default to producing Little-End network streams. 24 private static readonly int B16_1 = 1; 25 private static readonly int B16_0 = 0; 26 27 private static readonly int B32_3 = 3; 28 private static readonly int B32_2 = 2; 29 private static readonly int B32_1 = 1; 30 private static readonly int B32_0 = 0; 31 32 private static readonly int B64_7 = 7; 33 private static readonly int B64_6 = 6; 34 private static readonly int B64_5 = 5; 35 private static readonly int B64_4 = 4; 36 private static readonly int B64_3 = 3; 37 private static readonly int B64_2 = 2; 38 private static readonly int B64_1 = 1; 39 private static readonly int B64_0 = 0; 40 #endif 41 public static readonly 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 }