diff --git a/BurnOutSharp.Compression/Quantum.cs b/BurnOutSharp.Compression/Quantum.cs
index 43b5f5bd..d06e30dd 100644
--- a/BurnOutSharp.Compression/Quantum.cs
+++ b/BurnOutSharp.Compression/Quantum.cs
@@ -1,9 +1,118 @@
+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
+
+ ///
+ /// 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.Models/Compression/Quantum/Constants.cs b/BurnOutSharp.Models/Compression/Quantum/Constants.cs
new file mode 100644
index 00000000..04af0e32
--- /dev/null
+++ b/BurnOutSharp.Models/Compression/Quantum/Constants.cs
@@ -0,0 +1,45 @@
+namespace BurnOutSharp.Models.Compression.Quantum
+{
+ public static class Constants
+ {
+ ///
+ /// Mask for Quantum Compression Level
+ ///
+ public const ushort MASK_QUANTUM_LEVEL = 0x00F0;
+
+ ///
+ /// Lowest Quantum Level (1)
+ ///
+ public const ushort QUANTUM_LEVEL_LO = 0x0010;
+
+ ///
+ /// Highest Quantum Level (7)
+ ///
+ public const ushort QUANTUM_LEVEL_HI = 0x0070;
+
+ ///
+ /// Amount to shift over to get int
+ ///
+ public const ushort SHIFT_QUANTUM_LEVEL = 4;
+
+ ///
+ /// Mask for Quantum Compression Memory
+ ///
+ public const ushort MASK_QUANTUM_MEM = 0x1F00;
+
+ ///
+ /// Lowest Quantum Memory (10)
+ ///
+ public const ushort QUANTUM_MEM_LO = 0x0A00;
+
+ ///
+ /// Highest Quantum Memory (21)
+ ///
+ public const ushort QUANTUM_MEM_HI = 0x1500;
+
+ ///
+ /// Amount to shift over to get int
+ ///
+ public const ushort SHIFT_QUANTUM_MEM = 8;
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Models/Compression/Quantum/Model.cs b/BurnOutSharp.Models/Compression/Quantum/Model.cs
index 6c8cbf12..de9471c4 100644
--- a/BurnOutSharp.Models/Compression/Quantum/Model.cs
+++ b/BurnOutSharp.Models/Compression/Quantum/Model.cs
@@ -1,10 +1,15 @@
namespace BurnOutSharp.Models.Compression.Quantum
{
+ ///
///
- public class Model
+ public sealed class Model
{
- public int Entries { get; set; }
+ public int ShiftsLeft;
- public ModelSymbol[] Symbols { get; set; }
+ public int Entries;
+
+ public ModelSymbol[] Symbols;
+
+ public ushort[] LookupTable = new ushort[256];
}
}
\ No newline at end of file
diff --git a/BurnOutSharp.Models/Compression/Quantum/ModelSymbol.cs b/BurnOutSharp.Models/Compression/Quantum/ModelSymbol.cs
index 4998a6fd..0e0f2641 100644
--- a/BurnOutSharp.Models/Compression/Quantum/ModelSymbol.cs
+++ b/BurnOutSharp.Models/Compression/Quantum/ModelSymbol.cs
@@ -1,10 +1,11 @@
namespace BurnOutSharp.Models.Compression.Quantum
{
+ ///
///
- public class ModelSymbol
+ public sealed class ModelSymbol
{
- public ushort Symbol { get; private set; }
+ public ushort Symbol;
- public ushort CumulativeFrequency { get; private set; }
+ public ushort CumulativeFrequency;
}
}
\ No newline at end of file
diff --git a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.Quantum.cs b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.Quantum.cs
index 7fa1d293..3aeb8d22 100644
--- a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.Quantum.cs
+++ b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.Quantum.cs
@@ -1,3 +1,5 @@
+// using BurnOutSharp.Compression;
+// using BurnOutSharp.Models.Compression.Quantum;
// using static BurnOutSharp.Wrappers.CabinetConstants;
// using static BurnOutSharp.Wrappers.FDIcConstants;
// using static BurnOutSharp.Wrappers.FDIConstants;
@@ -9,94 +11,53 @@
// namespace BurnOutSharp.Wrappers
// {
-// internal unsafe class Quantumfdi
+// ///
+// internal class QuantumState
// {
// ///
-// /// QTMupdatemodel (internal)
+// /// the actual decoding window
// ///
-// internal static void QTMupdatemodel(QTMmodel model, int sym)
-// {
-// for (int i = 0; i < sym; i++)
-// {
-// model.syms[i].cumfreq += 8;
-// }
-
-// if (model.syms[0].cumfreq > 3800)
-// {
-// if (--model.shiftsleft != 0)
-// {
-// for (int i = model.entries - 1; i >= 0; i--)
-// {
-// // -1, not -2; the 0 entry saves this
-// model.syms[i].cumfreq >>= 1;
-// if (model.syms[i].cumfreq <= model.syms[i + 1].cumfreq)
-// model.syms[i].cumfreq = (ushort)(model.syms[i + 1].cumfreq + 1);
-// }
-// }
-// else
-// {
-// model.shiftsleft = 50;
-// 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.syms[i].cumfreq -= model.syms[i + 1].cumfreq;
-// model.syms[i].cumfreq++; /* avoid losing things entirely */
-// model.syms[i].cumfreq >>= 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.syms[i].cumfreq < model.syms[j].cumfreq)
-// {
-// QTMmodelsym temp = model.syms[i];
-// model.syms[i] = model.syms[j];
-// model.syms[j] = temp;
-// }
-// }
-// }
-
-// // Then convert frequencies back to cumfreq
-// for (int i = model.entries - 1; i >= 0; i--)
-// {
-// model.syms[i].cumfreq += model.syms[i + 1].cumfreq;
-// }
-
-// // Then update the other part of the table
-// for (int i = 0; i < model.entries; i++)
-// {
-// model.tabloc[model.syms[i].sym] = (ushort)i;
-// }
-// }
-// }
-// }
+// public byte[] window;
// ///
-// /// QTMfdi_initmodel (internal)
-// ///
-// /// Initialize a model which decodes symbols from [s] to [s]+[n]-1
+// /// window size (1Kb through 2Mb)
// ///
-// internal static void QTMfdi_initmodel(QTMmodel m, QTMmodelsym[] sym, int n, int s)
-// {
-// int i;
-// m.shiftsleft = 4;
-// m.entries = n;
-// m.syms = sym;
-// memset(m.tabloc, 0xFF, sizeof(m.tabloc)); /* clear out look-up table */
-// for (i = 0; i < n; i++)
-// {
-// m.tabloc[i + s] = (ushort)i; /* set up a look-up entry for symbol */
-// m.syms[i].sym = (ushort)(i + s); /* actual symbol */
-// m.syms[i].cumfreq = (ushort)(n - i); /* current frequency of that symbol */
-// }
-// m.syms[n].cumfreq = 0;
-// }
+// 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)
// ///
@@ -136,20 +97,20 @@
// /* initialize arithmetic coding models */
-// QTMfdi_initmodel(decomp_state.qtm.model7, decomp_state.qtm.m7sym, 7, 0);
+// Quantum.InitModel(decomp_state.qtm.model7, decomp_state.qtm.m7sym, 7, 0);
-// QTMfdi_initmodel(decomp_state.qtm.model00, decomp_state.qtm.m00sym, 0x40, 0x00);
-// QTMfdi_initmodel(decomp_state.qtm.model40, decomp_state.qtm.m40sym, 0x40, 0x40);
-// QTMfdi_initmodel(decomp_state.qtm.model80, decomp_state.qtm.m80sym, 0x40, 0x80);
-// QTMfdi_initmodel(decomp_state.qtm.modelC0, decomp_state.qtm.mC0sym, 0x40, 0xC0);
+// 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 */
-// QTMfdi_initmodel(decomp_state.qtm.model4, decomp_state.qtm.m4sym, (msz < 24) ? msz : 24, 0);
+// 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 */
-// QTMfdi_initmodel(decomp_state.qtm.model5, decomp_state.qtm.m5sym, (msz < 36) ? msz : 36, 0);
+// 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 */
-// QTMfdi_initmodel(decomp_state.qtm.model6pos, decomp_state.qtm.m6psym, msz, 0);
-// QTMfdi_initmodel(decomp_state.qtm.model6len, decomp_state.qtm.m6lsym, 27, 0);
+// 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;
// }
diff --git a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.cs b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.cs
index dee12406..5dc244d7 100644
--- a/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.cs
+++ b/BurnOutSharp.Wrappers/MicrosoftCabinet.fdi.cs
@@ -2,6 +2,7 @@
// using System.Collections.Generic;
// using System.IO;
// using System.Linq;
+// using BurnOutSharp.Compression;
// using static BurnOutSharp.Wrappers.CabinetConstants;
// using static BurnOutSharp.Wrappers.FDIcConstants;
// using static BurnOutSharp.Wrappers.FDIConstants;
@@ -697,46 +698,6 @@
// ///
// public const ushort tcompSHIFT_LZX_WINDOW = 8;
-// ///
-// /// Mask for Quantum Compression Level
-// ///
-// public const ushort tcompMASK_QUANTUM_LEVEL = 0x00F0;
-
-// ///
-// /// Lowest Quantum Level (1)
-// ///
-// public const ushort tcompQUANTUM_LEVEL_LO = 0x0010;
-
-// ///
-// /// Highest Quantum Level (7)
-// ///
-// public const ushort tcompQUANTUM_LEVEL_HI = 0x0070;
-
-// ///
-// /// Amount to shift over to get int
-// ///
-// public const ushort tcompSHIFT_QUANTUM_LEVEL = 4;
-
-// ///
-// /// Mask for Quantum Compression Memory
-// ///
-// public const ushort tcompMASK_QUANTUM_MEM = 0x1F00;
-
-// ///
-// /// Lowest Quantum Memory (10)
-// ///
-// public const ushort tcompQUANTUM_MEM_LO = 0x0A00;
-
-// ///
-// /// Highest Quantum Memory (21)
-// ///
-// public const ushort tcompQUANTUM_MEM_HI = 0x1500;
-
-// ///
-// /// Amount to shift over to get int
-// ///
-// public const ushort tcompSHIFT_QUANTUM_MEM = 8;
-
// ///
// /// Reserved bits (high 3 bits)
// ///
@@ -1336,73 +1297,6 @@
// public byte* inpos;
// }
-// /* Quantum stuff */
-
-// ///
-// internal class QTMmodelsym
-// {
-// public ushort sym;
-
-// public ushort cumfreq;
-// }
-
-// ///
-// internal class QTMmodel
-// {
-// public int shiftsleft;
-
-// public int entries;
-
-// public QTMmodelsym[] syms;
-
-// public ushort[] tabloc = new ushort[256];
-// }
-
-// ///
-// internal class QTMstate
-// {
-// ///
-// /// 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 QTMmodel model7;
-// public QTMmodelsym[] m7sym = new QTMmodelsym[7 + 1];
-
-// public QTMmodel model4;
-// public QTMmodel model5;
-// public QTMmodel model6pos;
-// public QTMmodel model6len;
-// public QTMmodelsym[] m4sym = new QTMmodelsym[0x18 + 1];
-// public QTMmodelsym[] m5sym = new QTMmodelsym[0x24 + 1];
-// public QTMmodelsym[] m6psym = new QTMmodelsym[0x2a + 1];
-// public QTMmodelsym[] m6lsym = new QTMmodelsym[0x1b + 1];
-
-// public QTMmodel model00;
-// public QTMmodel model40;
-// public QTMmodel model80;
-// public QTMmodel modelC0;
-// public QTMmodelsym[] m00sym = new QTMmodelsym[0x40 + 1];
-// public QTMmodelsym[] m40sym = new QTMmodelsym[0x40 + 1];
-// public QTMmodelsym[] m80sym = new QTMmodelsym[0x40 + 1];
-// public QTMmodelsym[] mC0sym = new QTMmodelsym[0x40 + 1];
-// }
-
// /* LZX stuff */
// ///
@@ -1699,7 +1593,7 @@
// #region methods
// public ZIPstate zip;
-// public QTMstate qtm;
+// public QuantumState qtm;
// public LZXstate lzx;
// #endregion
@@ -1792,7 +1686,7 @@
// // Q_REMOVE_BITS(1); \
// // } \
// // \
-// // QTMupdatemodel(&(decomp_state.qtm.m)), i); \
+// // Quantum.UpdateModel(&(decomp_state.qtm.m)), i); \
// // } while (0)
// /* Bitstream reading macros (LZX / intel little-endian byte order)
@@ -2115,7 +2009,7 @@
// #region methods
// public ZIPstate zip;
-// public QTMstate qtm;
+// public QuantumState qtm;
// public LZXstate lzx;
// #endregion