1 using System; 2 using System.IO; 3 using ICSharpCode.SharpZipLib.Checksum; 4 5 namespace ICSharpCode.SharpZipLib.BZip2 6 { 7 /// <summary> 8 /// An input stream that decompresses files in the BZip2 format 9 /// </summary> 10 public class BZip2InputStream : Stream 11 { 12 #region Constants 13 const int START_BLOCK_STATE = 1; 14 const int RAND_PART_A_STATE = 2; 15 const int RAND_PART_B_STATE = 3; 16 const int RAND_PART_C_STATE = 4; 17 const int NO_RAND_PART_A_STATE = 5; 18 const int NO_RAND_PART_B_STATE = 6; 19 const int NO_RAND_PART_C_STATE = 7; 20 #endregion 21 #region Constructors 22 /// <summary> 23 /// Construct instance for reading from stream 24 /// </summary> 25 /// <param name="stream">Data source</param> BZip2InputStream(Stream stream)26 public BZip2InputStream(Stream stream) 27 { 28 // init arrays 29 for (int i = 0; i < BZip2Constants.GroupCount; ++i) { 30 limit[i] = new int[BZip2Constants.MaximumAlphaSize]; 31 baseArray[i] = new int[BZip2Constants.MaximumAlphaSize]; 32 perm[i] = new int[BZip2Constants.MaximumAlphaSize]; 33 } 34 35 BsSetStream(stream); 36 Initialize(); 37 InitBlock(); 38 SetupBlock(); 39 } 40 41 #endregion 42 43 /// <summary> 44 /// Get/set flag indicating ownership of underlying stream. 45 /// When the flag is true <see cref="Close"></see> will close the underlying stream also. 46 /// </summary> 47 public bool IsStreamOwner { 48 get { return isStreamOwner; } 49 set { isStreamOwner = value; } 50 } 51 52 53 #region Stream Overrides 54 /// <summary> 55 /// Gets a value indicating if the stream supports reading 56 /// </summary> 57 public override bool CanRead { 58 get { 59 return baseStream.CanRead; 60 } 61 } 62 63 /// <summary> 64 /// Gets a value indicating whether the current stream supports seeking. 65 /// </summary> 66 public override bool CanSeek { 67 get { 68 return baseStream.CanSeek; 69 } 70 } 71 72 /// <summary> 73 /// Gets a value indicating whether the current stream supports writing. 74 /// This property always returns false 75 /// </summary> 76 public override bool CanWrite { 77 get { 78 return false; 79 } 80 } 81 82 /// <summary> 83 /// Gets the length in bytes of the stream. 84 /// </summary> 85 public override long Length { 86 get { 87 return baseStream.Length; 88 } 89 } 90 91 /// <summary> 92 /// Gets or sets the streams position. 93 /// Setting the position is not supported and will throw a NotSupportException 94 /// </summary> 95 /// <exception cref="NotSupportedException">Any attempt to set the position</exception> 96 public override long Position { 97 get { 98 return baseStream.Position; 99 } 100 set { 101 throw new NotSupportedException("BZip2InputStream position cannot be set"); 102 } 103 } 104 105 /// <summary> 106 /// Flushes the stream. 107 /// </summary> Flush()108 public override void Flush() 109 { 110 if (baseStream != null) { 111 baseStream.Flush(); 112 } 113 } 114 115 /// <summary> 116 /// Set the streams position. This operation is not supported and will throw a NotSupportedException 117 /// </summary> 118 /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param> 119 /// <param name="origin">A value of type <see cref="SeekOrigin"/> indicating the reference point used to obtain the new position.</param> 120 /// <returns>The new position of the stream.</returns> 121 /// <exception cref="NotSupportedException">Any access</exception> Seek(long offset, SeekOrigin origin)122 public override long Seek(long offset, SeekOrigin origin) 123 { 124 throw new NotSupportedException("BZip2InputStream Seek not supported"); 125 } 126 127 /// <summary> 128 /// Sets the length of this stream to the given value. 129 /// This operation is not supported and will throw a NotSupportedExceptionortedException 130 /// </summary> 131 /// <param name="value">The new length for the stream.</param> 132 /// <exception cref="NotSupportedException">Any access</exception> SetLength(long value)133 public override void SetLength(long value) 134 { 135 throw new NotSupportedException("BZip2InputStream SetLength not supported"); 136 } 137 138 /// <summary> 139 /// Writes a block of bytes to this stream using data from a buffer. 140 /// This operation is not supported and will throw a NotSupportedException 141 /// </summary> 142 /// <param name="buffer">The buffer to source data from.</param> 143 /// <param name="offset">The offset to start obtaining data from.</param> 144 /// <param name="count">The number of bytes of data to write.</param> 145 /// <exception cref="NotSupportedException">Any access</exception> Write(byte[] buffer, int offset, int count)146 public override void Write(byte[] buffer, int offset, int count) 147 { 148 throw new NotSupportedException("BZip2InputStream Write not supported"); 149 } 150 151 /// <summary> 152 /// Writes a byte to the current position in the file stream. 153 /// This operation is not supported and will throw a NotSupportedException 154 /// </summary> 155 /// <param name="value">The value to write.</param> 156 /// <exception cref="NotSupportedException">Any access</exception> WriteByte(byte value)157 public override void WriteByte(byte value) 158 { 159 throw new NotSupportedException("BZip2InputStream WriteByte not supported"); 160 } 161 162 /// <summary> 163 /// Read a sequence of bytes and advances the read position by one byte. 164 /// </summary> 165 /// <param name="buffer">Array of bytes to store values in</param> 166 /// <param name="offset">Offset in array to begin storing data</param> 167 /// <param name="count">The maximum number of bytes to read</param> 168 /// <returns>The total number of bytes read into the buffer. This might be less 169 /// than the number of bytes requested if that number of bytes are not 170 /// currently available or zero if the end of the stream is reached. 171 /// </returns> Read(byte[] buffer, int offset, int count)172 public override int Read(byte[] buffer, int offset, int count) 173 { 174 if (buffer == null) { 175 throw new ArgumentNullException(nameof(buffer)); 176 } 177 178 for (int i = 0; i < count; ++i) { 179 int rb = ReadByte(); 180 if (rb == -1) { 181 return i; 182 } 183 buffer[offset + i] = (byte)rb; 184 } 185 return count; 186 } 187 188 /// <summary> 189 /// Closes the stream, releasing any associated resources. 190 /// </summary> Dispose(bool disposing)191 protected override void Dispose(bool disposing) 192 { 193 if (disposing && IsStreamOwner && (baseStream != null)) { 194 baseStream.Dispose(); 195 } 196 } 197 /// <summary> 198 /// Read a byte from stream advancing position 199 /// </summary> 200 /// <returns>byte read or -1 on end of stream</returns> ReadByte()201 public override int ReadByte() 202 { 203 if (streamEnd) { 204 return -1; // ok 205 } 206 207 int retChar = currentChar; 208 switch (currentState) { 209 case RAND_PART_B_STATE: 210 SetupRandPartB(); 211 break; 212 case RAND_PART_C_STATE: 213 SetupRandPartC(); 214 break; 215 case NO_RAND_PART_B_STATE: 216 SetupNoRandPartB(); 217 break; 218 case NO_RAND_PART_C_STATE: 219 SetupNoRandPartC(); 220 break; 221 case START_BLOCK_STATE: 222 case NO_RAND_PART_A_STATE: 223 case RAND_PART_A_STATE: 224 break; 225 } 226 return retChar; 227 } 228 229 #endregion 230 MakeMaps()231 void MakeMaps() 232 { 233 nInUse = 0; 234 for (int i = 0; i < 256; ++i) { 235 if (inUse[i]) { 236 seqToUnseq[nInUse] = (byte)i; 237 unseqToSeq[i] = (byte)nInUse; 238 nInUse++; 239 } 240 } 241 } 242 Initialize()243 void Initialize() 244 { 245 char magic1 = BsGetUChar(); 246 char magic2 = BsGetUChar(); 247 248 char magic3 = BsGetUChar(); 249 char magic4 = BsGetUChar(); 250 251 if (magic1 != 'B' || magic2 != 'Z' || magic3 != 'h' || magic4 < '1' || magic4 > '9') { 252 streamEnd = true; 253 return; 254 } 255 256 SetDecompressStructureSizes(magic4 - '0'); 257 computedCombinedCRC = 0; 258 } 259 InitBlock()260 void InitBlock() 261 { 262 char magic1 = BsGetUChar(); 263 char magic2 = BsGetUChar(); 264 char magic3 = BsGetUChar(); 265 char magic4 = BsGetUChar(); 266 char magic5 = BsGetUChar(); 267 char magic6 = BsGetUChar(); 268 269 if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) { 270 Complete(); 271 return; 272 } 273 274 if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) { 275 BadBlockHeader(); 276 streamEnd = true; 277 return; 278 } 279 280 storedBlockCRC = BsGetInt32(); 281 282 blockRandomised = (BsR(1) == 1); 283 284 GetAndMoveToFrontDecode(); 285 286 mCrc.Reset(); 287 currentState = START_BLOCK_STATE; 288 } 289 EndBlock()290 void EndBlock() 291 { 292 computedBlockCRC = (int)mCrc.Value; 293 294 // -- A bad CRC is considered a fatal error. -- 295 if (storedBlockCRC != computedBlockCRC) { 296 CrcError(); 297 } 298 299 // 1528150659 300 computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFF) | (computedCombinedCRC >> 31); 301 computedCombinedCRC = computedCombinedCRC ^ (uint)computedBlockCRC; 302 } 303 Complete()304 void Complete() 305 { 306 storedCombinedCRC = BsGetInt32(); 307 if (storedCombinedCRC != (int)computedCombinedCRC) { 308 CrcError(); 309 } 310 311 streamEnd = true; 312 } 313 BsSetStream(Stream stream)314 void BsSetStream(Stream stream) 315 { 316 baseStream = stream; 317 bsLive = 0; 318 bsBuff = 0; 319 } 320 FillBuffer()321 void FillBuffer() 322 { 323 int thech = 0; 324 325 try { 326 thech = baseStream.ReadByte(); 327 } catch (Exception) { 328 CompressedStreamEOF(); 329 } 330 331 if (thech == -1) { 332 CompressedStreamEOF(); 333 } 334 335 bsBuff = (bsBuff << 8) | (thech & 0xFF); 336 bsLive += 8; 337 } 338 BsR(int n)339 int BsR(int n) 340 { 341 while (bsLive < n) { 342 FillBuffer(); 343 } 344 345 int v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1); 346 bsLive -= n; 347 return v; 348 } 349 BsGetUChar()350 char BsGetUChar() 351 { 352 return (char)BsR(8); 353 } 354 BsGetIntVS(int numBits)355 int BsGetIntVS(int numBits) 356 { 357 return BsR(numBits); 358 } 359 BsGetInt32()360 int BsGetInt32() 361 { 362 int result = BsR(8); 363 result = (result << 8) | BsR(8); 364 result = (result << 8) | BsR(8); 365 result = (result << 8) | BsR(8); 366 return result; 367 } 368 RecvDecodingTables()369 void RecvDecodingTables() 370 { 371 char[][] len = new char[BZip2Constants.GroupCount][]; 372 for (int i = 0; i < BZip2Constants.GroupCount; ++i) { 373 len[i] = new char[BZip2Constants.MaximumAlphaSize]; 374 } 375 376 bool[] inUse16 = new bool[16]; 377 378 //--- Receive the mapping table --- 379 for (int i = 0; i < 16; i++) { 380 inUse16[i] = (BsR(1) == 1); 381 } 382 383 for (int i = 0; i < 16; i++) { 384 if (inUse16[i]) { 385 for (int j = 0; j < 16; j++) { 386 inUse[i * 16 + j] = (BsR(1) == 1); 387 } 388 } else { 389 for (int j = 0; j < 16; j++) { 390 inUse[i * 16 + j] = false; 391 } 392 } 393 } 394 395 MakeMaps(); 396 int alphaSize = nInUse + 2; 397 398 //--- Now the selectors --- 399 int nGroups = BsR(3); 400 int nSelectors = BsR(15); 401 402 for (int i = 0; i < nSelectors; i++) { 403 int j = 0; 404 while (BsR(1) == 1) { 405 j++; 406 } 407 selectorMtf[i] = (byte)j; 408 } 409 410 //--- Undo the MTF values for the selectors. --- 411 byte[] pos = new byte[BZip2Constants.GroupCount]; 412 for (int v = 0; v < nGroups; v++) { 413 pos[v] = (byte)v; 414 } 415 416 for (int i = 0; i < nSelectors; i++) { 417 int v = selectorMtf[i]; 418 byte tmp = pos[v]; 419 while (v > 0) { 420 pos[v] = pos[v - 1]; 421 v--; 422 } 423 pos[0] = tmp; 424 selector[i] = tmp; 425 } 426 427 //--- Now the coding tables --- 428 for (int t = 0; t < nGroups; t++) { 429 int curr = BsR(5); 430 for (int i = 0; i < alphaSize; i++) { 431 while (BsR(1) == 1) { 432 if (BsR(1) == 0) { 433 curr++; 434 } else { 435 curr--; 436 } 437 } 438 len[t][i] = (char)curr; 439 } 440 } 441 442 //--- Create the Huffman decoding tables --- 443 for (int t = 0; t < nGroups; t++) { 444 int minLen = 32; 445 int maxLen = 0; 446 for (int i = 0; i < alphaSize; i++) { 447 maxLen = Math.Max(maxLen, len[t][i]); 448 minLen = Math.Min(minLen, len[t][i]); 449 } 450 HbCreateDecodeTables(limit[t], baseArray[t], perm[t], len[t], minLen, maxLen, alphaSize); 451 minLens[t] = minLen; 452 } 453 } 454 GetAndMoveToFrontDecode()455 void GetAndMoveToFrontDecode() 456 { 457 byte[] yy = new byte[256]; 458 int nextSym; 459 460 int limitLast = BZip2Constants.BaseBlockSize * blockSize100k; 461 origPtr = BsGetIntVS(24); 462 463 RecvDecodingTables(); 464 int EOB = nInUse + 1; 465 int groupNo = -1; 466 int groupPos = 0; 467 468 /*-- 469 Setting up the unzftab entries here is not strictly 470 necessary, but it does save having to do it later 471 in a separate pass, and so saves a block's worth of 472 cache misses. 473 --*/ 474 for (int i = 0; i <= 255; i++) { 475 unzftab[i] = 0; 476 } 477 478 for (int i = 0; i <= 255; i++) { 479 yy[i] = (byte)i; 480 } 481 482 last = -1; 483 484 if (groupPos == 0) { 485 groupNo++; 486 groupPos = BZip2Constants.GroupSize; 487 } 488 489 groupPos--; 490 int zt = selector[groupNo]; 491 int zn = minLens[zt]; 492 int zvec = BsR(zn); 493 int zj; 494 495 while (zvec > limit[zt][zn]) { 496 if (zn > 20) { // the longest code 497 throw new BZip2Exception("Bzip data error"); 498 } 499 zn++; 500 while (bsLive < 1) { 501 FillBuffer(); 502 } 503 zj = (bsBuff >> (bsLive - 1)) & 1; 504 bsLive--; 505 zvec = (zvec << 1) | zj; 506 } 507 if (zvec - baseArray[zt][zn] < 0 || zvec - baseArray[zt][zn] >= BZip2Constants.MaximumAlphaSize) { 508 throw new BZip2Exception("Bzip data error"); 509 } 510 nextSym = perm[zt][zvec - baseArray[zt][zn]]; 511 512 while (true) { 513 if (nextSym == EOB) { 514 break; 515 } 516 517 if (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB) { 518 int s = -1; 519 int n = 1; 520 do { 521 if (nextSym == BZip2Constants.RunA) { 522 s += (0 + 1) * n; 523 } else if (nextSym == BZip2Constants.RunB) { 524 s += (1 + 1) * n; 525 } 526 527 n <<= 1; 528 529 if (groupPos == 0) { 530 groupNo++; 531 groupPos = BZip2Constants.GroupSize; 532 } 533 534 groupPos--; 535 536 zt = selector[groupNo]; 537 zn = minLens[zt]; 538 zvec = BsR(zn); 539 540 while (zvec > limit[zt][zn]) { 541 zn++; 542 while (bsLive < 1) { 543 FillBuffer(); 544 } 545 zj = (bsBuff >> (bsLive - 1)) & 1; 546 bsLive--; 547 zvec = (zvec << 1) | zj; 548 } 549 nextSym = perm[zt][zvec - baseArray[zt][zn]]; 550 } while (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB); 551 552 s++; 553 byte ch = seqToUnseq[yy[0]]; 554 unzftab[ch] += s; 555 556 while (s > 0) { 557 last++; 558 ll8[last] = ch; 559 s--; 560 } 561 562 if (last >= limitLast) { 563 BlockOverrun(); 564 } 565 continue; 566 } else { 567 last++; 568 if (last >= limitLast) { 569 BlockOverrun(); 570 } 571 572 byte tmp = yy[nextSym - 1]; 573 unzftab[seqToUnseq[tmp]]++; 574 ll8[last] = seqToUnseq[tmp]; 575 576 for (int j = nextSym - 1; j > 0; --j) { 577 yy[j] = yy[j - 1]; 578 } 579 yy[0] = tmp; 580 581 if (groupPos == 0) { 582 groupNo++; 583 groupPos = BZip2Constants.GroupSize; 584 } 585 586 groupPos--; 587 zt = selector[groupNo]; 588 zn = minLens[zt]; 589 zvec = BsR(zn); 590 while (zvec > limit[zt][zn]) { 591 zn++; 592 while (bsLive < 1) { 593 FillBuffer(); 594 } 595 zj = (bsBuff >> (bsLive - 1)) & 1; 596 bsLive--; 597 zvec = (zvec << 1) | zj; 598 } 599 nextSym = perm[zt][zvec - baseArray[zt][zn]]; 600 continue; 601 } 602 } 603 } 604 SetupBlock()605 void SetupBlock() 606 { 607 int[] cftab = new int[257]; 608 609 cftab[0] = 0; 610 Array.Copy(unzftab, 0, cftab, 1, 256); 611 612 for (int i = 1; i <= 256; i++) { 613 cftab[i] += cftab[i - 1]; 614 } 615 616 for (int i = 0; i <= last; i++) { 617 byte ch = ll8[i]; 618 tt[cftab[ch]] = i; 619 cftab[ch]++; 620 } 621 622 cftab = null; 623 624 tPos = tt[origPtr]; 625 626 count = 0; 627 i2 = 0; 628 ch2 = 256; /*-- not a char and not EOF --*/ 629 630 if (blockRandomised) { 631 rNToGo = 0; 632 rTPos = 0; 633 SetupRandPartA(); 634 } else { 635 SetupNoRandPartA(); 636 } 637 } 638 SetupRandPartA()639 void SetupRandPartA() 640 { 641 if (i2 <= last) { 642 chPrev = ch2; 643 ch2 = ll8[tPos]; 644 tPos = tt[tPos]; 645 if (rNToGo == 0) { 646 rNToGo = BZip2Constants.RandomNumbers[rTPos]; 647 rTPos++; 648 if (rTPos == 512) { 649 rTPos = 0; 650 } 651 } 652 rNToGo--; 653 ch2 ^= (int)((rNToGo == 1) ? 1 : 0); 654 i2++; 655 656 currentChar = ch2; 657 currentState = RAND_PART_B_STATE; 658 mCrc.Update(ch2); 659 } else { 660 EndBlock(); 661 InitBlock(); 662 SetupBlock(); 663 } 664 } 665 SetupNoRandPartA()666 void SetupNoRandPartA() 667 { 668 if (i2 <= last) { 669 chPrev = ch2; 670 ch2 = ll8[tPos]; 671 tPos = tt[tPos]; 672 i2++; 673 674 currentChar = ch2; 675 currentState = NO_RAND_PART_B_STATE; 676 mCrc.Update(ch2); 677 } else { 678 EndBlock(); 679 InitBlock(); 680 SetupBlock(); 681 } 682 } 683 SetupRandPartB()684 void SetupRandPartB() 685 { 686 if (ch2 != chPrev) { 687 currentState = RAND_PART_A_STATE; 688 count = 1; 689 SetupRandPartA(); 690 } else { 691 count++; 692 if (count >= 4) { 693 z = ll8[tPos]; 694 tPos = tt[tPos]; 695 if (rNToGo == 0) { 696 rNToGo = BZip2Constants.RandomNumbers[rTPos]; 697 rTPos++; 698 if (rTPos == 512) { 699 rTPos = 0; 700 } 701 } 702 rNToGo--; 703 z ^= (byte)((rNToGo == 1) ? 1 : 0); 704 j2 = 0; 705 currentState = RAND_PART_C_STATE; 706 SetupRandPartC(); 707 } else { 708 currentState = RAND_PART_A_STATE; 709 SetupRandPartA(); 710 } 711 } 712 } 713 SetupRandPartC()714 void SetupRandPartC() 715 { 716 if (j2 < (int)z) { 717 currentChar = ch2; 718 mCrc.Update(ch2); 719 j2++; 720 } else { 721 currentState = RAND_PART_A_STATE; 722 i2++; 723 count = 0; 724 SetupRandPartA(); 725 } 726 } 727 SetupNoRandPartB()728 void SetupNoRandPartB() 729 { 730 if (ch2 != chPrev) { 731 currentState = NO_RAND_PART_A_STATE; 732 count = 1; 733 SetupNoRandPartA(); 734 } else { 735 count++; 736 if (count >= 4) { 737 z = ll8[tPos]; 738 tPos = tt[tPos]; 739 currentState = NO_RAND_PART_C_STATE; 740 j2 = 0; 741 SetupNoRandPartC(); 742 } else { 743 currentState = NO_RAND_PART_A_STATE; 744 SetupNoRandPartA(); 745 } 746 } 747 } 748 SetupNoRandPartC()749 void SetupNoRandPartC() 750 { 751 if (j2 < (int)z) { 752 currentChar = ch2; 753 mCrc.Update(ch2); 754 j2++; 755 } else { 756 currentState = NO_RAND_PART_A_STATE; 757 i2++; 758 count = 0; 759 SetupNoRandPartA(); 760 } 761 } 762 SetDecompressStructureSizes(int newSize100k)763 void SetDecompressStructureSizes(int newSize100k) 764 { 765 if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && blockSize100k <= 9)) { 766 throw new BZip2Exception("Invalid block size"); 767 } 768 769 blockSize100k = newSize100k; 770 771 if (newSize100k == 0) { 772 return; 773 } 774 775 int n = BZip2Constants.BaseBlockSize * newSize100k; 776 ll8 = new byte[n]; 777 tt = new int[n]; 778 } 779 CompressedStreamEOF()780 static void CompressedStreamEOF() 781 { 782 throw new EndOfStreamException("BZip2 input stream end of compressed stream"); 783 } 784 BlockOverrun()785 static void BlockOverrun() 786 { 787 throw new BZip2Exception("BZip2 input stream block overrun"); 788 } 789 BadBlockHeader()790 static void BadBlockHeader() 791 { 792 throw new BZip2Exception("BZip2 input stream bad block header"); 793 } 794 CrcError()795 static void CrcError() 796 { 797 throw new BZip2Exception("BZip2 input stream crc error"); 798 } 799 HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen, int maxLen, int alphaSize)800 static void HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen, int maxLen, int alphaSize) 801 { 802 int pp = 0; 803 804 for (int i = minLen; i <= maxLen; ++i) { 805 for (int j = 0; j < alphaSize; ++j) { 806 if (length[j] == i) { 807 perm[pp] = j; 808 ++pp; 809 } 810 } 811 } 812 813 for (int i = 0; i < BZip2Constants.MaximumCodeLength; i++) { 814 baseArray[i] = 0; 815 } 816 817 for (int i = 0; i < alphaSize; i++) { 818 ++baseArray[length[i] + 1]; 819 } 820 821 for (int i = 1; i < BZip2Constants.MaximumCodeLength; i++) { 822 baseArray[i] += baseArray[i - 1]; 823 } 824 825 for (int i = 0; i < BZip2Constants.MaximumCodeLength; i++) { 826 limit[i] = 0; 827 } 828 829 int vec = 0; 830 831 for (int i = minLen; i <= maxLen; i++) { 832 vec += (baseArray[i + 1] - baseArray[i]); 833 limit[i] = vec - 1; 834 vec <<= 1; 835 } 836 837 for (int i = minLen + 1; i <= maxLen; i++) { 838 baseArray[i] = ((limit[i - 1] + 1) << 1) - baseArray[i]; 839 } 840 } 841 842 #region Instance Fields 843 /*-- 844 index of the last char in the block, so 845 the block size == last + 1. 846 --*/ 847 int last; 848 849 /*-- 850 index in zptr[] of original string after sorting. 851 --*/ 852 int origPtr; 853 854 /*-- 855 always: in the range 0 .. 9. 856 The current block size is 100000 * this number. 857 --*/ 858 int blockSize100k; 859 860 bool blockRandomised; 861 862 int bsBuff; 863 int bsLive; 864 IChecksum mCrc = new BZip2Crc(); 865 866 bool[] inUse = new bool[256]; 867 int nInUse; 868 869 byte[] seqToUnseq = new byte[256]; 870 byte[] unseqToSeq = new byte[256]; 871 872 byte[] selector = new byte[BZip2Constants.MaximumSelectors]; 873 byte[] selectorMtf = new byte[BZip2Constants.MaximumSelectors]; 874 875 int[] tt; 876 byte[] ll8; 877 878 /*-- 879 freq table collected to save a pass over the data 880 during decompression. 881 --*/ 882 int[] unzftab = new int[256]; 883 884 int[][] limit = new int[BZip2Constants.GroupCount][]; 885 int[][] baseArray = new int[BZip2Constants.GroupCount][]; 886 int[][] perm = new int[BZip2Constants.GroupCount][]; 887 int[] minLens = new int[BZip2Constants.GroupCount]; 888 889 Stream baseStream; 890 bool streamEnd; 891 892 int currentChar = -1; 893 894 int currentState = START_BLOCK_STATE; 895 896 int storedBlockCRC, storedCombinedCRC; 897 int computedBlockCRC; 898 uint computedCombinedCRC; 899 900 int count, chPrev, ch2; 901 int tPos; 902 int rNToGo; 903 int rTPos; 904 int i2, j2; 905 byte z; 906 bool isStreamOwner = true; 907 #endregion 908 } 909 } 910