Some Quantum things to models / compression

This commit is contained in:
Matt Nadareski
2023-01-01 22:02:54 -08:00
parent 96fbb38b1c
commit 895f40414d
6 changed files with 221 additions and 206 deletions

View File

@@ -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
/// <summary>
/// Initialize a Quantum model that decodes symbols from s to (s + n - 1)
/// </summary>
/// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/fdi.c"/>
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<ushort>(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;
}
/// <summary>
/// Update the quantum model for a particular symbol
/// </summary>
/// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/fdi.c"/>
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;
}
}
}
}
}

View File

@@ -0,0 +1,45 @@
namespace BurnOutSharp.Models.Compression.Quantum
{
public static class Constants
{
/// <summary>
/// Mask for Quantum Compression Level
/// </summary>
public const ushort MASK_QUANTUM_LEVEL = 0x00F0;
/// <summary>
/// Lowest Quantum Level (1)
/// </summary>
public const ushort QUANTUM_LEVEL_LO = 0x0010;
/// <summary>
/// Highest Quantum Level (7)
/// </summary>
public const ushort QUANTUM_LEVEL_HI = 0x0070;
/// <summary>
/// Amount to shift over to get int
/// </summary>
public const ushort SHIFT_QUANTUM_LEVEL = 4;
/// <summary>
/// Mask for Quantum Compression Memory
/// </summary>
public const ushort MASK_QUANTUM_MEM = 0x1F00;
/// <summary>
/// Lowest Quantum Memory (10)
/// </summary>
public const ushort QUANTUM_MEM_LO = 0x0A00;
/// <summary>
/// Highest Quantum Memory (21)
/// </summary>
public const ushort QUANTUM_MEM_HI = 0x1500;
/// <summary>
/// Amount to shift over to get int
/// </summary>
public const ushort SHIFT_QUANTUM_MEM = 8;
}
}

View File

@@ -1,10 +1,15 @@
namespace BurnOutSharp.Models.Compression.Quantum
{
/// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
/// <see href="http://www.russotto.net/quantumcomp.html"/>
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];
}
}

View File

@@ -1,10 +1,11 @@
namespace BurnOutSharp.Models.Compression.Quantum
{
/// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
/// <see href="http://www.russotto.net/quantumcomp.html"/>
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;
}
}

View File

@@ -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
// /// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
// internal class QuantumState
// {
// /// <summary>
// /// QTMupdatemodel (internal)
// /// the actual decoding window
// /// </summary>
// 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;
// /// <summary>
// /// QTMfdi_initmodel (internal)
// ///
// /// Initialize a model which decodes symbols from [s] to [s]+[n]-1
// /// window size (1Kb through 2Mb)
// /// </summary>
// 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;
// /// <summary>
// /// window size when it was first allocated
// /// </summary>
// public uint actual_size;
// /// <summary>
// /// current offset within the window
// /// </summary>
// 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
// {
// /// <summary>
// /// QTMfdi_init (internal)
// /// </summary>
@@ -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;
// }

View File

@@ -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 @@
// /// </summary>
// public const ushort tcompSHIFT_LZX_WINDOW = 8;
// /// <summary>
// /// Mask for Quantum Compression Level
// /// </summary>
// public const ushort tcompMASK_QUANTUM_LEVEL = 0x00F0;
// /// <summary>
// /// Lowest Quantum Level (1)
// /// </summary>
// public const ushort tcompQUANTUM_LEVEL_LO = 0x0010;
// /// <summary>
// /// Highest Quantum Level (7)
// /// </summary>
// public const ushort tcompQUANTUM_LEVEL_HI = 0x0070;
// /// <summary>
// /// Amount to shift over to get int
// /// </summary>
// public const ushort tcompSHIFT_QUANTUM_LEVEL = 4;
// /// <summary>
// /// Mask for Quantum Compression Memory
// /// </summary>
// public const ushort tcompMASK_QUANTUM_MEM = 0x1F00;
// /// <summary>
// /// Lowest Quantum Memory (10)
// /// </summary>
// public const ushort tcompQUANTUM_MEM_LO = 0x0A00;
// /// <summary>
// /// Highest Quantum Memory (21)
// /// </summary>
// public const ushort tcompQUANTUM_MEM_HI = 0x1500;
// /// <summary>
// /// Amount to shift over to get int
// /// </summary>
// public const ushort tcompSHIFT_QUANTUM_MEM = 8;
// /// <summary>
// /// Reserved bits (high 3 bits)
// /// </summary>
@@ -1336,73 +1297,6 @@
// public byte* inpos;
// }
// /* Quantum stuff */
// /// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
// internal class QTMmodelsym
// {
// public ushort sym;
// public ushort cumfreq;
// }
// /// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
// internal class QTMmodel
// {
// public int shiftsleft;
// public int entries;
// public QTMmodelsym[] syms;
// public ushort[] tabloc = new ushort[256];
// }
// /// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
// internal class QTMstate
// {
// /// <summary>
// /// the actual decoding window
// /// </summary>
// public byte[] window;
// /// <summary>
// /// window size (1Kb through 2Mb)
// /// </summary>
// public uint window_size;
// /// <summary>
// /// window size when it was first allocated
// /// </summary>
// public uint actual_size;
// /// <summary>
// /// current offset within the window
// /// </summary>
// 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 */
// /// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
@@ -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