diff --git a/BurnOutSharp.Compression/bzip2/Constants.cs b/BurnOutSharp.Compression/bzip2/Constants.cs
new file mode 100644
index 00000000..b044c289
--- /dev/null
+++ b/BurnOutSharp.Compression/bzip2/Constants.cs
@@ -0,0 +1,304 @@
+namespace BurnOutSharp.Compression.bzip2
+{
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static class Constants
+ {
+ #region bzlib.h
+
+ public const int BZ_RUN = 0;
+ public const int BZ_FLUSH = 1;
+ public const int BZ_FINISH = 2;
+
+ public const int BZ_OK = 0;
+ public const int BZ_RUN_OK = 1;
+ public const int BZ_FLUSH_OK = 2;
+ public const int BZ_FINISH_OK = 3;
+ public const int BZ_STREAM_END = 4;
+ public const int BZ_SEQUENCE_ERROR = (-1);
+ public const int BZ_PARAM_ERROR = (-2);
+ public const int BZ_MEM_ERROR = (-3);
+ public const int BZ_DATA_ERROR = (-4);
+ public const int BZ_DATA_ERROR_MAGIC = (-5);
+ public const int BZ_IO_ERROR = (-6);
+ public const int BZ_UNEXPECTED_EOF = (-7);
+ public const int BZ_OUTBUFF_FULL = (-8);
+ public const int BZ_CONFIG_ERROR = (-9);
+
+ public const int BZ_MAX_UNUSED = 5000;
+
+ #endregion
+
+ #region bzlib_private.h
+
+ internal const string BZ_VERSION = "1.0.5, 10-Dec-2007";
+
+ /*-- Header bytes. --*/
+
+ internal const byte BZ_HDR_B = 0x42; /* 'B' */
+ internal const byte BZ_HDR_Z = 0x5a; /* 'Z' */
+ internal const byte BZ_HDR_h = 0x68; /* 'h' */
+ internal const byte BZ_HDR_0 = 0x30; /* '0' */
+
+ /*-- Constants for the back end. --*/
+
+ internal const int BZ_MAX_ALPHA_SIZE = 258;
+ internal const int BZ_MAX_CODE_LEN = 23;
+
+ internal const int BZ_RUNA = 0;
+ internal const int BZ_RUNB = 1;
+
+ internal const int BZ_N_GROUPS = 6;
+ internal const int BZ_G_SIZE = 50;
+ internal const int BZ_N_ITERS = 4;
+
+ internal const int BZ_MAX_SELECTORS = (2 + (900000 / BZ_G_SIZE));
+
+ /*-- States and modes for compression. --*/
+
+ internal const int BZ_M_IDLE = 1;
+ internal const int BZ_M_RUNNING = 2;
+ internal const int BZ_M_FLUSHING = 3;
+ internal const int BZ_M_FINISHING = 4;
+
+ internal const int BZ_S_OUTPUT = 1;
+ internal const int BZ_S_INPUT = 2;
+
+ internal const int BZ_N_RADIX = 2;
+ internal const int BZ_N_QSORT = 12;
+ internal const int BZ_N_SHELL = 18;
+ internal const int BZ_N_OVERSHOOT = (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2);
+
+ /*-- states for decompression. --*/
+
+ internal const int BZ_X_IDLE = 1;
+ internal const int BZ_X_OUTPUT = 2;
+
+ internal const int BZ_X_MAGIC_1 = 10;
+ internal const int BZ_X_MAGIC_2 = 11;
+ internal const int BZ_X_MAGIC_3 = 12;
+ internal const int BZ_X_MAGIC_4 = 13;
+ internal const int BZ_X_BLKHDR_1 = 14;
+ internal const int BZ_X_BLKHDR_2 = 15;
+ internal const int BZ_X_BLKHDR_3 = 16;
+ internal const int BZ_X_BLKHDR_4 = 17;
+ internal const int BZ_X_BLKHDR_5 = 18;
+ internal const int BZ_X_BLKHDR_6 = 19;
+ internal const int BZ_X_BCRC_1 = 20;
+ internal const int BZ_X_BCRC_2 = 21;
+ internal const int BZ_X_BCRC_3 = 22;
+ internal const int BZ_X_BCRC_4 = 23;
+ internal const int BZ_X_RANDBIT = 24;
+ internal const int BZ_X_ORIGPTR_1 = 25;
+ internal const int BZ_X_ORIGPTR_2 = 26;
+ internal const int BZ_X_ORIGPTR_3 = 27;
+ internal const int BZ_X_MAPPING_1 = 28;
+ internal const int BZ_X_MAPPING_2 = 29;
+ internal const int BZ_X_SELECTOR_1 = 30;
+ internal const int BZ_X_SELECTOR_2 = 31;
+ internal const int BZ_X_SELECTOR_3 = 32;
+ internal const int BZ_X_CODING_1 = 33;
+ internal const int BZ_X_CODING_2 = 34;
+ internal const int BZ_X_CODING_3 = 35;
+ internal const int BZ_X_MTF_1 = 36;
+ internal const int BZ_X_MTF_2 = 37;
+ internal const int BZ_X_MTF_3 = 38;
+ internal const int BZ_X_MTF_4 = 39;
+ internal const int BZ_X_MTF_5 = 40;
+ internal const int BZ_X_MTF_6 = 41;
+ internal const int BZ_X_ENDHDR_2 = 42;
+ internal const int BZ_X_ENDHDR_3 = 43;
+ internal const int BZ_X_ENDHDR_4 = 44;
+ internal const int BZ_X_ENDHDR_5 = 45;
+ internal const int BZ_X_ENDHDR_6 = 46;
+ internal const int BZ_X_CCRC_1 = 47;
+ internal const int BZ_X_CCRC_2 = 48;
+ internal const int BZ_X_CCRC_3 = 49;
+ internal const int BZ_X_CCRC_4 = 50;
+
+ /*-- Constants for the fast MTF decoder. --*/
+
+ internal const int MTFA_SIZE = 4096;
+ internal const int MTFL_SIZE = 16;
+
+ #endregion
+
+ #region blocksort.c
+
+ internal const int FALLBACK_QSORT_SMALL_THRESH = 10;
+
+ internal const int FALLBACK_QSORT_STACK_SIZE = 100;
+
+ /*--
+ Knuth's increments seem to work better
+ than Incerpi-Sedgewick here. Possibly
+ because the number of elems to sort is
+ usually small, typically <= 20.
+ --*/
+ internal static readonly int[] incs = new int[14]
+ {
+ 1, 4, 13, 40, 121, 364, 1093, 3280,
+ 9841, 29524, 88573, 265720, 797161, 2391484
+ };
+
+ /*--
+ The following is an implementation of
+ an elegant 3-way quicksort for strings,
+ described in a paper "Fast Algorithms for
+ Sorting and Searching Strings", by Robert
+ Sedgewick and Jon L. Bentley.
+ --*/
+ internal const int MAIN_QSORT_SMALL_THRESH = 20;
+
+ internal const int MAIN_QSORT_DEPTH_THRESH = (BZ_N_RADIX + BZ_N_QSORT);
+
+ internal const int MAIN_QSORT_STACK_SIZE = 100;
+
+ internal const uint SETMASK = 1 << 21;
+
+ internal const uint CLEARMASK = ~SETMASK;
+
+ #endregion
+
+ #region crctable.c
+
+ ///
+ /// Table for doing CRCs
+ ///
+ internal static readonly uint[] BZ2_crc32Table = new uint[256]
+ {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+ 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+ 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+ 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+ 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+ 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+ 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+ 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+ 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+ 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+ 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+ 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+ 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+ 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+ 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+ 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+ 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+ 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+ 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+ 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+ 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+ 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+ 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+ 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+ 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+ 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+ 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+ 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+ 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+ 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+ 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+ 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+ 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+ 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+ 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+ 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+ 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+ 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+ 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+ 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+ 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+ 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+ 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+ };
+
+ #endregion
+
+ #region randtable.c
+
+ ///
+ /// Table for randomising repetitive blocks
+ ///
+ internal static readonly int[] BZ2_rNums = new int[512]
+ {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+ };
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/bzip2/DState.cs b/BurnOutSharp.Compression/bzip2/DState.cs
new file mode 100644
index 00000000..8c57c7f5
--- /dev/null
+++ b/BurnOutSharp.Compression/bzip2/DState.cs
@@ -0,0 +1,100 @@
+using static BurnOutSharp.Compression.bzip2.Constants;
+
+namespace BurnOutSharp.Compression.bzip2
+{
+ ///
+ /// Structure holding all the decompression-side stuff.
+ ///
+ ///
+ internal unsafe class DState
+ {
+ /* pointer back to the struct bz_stream */
+ public bz_stream strm;
+
+ /* state indicator for this stream */
+ public int state;
+
+ /* for doing the final run-length decoding */
+ public byte state_out_ch;
+ public int state_out_len;
+ public bool blockRandomised;
+ public int rNToGo;
+ public int rTPos;
+
+ /* the buffer for bit stream reading */
+ public uint bsBuff;
+ public int bsLive;
+
+ /* misc administratium */
+ public int blockSize100k;
+ public bool smallDecompress;
+ public int currBlockNo;
+ public int verbosity;
+
+ /* for undoing the Burrows-Wheeler transform */
+ public int origPtr;
+ public uint tPos;
+ public int k0;
+ public int[] unzftab = new int[256];
+ public int nblock_used;
+ public int[] cftab = new int[257];
+ public int[] cftabCopy = new int[257];
+
+ /* for undoing the Burrows-Wheeler transform (FAST) */
+ public uint* tt;
+
+ /* for undoing the Burrows-Wheeler transform (SMALL) */
+ public ushort* ll16;
+ public byte* ll4;
+
+ /* stored and calculated CRCs */
+ public uint storedBlockCRC;
+ public uint storedCombinedCRC;
+ public uint calculatedBlockCRC;
+ public uint calculatedCombinedCRC;
+
+ /* map of bytes used in block */
+ public int nInUse;
+ public bool[] inUse = new bool[256];
+ public bool[] inUse16 = new bool[16];
+ public byte[] seqToUnseq = new byte[256];
+
+ /* for decoding the MTF values */
+ public byte[] mtfa = new byte[MTFA_SIZE];
+ public int[] mtfbase = new int[256 / MTFL_SIZE];
+ public byte[] selector = new byte[BZ_MAX_SELECTORS];
+ public byte[] selectorMtf = new byte[BZ_MAX_SELECTORS];
+ public byte[,] len = new byte[BZ_N_GROUPS, BZ_MAX_ALPHA_SIZE];
+
+ public int[,] limit = new int[BZ_N_GROUPS, BZ_MAX_ALPHA_SIZE];
+ public int[,] @base = new int[BZ_N_GROUPS, BZ_MAX_ALPHA_SIZE];
+ public int[,] perm = new int[BZ_N_GROUPS, BZ_MAX_ALPHA_SIZE];
+ public int[] minLens = new int[BZ_N_GROUPS];
+
+ /* save area for scalars in the main decompress code */
+ public int save_i;
+ public int save_j;
+ public int save_t;
+ public int save_alphaSize;
+ public int save_nGroups;
+ public int save_nSelectors;
+ public int save_EOB;
+ public int save_groupNo;
+ public int save_groupPos;
+ public int save_nextSym;
+ public int save_nblockMAX;
+ public int save_nblock;
+ public int save_es;
+ public int save_N;
+ public int save_curr;
+ public int save_zt;
+ public int save_zn;
+ public int save_zvec;
+ public int save_zj;
+ public int save_gSel;
+ public int save_gMinlen;
+ public int* save_gLimit;
+ public int* save_gBase;
+ public int* save_gPerm;
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/bzip2/EState.cs b/BurnOutSharp.Compression/bzip2/EState.cs
new file mode 100644
index 00000000..0cdd22ae
--- /dev/null
+++ b/BurnOutSharp.Compression/bzip2/EState.cs
@@ -0,0 +1,80 @@
+using static BurnOutSharp.Compression.bzip2.Constants;
+
+namespace BurnOutSharp.Compression.bzip2
+{
+ ///
+ /// Structure holding all the compression-side stuff.
+ ///
+ ///
+ internal unsafe class EState
+ {
+ /* pointer back to the struct bz_stream */
+ public bz_stream* strm;
+
+ /* mode this stream is in, and whether inputting */
+ /* or outputting data */
+ public int mode;
+ public int state;
+
+ /* remembers avail_in when flush/finish requested */
+ public uint avail_in_expect;
+
+ /* for doing the block sorting */
+ public uint* arr1;
+ public uint* arr2;
+ public uint* ftab;
+ public int origPtr;
+
+ /* aliases for arr1 and arr2 */
+ public uint* ptr;
+ public byte* block;
+ public ushort* mtfv;
+ public byte* zbits;
+
+ /* for deciding when to use the fallback sorting algorithm */
+ public int workFactor;
+
+ /* run-length-encoding of the input */
+ public uint state_in_ch;
+ public int state_in_len;
+ public int rNToGo;
+ public int rTPos;
+
+ /* input and output limits and current posns */
+ public int nblock;
+ public int nblockMAX;
+ public int numZ;
+ public int state_out_pos;
+
+ /* map of bytes used in block */
+ public int nInUse;
+ public bool[] inUse = new bool[256];
+ public byte[] unseqToSeq = new byte[256];
+
+ /* the buffer for bit stream creation */
+ public uint bsBuff;
+ public int bsLive;
+
+ /* block and combined CRCs */
+ public uint blockCRC;
+ public uint combinedCRC;
+
+ /* misc administratium */
+ public int verbosity;
+ public int blockNo;
+ public int blockSize100k;
+
+ /* stuff for coding the MTF values */
+ public int nMTF;
+ public int[] mtfFreq = new int[BZ_MAX_ALPHA_SIZE];
+ public byte[] selector = new byte[BZ_MAX_SELECTORS];
+ public byte[] selectorMtf = new byte[BZ_MAX_SELECTORS];
+
+ public byte[,] len = new byte[BZ_N_GROUPS, BZ_MAX_ALPHA_SIZE];
+ public int[,] code = new int[BZ_N_GROUPS, BZ_MAX_ALPHA_SIZE];
+ public int[,] rfreq = new int[BZ_N_GROUPS, BZ_MAX_ALPHA_SIZE];
+
+ /* second dimension: only 3 needed; 4 makes index calculations faster */
+ public uint[,] len_pack = new uint[BZ_MAX_ALPHA_SIZE, 4];
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/bzip2/Huffman.cs b/BurnOutSharp.Compression/bzip2/Huffman.cs
new file mode 100644
index 00000000..63138bd0
--- /dev/null
+++ b/BurnOutSharp.Compression/bzip2/Huffman.cs
@@ -0,0 +1,217 @@
+using static BurnOutSharp.Compression.bzip2.Constants;
+
+namespace BurnOutSharp.Compression.bzip2
+{
+ ///
+ /// Huffman coding low-level stuff
+ ///
+ ///
+ internal static unsafe class Huffman
+ {
+ public static void BZ2_hbMakeCodeLengths(byte* len, int* freq, int alphaSize, int maxLen)
+ {
+ /*--
+ Nodes and heap entries run from 1. Entry 0
+ for both the heap and nodes is a sentinel.
+ --*/
+ int nNodes, nHeap, n1, n2, i, j, k;
+ bool tooLong;
+
+ int[] heap = new int[BZ_MAX_ALPHA_SIZE + 2];
+ int[] weight = new int[BZ_MAX_ALPHA_SIZE * 2];
+ int[] parent = new int[BZ_MAX_ALPHA_SIZE * 2];
+
+ for (i = 0; i < alphaSize; i++)
+ {
+ weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+ }
+
+ while (true)
+ {
+
+ nNodes = alphaSize;
+ nHeap = 0;
+
+ heap[0] = 0;
+ weight[0] = 0;
+ parent[0] = -2;
+
+ for (i = 1; i <= alphaSize; i++)
+ {
+ parent[i] = -1;
+ nHeap++;
+ heap[nHeap] = i;
+ UPHEAP(nHeap, heap, weight);
+ }
+
+ //AssertH(nHeap < (BZ_MAX_ALPHA_SIZE + 2), 2001);
+
+ while (nHeap > 1)
+ {
+ n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1, nHeap, heap, weight);
+ n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1, nHeap, heap, weight);
+ nNodes++;
+ parent[n1] = parent[n2] = nNodes;
+ weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
+ parent[nNodes] = -1;
+ nHeap++;
+ heap[nHeap] = nNodes;
+ UPHEAP(nHeap, heap, weight);
+ }
+
+ //AssertH(nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002);
+
+ tooLong = false;
+ for (i = 1; i <= alphaSize; i++)
+ {
+ j = 0;
+ k = i;
+ while (parent[k] >= 0) { k = parent[k]; j++; }
+ len[i - 1] = (byte)j;
+ if (j > maxLen) tooLong = true;
+ }
+
+ if (!tooLong) break;
+
+ /* 17 Oct 04: keep-going condition for the following loop used
+ to be 'i < alphaSize', which missed the last element,
+ theoretically leading to the possibility of the compressor
+ looping. However, this count-scaling step is only needed if
+ one of the generated Huffman code words is longer than
+ maxLen, which up to and including version 1.0.2 was 20 bits,
+ which is extremely unlikely. In version 1.0.3 maxLen was
+ changed to 17 bits, which has minimal effect on compression
+ ratio, but does mean this scaling step is used from time to
+ time, enough to verify that it works.
+ This means that bzip2-1.0.3 and later will only produce
+ Huffman codes with a maximum length of 17 bits. However, in
+ order to preserve backwards compatibility with bitstreams
+ produced by versions pre-1.0.3, the decompressor must still
+ handle lengths of up to 20. */
+
+ for (i = 1; i <= alphaSize; i++)
+ {
+ j = weight[i] >> 8;
+ j = 1 + (j / 2);
+ weight[i] = j << 8;
+ }
+ }
+ }
+
+ public static void BZ2_hbAssignCodes(int* code, byte* length, int minLen, int maxLen, int alphaSize)
+ {
+ int n, vec, i;
+
+ vec = 0;
+ for (n = minLen; n <= maxLen; n++)
+ {
+ for (i = 0; i < alphaSize; i++)
+ {
+ if (length[i] == n)
+ {
+ code[i] = vec;
+ vec++;
+ }
+ };
+
+ vec <<= 1;
+ }
+ }
+
+ public static void BZ2_hbCreateDecodeTables(int* limit, int* @base, int* perm, byte* length, int minLen, int maxLen, int alphaSize)
+ {
+ int pp, i, j, vec;
+
+ pp = 0;
+ for (i = minLen; i <= maxLen; i++)
+ {
+ for (j = 0; j < alphaSize; j++)
+ {
+ if (length[j] == i) { perm[pp] = j; pp++; }
+ }
+ };
+
+ for (i = 0; i < BZ_MAX_CODE_LEN; i++)
+ {
+ @base[i] = 0;
+ }
+
+ for (i = 0; i < alphaSize; i++)
+ {
+ @base[length[i] + 1]++;
+ }
+
+ for (i = 1; i < BZ_MAX_CODE_LEN; i++)
+ {
+ @base[i] += @base[i - 1];
+ }
+
+ for (i = 0; i < BZ_MAX_CODE_LEN; i++)
+ {
+ limit[i] = 0;
+ }
+
+ vec = 0;
+
+ for (i = minLen; i <= maxLen; i++)
+ {
+ vec += (@base[i + 1] - @base[i]);
+ limit[i] = vec - 1;
+ vec <<= 1;
+ }
+
+ for (i = minLen + 1; i <= maxLen; i++)
+ {
+ @base[i] = ((limit[i - 1] + 1) << 1) - @base[i];
+ }
+ }
+
+ #region Macros
+
+ private static int WEIGHTOF(int zz0) => (int)(zz0 & 0xffffff00);
+
+ private static int DEPTHOF(int zz1) => zz1 & 0x000000ff;
+
+ private static int MYMAX(int zz2, int zz3) => zz2 > zz3 ? zz2 : zz3;
+
+ private static int ADDWEIGHTS(int zw1, int zw2) => (WEIGHTOF(zw1) + WEIGHTOF(zw2)) | (1 + MYMAX(DEPTHOF(zw1), DEPTHOF(zw2)));
+
+ private static void UPHEAP(int z, int[] heap, int[] weight)
+ {
+ int zz, tmp;
+ zz = z; tmp = heap[zz];
+ while (weight[tmp] < weight[heap[zz >> 1]])
+ {
+ heap[zz] = heap[zz >> 1];
+ zz >>= 1;
+ }
+
+ heap[zz] = tmp;
+ }
+
+ private static void DOWNHEAP(int z, int nHeap, int[] heap, int[] weight)
+ {
+ int zz, yy, tmp;
+ zz = z; tmp = heap[zz];
+ while (true)
+ {
+ yy = zz << 1;
+ if (yy > nHeap)
+ break;
+
+ if (yy < nHeap && weight[heap[yy + 1]] < weight[heap[yy]])
+ yy++;
+
+ if (weight[tmp] < weight[heap[yy]])
+ break;
+
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+
+ heap[zz] = tmp;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/bzip2/blocksort.cs b/BurnOutSharp.Compression/bzip2/blocksort.cs
new file mode 100644
index 00000000..3aa73f28
--- /dev/null
+++ b/BurnOutSharp.Compression/bzip2/blocksort.cs
@@ -0,0 +1,1188 @@
+using static BurnOutSharp.Compression.bzip2.Constants;
+
+namespace BurnOutSharp.Compression.bzip2
+{
+ ///
+ /// Block sorting machinery
+ ///
+ ///
+ internal static unsafe class blocksort
+ {
+ ///
+ /// Fallback O(N log(N)^2) sorting algorithm, for repetitive blocks
+ ///
+ public static void fallbackSimpleSort(uint* fmap, uint* eclass, int lo, int hi)
+ {
+ int i, j, tmp;
+ uint ec_tmp;
+
+ if (lo == hi) return;
+
+ if (hi - lo > 3)
+ {
+ for (i = hi - 4; i >= lo; i--)
+ {
+ tmp = (int)fmap[i];
+ ec_tmp = eclass[tmp];
+ for (j = i + 4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4)
+ fmap[j - 4] = fmap[j];
+ fmap[j - 4] = (uint)tmp;
+ }
+ }
+
+ for (i = hi - 1; i >= lo; i--)
+ {
+ tmp = (int)fmap[i];
+ ec_tmp = eclass[tmp];
+ for (j = i + 1; j <= hi && ec_tmp > eclass[fmap[j]]; j++)
+ fmap[j - 1] = fmap[j];
+ fmap[j - 1] = (uint)tmp;
+ }
+ }
+
+ public static void fallbackQSort3(uint* fmap, uint* eclass, int loSt, int hiSt)
+ {
+ int unLo, unHi, ltLo, gtHi, n, m;
+ int sp, lo = 0, hi = 0;
+ uint med, r, r3;
+ int[] stackLo = new int[FALLBACK_QSORT_STACK_SIZE];
+ int[] stackHi = new int[FALLBACK_QSORT_STACK_SIZE];
+
+ r = 0;
+
+ sp = 0;
+ fpush(loSt, hiSt, stackLo, stackHi, ref sp);
+
+ while (sp > 0)
+ {
+ //AssertH(sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004);
+
+ fpop(ref lo, ref hi, stackLo, stackHi, ref sp);
+ if (hi - lo < FALLBACK_QSORT_SMALL_THRESH)
+ {
+ fallbackSimpleSort(fmap, eclass, lo, hi);
+ continue;
+ }
+
+ /* Random partitioning. Median of 3 sometimes fails to
+ avoid bad cases. Median of 9 seems to help but
+ looks rather expensive. This too seems to work but
+ is cheaper. Guidance for the magic constants
+ 7621 and 32768 is taken from Sedgewick's algorithms
+ book, chapter 35.
+ */
+ r = ((r * 7621) + 1) % 32768;
+ r3 = r % 3;
+ if (r3 == 0)
+ med = eclass[fmap[lo]];
+ else if (r3 == 1)
+ med = eclass[fmap[(lo + hi) >> 1]];
+ else
+ med = eclass[fmap[hi]];
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (true)
+ {
+ while (true)
+ {
+ if (unLo > unHi) break;
+ n = (int)eclass[fmap[unLo]] - (int)med;
+ if (n == 0)
+ {
+ fswap(ref fmap[unLo], ref fmap[ltLo]);
+ ltLo++; unLo++;
+ continue;
+ };
+ if (n > 0) break;
+ unLo++;
+ }
+ while (true)
+ {
+ if (unLo > unHi)
+ break;
+
+ n = (int)eclass[fmap[unHi]] - (int)med;
+ if (n == 0)
+ {
+ fswap(ref fmap[unHi], ref fmap[gtHi]);
+ gtHi--; unHi--;
+ continue;
+ };
+
+ if (n < 0)
+ break;
+
+ unHi--;
+ }
+
+ if (unLo > unHi)
+ break;
+
+ fswap(ref fmap[unLo], ref fmap[unHi]); unLo++; unHi--;
+ }
+
+ //AssertD(unHi == unLo - 1, "fallbackQSort3(2)");
+
+ if (gtHi < ltLo) continue;
+
+ n = fmin(ltLo - lo, unLo - ltLo); fvswap(fmap, lo, unLo - n, n);
+ m = fmin(hi - gtHi, gtHi - unHi); fvswap(fmap, unLo, hi - m + 1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ if (n - lo > hi - m)
+ {
+ fpush(lo, n, stackLo, stackHi, ref sp);
+ fpush(m, hi, stackLo, stackHi, ref sp);
+ }
+ else
+ {
+ fpush(m, hi, stackLo, stackHi, ref sp);
+ fpush(lo, n, stackLo, stackHi, ref sp);
+ }
+ }
+ }
+
+ /*
+ Pre:
+ nblock > 0
+ eclass exists for [0 .. nblock-1]
+ ((byte*)eclass) [0 .. nblock-1] holds block
+ ptr exists for [0 .. nblock-1]
+ Post:
+ ((byte*)eclass) [0 .. nblock-1] holds block
+ All other areas of eclass destroyed
+ fmap [0 .. nblock-1] holds sorted order
+ bhtab [ 0 .. 2+(nblock/32) ] destroyed
+ */
+
+ public static void fallbackSort(uint* fmap, uint* eclass, uint* bhtab, int nblock, int verb)
+ {
+ int[] ftab = new int[257];
+ int[] ftabCopy = new int[256];
+ int H, i, j, k, l, r, cc, cc1;
+ int nNotDone;
+ int nBhtab;
+ byte* eclass8 = (byte*)eclass;
+
+ /*--
+ Initial 1-char radix sort to generate
+ initial fmap and initial BH bits.
+ --*/
+ // if (verb >= 4)
+ // VPrintf0(" bucket sorting ...\n");
+ for (i = 0; i < 257; i++)
+ {
+ ftab[i] = 0;
+ }
+
+ for (i = 0; i < nblock; i++)
+ {
+ ftab[eclass8[i]]++;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ ftabCopy[i] = ftab[i];
+ }
+
+ for (i = 1; i < 257; i++)
+ {
+ ftab[i] += ftab[i - 1];
+ }
+
+ for (i = 0; i < nblock; i++)
+ {
+ j = eclass8[i];
+ k = ftab[j] - 1;
+ ftab[j] = k;
+ fmap[k] = (uint)i;
+ }
+
+ nBhtab = 2 + (nblock / 32);
+ for (i = 0; i < nBhtab; i++)
+ {
+ bhtab[i] = 0;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ SET_BH(ftab[i], bhtab);
+ }
+
+ /*--
+ Inductively refine the buckets. Kind-of an
+ "exponential radix sort" (!), inspired by the
+ Manber-Myers suffix array construction algorithm.
+ --*/
+
+ /*-- set sentinel bits for block-end detection --*/
+ for (i = 0; i < 32; i++)
+ {
+ SET_BH(nblock + 2 * i, bhtab);
+ CLEAR_BH(nblock + 2 * i + 1, bhtab);
+ }
+
+ /*-- the log(N) loop --*/
+ H = 1;
+ while (true)
+ {
+ // if (verb >= 4)
+ // VPrintf1(" depth %6d has ", H);
+
+ j = 0;
+ for (i = 0; i < nblock; i++)
+ {
+ if (ISSET_BH(i, bhtab))
+ j = i;
+
+ k = (int)(fmap[i] - H);
+ if (k < 0)
+ k += nblock;
+
+ eclass[k] = (uint)j;
+ }
+
+ nNotDone = 0;
+ r = -1;
+ while (true)
+ {
+
+ /*-- find the next non-singleton bucket --*/
+ k = r + 1;
+ while (ISSET_BH(k, bhtab) && UNALIGNED_BH(k) != 0)
+ {
+ k++;
+ }
+
+ if (ISSET_BH(k, bhtab))
+ {
+ while (WORD_BH(k, bhtab) == 0xffffffff)
+ {
+ k += 32;
+ }
+
+ while (ISSET_BH(k, bhtab))
+ {
+ k++;
+ }
+ }
+
+ l = k - 1;
+ if (l >= nblock)
+ break;
+
+ while (!ISSET_BH(k, bhtab) && UNALIGNED_BH(k) != 0)
+ {
+ k++;
+ }
+
+ if (!ISSET_BH(k, bhtab))
+ {
+ while (WORD_BH(k, bhtab) == 0x00000000)
+ {
+ k += 32;
+ }
+
+ while (!ISSET_BH(k, bhtab))
+ {
+ k++;
+ }
+ }
+
+ r = k - 1;
+ if (r >= nblock)
+ break;
+
+ /*-- now [l, r] bracket current bucket --*/
+ if (r > l)
+ {
+ nNotDone += (r - l + 1);
+ fallbackQSort3(fmap, eclass, l, r);
+
+ /*-- scan bucket and generate header bits-- */
+ cc = -1;
+ for (i = l; i <= r; i++)
+ {
+ cc1 = (int)eclass[fmap[i]];
+ if (cc != cc1)
+ {
+ SET_BH(i, bhtab);
+ cc = cc1;
+ };
+ }
+ }
+ }
+
+ // if (verb >= 4)
+ // VPrintf1("%6d unresolved strings\n", nNotDone);
+
+ H *= 2;
+ if (H > nblock || nNotDone == 0)
+ break;
+ }
+
+ /*--
+ Reconstruct the original block in
+ eclass8 [0 .. nblock-1], since the
+ previous phase destroyed it.
+ --*/
+ // if (verb >= 4)
+ // VPrintf0(" reconstructing block ...\n");
+
+ j = 0;
+ for (i = 0; i < nblock; i++)
+ {
+ while (ftabCopy[j] == 0)
+ {
+ j++;
+ }
+
+ ftabCopy[j]--;
+ eclass8[fmap[i]] = (byte)j;
+ }
+
+ //AssertH(j < 256, 1005);
+ }
+
+ ///
+ /// The main, O(N^2 log(N)) sorting algorithm.
+ /// Faster for "normal" non-repetitive blocks.
+ ///
+ public static bool mainGtU(uint i1, uint i2, byte* block, ushort* quadrant, uint nblock, int* budget)
+ {
+ uint k;
+ byte c1, c2;
+ ushort s1, s2;
+
+ //AssertD(i1 != i2, "mainGtU");
+ /* 1 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 2 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 3 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 4 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 5 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 6 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 7 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 8 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 9 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 10 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 11 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 12 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+
+ k = nblock + 8;
+
+ do
+ {
+ /* 1 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 2 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 3 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 4 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 5 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 6 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 7 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 8 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+
+ if (i1 >= nblock) i1 -= nblock;
+ if (i2 >= nblock) i2 -= nblock;
+
+ k -= 8;
+ (*budget)--;
+ }
+ while (k >= 0);
+
+ return false;
+ }
+
+ public static void mainSimpleSort(uint* ptr, byte* block, ushort* quadrant, int nblock, int lo, int hi, int d, int* budget)
+ {
+ int i, j, h, bigN, hp;
+ uint v;
+
+ bigN = hi - lo + 1;
+ if (bigN < 2)
+ return;
+
+ hp = 0;
+ while (incs[hp] < bigN) hp++;
+ hp--;
+
+ for (; hp >= 0; hp--)
+ {
+ h = incs[hp];
+
+ i = lo + h;
+ while (true)
+ {
+ /*-- copy 1 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while (mainGtU((uint)(ptr[j - h] + d), (uint)(v + d), block, quadrant, (uint)nblock, budget))
+ {
+ ptr[j] = ptr[j - h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+
+ ptr[j] = v;
+ i++;
+
+ /*-- copy 2 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while (mainGtU((uint)(ptr[j - h] + d), (uint)(v + d), block, quadrant, (uint)nblock, budget))
+ {
+ ptr[j] = ptr[j - h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+
+ ptr[j] = v;
+ i++;
+
+ /*-- copy 3 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while (mainGtU((uint)(ptr[j - h] + d), (uint)(v + d), block, quadrant, (uint)nblock, budget))
+ {
+ ptr[j] = ptr[j - h];
+ j = j - h;
+ if (j <= (lo + h - 1))
+ break;
+ }
+
+ ptr[j] = v;
+ i++;
+
+ if (*budget < 0)
+ return;
+ }
+ }
+ }
+
+ /*--
+ The following is an implementation of
+ an elegant 3-way quicksort for strings,
+ described in a paper "Fast Algorithms for
+ Sorting and Searching Strings", by Robert
+ Sedgewick and Jon L. Bentley.
+ --*/
+ public static byte mmed3(byte a, byte b, byte c)
+ {
+ byte t;
+ if (a > b)
+ {
+ t = a;
+ a = b;
+ b = t;
+ };
+
+ if (b > c)
+ {
+ b = c;
+ if (a > b)
+ b = a;
+ }
+
+ return b;
+ }
+
+ public static void mainQSort3(uint* ptr, byte* block, ushort* quadrant, int nblock, int loSt, int hiSt, int dSt, int* budget)
+ {
+ int unLo, unHi, ltLo, gtHi, n, m, med;
+ int sp, lo = 0, hi = 0, d = 0;
+
+ int[] stackLo = new int[MAIN_QSORT_STACK_SIZE];
+ int[] stackHi = new int[MAIN_QSORT_STACK_SIZE];
+ int[] stackD = new int[MAIN_QSORT_STACK_SIZE];
+
+ int[] nextLo = new int[3];
+ int[] nextHi = new int[3];
+ int[] nextD = new int[3];
+
+ sp = 0;
+ mpush(loSt, hiSt, dSt, stackLo, stackHi, stackD, ref sp);
+
+ while (sp > 0)
+ {
+ //AssertH(sp < MAIN_QSORT_STACK_SIZE - 2, 1001);
+
+ mpop(ref lo, ref hi, ref d, stackLo, stackHi, stackD, ref sp);
+ if (hi - lo < MAIN_QSORT_SMALL_THRESH ||
+ d > MAIN_QSORT_DEPTH_THRESH)
+ {
+ mainSimpleSort(ptr, block, quadrant, nblock, lo, hi, d, budget);
+ if (*budget < 0) return;
+ continue;
+ }
+
+ med = mmed3(block[ptr[lo] + d], block[ptr[hi] + d], block[ptr[(lo + hi) >> 1] + d]);
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (true)
+ {
+ while (true)
+ {
+ if (unLo > unHi)
+ break;
+
+ n = (block[ptr[unLo] + d]) - med;
+ if (n == 0)
+ {
+ mswap(ref ptr[unLo], ref ptr[ltLo]);
+ ltLo++; unLo++; continue;
+ };
+
+ if (n > 0)
+ break;
+
+ unLo++;
+ }
+ while (true)
+ {
+ if (unLo > unHi)
+ break;
+
+ n = (block[ptr[unHi] + d]) - med;
+ if (n == 0)
+ {
+ mswap(ref ptr[unHi], ref ptr[gtHi]);
+ gtHi--;
+ unHi--;
+ continue;
+ };
+
+ if (n < 0)
+ break;
+
+ unHi--;
+ }
+
+ if (unLo > unHi)
+ break;
+
+ mswap(ref ptr[unLo], ref ptr[unHi]);
+ unLo++;
+ unHi--;
+ }
+
+ //AssertD(unHi == unLo - 1, "mainQSort3(2)");
+
+ if (gtHi < ltLo)
+ {
+ mpush(lo, hi, d + 1, stackLo, stackHi, stackD, ref sp);
+ continue;
+ }
+
+ n = mmin(ltLo - lo, unLo - ltLo); mvswap(ptr, lo, unLo - n, n);
+ m = mmin(hi - gtHi, gtHi - unHi); mvswap(ptr, unLo, hi - m + 1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ nextLo[0] = lo; nextHi[0] = n; nextD[0] = d;
+ nextLo[1] = m; nextHi[1] = hi; nextD[1] = d;
+ nextLo[2] = n + 1; nextHi[2] = m - 1; nextD[2] = d + 1;
+
+ if (mnextsize(0, nextLo, nextHi) < mnextsize(1, nextLo, nextHi)) mnextswap(0, 1, nextLo, nextHi, nextD);
+ if (mnextsize(1, nextLo, nextHi) < mnextsize(2, nextLo, nextHi)) mnextswap(1, 2, nextLo, nextHi, nextD);
+ if (mnextsize(0, nextLo, nextHi) < mnextsize(1, nextLo, nextHi)) mnextswap(0, 1, nextLo, nextHi, nextD);
+
+ //AssertD(mnextsize(0) >= mnextsize(1), "mainQSort3(8)");
+ //AssertD(mnextsize(1) >= mnextsize(2), "mainQSort3(9)");
+
+ mpush(nextLo[0], nextHi[0], nextD[0], stackLo, stackHi, stackD, ref sp);
+ mpush(nextLo[1], nextHi[1], nextD[1], stackLo, stackHi, stackD, ref sp);
+ mpush(nextLo[2], nextHi[2], nextD[2], stackLo, stackHi, stackD, ref sp);
+ }
+ }
+
+ /*
+ Pre:
+ nblock > N_OVERSHOOT
+ block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ ((byte*)block32) [0 .. nblock-1] holds block
+ ptr exists for [0 .. nblock-1]
+ Post:
+ ((byte*)block32) [0 .. nblock-1] holds block
+ All other areas of block32 destroyed
+ ftab [0 .. 65536 ] destroyed
+ ptr [0 .. nblock-1] holds sorted order
+ if (*budget < 0), sorting was abandoned
+ */
+
+ public static void mainSort(uint* ptr, byte* block, ushort* quadrant, uint* ftab, int nblock, int verb, int* budget)
+ {
+ int i, j, k, ss, sb;
+ int[] runningOrder = new int[256];
+ bool[] bigDone = new bool[256];
+ int[] copyStart = new int[256];
+ int[] copyEnd = new int[256];
+ byte c1;
+ int numQSorted;
+ ushort s;
+
+ // if (verb >= 4) VPrintf0(" main sort initialise ...\n");
+
+ /*-- set up the 2-byte frequency table --*/
+ for (i = 65536; i >= 0; i--)
+ {
+ ftab[i] = 0;
+ }
+
+ j = block[0] << 8;
+ i = nblock - 1;
+ for (; i >= 3; i -= 4)
+ {
+ quadrant[i] = 0;
+ j = (j >> 8) | ((block[i]) << 8);
+ ftab[j]++;
+
+ quadrant[i - 1] = 0;
+ j = (j >> 8) | ((block[i - 1]) << 8);
+ ftab[j]++;
+
+ quadrant[i - 2] = 0;
+ j = (j >> 8) | ((block[i - 2]) << 8);
+ ftab[j]++;
+
+ quadrant[i - 3] = 0;
+ j = (j >> 8) | ((block[i - 3]) << 8);
+ ftab[j]++;
+ }
+
+ for (; i >= 0; i--)
+ {
+ quadrant[i] = 0;
+ j = (j >> 8) | ((block[i]) << 8);
+ ftab[j]++;
+ }
+
+ /*-- (emphasises close relationship of block & quadrant) --*/
+ for (i = 0; i < BZ_N_OVERSHOOT; i++)
+ {
+ block[nblock + i] = block[i];
+ quadrant[nblock + i] = 0;
+ }
+
+ // if (verb >= 4) VPrintf0(" bucket sorting ...\n");
+
+ /*-- Complete the initial radix sort --*/
+ for (i = 1; i <= 65536; i++) ftab[i] += ftab[i - 1];
+
+ s = (ushort)(block[0] << 8);
+ i = nblock - 1;
+ for (; i >= 3; i -= 4)
+ {
+ s = (ushort)((s >> 8) | (block[i] << 8));
+ j = (int)(ftab[s] - 1);
+ ftab[s] = (uint)j;
+ ptr[j] = (uint)i;
+
+ s = (ushort)((s >> 8) | (block[i - 1] << 8));
+ j = (int)(ftab[s] - 1);
+ ftab[s] = (uint)j;
+ ptr[j] = (uint)(i - 1);
+
+ s = (ushort)((s >> 8) | (block[i - 2] << 8));
+ j = (int)(ftab[s] - 1);
+ ftab[s] = (uint)j;
+ ptr[j] = (uint)(i - 2);
+
+ s = (ushort)((s >> 8) | (block[i - 3] << 8));
+ j = (int)(ftab[s] - 1);
+ ftab[s] = (uint)j;
+ ptr[j] = (uint)(i - 3);
+ }
+
+ for (; i >= 0; i--)
+ {
+ s = (ushort)((s >> 8) | (block[i] << 8));
+ j = (int)(ftab[s] - 1);
+ ftab[s] = (uint)j;
+ ptr[j] = (uint)i;
+ }
+
+ /*--
+ Now ftab contains the first loc of every small bucket.
+ Calculate the running order, from smallest to largest
+ big bucket.
+ --*/
+ for (i = 0; i <= 255; i++)
+ {
+ bigDone[i] = false;
+ runningOrder[i] = i;
+ }
+
+ {
+ int vv;
+ int h = 1;
+ do
+ {
+ h = 3 * h + 1;
+ }
+ while (h <= 256);
+
+ do
+ {
+ h = h / 3;
+ for (i = h; i <= 255; i++)
+ {
+ vv = runningOrder[i];
+ j = i;
+ while (BIGFREQ(runningOrder[j - h], ftab) > BIGFREQ(vv, ftab))
+ {
+ runningOrder[j] = runningOrder[j - h];
+ j = j - h;
+ if (j <= (h - 1))
+ goto zero;
+ }
+
+ zero:
+ runningOrder[j] = vv;
+ }
+ } while (h != 1);
+ }
+
+ /*--
+ The main sorting loop.
+ --*/
+
+ numQSorted = 0;
+
+ for (i = 0; i <= 255; i++)
+ {
+
+ /*--
+ Process big buckets, starting with the least full.
+ Basically this is a 3-step process in which we call
+ mainQSort3 to sort the small buckets [ss, j], but
+ also make a big effort to avoid the calls if we can.
+ --*/
+ ss = runningOrder[i];
+
+ /*--
+ Step 1:
+ Complete the big bucket [ss] by quicksorting
+ any unsorted small buckets [ss, j], for j != ss.
+ Hopefully previous pointer-scanning phases have already
+ completed many of the small buckets [ss, j], so
+ we don't have to sort them at all.
+ --*/
+ for (j = 0; j <= 255; j++)
+ {
+ if (j != ss)
+ {
+ sb = (ss << 8) + j;
+ if ((ftab[sb] & SETMASK) == 0)
+ {
+ int lo = (int)(ftab[sb] & CLEARMASK);
+ int hi = (int)((ftab[sb + 1] & CLEARMASK) - 1);
+ if (hi > lo)
+ {
+ // if (verb >= 4)
+ // VPrintf4(" qsort [0x%x, 0x%x] "
+
+ // "done %d this %d\n",
+ // ss, j, numQSorted, hi - lo + 1);
+
+ mainQSort3(
+ ptr, block, quadrant, nblock,
+ lo, hi, BZ_N_RADIX, budget
+ );
+ numQSorted += (hi - lo + 1);
+ if (*budget < 0) return;
+ }
+ }
+
+ ftab[sb] |= SETMASK;
+ }
+ }
+
+ //AssertH(!bigDone[ss], 1006);
+
+ /*--
+ Step 2:
+ Now scan this big bucket [ss] so as to synthesise the
+ sorted order for small buckets [t, ss] for all t,
+ including, magically, the bucket [ss,ss] too.
+ This will avoid doing Real Work in subsequent Step 1's.
+ --*/
+ {
+ for (j = 0; j <= 255; j++)
+ {
+ copyStart[j] = (int)(ftab[(j << 8) + ss] & CLEARMASK);
+ copyEnd[j] = (int)((ftab[(j << 8) + ss + 1] & CLEARMASK) - 1);
+ }
+
+ for (j = (int)(ftab[ss << 8] & CLEARMASK); j < copyStart[ss]; j++)
+ {
+ k = (int)(ptr[j] - 1);
+ if (k < 0)
+ k += nblock;
+
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[copyStart[c1]++] = (uint)k;
+ }
+
+ for (j = (int)((ftab[(ss + 1) << 8] & CLEARMASK) - 1); j > copyEnd[ss]; j--)
+ {
+ k = (int)(ptr[j] - 1);
+ if (k < 0)
+ k += nblock;
+
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[copyEnd[c1]--] = (uint)k;
+ }
+ }
+
+ // AssertH((copyStart[ss] - 1 == copyEnd[ss])
+ // ||
+ // /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+ // Necessity for this case is demonstrated by compressing
+ // a sequence of approximately 48.5 million of character
+ // 251; 1.0.0/1.0.1 will then die here. */
+ // (copyStart[ss] == 0 && copyEnd[ss] == nblock - 1),
+ // 1007)
+
+
+ for (j = 0; j <= 255; j++)
+ {
+ ftab[(j << 8) + ss] |= SETMASK;
+ }
+
+ /*--
+ Step 3:
+ The [ss] big bucket is now done. Record this fact,
+ and update the quadrant descriptors. Remember to
+ update quadrants in the overshoot area too, if
+ necessary. The "if (i < 255)" test merely skips
+ this updating for the last bucket processed, since
+ updating for the last bucket is pointless.
+ The quadrant array provides a way to incrementally
+ cache sort orderings, as they appear, so as to
+ make subsequent comparisons in fullGtU() complete
+ faster. For repetitive blocks this makes a big
+ difference (but not big enough to be able to avoid
+ the fallback sorting mechanism, exponential radix sort).
+ The precise meaning is: at all times:
+ for 0 <= i < nblock and 0 <= j <= nblock
+ if block[i] != block[j],
+ then the relative values of quadrant[i] and
+ quadrant[j] are meaningless.
+ else {
+ if quadrant[i] < quadrant[j]
+ then the string starting at i lexicographically
+ precedes the string starting at j
+ else if quadrant[i] > quadrant[j]
+ then the string starting at j lexicographically
+ precedes the string starting at i
+ else
+ the relative ordering of the strings starting
+ at i and j has not yet been determined.
+ }
+ --*/
+ bigDone[ss] = true;
+
+ if (i < 255)
+ {
+ int bbStart = (int)(ftab[ss << 8] & CLEARMASK);
+ int bbSize = (int)((ftab[(ss + 1) << 8] & CLEARMASK) - bbStart);
+ int shifts = 0;
+
+ while ((bbSize >> shifts) > 65534) shifts++;
+
+ for (j = bbSize - 1; j >= 0; j--)
+ {
+ int a2update = (int)ptr[bbStart + j];
+ ushort qVal = (ushort)(j >> shifts);
+ quadrant[a2update] = qVal;
+ if (a2update < BZ_N_OVERSHOOT)
+ quadrant[a2update + nblock] = qVal;
+ }
+
+ // AssertH(((bbSize - 1) >> shifts) <= 65535, 1002);
+ }
+
+ }
+
+ // if (verb >= 4)
+ // VPrintf3(" %d pointers, %d sorted, %d scanned\n",
+ // nblock, numQSorted, nblock - numQSorted);
+ }
+
+ /*
+ Pre:
+ nblock > 0
+ arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ ((byte*)arr2) [0 .. nblock-1] holds block
+ arr1 exists for [0 .. nblock-1]
+ Post:
+ ((byte*)arr2) [0 .. nblock-1] holds block
+ All other areas of block destroyed
+ ftab [ 0 .. 65536 ] destroyed
+ arr1 [0 .. nblock-1] holds sorted order
+ */
+
+ public static void BZ2_blockSort(EState s)
+ {
+ uint* ptr = s.ptr;
+ byte* block = s.block;
+ uint* ftab = s.ftab;
+ int nblock = s.nblock;
+ int verb = s.verbosity;
+ int wfact = s.workFactor;
+ ushort* quadrant;
+ int budget;
+ int budgetInit;
+ int i;
+
+ if (nblock < 10000)
+ {
+ fallbackSort(s.arr1, s.arr2, ftab, nblock, verb);
+ }
+ else
+ {
+ /* Calculate the location for quadrant, remembering to get
+ the alignment right. Assumes that &(block[0]) is at least
+ 2-byte aligned -- this should be ok since block is really
+ the first section of arr2.
+ */
+ i = nblock + BZ_N_OVERSHOOT;
+ if ((i & 1) != 0) i++;
+ quadrant = (ushort*)(&(block[i]));
+
+ /* (wfact-1) / 3 puts the default-factor-30
+ transition point at very roughly the same place as
+ with v0.1 and v0.9.0.
+ Not that it particularly matters any more, since the
+ resulting compressed stream is now the same regardless
+ of whether or not we use the main sort or fallback sort.
+ */
+ if (wfact < 1) wfact = 1;
+ if (wfact > 100) wfact = 100;
+ budgetInit = nblock * ((wfact - 1) / 3);
+ budget = budgetInit;
+
+ mainSort(ptr, block, quadrant, ftab, nblock, verb, &budget);
+ // if (verb >= 3)
+ // VPrintf3(" %d work, %d block, ratio %5.2f\n",
+ // budgetInit - budget,
+ // nblock,
+ // (float)(budgetInit - budget) /
+ // (float)(nblock == 0 ? 1 : nblock));
+ if (budget < 0)
+ {
+ // if (verb >= 2)
+ // VPrintf0(" too repetitive; using fallback"
+
+ // " sorting algorithm\n");
+ fallbackSort(s.arr1, s.arr2, ftab, nblock, verb);
+ }
+ }
+
+ s.origPtr = -1;
+ for (i = 0; i < s.nblock; i++)
+ if (ptr[i] == 0)
+ { s.origPtr = i; break; };
+
+ //AssertH(s.origPtr != -1, 1003);
+ }
+
+ #region Macros
+
+ private static void fswap(ref int zz1, ref int zz2)
+ {
+ int zztmp = zz1;
+ zz1 = zz2;
+ zz2 = zztmp;
+ }
+
+ private static void fswap(ref uint zz1, ref uint zz2)
+ {
+ uint zztmp = zz1;
+ zz1 = zz2;
+ zz2 = zztmp;
+ }
+
+ private static void fvswap(uint* fmap, int zzp1, int zzp2, int zzn)
+ {
+ int yyp1 = (zzp1);
+ int yyp2 = (zzp2);
+ int yyn = (zzn);
+ while (yyn > 0)
+ {
+ fswap(ref fmap[yyp1], ref fmap[yyp2]);
+ yyp1++; yyp2++; yyn--;
+ }
+ }
+
+ private static int fmin(int a, int b) => (a < b) ? a : b;
+
+ private static void fpush(int lz, int hz, int[] stackLo, int[] stackHi, ref int sp)
+ {
+ stackLo[sp] = lz;
+ stackHi[sp] = hz;
+ sp++;
+ }
+
+ private static void fpop(ref int lz, ref int hz, int[] stackLo, int[] stackHi, ref int sp)
+ {
+ sp--;
+ lz = stackLo[sp];
+ hz = stackHi[sp];
+ }
+
+ private static void SET_BH(int zz, uint* bhtab)
+ {
+ bhtab[zz >> 5] |= (uint)(1 << (zz & 31));
+ }
+
+ private static void CLEAR_BH(int zz, uint* bhtab)
+ {
+ bhtab[zz >> 5] &= (uint)~(1 << (zz & 31));
+ }
+
+ private static bool ISSET_BH(int zz, uint* bhtab) => (bhtab[zz >> 5] & (1 << (zz & 31))) != 0;
+
+ private static uint WORD_BH(int zz, uint* bhtab) => bhtab[(zz) >> 5];
+
+ private static int UNALIGNED_BH(int zz) => zz & 0x01f;
+
+ private static void mswap(ref uint zz1, ref uint zz2)
+ {
+ uint zztmp = zz1;
+ zz1 = zz2;
+ zz2 = zztmp;
+ }
+
+ private static void mvswap(uint* ptr, int zzp1, int zzp2, int zzn)
+ {
+ int yyp1 = (zzp1);
+ int yyp2 = (zzp2);
+ int yyn = (zzn);
+ while (yyn > 0)
+ {
+ mswap(ref ptr[yyp1], ref ptr[yyp2]);
+ yyp1++; yyp2++; yyn--;
+ }
+ }
+
+ private static int mmin(int a, int b) => (a < b) ? a : b;
+
+ private static void mpush(int lz, int hz, int dz, int[] stackLo, int[] stackHi, int[] stackD, ref int sp)
+ {
+ stackLo[sp] = lz;
+ stackHi[sp] = hz;
+ stackD[sp] = dz;
+ sp++;
+ }
+
+ private static void mpop(ref int lz, ref int hz, ref int dz, int[] stackLo, int[] stackHi, int[] stackD, ref int sp)
+ {
+ sp--;
+ lz = stackLo[sp];
+ hz = stackHi[sp];
+ dz = stackD[sp];
+ }
+
+ private static int mnextsize(int az, int[] nextLo, int[] nextHi) => nextHi[az] - nextLo[az];
+
+ private static void mnextswap(int az, int bz, int[] nextLo, int[] nextHi, int[] nextD)
+ {
+ int tz;
+ tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz;
+ tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz;
+ tz = nextD[az]; nextD[az] = nextD[bz]; nextD[bz] = tz;
+ }
+
+ private static uint BIGFREQ(int b, uint* ftab) => ftab[(b + 1) << 8] - ftab[b << 8];
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/bzip2/bz_stream.cs b/BurnOutSharp.Compression/bzip2/bz_stream.cs
new file mode 100644
index 00000000..b5fe6199
--- /dev/null
+++ b/BurnOutSharp.Compression/bzip2/bz_stream.cs
@@ -0,0 +1,22 @@
+namespace BurnOutSharp.Compression.bzip2
+{
+ ///
+ public unsafe struct bz_stream
+ {
+ public char* next_in;
+ public uint avail_in;
+ public uint total_in_lo32;
+ public uint total_in_hi32;
+
+ public char* next_out;
+ public uint avail_out;
+ public uint total_out_lo32;
+ public uint total_out_hi32;
+
+ public void* state;
+
+ // void *(*bzalloc)(void *,int,int);
+ // void (*bzfree)(void *,void *);
+ // void *opaque;
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/bzip2/decompress.cs b/BurnOutSharp.Compression/bzip2/decompress.cs
new file mode 100644
index 00000000..9e0cd030
--- /dev/null
+++ b/BurnOutSharp.Compression/bzip2/decompress.cs
@@ -0,0 +1,2194 @@
+using System.Runtime.InteropServices;
+using static BurnOutSharp.Compression.bzip2.Constants;
+using static BurnOutSharp.Compression.bzip2.Huffman;
+
+namespace BurnOutSharp.Compression.bzip2
+{
+ ///
+ internal static unsafe class decompress
+ {
+ private static void makeMaps_d(DState s)
+ {
+ int i;
+ s.nInUse = 0;
+ for (i = 0; i < 256; i++)
+ {
+ if (s.inUse[i])
+ {
+ s.seqToUnseq[s.nInUse] = (byte)i;
+ s.nInUse++;
+ }
+ }
+ }
+
+ public static int BZ2_decompress(DState s)
+ {
+ byte uc = 0;
+ int retVal;
+ int minLen, maxLen;
+ bz_stream strm = s.strm;
+
+ /* stuff that needs to be saved/restored */
+ int i;
+ int j;
+ int t;
+ int alphaSize;
+ int nGroups;
+ int nSelectors;
+ int EOB;
+ int groupNo;
+ int groupPos;
+ int nextSym;
+ int nblockMAX;
+ int nblock;
+ int es;
+ int N;
+ int curr;
+ int zt;
+ int zn;
+ int zvec;
+ int zj;
+ int gSel;
+ int gMinlen;
+ int* gLimit;
+ int* gBase;
+ int* gPerm;
+
+ if (s.state == BZ_X_MAGIC_1)
+ {
+ /*initialise the save area*/
+ s.save_i = 0;
+ s.save_j = 0;
+ s.save_t = 0;
+ s.save_alphaSize = 0;
+ s.save_nGroups = 0;
+ s.save_nSelectors = 0;
+ s.save_EOB = 0;
+ s.save_groupNo = 0;
+ s.save_groupPos = 0;
+ s.save_nextSym = 0;
+ s.save_nblockMAX = 0;
+ s.save_nblock = 0;
+ s.save_es = 0;
+ s.save_N = 0;
+ s.save_curr = 0;
+ s.save_zt = 0;
+ s.save_zn = 0;
+ s.save_zvec = 0;
+ s.save_zj = 0;
+ s.save_gSel = 0;
+ s.save_gMinlen = 0;
+ s.save_gLimit = null;
+ s.save_gBase = null;
+ s.save_gPerm = null;
+ }
+
+ /*restore from the save area*/
+ i = s.save_i;
+ j = s.save_j;
+ t = s.save_t;
+ alphaSize = s.save_alphaSize;
+ nGroups = s.save_nGroups;
+ nSelectors = s.save_nSelectors;
+ EOB = s.save_EOB;
+ groupNo = s.save_groupNo;
+ groupPos = s.save_groupPos;
+ nextSym = s.save_nextSym;
+ nblockMAX = s.save_nblockMAX;
+ nblock = s.save_nblock;
+ es = s.save_es;
+ N = s.save_N;
+ curr = s.save_curr;
+ zt = s.save_zt;
+ zn = s.save_zn;
+ zvec = s.save_zvec;
+ zj = s.save_zj;
+ gSel = s.save_gSel;
+ gMinlen = s.save_gMinlen;
+ gLimit = s.save_gLimit;
+ gBase = s.save_gBase;
+ gPerm = s.save_gPerm;
+
+ retVal = BZ_OK;
+
+ switch (s.state)
+ {
+ // States that don't map to cases -- TODO: Figure out how to reference the right labels
+ // case BZ_X_MAPPING_1: goto BZ_X_MAPPING_1; break;
+ // case BZ_X_MAPPING_2: goto BZ_X_MAPPING_2; break;
+ // case BZ_X_SELECTOR_3: goto BZ_X_SELECTOR_3; break;
+ // case BZ_X_CODING_1: goto BZ_X_CODING_1; break;
+ // case BZ_X_CODING_2: goto BZ_X_CODING_2; break;
+ // case BZ_X_CODING_3: goto BZ_X_CODING_3; break;
+ // case BZ_X_MTF_2: goto BZ_X_MTF_2; break;
+ // case BZ_X_MTF_3: goto BZ_X_MTF_3; break;
+ // case BZ_X_MTF_4: goto BZ_X_MTF_4; break;
+ // case BZ_X_MTF_5: goto BZ_X_MTF_5; break;
+ // case BZ_X_MTF_6: goto BZ_X_MTF_6; break;
+
+ case BZ_X_MAGIC_1:
+ s.state = BZ_X_MAGIC_1;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != BZ_HDR_B)
+ {
+ retVal = BZ_DATA_ERROR_MAGIC;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_MAGIC_2;
+
+ case BZ_X_MAGIC_2:
+ s.state = BZ_X_MAGIC_2;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != BZ_HDR_Z)
+ {
+ retVal = BZ_DATA_ERROR_MAGIC;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_MAGIC_3;
+
+ case BZ_X_MAGIC_3:
+ s.state = BZ_X_MAGIC_3;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != BZ_HDR_h)
+ {
+ retVal = BZ_DATA_ERROR_MAGIC;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_MAGIC_4;
+
+ case BZ_X_MAGIC_4:
+ s.state = BZ_X_MAGIC_4;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ s.blockSize100k = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (s.blockSize100k < (BZ_HDR_0 + 1) || s.blockSize100k > (BZ_HDR_0 + 9))
+ {
+ retVal = BZ_DATA_ERROR_MAGIC;
+ goto save_state_and_return;
+ }
+
+ s.blockSize100k -= BZ_HDR_0;
+
+ if (s.smallDecompress)
+ {
+ s.ll16 = (ushort*)Marshal.AllocHGlobal(s.blockSize100k * 100000 * sizeof(ushort));
+ s.ll4 = (byte*)Marshal.AllocHGlobal(((1 + s.blockSize100k * 100000) >> 1) * sizeof(byte));
+ if (s.ll16 == null || s.ll4 == null)
+ {
+ retVal = BZ_MEM_ERROR;
+ goto save_state_and_return;
+ }
+ }
+ else
+ {
+ s.tt = (uint*)Marshal.AllocHGlobal(s.blockSize100k * 100000 * sizeof(int));
+ if (s.tt == null)
+ {
+ retVal = BZ_MEM_ERROR;
+ goto save_state_and_return;
+ }
+ }
+
+ // Fallthrough
+ goto case BZ_X_BLKHDR_1;
+
+ case BZ_X_BLKHDR_1:
+ s.state = BZ_X_BLKHDR_1;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc == 0x17)
+ goto case BZ_X_ENDHDR_2;
+
+ if (uc != 0x31)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_BLKHDR_2;
+
+ case BZ_X_BLKHDR_2:
+ s.state = BZ_X_BLKHDR_2;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x41)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_BLKHDR_3;
+
+ case BZ_X_BLKHDR_3:
+ s.state = BZ_X_BLKHDR_3;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x59)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_BLKHDR_4;
+
+ case BZ_X_BLKHDR_4:
+ s.state = BZ_X_BLKHDR_4;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x26)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_BLKHDR_5;
+
+ case BZ_X_BLKHDR_5:
+ s.state = BZ_X_BLKHDR_5;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x53)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_BLKHDR_6;
+
+ case BZ_X_BLKHDR_6:
+ s.state = BZ_X_BLKHDR_6;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x59)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ s.currBlockNo++;
+ // if (s.verbosity >= 2)
+ // VPrintf1("\n [%d: huff+mtf ", s.currBlockNo);
+
+ s.storedBlockCRC = 0;
+
+ // Fallthrough
+ goto case BZ_X_BCRC_1;
+
+ case BZ_X_BCRC_1:
+ s.state = BZ_X_BCRC_1;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.storedBlockCRC = (s.storedBlockCRC << 8) | ((uint)uc);
+
+ // Fallthrough
+ goto case BZ_X_BCRC_2;
+
+ case BZ_X_BCRC_2:
+ s.state = BZ_X_BCRC_2;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.storedBlockCRC = (s.storedBlockCRC << 8) | ((uint)uc);
+
+ // Fallthrough
+ goto case BZ_X_BCRC_3;
+
+ case BZ_X_BCRC_3:
+ s.state = BZ_X_BCRC_3;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.storedBlockCRC = (s.storedBlockCRC << 8) | ((uint)uc);
+
+ // Fallthrough
+ goto case BZ_X_BCRC_4;
+
+ case BZ_X_BCRC_4:
+ s.state = BZ_X_BCRC_4;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.storedBlockCRC = (s.storedBlockCRC << 8) | ((uint)uc);
+
+ // Fallthrough
+ goto case BZ_X_RANDBIT;
+
+ case BZ_X_RANDBIT:
+ s.state = BZ_X_RANDBIT;
+ while (true)
+ {
+ if (s.bsLive >= 1)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 1)) & ((1 << 1) - 1));
+ s.bsLive -= 1;
+ s.blockRandomised = v != 0;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.origPtr = 0;
+
+ // Fallthrough
+ goto case BZ_X_ORIGPTR_1;
+
+ case BZ_X_ORIGPTR_1:
+ s.state = BZ_X_ORIGPTR_1;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.origPtr = (s.origPtr << 8) | ((int)uc);
+
+ // Fallthrough
+ goto case BZ_X_ORIGPTR_2;
+
+ case BZ_X_ORIGPTR_2:
+ s.state = BZ_X_ORIGPTR_2;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.origPtr = (s.origPtr << 8) | ((int)uc);
+
+ // Fallthrough
+ goto case BZ_X_ORIGPTR_3;
+
+ case BZ_X_ORIGPTR_3:
+
+ s.state = BZ_X_ORIGPTR_3;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.origPtr = (s.origPtr << 8) | ((int)uc);
+
+ if (s.origPtr < 0)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ if (s.origPtr > 10 + 100000 * s.blockSize100k)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ /*--- Receive the mapping table ---*/
+ for (i = 0; i < 16; i++)
+ {
+ BZ_X_MAPPING_1:
+ s.state = BZ_X_MAPPING_1;
+ while (true)
+ {
+ if (s.bsLive >= 1)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 1)) & ((1 << 1) - 1));
+ s.bsLive -= 1;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc == 1)
+ s.inUse16[i] = true;
+ else
+ s.inUse16[i] = false;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ s.inUse[i] = false;
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ if (s.inUse16[i])
+ {
+ for (j = 0; j < 16; j++)
+ {
+ BZ_X_MAPPING_2:
+ s.state = BZ_X_MAPPING_2;
+ while (true)
+ {
+ if (s.bsLive >= 1)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 1)) & ((1 << 1) - 1));
+ s.bsLive -= 1;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc == 1)
+ s.inUse[i * 16 + j] = true;
+ }
+ }
+ }
+
+ makeMaps_d(s);
+ if (s.nInUse == 0)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ alphaSize = s.nInUse + 2;
+
+ // Fallthrough
+ goto case BZ_X_SELECTOR_1;
+
+ /*--- Now the selectors ---*/
+ case BZ_X_SELECTOR_1:
+ s.state = BZ_X_SELECTOR_1;
+ while (true)
+ {
+ if (s.bsLive >= 3)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 3)) & ((1 << 3) - 1));
+ s.bsLive -= 3;
+ nGroups = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (nGroups < 2 || nGroups > 6)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_SELECTOR_2;
+
+ case BZ_X_SELECTOR_2:
+ s.state = BZ_X_SELECTOR_2;
+ while (true)
+ {
+ if (s.bsLive >= 15)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 15)) & ((1 << 15) - 1));
+ s.bsLive -= 15;
+ nSelectors = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (nSelectors < 1)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ for (i = 0; i < nSelectors; i++)
+ {
+ j = 0;
+ while (true)
+ {
+ BZ_X_SELECTOR_3:
+ s.state = BZ_X_SELECTOR_3;
+ while (true)
+ {
+ if (s.bsLive >= 1)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 1)) & ((1 << 1) - 1));
+ s.bsLive -= 1;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)s.strm.next_in;
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc == 0)
+ break;
+
+ j++;
+ if (j >= nGroups)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+ }
+
+ s.selectorMtf[i] = (byte)j;
+ }
+
+ /*--- Undo the MTF values for the selectors. ---*/
+ {
+ byte[] pos = new byte[BZ_N_GROUPS]; byte tmp, v;
+ for (v = 0; v < nGroups; v++)
+ {
+ pos[v] = v;
+ }
+
+ for (i = 0; i < nSelectors; i++)
+ {
+ v = s.selectorMtf[i];
+ tmp = pos[v];
+ while (v > 0) { pos[v] = pos[v - 1]; v--; }
+ pos[0] = tmp;
+ s.selector[i] = tmp;
+ }
+ }
+
+ /*--- Now the coding tables ---*/
+ for (t = 0; t < nGroups; t++)
+ {
+ BZ_X_CODING_1:
+ s.state = BZ_X_CODING_1;
+ while (true)
+ {
+ if (s.bsLive >= 5)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 5)) & ((1 << 5) - 1));
+ s.bsLive -= 5;
+ curr = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ for (i = 0; i < alphaSize; i++)
+ {
+ while (true)
+ {
+ if (curr < 1 || curr > 20)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ BZ_X_CODING_2:
+ s.state = BZ_X_CODING_2;
+ while (true)
+ {
+ if (s.bsLive >= 1)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 1)) & ((1 << 1) - 1));
+ s.bsLive -= 1;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc == 0)
+ break;
+
+ BZ_X_CODING_3:
+ s.state = BZ_X_CODING_3;
+ while (true)
+ {
+ if (s.bsLive >= 1)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 1)) & ((1 << 1) - 1));
+ s.bsLive -= 1;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc == 0)
+ curr++;
+ else
+ curr--;
+ }
+
+ s.len[t, i] = (byte)curr;
+ }
+ }
+
+ /*--- Create the Huffman decoding tables ---*/
+ for (t = 0; t < nGroups; t++)
+ {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++)
+ {
+ if (s.len[t, i] > maxLen)
+ maxLen = s.len[t, i];
+ if (s.len[t, i] < minLen)
+ minLen = s.len[t, i];
+ }
+
+ fixed (int* s_limit_t_0 = &s.limit[t, 0])
+ fixed (int* s_base_t_0 = &s.@base[t, 0])
+ fixed (int* s_perm_t_0 = &s.perm[t, 0])
+ fixed (byte* s_len_t_0 = &s.len[t, 0])
+ {
+ BZ2_hbCreateDecodeTables(s_limit_t_0, s_base_t_0, s_perm_t_0, s_len_t_0, minLen, maxLen, alphaSize);
+ }
+
+ s.minLens[t] = minLen;
+ }
+
+ /*--- Now the MTF values ---*/
+
+ EOB = s.nInUse + 1;
+ nblockMAX = 100000 * s.blockSize100k;
+ groupNo = -1;
+ groupPos = 0;
+
+ for (i = 0; i <= 255; i++) s.unzftab[i] = 0;
+
+ /*-- MTF init --*/
+ {
+ int ii, jj, kk;
+ kk = MTFA_SIZE - 1;
+ for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--)
+ {
+ for (jj = MTFL_SIZE - 1; jj >= 0; jj--)
+ {
+ s.mtfa[kk] = (byte)(ii * MTFL_SIZE + jj);
+ kk--;
+ }
+
+ s.mtfbase[ii] = kk + 1;
+ }
+ }
+ /*-- end MTF init --*/
+
+ nblock = 0;
+
+ if (groupPos == 0)
+ {
+ groupNo++;
+ if (groupNo >= nSelectors)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ groupPos = BZ_G_SIZE;
+ gSel = s.selector[groupNo];
+ gMinlen = s.minLens[gSel];
+
+ fixed (int* s_limit_gSel_0 = &s.limit[gSel, 0])
+ gLimit = s_limit_gSel_0;
+ fixed (int* s_perm_gSel_0 = &s.perm[gSel, 0])
+ gPerm = s_perm_gSel_0;
+ fixed (int* s_base_gSel_0 = &s.@base[gSel, 0])
+ gPerm = s_base_gSel_0;
+ }
+
+ groupPos--;
+ zn = gMinlen;
+
+ // Fallthrough
+ goto case BZ_X_MTF_1;
+
+ case BZ_X_MTF_1:
+ s.state = BZ_X_MTF_1;
+ while (true)
+ {
+ if (s.bsLive >= zn)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - zn)) & ((1 << zn) - 1));
+ s.bsLive -= zn;
+ zvec = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ while (true)
+ {
+ if (zn > 20 /* the longest code */)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+ if (zvec <= gLimit[zn])
+ break;
+
+ zn++;
+
+ BZ_X_MTF_2:
+ s.state = BZ_X_MTF_2;
+ while (true)
+ {
+ if (s.bsLive >= 1)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 1)) & ((1 << 1) - 1));
+ s.bsLive -= 1;
+ zj = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ zvec = (zvec << 1) | zj;
+ };
+
+ if (zvec - gBase[zn] < 0 || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ nextSym = gPerm[zvec - gBase[zn]];
+
+ while (true)
+ {
+ if (nextSym == EOB) break;
+
+ if (nextSym == BZ_RUNA || nextSym == BZ_RUNB)
+ {
+ es = -1;
+ N = 1;
+ do
+ {
+ if (nextSym == BZ_RUNA)
+ es = es + (0 + 1) * N;
+ else if (nextSym == BZ_RUNB)
+ es = es + (1 + 1) * N;
+
+ N = N * 2;
+ if (groupPos == 0)
+ {
+ groupNo++;
+ if (groupNo >= nSelectors)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ groupPos = BZ_G_SIZE;
+ gSel = s.selector[groupNo];
+ gMinlen = s.minLens[gSel];
+
+ fixed (int* s_limit_gSel_0 = &s.limit[gSel, 0])
+ gLimit = s_limit_gSel_0;
+ fixed (int* s_perm_gSel_0 = &s.perm[gSel, 0])
+ gPerm = s_perm_gSel_0;
+ fixed (int* s_base_gSel_0 = &s.@base[gSel, 0])
+ gPerm = s_base_gSel_0;
+ }
+
+ groupPos--;
+ zn = gMinlen;
+
+ BZ_X_MTF_3:
+ s.state = BZ_X_MTF_3;
+ while (true)
+ {
+ if (s.bsLive >= zn)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - zn)) & ((1 << zn) - 1));
+ s.bsLive -= zn;
+ zvec = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ while (true)
+ {
+ if (zn > 20 /* the longest code */)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ if (zvec <= gLimit[zn])
+ break;
+
+ zn++;
+
+ BZ_X_MTF_4:
+ s.state = BZ_X_MTF_4;
+ while (true)
+ {
+ if (s.bsLive >= 1)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 1)) & ((1 << 1) - 1));
+ s.bsLive -= 1;
+ zj = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ zvec = (zvec << 1) | zj;
+ };
+
+ if (zvec - gBase[zn] < 0 || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ nextSym = gPerm[zvec - gBase[zn]];
+
+ } while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
+
+ es++;
+ uc = s.seqToUnseq[s.mtfa[s.mtfbase[0]]];
+ s.unzftab[uc] += es;
+
+ if (s.smallDecompress)
+ {
+ while (es > 0)
+ {
+ if (nblock >= nblockMAX)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ s.ll16[nblock] = (ushort)uc;
+ nblock++;
+ es--;
+ }
+ }
+ else
+ {
+ while (es > 0)
+ {
+ if (nblock >= nblockMAX)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ s.tt[nblock] = (uint)uc;
+ nblock++;
+ es--;
+ }
+ };
+
+ continue;
+ }
+ else
+ {
+ if (nblock >= nblockMAX)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ /*-- uc = MTF ( nextSym-1 ) --*/
+ {
+ int ii, jj, kk, pp, lno, off;
+ uint nn;
+ nn = (uint)(nextSym - 1);
+
+ if (nn < MTFL_SIZE)
+ {
+ /* avoid general-case expense */
+ pp = s.mtfbase[0];
+ uc = s.mtfa[pp + nn];
+ while (nn > 3)
+ {
+ int z = (int)(pp + nn);
+ s.mtfa[(z)] = s.mtfa[(z) - 1];
+ s.mtfa[(z) - 1] = s.mtfa[(z) - 2];
+ s.mtfa[(z) - 2] = s.mtfa[(z) - 3];
+ s.mtfa[(z) - 3] = s.mtfa[(z) - 4];
+ nn -= 4;
+ }
+
+ while (nn > 0)
+ {
+ s.mtfa[(pp + nn)] = s.mtfa[(pp + nn) - 1]; nn--;
+ };
+
+ s.mtfa[pp] = uc;
+ }
+ else
+ {
+ /* general case */
+ lno = (int)(nn / MTFL_SIZE);
+ off = (int)(nn % MTFL_SIZE);
+ pp = s.mtfbase[lno] + off;
+ uc = s.mtfa[pp];
+ while (pp > s.mtfbase[lno])
+ {
+ s.mtfa[pp] = s.mtfa[pp - 1]; pp--;
+ };
+
+ s.mtfbase[lno]++;
+ while (lno > 0)
+ {
+ s.mtfbase[lno]--;
+ s.mtfa[s.mtfbase[lno]] = s.mtfa[s.mtfbase[lno - 1] + MTFL_SIZE - 1];
+ lno--;
+ }
+
+ s.mtfbase[0]--;
+ s.mtfa[s.mtfbase[0]] = uc;
+ if (s.mtfbase[0] == 0)
+ {
+ kk = MTFA_SIZE - 1;
+ for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--)
+ {
+ for (jj = MTFL_SIZE - 1; jj >= 0; jj--)
+ {
+ s.mtfa[kk] = s.mtfa[s.mtfbase[ii] + jj];
+ kk--;
+ }
+
+ s.mtfbase[ii] = kk + 1;
+ }
+ }
+ }
+ }
+ /*-- end uc = MTF ( nextSym-1 ) --*/
+
+ s.unzftab[s.seqToUnseq[uc]]++;
+ if (s.smallDecompress)
+ s.ll16[nblock] = (ushort)(s.seqToUnseq[uc]);
+ else
+ s.tt[nblock] = (uint)(s.seqToUnseq[uc]);
+ nblock++;
+
+ if (groupPos == 0)
+ {
+ groupNo++;
+ if (groupNo >= nSelectors)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ groupPos = BZ_G_SIZE;
+ gSel = s.selector[groupNo];
+ gMinlen = s.minLens[gSel];
+
+ fixed (int* s_limit_gSel_0 = &s.limit[gSel, 0])
+ gLimit = s_limit_gSel_0;
+ fixed (int* s_perm_gSel_0 = &s.perm[gSel, 0])
+ gPerm = s_perm_gSel_0;
+ fixed (int* s_base_gSel_0 = &s.@base[gSel, 0])
+ gPerm = s_base_gSel_0;
+ }
+
+ groupPos--;
+ zn = gMinlen;
+
+ BZ_X_MTF_5:
+ s.state = BZ_X_MTF_5;
+ while (true)
+ {
+ if (s.bsLive >= zn)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - zn)) & ((1 << zn) - 1));
+ s.bsLive -= zn;
+ zvec = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ while (true)
+ {
+ if (zn > 20 /* the longest code */)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ if (zvec <= gLimit[zn])
+ break;
+
+ zn++;
+
+ BZ_X_MTF_6:
+ s.state = BZ_X_MTF_6;
+ while (true)
+ {
+ if (s.bsLive >= 1)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 1)) & ((1 << 1) - 1));
+ s.bsLive -= 1;
+ zj = (int)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ zvec = (zvec << 1) | zj;
+ };
+
+ if (zvec - gBase[zn] < 0 || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ nextSym = gPerm[zvec - gBase[zn]];
+ }
+
+ continue;
+ }
+
+ /* Now we know what nblock is, we can do a better sanity
+ check on s.origPtr.
+ */
+ if (s.origPtr < 0 || s.origPtr >= nblock)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ /*-- Set up cftab to facilitate generation of T^(-1) --*/
+ s.cftab[0] = 0;
+ for (i = 1; i <= 256; i++)
+ {
+ s.cftab[i] = s.unzftab[i - 1];
+ }
+
+ for (i = 1; i <= 256; i++)
+ {
+ s.cftab[i] += s.cftab[i - 1];
+ }
+
+ for (i = 0; i <= 256; i++)
+ {
+ if (s.cftab[i] < 0 || s.cftab[i] > nblock)
+ {
+ /* s.cftab[i] can legitimately be == nblock */
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+ }
+
+ s.state_out_len = 0;
+ s.state_out_ch = 0;
+ s.calculatedBlockCRC = 0xffffffff;
+ s.state = BZ_X_OUTPUT;
+ // if (s.verbosity >= 2) VPrintf0("rt+rld");
+
+ if (s.smallDecompress)
+ {
+ /*-- Make a copy of cftab, used in generation of T --*/
+ for (i = 0; i <= 256; i++) s.cftabCopy[i] = s.cftab[i];
+
+ /*-- compute the T vector --*/
+ for (i = 0; i < nblock; i++)
+ {
+ uc = (byte)(s.ll16[i]);
+ s.ll16[i] = (ushort)(s.cftabCopy[uc] & 0x0000ffff);
+ if ((i & 0x1) == 0)
+ s.ll4[i >> 1] = (byte)((s.ll4[i >> 1] & 0xf0) | (s.cftabCopy[uc]));
+ else
+ s.ll4[i >> 1] = (byte)((s.ll4[i >> 1] & 0x0f) | ((s.cftabCopy[uc]) << 4));
+
+ s.cftabCopy[uc]++;
+ }
+
+ /*-- Compute T^(-1) by pointer reversal on T --*/
+ i = s.origPtr;
+ j = (int)(s.ll16[i] | (((((uint)s.ll4[i >> 1]) >> ((i << 2) & 0x4)) & 0xF) << 16));
+ do
+ {
+ int tmp = (int)(s.ll16[j] | (((((uint)s.ll4[j >> 1]) >> ((j << 2) & 0x4)) & 0xF) << 16));
+ s.ll16[j] = (ushort)(i & 0x0000ffff);
+ if ((j & 0x1) == 0)
+ s.ll4[j >> 1] = (byte)((s.ll4[j >> 1] & 0xf0) | i);
+ else
+ s.ll4[j >> 1] = (byte)((s.ll4[j >> 1] & 0x0f) | (i << 4));
+
+ i = j;
+ j = tmp;
+ }
+ while (i != s.origPtr);
+
+ s.tPos = (uint)s.origPtr;
+ s.nblock_used = 0;
+ if (s.blockRandomised)
+ {
+ s.rNToGo = 0;
+ s.rTPos = 0;
+
+ /* c_tPos is unsigned, hence test < 0 is pointless. */
+ if (s.tPos >= (uint)100000 * (uint)s.blockSize100k)
+ return 1;
+
+ fixed (int* s_cftab = s.cftab)
+ s.k0 = BZ2_indexIntoF((int)s.tPos, s_cftab);
+
+ s.tPos = (s.ll16[s.tPos]) | (((((uint)s.ll4[s.tPos >> 1]) >> (int)((s.tPos << 2) & 0x4)) & 0xF) << 16);
+
+ s.nblock_used++;
+ if (s.rNToGo == 0)
+ {
+ s.rNToGo = BZ2_rNums[s.rTPos];
+ s.rTPos++;
+ if (s.rTPos == 512)
+ s.rTPos = 0;
+ }
+
+ s.rNToGo--;
+ s.k0 ^= (s.rNToGo == 1) ? 1 : 0;
+ }
+ else
+ {
+ /* c_tPos is unsigned, hence test < 0 is pointless. */
+ if (s.tPos >= 100000 * (uint)s.blockSize100k)
+ return 1;
+
+ fixed (int* s_cftab = s.cftab)
+ s.k0 = BZ2_indexIntoF((int)s.tPos, s_cftab);
+
+ s.tPos = ((uint)s.ll16[s.tPos]) | (((((uint)s.ll4[s.tPos >> 1]) >> (int)((s.tPos << 2) & 0x4)) & 0xF) << 16);
+
+ s.nblock_used++;
+ }
+ }
+ else
+ {
+ /*-- compute the T^(-1) vector --*/
+ for (i = 0; i < nblock; i++)
+ {
+ uc = (byte)(s.tt[i] & 0xff);
+ s.tt[s.cftab[uc]] |= (uint)(i << 8);
+ s.cftab[uc]++;
+ }
+
+ s.tPos = s.tt[s.origPtr] >> 8;
+ s.nblock_used = 0;
+ if (s.blockRandomised)
+ {
+ s.rNToGo = 0;
+ s.rTPos = 0;
+
+ /* c_tPos is unsigned, hence test < 0 is pointless. */
+ if (s.tPos >= 100000 * (uint)s.blockSize100k)
+ return 1;
+
+ s.tPos = s.tt[s.tPos];
+ s.k0 = (byte)(s.tPos & 0xff);
+ s.tPos >>= 8;
+
+ s.nblock_used++;
+ if (s.rNToGo == 0)
+ {
+ s.rNToGo = BZ2_rNums[s.rTPos];
+ s.rTPos++;
+ if (s.rTPos == 512)
+ s.rTPos = 0;
+ }
+
+ s.rNToGo--;
+ s.k0 ^= (s.rNToGo == 1) ? 1 : 0;
+ }
+ else
+ {
+ /* c_tPos is unsigned, hence test < 0 is pointless. */
+ if (s.tPos >= 100000 * (uint)s.blockSize100k)
+ return 1;
+
+ s.tPos = s.tt[s.tPos];
+ s.k0 = (byte)(s.tPos & 0xff);
+ s.tPos >>= 8;
+
+ s.nblock_used++;
+ }
+ }
+
+ retVal = BZ_OK;
+ goto save_state_and_return;
+
+ case BZ_X_ENDHDR_2:
+ s.state = BZ_X_ENDHDR_2;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x72)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_ENDHDR_3;
+
+ case BZ_X_ENDHDR_3:
+ s.state = BZ_X_ENDHDR_3;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x45)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_ENDHDR_4;
+
+ case BZ_X_ENDHDR_4:
+ s.state = BZ_X_ENDHDR_4;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x38)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_ENDHDR_5;
+
+ case BZ_X_ENDHDR_5:
+ s.state = BZ_X_ENDHDR_5;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x50)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ // Fallthrough
+ goto case BZ_X_ENDHDR_6;
+
+ case BZ_X_ENDHDR_6:
+ s.state = BZ_X_ENDHDR_6;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ if (uc != 0x90)
+ {
+ retVal = BZ_DATA_ERROR;
+ goto save_state_and_return;
+ }
+
+ s.storedCombinedCRC = 0;
+
+ // Fallthrough
+ goto case BZ_X_CCRC_1;
+
+ case BZ_X_CCRC_1:
+ s.state = BZ_X_CCRC_1;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.storedCombinedCRC = (s.storedCombinedCRC << 8) | ((uint)uc);
+
+ // Fallthrough
+ goto case BZ_X_CCRC_2;
+
+ case BZ_X_CCRC_2:
+ s.state = BZ_X_CCRC_2;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.storedCombinedCRC = (s.storedCombinedCRC << 8) | ((uint)uc);
+
+ // Fallthrough
+ goto case BZ_X_CCRC_3;
+
+ case BZ_X_CCRC_3:
+ s.state = BZ_X_CCRC_3;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.storedCombinedCRC = (s.storedCombinedCRC << 8) | ((uint)uc);
+
+ // Fallthrough
+ goto case BZ_X_CCRC_4;
+
+ case BZ_X_CCRC_4:
+ s.state = BZ_X_CCRC_4;
+ while (true)
+ {
+ if (s.bsLive >= 8)
+ {
+ uint v;
+ v = (uint)((s.bsBuff >> (s.bsLive - 8)) & ((1 << 8) - 1));
+ s.bsLive -= 8;
+ uc = (byte)v;
+ break;
+ }
+
+ if (s.strm.avail_in == 0)
+ {
+ retVal = BZ_OK;
+ goto save_state_and_return;
+ }
+
+ s.bsBuff = (s.bsBuff << 8) | *(byte*)(s.strm.next_in);
+ s.bsLive += 8;
+ s.strm.next_in++;
+ s.strm.avail_in--;
+ s.strm.total_in_lo32++;
+ if (s.strm.total_in_lo32 == 0)
+ s.strm.total_in_hi32++;
+ }
+
+ s.storedCombinedCRC = (s.storedCombinedCRC << 8) | ((uint)uc);
+
+ s.state = BZ_X_IDLE;
+ retVal = BZ_STREAM_END;
+ goto save_state_and_return;
+ }
+
+ save_state_and_return:
+
+ s.save_i = i;
+ s.save_j = j;
+ s.save_t = t;
+ s.save_alphaSize = alphaSize;
+ s.save_nGroups = nGroups;
+ s.save_nSelectors = nSelectors;
+ s.save_EOB = EOB;
+ s.save_groupNo = groupNo;
+ s.save_groupPos = groupPos;
+ s.save_nextSym = nextSym;
+ s.save_nblockMAX = nblockMAX;
+ s.save_nblock = nblock;
+ s.save_es = es;
+ s.save_N = N;
+ s.save_curr = curr;
+ s.save_zt = zt;
+ s.save_zn = zn;
+ s.save_zvec = zvec;
+ s.save_zj = zj;
+ s.save_gSel = gSel;
+ s.save_gMinlen = gMinlen;
+ s.save_gLimit = gLimit;
+ s.save_gBase = gBase;
+ s.save_gPerm = gPerm;
+
+ return retVal;
+ }
+
+ #region Helpers
+
+ private static int BZ2_indexIntoF(int indx, int* cftab)
+ {
+ int nb, na, mid;
+ nb = 0;
+ na = 256;
+
+ do
+ {
+ mid = (nb + na) >> 1;
+ if (indx >= cftab[mid])
+ nb = mid;
+ else
+ na = mid;
+ } while (na - nb != 1);
+
+ return nb;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file