diff --git a/BurnOutSharp.Compression/Quantum.cs b/BurnOutSharp.Compression/Quantum.cs
deleted file mode 100644
index 369b5b78..00000000
--- a/BurnOutSharp.Compression/Quantum.cs
+++ /dev/null
@@ -1,203 +0,0 @@
-using System.Linq;
-using BurnOutSharp.Models.Compression.Quantum;
-using static BurnOutSharp.Models.Compression.Quantum.Constants;
-
-namespace BurnOutSharp.Compression
-{
- public class Quantum
- {
- // TODO: Implement Quantum decompression
-
- /* Bitstream reading macros (Quantum / normal byte order)
- *
- * Q_INIT_BITSTREAM should be used first to set up the system
- * Q_READ_BITS(var,n) takes N bits from the buffer and puts them in var.
- * unlike LZX, this can loop several times to get the
- * requisite number of bits.
- * Q_FILL_BUFFER adds more data to the bit buffer, if there is room
- * for another 16 bits.
- * Q_PEEK_BITS(n) extracts (without removing) N bits from the bit
- * buffer
- * Q_REMOVE_BITS(n) removes N bits from the bit buffer
- *
- * These bit access routines work by using the area beyond the MSB and the
- * LSB as a free source of zeroes. This avoids having to mask any bits.
- * So we have to know the bit width of the bitbuffer variable. This is
- * defined as Uint_BITS.
- *
- * Uint_BITS should be at least 16 bits. Unlike LZX's Huffman decoding,
- * Quantum's arithmetic decoding only needs 1 bit at a time, it doesn't
- * need an assured number. Retrieving larger bitstrings can be done with
- * multiple reads and fills of the bitbuffer. The code should work fine
- * for machines where Uint >= 32 bits.
- *
- * Also note that Quantum reads bytes in normal order; LZX is in
- * little-endian order.
- */
-
- // #define Q_INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0)
-
- // #define Q_FILL_BUFFER do { \
- // if (bitsleft <= (CAB_Uint_BITS - 16)) { \
- // bitbuf |= ((inpos[0]<<8)|inpos[1]) << (CAB_Uint_BITS-16 - bitsleft); \
- // bitsleft += 16; inpos += 2; \
- // } \
- // } while (0)
-
- // #define Q_PEEK_BITS(n) (bitbuf >> (CAB_Uint_BITS - (n)))
- // #define Q_REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n)))
-
- // #define Q_READ_BITS(v,n) do { \
- // (v) = 0; \
- // for (bitsneed = (n); bitsneed; bitsneed -= bitrun) { \
- // Q_FILL_BUFFER; \
- // bitrun = (bitsneed > bitsleft) ? bitsleft : bitsneed; \
- // (v) = ((v) << bitrun) | Q_PEEK_BITS(bitrun); \
- // Q_REMOVE_BITS(bitrun); \
- // } \
- // } while (0)
-
- // #define Q_MENTRIES(model) (decomp_state.qtm.model).entries)
- // #define Q_MSYM(model,symidx) (decomp_state.qtm.model).syms[(symidx)].sym)
- // #define Q_MSYMFREQ(model,symidx) (decomp_state.qtm.model).syms[(symidx)].cumfreq)
-
- /* GET_SYMBOL(model, var) fetches the next symbol from the stated model
- * and puts it in var. it may need to read the bitstream to do this.
- */
- // #define GET_SYMBOL(m, var) do { \
- // range = ((H - L) & 0xFFFF) + 1; \
- // symf = ((((C - L + 1) * Q_MSYMFREQ(m,0)) - 1) / range) & 0xFFFF; \
- // \
- // for (i=1; i < Q_MENTRIES(m); i++) { \
- // if (Q_MSYMFREQ(m,i) <= symf) break; \
- // } \
- // (var) = Q_MSYM(m,i-1); \
- // \
- // range = (H - L) + 1; \
- // H = L + ((Q_MSYMFREQ(m,i-1) * range) / Q_MSYMFREQ(m,0)) - 1; \
- // L = L + ((Q_MSYMFREQ(m,i) * range) / Q_MSYMFREQ(m,0)); \
- // while (1) { \
- // if ((L & 0x8000) != (H & 0x8000)) { \
- // if ((L & 0x4000) && !(H & 0x4000)) { \
- // /* underflow case */ \
- // C ^= 0x4000; L &= 0x3FFF; H |= 0x4000; \
- // } \
- // else break; \
- // } \
- // L <<= 1; H = (H << 1) | 1; \
- // Q_FILL_BUFFER; \
- // C = (C << 1) | Q_PEEK_BITS(1); \
- // Q_REMOVE_BITS(1); \
- // } \
- // \
- // Quantum.UpdateModel(&(decomp_state.qtm.m)), i); \
- // } while (0)
-
- ///
- /// Initialize a Quantum model that decodes symbols from s to (s + n - 1)
- ///
- ///
- public static void InitModel(Model model, ModelSymbol[] symbols, int entryCount, int initialSymbol)
- {
- // Set the basic values
- model.ShiftsLeft = 4;
- model.Entries = entryCount;
- model.Symbols = symbols;
-
- // Clear out the look-up table
- model.LookupTable = Enumerable.Repeat(0xFF, model.LookupTable.Length).ToArray();
-
- // Loop through and build the look-up table
- for (ushort i = 0; i < entryCount; i++)
- {
- // Set up a look-up entry for symbol
- model.LookupTable[i + initialSymbol] = i;
-
- // Actual symbol
- model.Symbols[i].Symbol = (ushort)(i + initialSymbol);
-
- // Current frequency of that symbol
- model.Symbols[i].CumulativeFrequency = (ushort)(entryCount - i);
- }
-
- // Set the last symbol frequency to 0
- model.Symbols[entryCount].CumulativeFrequency = 0;
- }
-
- ///
- /// Update the quantum model for a particular symbol
- ///
- ///
- public static void UpdateModel(Model model, int symbol)
- {
- // Update the cumulative frequency for all symbols less than the provided
- for (int i = 0; i < symbol; i++)
- {
- model.Symbols[i].CumulativeFrequency += 8;
- }
-
- // If the first symbol still has a cumulative frequency under 3800
- if (model.Symbols[0].CumulativeFrequency <= 3800)
- return;
-
- // If we have more than 1 shift left in the model
- if (--model.ShiftsLeft != 0)
- {
- // Loop through the entries from highest to lowest,
- // performing the shift on the cumulative frequencies
- for (int i = model.Entries - 1; i >= 0; i--)
- {
- // -1, not -2; the 0 entry saves this
- model.Symbols[i].CumulativeFrequency >>= 1;
- if (model.Symbols[i].CumulativeFrequency <= model.Symbols[i + 1].CumulativeFrequency)
- model.Symbols[i].CumulativeFrequency = (ushort)(model.Symbols[i + 1].CumulativeFrequency + 1);
- }
- }
-
- // If we have no shifts left in the model
- else
- {
- // Reset the shifts left value to 50
- model.ShiftsLeft = 50;
-
- // Loop through the entries setting the cumulative frequencies
- for (int i = 0; i < model.Entries; i++)
- {
- // No -1, want to include the 0 entry
- // This converts cumfreqs into frequencies, then shifts right
- model.Symbols[i].CumulativeFrequency -= model.Symbols[i + 1].CumulativeFrequency;
- model.Symbols[i].CumulativeFrequency++; // Avoid losing things entirely
- model.Symbols[i].CumulativeFrequency >>= 1;
- }
-
- // Now sort by frequencies, decreasing order -- this must be an
- // inplace selection sort, or a sort with the same (in)stability
- // characteristics
- for (int i = 0; i < model.Entries - 1; i++)
- {
- for (int j = i + 1; j < model.Entries; j++)
- {
- if (model.Symbols[i].CumulativeFrequency < model.Symbols[j].CumulativeFrequency)
- {
- var temp = model.Symbols[i];
- model.Symbols[i] = model.Symbols[j];
- model.Symbols[j] = temp;
- }
- }
- }
-
- // Then convert frequencies back to cumfreq
- for (int i = model.Entries - 1; i >= 0; i--)
- {
- model.Symbols[i].CumulativeFrequency += model.Symbols[i + 1].CumulativeFrequency;
- }
-
- // Then update the other part of the table
- for (int i = 0; i < model.Entries; i++)
- {
- model.LookupTable[model.Symbols[i].Symbol] = (ushort)i;
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/Quantum/Decompressor.cs b/BurnOutSharp.Compression/Quantum/Decompressor.cs
new file mode 100644
index 00000000..9fb363e0
--- /dev/null
+++ b/BurnOutSharp.Compression/Quantum/Decompressor.cs
@@ -0,0 +1,402 @@
+using System.Linq;
+using BurnOutSharp.Models.Compression.Quantum;
+using static BurnOutSharp.Models.Compression.Quantum.Constants;
+
+namespace BurnOutSharp.Compression.Quantum
+{
+ public class Decompressor
+ {
+ // TODO: Implement Quantum decompression
+
+ ///
+ /// Decompress a byte array using a given State
+ ///
+ public static bool Decompress(State state, int inlen, byte[] inbuf, int outlen, byte[] outbuf)
+ {
+ // Port from MicrosoftCabinet.fdi.Quantum.cs
+ return false;
+ }
+
+ ///
+ /// Initialize a Quantum decompressor state
+ ///
+ public static bool InitState(int window, int level, State state)
+ {
+ uint windowSize = (uint)(1 << window);
+ int msz = window * 2, i;
+ uint j;
+
+ // QTM supports window sizes of 2^10 (1Kb) through 2^21 (2Mb)
+ // If a previously allocated window is big enough, keep it
+ if (window < 10 || window > 21)
+ return false;
+
+ // If we don't have the proper window size
+ if (state.ActualSize < windowSize)
+ state.Window = null;
+
+ // If we have no window
+ if (state.Window == null)
+ {
+ state.Window = new byte[windowSize];
+ state.ActualSize = windowSize;
+ }
+
+ // Set the window size and position
+ state.WindowSize = windowSize;
+ state.WindowPosition = 0;
+
+ // Initialize static slot/extrabits tables
+ for (i = 0, j = 0; i < 27; i++)
+ {
+ state.q_length_extra[i] = (byte)((i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2);
+ state.q_length_base[i] = (byte)j; j += (uint)(1 << ((i == 26) ? 5 : state.q_length_extra[i]));
+ }
+
+ for (i = 0, j = 0; i < 42; i++)
+ {
+ state.q_extra_bits[i] = (byte)((i < 2 ? 0 : i - 2) >> 1);
+ state.q_position_base[i] = j; j += (uint)(1 << state.q_extra_bits[i]);
+ }
+
+ // Initialize arithmetic coding models
+ InitModel(state.Model7, state.Model7Symbols, 7, 0);
+
+ InitModel(state.Model7Submodel00, state.Model7Submodel00Symbols, 0x40, 0x00);
+ InitModel(state.Model7Submodel40, state.Model7Submodel40Symbols, 0x40, 0x40);
+ InitModel(state.Model7Submodel80, state.Model7Submodel80Symbols, 0x40, 0x80);
+ InitModel(state.Model7SubmodelC0, state.Model7SubmodelC0Symbols, 0x40, 0xC0);
+
+ // Model 4 depends on table size, ranges from 20 to 24
+ InitModel(state.Model4, state.Model4Symbols, (msz < 24) ? msz : 24, 0);
+
+ // Model 5 depends on table size, ranges from 20 to 36
+ InitModel(state.Model5, symbols: state.Model5Symbols, (msz < 36) ? msz : 36, 0);
+
+ // Model 6 Position depends on table size, ranges from 20 to 42
+ InitModel(state.Model6Position, state.Model6PositionSymbols, msz, 0);
+ InitModel(state.Model6Length, state.Model6LengthSymbols, 27, 0);
+
+ return true;
+ }
+
+ ///
+ /// Initialize a Quantum model that decodes symbols from s to (s + n - 1)
+ ///
+ ///
+ public static void InitModel(Model model, ModelSymbol[] symbols, int entryCount, int initialSymbol)
+ {
+ // Set the basic values
+ model.ShiftsLeft = 4;
+ model.Entries = entryCount;
+ model.Symbols = symbols;
+
+ // Clear out the look-up table
+ model.LookupTable = Enumerable.Repeat(0xFF, model.LookupTable.Length).ToArray();
+
+ // Loop through and build the look-up table
+ for (ushort i = 0; i < entryCount; i++)
+ {
+ // Set up a look-up entry for symbol
+ model.LookupTable[i + initialSymbol] = i;
+
+ // Actual symbol
+ model.Symbols[i].Symbol = (ushort)(i + initialSymbol);
+
+ // Current frequency of that symbol
+ model.Symbols[i].CumulativeFrequency = (ushort)(entryCount - i);
+ }
+
+ // Set the last symbol frequency to 0
+ model.Symbols[entryCount].CumulativeFrequency = 0;
+ }
+
+ ///
+ /// Update the quantum model for a particular symbol
+ ///
+ ///
+ public static void UpdateModel(Model model, int symbol)
+ {
+ // Update the cumulative frequency for all symbols less than the provided
+ for (int i = 0; i < symbol; i++)
+ {
+ model.Symbols[i].CumulativeFrequency += 8;
+ }
+
+ // If the first symbol still has a cumulative frequency under 3800
+ if (model.Symbols[0].CumulativeFrequency <= 3800)
+ return;
+
+ // If we have more than 1 shift left in the model
+ if (--model.ShiftsLeft != 0)
+ {
+ // Loop through the entries from highest to lowest,
+ // performing the shift on the cumulative frequencies
+ for (int i = model.Entries - 1; i >= 0; i--)
+ {
+ // -1, not -2; the 0 entry saves this
+ model.Symbols[i].CumulativeFrequency >>= 1;
+ if (model.Symbols[i].CumulativeFrequency <= model.Symbols[i + 1].CumulativeFrequency)
+ model.Symbols[i].CumulativeFrequency = (ushort)(model.Symbols[i + 1].CumulativeFrequency + 1);
+ }
+ }
+
+ // If we have no shifts left in the model
+ else
+ {
+ // Reset the shifts left value to 50
+ model.ShiftsLeft = 50;
+
+ // Loop through the entries setting the cumulative frequencies
+ for (int i = 0; i < model.Entries; i++)
+ {
+ // No -1, want to include the 0 entry
+ // This converts cumfreqs into frequencies, then shifts right
+ model.Symbols[i].CumulativeFrequency -= model.Symbols[i + 1].CumulativeFrequency;
+ model.Symbols[i].CumulativeFrequency++; // Avoid losing things entirely
+ model.Symbols[i].CumulativeFrequency >>= 1;
+ }
+
+ // Now sort by frequencies, decreasing order -- this must be an
+ // inplace selection sort, or a sort with the same (in)stability
+ // characteristics
+ for (int i = 0; i < model.Entries - 1; i++)
+ {
+ for (int j = i + 1; j < model.Entries; j++)
+ {
+ if (model.Symbols[i].CumulativeFrequency < model.Symbols[j].CumulativeFrequency)
+ {
+ var temp = model.Symbols[i];
+ model.Symbols[i] = model.Symbols[j];
+ model.Symbols[j] = temp;
+ }
+ }
+ }
+
+ // Then convert frequencies back to cumfreq
+ for (int i = model.Entries - 1; i >= 0; i--)
+ {
+ model.Symbols[i].CumulativeFrequency += model.Symbols[i + 1].CumulativeFrequency;
+ }
+
+ // Then update the other part of the table
+ for (int i = 0; i < model.Entries; i++)
+ {
+ model.LookupTable[model.Symbols[i].Symbol] = (ushort)i;
+ }
+ }
+ }
+
+ #region Macros
+
+ /* Bitstream reading macros (Quantum / normal byte order)
+ *
+ * Q_INIT_BITSTREAM should be used first to set up the system
+ * Q_READ_BITS(var,n) takes N bits from the buffer and puts them in var.
+ * unlike LZX, this can loop several times to get the
+ * requisite number of bits.
+ * Q_FILL_BUFFER adds more data to the bit buffer, if there is room
+ * for another 16 bits.
+ * Q_PEEK_BITS(n) extracts (without removing) N bits from the bit
+ * buffer
+ * Q_REMOVE_BITS(n) removes N bits from the bit buffer
+ *
+ * These bit access routines work by using the area beyond the MSB and the
+ * LSB as a free source of zeroes. This avoids having to mask any bits.
+ * So we have to know the bit width of the bitbuffer variable. This is
+ * defined as Uint_BITS.
+ *
+ * Uint_BITS should be at least 16 bits. Unlike LZX's Huffman decoding,
+ * Quantum's arithmetic decoding only needs 1 bit at a time, it doesn't
+ * need an assured number. Retrieving larger bitstrings can be done with
+ * multiple reads and fills of the bitbuffer. The code should work fine
+ * for machines where Uint >= 32 bits.
+ *
+ * Also note that Quantum reads bytes in normal order; LZX is in
+ * little-endian order.
+ */
+
+ // #define Q_INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0)
+
+ // #define Q_FILL_BUFFER do { \
+ // if (bitsleft <= (16)) { \
+ // bitbuf |= ((inpos[0]<<8)|inpos[1]) << (32-16 - bitsleft); \
+ // bitsleft += 16; inpos += 2; \
+ // } \
+ // } while (0)
+
+ // #define Q_PEEK_BITS(n) (bitbuf >> (32 - (n)))
+ // #define Q_REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n)))
+
+ // #define Q_READ_BITS(v,n) do { \
+ // (v) = 0; \
+ // for (bitsneed = (n); bitsneed; bitsneed -= bitrun) { \
+ // Q_FILL_BUFFER; \
+ // bitrun = (bitsneed > bitsleft) ? bitsleft : bitsneed; \
+ // (v) = ((v) << bitrun) | Q_PEEK_BITS(bitrun); \
+ // Q_REMOVE_BITS(bitrun); \
+ // } \
+ // } while (0)
+
+ // #define Q_MENTRIES(model) (state.qtm.model).Entries)
+ // #define Q_MSYM(model,symidx) (state.qtm.model).syms[(symidx)].sym)
+ // #define Q_MSYMFREQ(model,symidx) (state.qtm.model).syms[(symidx)].cumfreq)
+
+ /* GET_SYMBOL(model, var) fetches the next symbol from the stated model
+ * and puts it in var. it may need to read the bitstream to do this.
+ */
+ // #define GET_SYMBOL(m, var) do { \
+ // range = ((H - L) & 0xFFFF) + 1; \
+ // symf = ((((C - L + 1) * (state.qtm.m).syms[(0)].cumfreq) - 1) / range) & 0xFFFF; \
+ // \
+ // for (i=1; i < (state.qtm.m).Entries); i++) { \
+ // if ((state.qtm.m).syms[(i)].cumfreq) <= symf) break; \
+ // } \
+ // (var) = (state.qtm.m).syms[(i-1)].sym) \
+ // \
+ // range = (H - L) + 1; \
+ // H = L + (((state.qtm.m).syms[(i-1)].cumfreq) * range) / (state.qtm.m).syms[(0)].cumfreq) - 1; \
+ // L = L + (((state.qtm.m).syms[(i)].cumfreq) * range) / (state.qtm.m).syms[(0)].cumfreq); \
+ // while (1) { \
+ // if ((L & 0x8000) != (H & 0x8000)) { \
+ // if ((L & 0x4000) && !(H & 0x4000)) { \
+ // /* underflow case */ \
+ // C ^= 0x4000; L &= 0x3FFF; H |= 0x4000; \
+ // } \
+ // else break; \
+ // } \
+ // L <<= 1; H = (H << 1) | 1; \
+ // Q_FILL_BUFFER; \
+ // C = (C << 1) | Q_PEEK_BITS(1); \
+ // Q_REMOVE_BITS(1); \
+ // } \
+ // \
+ // Quantum.UpdateModel(&(state.qtm.m)), i); \
+ // } while (0)
+
+ ///
+ /// Should be used first to set up the system
+ ///
+ private static void Q_INIT_BITSTREAM(out int bitsleft, out uint bitbuf)
+ {
+ bitsleft = 0; bitbuf = 0;
+ }
+
+ ///
+ /// Adds more data to the bit buffer, if there is room for another 16 bits.
+ ///
+ private static void Q_FILL_BUFFER(byte[] inbuf, ref int inpos, ref int bitsleft, ref uint bitbuf)
+ {
+ if (bitsleft <= 16)
+ {
+ bitbuf |= (uint)((inbuf[inpos + 0] << 8) | inbuf[inpos + 1]) << (16 - bitsleft);
+ bitsleft += 16; inpos += 2;
+ }
+ }
+
+ ///
+ /// Extracts (without removing) N bits from the bit buffer
+ ///
+ private static uint Q_PEEK_BITS(int n, uint bitbuf)
+ {
+ return bitbuf >> (32 - n);
+ }
+
+ ///
+ /// Removes N bits from the bit buffer
+ ///
+ private static void Q_REMOVE_BITS(int n, ref int bitsleft, ref uint bitbuf)
+ {
+ bitbuf <<= n;
+ bitsleft -= n;
+ }
+
+ ///
+ /// Takes N bits from the buffer and puts them in v. Unlike LZX, this can loop
+ /// several times to get the requisite number of bits.
+ ///
+ private static ushort Q_READ_BITS_UINT16(int n, byte[] inbuf, ref int inpos, ref int bitsleft, ref uint bitbuf)
+ {
+ ushort v = 0; int bitrun;
+ for (int bitsneed = n; bitsneed != 0; bitsneed -= bitrun)
+ {
+ Q_FILL_BUFFER(inbuf, ref inpos, ref bitsleft, ref bitbuf);
+
+ bitrun = (bitsneed > bitsleft) ? bitsleft : bitsneed;
+ v = (ushort)((v << bitrun) | Q_PEEK_BITS(bitrun, bitbuf));
+
+ Q_REMOVE_BITS(bitrun, ref bitsleft, ref bitbuf);
+ }
+
+ return v;
+ }
+
+ ///
+ /// Takes N bits from the buffer and puts them in v. Unlike LZX, this can loop
+ /// several times to get the requisite number of bits.
+ ///
+ private static int Q_READ_BITS_INT32(int n, byte[] inbuf, ref int inpos, ref int bitsleft, ref uint bitbuf)
+ {
+ int v = 0; int bitrun;
+ for (int bitsneed = n; bitsneed != 0; bitsneed -= bitrun)
+ {
+ Q_FILL_BUFFER(inbuf, ref inpos, ref bitsleft, ref bitbuf);
+
+ bitrun = (bitsneed > bitsleft) ? bitsleft : bitsneed;
+ v = (int)((v << bitrun) | Q_PEEK_BITS(bitrun, bitbuf));
+
+ Q_REMOVE_BITS(bitrun, ref bitsleft, ref bitbuf);
+ }
+
+ return v;
+ }
+
+ ///
+ /// Fetches the next symbol from the stated model and puts it in v.
+ /// It may need to read the bitstream to do this.
+ ///
+ private static int GET_SYMBOL(Model model, ref ushort H, ref ushort L, ref ushort C, byte[] inbuf, ref int inpos, ref int bitsleft, ref uint bitbuf)
+ {
+ uint range = (uint)(((H - L) & 0xFFFF) + 1);
+ ushort symf = (ushort)(((((C - L + 1) * model.Symbols[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
+
+ int i;
+ for (i = 1; i < model.Entries; i++)
+ {
+ if (model.Symbols[i].CumulativeFrequency <= symf)
+ break;
+ }
+
+ int v = model.Symbols[i - 1].Symbol;
+ range = (uint)(H - L + 1);
+ H = (ushort)(L + ((model.Symbols[i - 1].CumulativeFrequency * range) / model.Symbols[0].CumulativeFrequency) - 1);
+ L = (ushort)(L + ((model.Symbols[i].CumulativeFrequency * range) / model.Symbols[0].CumulativeFrequency));
+
+ while (true)
+ {
+ if ((L & 0x8000) != (H & 0x8000))
+ {
+ if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
+ {
+ // Underflow case
+ C ^= 0x4000; L &= 0x3FFF; H |= 0x4000;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ L <<= 1; H = (ushort)((H << 1) | 1);
+ Q_FILL_BUFFER(inbuf, ref inpos, ref bitsleft, ref bitbuf);
+ C = (ushort)((C << 1) | Q_PEEK_BITS(1, bitbuf));
+ Q_REMOVE_BITS(1, ref bitsleft, ref bitbuf);
+ }
+
+ Decompressor.UpdateModel(model, i);
+ return v;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Compression/Quantum/State.cs b/BurnOutSharp.Compression/Quantum/State.cs
new file mode 100644
index 00000000..4aee4912
--- /dev/null
+++ b/BurnOutSharp.Compression/Quantum/State.cs
@@ -0,0 +1,150 @@
+using BurnOutSharp.Models.Compression.Quantum;
+
+namespace BurnOutSharp.Compression.Quantum
+{
+ ///
+ public class State
+ {
+ ///
+ /// The actual decoding window
+ ///
+ public byte[] Window;
+
+ ///
+ /// Window size (1Kb through 2Mb)
+ ///
+ public uint WindowSize;
+
+ ///
+ /// Window size when it was first allocated
+ ///
+ public uint ActualSize;
+
+ ///
+ /// Current offset within the window
+ ///
+ public uint WindowPosition;
+
+ #region Models
+
+ ///
+ /// Model for Model 4
+ ///
+ public Model Model4;
+
+ ///
+ /// Model for Model 5
+ ///
+ public Model Model5;
+
+ ///
+ /// Model for Model 6 Position
+ ///
+ public Model Model6Position;
+
+ ///
+ /// Model for Model 6 Length
+ ///
+ public Model Model6Length;
+
+ ///
+ /// Model for Model 7
+ ///
+ public Model Model7;
+
+ ///
+ /// Model for Model 7, Submodel 00
+ ///
+ public Model Model7Submodel00;
+
+ ///
+ /// Model for Model 7, Submodel 40
+ ///
+ public Model Model7Submodel40;
+
+ ///
+ /// Model for Model 7, Submodel 80
+ ///
+ public Model Model7Submodel80;
+
+ ///
+ /// Model for Model 7, Submodel C0
+ ///
+ public Model Model7SubmodelC0;
+
+ #endregion
+
+ #region Symbol Tables
+
+ ///
+ /// Symbol table for Model 4
+ ///
+ public ModelSymbol[] Model4Symbols = new ModelSymbol[0x18 + 1];
+
+ ///
+ /// Symbol table for Model 5
+ ///
+ public ModelSymbol[] Model5Symbols = new ModelSymbol[0x24 + 1];
+
+ ///
+ /// Symbol table for Model 6 Position
+ ///
+ public ModelSymbol[] Model6PositionSymbols = new ModelSymbol[0x2a + 1];
+
+ ///
+ /// Symbol table for Model 6 Length
+ ///
+ public ModelSymbol[] Model6LengthSymbols = new ModelSymbol[0x1b + 1];
+
+ ///
+ /// Symbol table for Model 7
+ ///
+ public ModelSymbol[] Model7Symbols = new ModelSymbol[7 + 1];
+
+ ///
+ /// Symbol table for Model 7, Submodel 00
+ ///
+ public ModelSymbol[] Model7Submodel00Symbols = new ModelSymbol[0x40 + 1];
+
+ ///
+ /// Symbol table for Model 7, Submodel 40
+ ///
+ public ModelSymbol[] Model7Submodel40Symbols = new ModelSymbol[0x40 + 1];
+
+ ///
+ /// Symbol table for Model 7, Submodel 80
+ ///
+ public ModelSymbol[] Model7Submodel80Symbols = new ModelSymbol[0x40 + 1];
+
+ ///
+ /// Symbol table for Model 7, Submodel C0
+ ///
+ public ModelSymbol[] Model7SubmodelC0Symbols = new ModelSymbol[0x40 + 1];
+
+ #endregion
+
+ #region Decompression Tables
+
+ ///
+ /// XXXXX
+ ///
+ public byte[] q_length_base = new byte[27];
+
+ ///
+ /// XXXXX
+ ///
+ public byte[] q_length_extra = new byte[27];
+
+ ///
+ /// XXXXX
+ ///
+ public byte[] q_extra_bits = new byte[42];
+
+ ///
+ /// XXXXX
+ ///
+ public uint[] q_position_base = new uint[42];
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.Quantum.cs b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.Quantum.cs
index 3aeb8d22..5f363039 100644
--- a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.Quantum.cs
+++ b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.Quantum.cs
@@ -1,4 +1,4 @@
-// using BurnOutSharp.Compression;
+// using BurnOutSharp.Compression.Quantum;
// using BurnOutSharp.Models.Compression.Quantum;
// using static BurnOutSharp.Wrappers.CabinetConstants;
// using static BurnOutSharp.Wrappers.FDIcConstants;
@@ -11,120 +11,18 @@
// namespace BurnOutSharp.Wrappers
// {
-// ///
-// internal class QuantumState
+// internal unsafe class Quantumfdi
// {
-// ///
-// /// the actual decoding window
-// ///
-// public byte[] window;
-
-// ///
-// /// window size (1Kb through 2Mb)
-// ///
-// public uint window_size;
-
-// ///
-// /// window size when it was first allocated
-// ///
-// public uint actual_size;
-
-// ///
-// /// current offset within the window
-// ///
-// public uint window_posn;
-
-// public Model model7;
-// public ModelSymbol[] m7sym = new ModelSymbol[7 + 1];
-
-// public Model model4;
-// public Model model5;
-// public Model model6pos;
-// public Model model6len;
-// public ModelSymbol[] m4sym = new ModelSymbol[0x18 + 1];
-// public ModelSymbol[] m5sym = new ModelSymbol[0x24 + 1];
-// public ModelSymbol[] m6psym = new ModelSymbol[0x2a + 1];
-// public ModelSymbol[] m6lsym = new ModelSymbol[0x1b + 1];
-
-// public Model model00;
-// public Model model40;
-// public Model model80;
-// public Model modelC0;
-// public ModelSymbol[] m00sym = new ModelSymbol[0x40 + 1];
-// public ModelSymbol[] m40sym = new ModelSymbol[0x40 + 1];
-// public ModelSymbol[] m80sym = new ModelSymbol[0x40 + 1];
-// public ModelSymbol[] mC0sym = new ModelSymbol[0x40 + 1];
-// }
-
-// internal class Quantumfdi
-// {
-// ///
-// /// QTMfdi_init (internal)
-// ///
-// internal static int QTMfdi_init(int window, int level, fdi_decomp_state decomp_state)
-// {
-// uint wndsize = (uint)(1 << window);
-// int msz = window * 2, i;
-// uint j;
-
-// /* QTM supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
-// /* if a previously allocated window is big enough, keep it */
-// if (window < 10 || window > 21) return DECR_DATAFORMAT;
-// if (decomp_state.qtm.actual_size < wndsize)
-// {
-// if (decomp_state.qtm.window != null) decomp_state.fdi.free(decomp_state.qtm.window);
-// decomp_state.qtm.window = null;
-// }
-// if (decomp_state.qtm.window == null)
-// {
-// if ((decomp_state.qtm.window = decomp_state.fdi.alloc((int)wndsize)) == null) return DECR_NOMEMORY;
-// decomp_state.qtm.actual_size = wndsize;
-// }
-// decomp_state.qtm.window_size = wndsize;
-// decomp_state.qtm.window_posn = 0;
-
-// /* initialize static slot/extrabits tables */
-// for (i = 0, j = 0; i < 27; i++)
-// {
-// decomp_state.q_length_extra[i] = (byte)((i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2);
-// decomp_state.q_length_base[i] = (byte)j; j += (uint)(1 << ((i == 26) ? 5 : decomp_state.q_length_extra[i]));
-// }
-// for (i = 0, j = 0; i < 42; i++)
-// {
-// decomp_state.q_extra_bits[i] = (byte)((i < 2 ? 0 : i - 2) >> 1);
-// decomp_state.q_position_base[i] = j; j += (uint)(1 << decomp_state.q_extra_bits[i]);
-// }
-
-// /* initialize arithmetic coding models */
-
-// Quantum.InitModel(decomp_state.qtm.model7, decomp_state.qtm.m7sym, 7, 0);
-
-// Quantum.InitModel(decomp_state.qtm.model00, decomp_state.qtm.m00sym, 0x40, 0x00);
-// Quantum.InitModel(decomp_state.qtm.model40, decomp_state.qtm.m40sym, 0x40, 0x40);
-// Quantum.InitModel(decomp_state.qtm.model80, decomp_state.qtm.m80sym, 0x40, 0x80);
-// Quantum.InitModel(decomp_state.qtm.modelC0, decomp_state.qtm.mC0sym, 0x40, 0xC0);
-
-// /* model 4 depends on table size, ranges from 20 to 24 */
-// Quantum.InitModel(decomp_state.qtm.model4, decomp_state.qtm.m4sym, (msz < 24) ? msz : 24, 0);
-// /* model 5 depends on table size, ranges from 20 to 36 */
-// Quantum.InitModel(decomp_state.qtm.model5, decomp_state.qtm.m5sym, (msz < 36) ? msz : 36, 0);
-// /* model 6pos depends on table size, ranges from 20 to 42 */
-// Quantum.InitModel(decomp_state.qtm.model6pos, decomp_state.qtm.m6psym, msz, 0);
-// Quantum.InitModel(decomp_state.qtm.model6len, decomp_state.qtm.m6lsym, 27, 0);
-
-// return DECR_OK;
-// }
-
// ///
// /// QTMfdi_decomp(internal)
// ///
// internal static int QTMfdi_decomp(int inlen, int outlen, fdi_decomp_state decomp_state)
// {
// cab_UBYTE* inpos = decomp_state.inbuf;
-// cab_UBYTE* window = decomp_state.qtm.window;
+// cab_UBYTE* window = decomp_state.Window;
// cab_UBYTE* runsrc, rundest;
-// cab_ULONG window_posn = decomp_state.qtm.window_posn;
-// cab_ULONG window_size = decomp_state.qtm.window_size;
+// cab_ULONG window_posn = decomp_state.WindowPosition;
+// cab_ULONG window_size = decomp_state.WindowSize;
// /* used by bitstream macros */
// int bitsleft, bitrun, bitsneed;
@@ -135,7 +33,7 @@
// cab_UWORD symf;
// int i;
-// int extra, togo = outlen, match_length = 0, copy_length;
+// int extra = 0, togo = outlen, match_length = 0, copy_length;
// cab_UBYTE selector, sym;
// cab_ULONG match_offset = 0;
@@ -144,8 +42,8 @@
// System.Diagnostics.Debug.WriteLine("(inlen == %d, outlen == %d)\n", inlen, outlen);
// /* read initial value of C */
-// Q_INIT_BITSTREAM;
-// Q_READ_BITS(C, 16);
+// Q_INIT_BITSTREAM(out bitsleft, out bitbuf);
+// C = Q_READ_BITS_UINT16(16, ref inpos, ref bitsleft, ref bitbuf);
// /* apply 2^x-1 mask */
// window_posn &= window_size - 1;
@@ -158,45 +56,53 @@
// while (togo > 0)
// {
-// GET_SYMBOL(model7, selector);
+// selector = GET_SYMBOL(state.Model7, ref H, ref L, ref C, ref inpos, ref bitsleft, ref bitbuf);
// switch (selector)
// {
// case 0:
-// GET_SYMBOL(model00, sym); window[window_posn++] = sym; togo--;
+// sym = GET_SYMBOL(state.Model7Submodel00, ref H, ref L, ref C, ref inpos, ref bitsleft, ref bitbuf);
+// window[window_posn++] = sym;
+// togo--;
// break;
// case 1:
-// GET_SYMBOL(model40, sym); window[window_posn++] = sym; togo--;
+// sym = GET_SYMBOL(state.Model7Submodel40, ref H, ref L, ref C, ref inpos, ref bitsleft, ref bitbuf);
+// window[window_posn++] = sym;
+// togo--;
// break;
// case 2:
-// GET_SYMBOL(model80, sym); window[window_posn++] = sym; togo--;
+// sym = GET_SYMBOL(state.Model7Submodel80, ref H, ref L, ref C, ref inpos, ref bitsleft, ref bitbuf);
+// window[window_posn++] = sym;
+// togo--;
// break;
// case 3:
-// GET_SYMBOL(modelC0, sym); window[window_posn++] = sym; togo--;
+// sym = GET_SYMBOL(state.Model7SubmodelC0, ref H, ref L, ref C, ref inpos, ref bitsleft, ref bitbuf);
+// window[window_posn++] = sym;
+// togo--;
// break;
+// // Selector 4 = fixed length of 3
// case 4:
-// /* selector 4 = fixed length of 3 */
-// GET_SYMBOL(model4, sym);
-// Q_READ_BITS(extra, decomp_state.q_extra_bits[sym]);
+// sym = GET_SYMBOL(state.Model4, ref H, ref L, ref C, ref inpos, ref bitsleft, ref bitbuf);
+// extra = Q_READ_BITS_INT32(state.q_extra_bits[sym], ref inpos, ref bitsleft, ref bitbuf);
// match_offset = decomp_state.q_position_base[sym] + extra + 1;
// match_length = 3;
// break;
+// // Selector 5 = fixed length of 4
// case 5:
-// /* selector 5 = fixed length of 4 */
-// GET_SYMBOL(model5, sym);
-// Q_READ_BITS(extra, decomp_state.q_extra_bits[sym]);
+// sym = GET_SYMBOL(state.Model5, ref H, ref L, ref C, ref inpos, ref bitsleft, ref bitbuf);
+// extra = Q_READ_BITS_INT32(state.q_extra_bits[sym], ref inpos, ref bitsleft, ref bitbuf);
// match_offset = decomp_state.q_position_base[sym] + extra + 1;
// match_length = 4;
// break;
+// // Selector 6 = variable length
// case 6:
-// /* selector 6 = variable length */
-// GET_SYMBOL(model6len, sym);
-// Q_READ_BITS(extra, decomp_state.q_length_extra[sym]);
+// sym = GET_SYMBOL(state.Model6Length, ref H, ref L, ref C, ref inpos, ref bitsleft, ref bitbuf);
+// extra = Q_READ_BITS_INT32(state.q_length_extra[sym], ref inpos, ref bitsleft, ref bitbuf);
// match_length = decomp_state.q_length_base[sym] + extra + 5;
-// GET_SYMBOL(model6pos, sym);
-// Q_READ_BITS(extra, decomp_state.q_extra_bits[sym]);
+// sym = GET_SYMBOL(state.Model6Position, ref H, ref L, ref C, ref inpos, ref bitsleft, ref bitbuf);
+// extra = Q_READ_BITS_INT32(state.q_extra_bits[sym], ref inpos, ref bitsleft, ref bitbuf);
// match_offset = decomp_state.q_position_base[sym] + extra + 1;
// break;
@@ -244,8 +150,131 @@
// memcpy(decomp_state.outbuf, window + ((!window_posn) ? window_size : window_posn) - outlen, outlen);
-// decomp_state.qtm.window_posn = window_posn;
+// decomp_state.WindowPosition = window_posn;
// return DECR_OK;
// }
+
+// ///
+// /// Should be used first to set up the system
+// ///
+// private static void Q_INIT_BITSTREAM(out int bitsleft, out uint bitbuf)
+// {
+// bitsleft = 0; bitbuf = 0;
+// }
+
+// ///
+// /// Adds more data to the bit buffer, if there is room for another 16 bits.
+// ///
+// private static void Q_FILL_BUFFER(ref byte* inpos, ref int bitsleft, ref uint bitbuf)
+// {
+// if (bitsleft <= 16)
+// {
+// bitbuf |= (uint)((inpos[0] << 8) | inpos[1]) << (16 - bitsleft);
+// bitsleft += 16; inpos += 2;
+// }
+// }
+
+// ///
+// /// Extracts (without removing) N bits from the bit buffer
+// ///
+// private static uint Q_PEEK_BITS(int n, uint bitbuf)
+// {
+// return bitbuf >> (32 - n);
+// }
+
+// ///
+// /// Removes N bits from the bit buffer
+// ///
+// private static void Q_REMOVE_BITS(int n, ref int bitsleft, ref uint bitbuf)
+// {
+// bitbuf <<= n;
+// bitsleft -= n;
+// }
+
+// ///
+// /// Takes N bits from the buffer and puts them in v. Unlike LZX, this can loop
+// /// several times to get the requisite number of bits.
+// ///
+// private static ushort Q_READ_BITS_UINT16(int n, ref byte* inpos, ref int bitsleft, ref uint bitbuf)
+// {
+// ushort v = 0; int bitrun;
+// for (int bitsneed = n; bitsneed != 0; bitsneed -= bitrun)
+// {
+// Q_FILL_BUFFER(ref inpos, ref bitsleft, ref bitbuf);
+
+// bitrun = (bitsneed > bitsleft) ? bitsleft : bitsneed;
+// v = (ushort)((v << bitrun) | Q_PEEK_BITS(bitrun, bitbuf));
+
+// Q_REMOVE_BITS(bitrun, ref bitsleft, ref bitbuf);
+// }
+
+// return v;
+// }
+
+// ///
+// /// Takes N bits from the buffer and puts them in v. Unlike LZX, this can loop
+// /// several times to get the requisite number of bits.
+// ///
+// private static int Q_READ_BITS_INT32(int n, ref byte* inpos, ref int bitsleft, ref uint bitbuf)
+// {
+// int v = 0; int bitrun;
+// for (int bitsneed = n; bitsneed != 0; bitsneed -= bitrun)
+// {
+// Q_FILL_BUFFER(ref inpos, ref bitsleft, ref bitbuf);
+
+// bitrun = (bitsneed > bitsleft) ? bitsleft : bitsneed;
+// v = (int)((v << bitrun) | Q_PEEK_BITS(bitrun, bitbuf));
+
+// Q_REMOVE_BITS(bitrun, ref bitsleft, ref bitbuf);
+// }
+
+// return v;
+// }
+
+// ///
+// /// Fetches the next symbol from the stated model and puts it in v.
+// /// It may need to read the bitstream to do this.
+// ///
+// private static int GET_SYMBOL(Model model, ref ushort H, ref ushort L, ref ushort C, ref byte* inpos, ref int bitsleft, ref uint bitbuf)
+// {
+// uint range = (uint)(((H - L) & 0xFFFF) + 1);
+// ushort symf = (ushort)(((((C - L + 1) * model.Symbols[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
+
+// int i;
+// for (i = 1; i < model.Entries; i++)
+// {
+// if (model.Symbols[i].CumulativeFrequency <= symf)
+// break;
+// }
+
+// int v = model.Symbols[i - 1].Symbol;
+// range = (uint)(H - L + 1);
+// H = (ushort)(L + ((model.Symbols[i - 1].CumulativeFrequency * range) / model.Symbols[0].CumulativeFrequency) - 1);
+// L = (ushort)(L + ((model.Symbols[i].CumulativeFrequency * range) / model.Symbols[0].CumulativeFrequency));
+
+// while (true)
+// {
+// if ((L & 0x8000) != (H & 0x8000))
+// {
+// if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
+// {
+// // Underflow case
+// C ^= 0x4000; L &= 0x3FFF; H |= 0x4000;
+// }
+// else
+// {
+// break;
+// }
+// }
+
+// L <<= 1; H = (ushort)((H << 1) | 1);
+// Q_FILL_BUFFER(ref inpos, ref bitsleft, ref bitbuf);
+// C = (ushort)((C << 1) | Q_PEEK_BITS(1, bitbuf));
+// Q_REMOVE_BITS(1, ref bitsleft, ref bitbuf);
+// }
+
+// Decompressor.UpdateModel(model, i);
+// return v;
+// }
// }
// }
\ No newline at end of file