diff --git a/Quantum/Decompressor.cs b/Quantum/Decompressor.cs index 5a9cba1..0069f27 100644 --- a/Quantum/Decompressor.cs +++ b/Quantum/Decompressor.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using SabreTools.Models.Compression.Quantum; namespace SabreTools.Compression.Quantum @@ -16,10 +17,105 @@ namespace SabreTools.Compression.Quantum private uint CS_L; private uint CS_C; + /// + /// Selector 0: literal, 64 entries, starting symbol 0 + /// + private Model _model0; + + /// + /// Selector 1: literal, 64 entries, starting symbol 64 + /// + private Model _model1; + + /// + /// Selector 2: literal, 64 entries, starting symbol 128 + /// + private Model _model2; + + /// + /// Selector 3: literal, 64 entries, starting symbol 192 + /// + private Model _model3; + + /// + /// Selector 4: LZ, 3 character matches + /// + private Model _model4; + + /// + /// Selector 5: LZ, 4 character matches + /// + private Model _model5; + + /// + /// Selector 6: LZ, 5+ character matches + /// + private Model _model6; + + /// + /// Selector 6 length model + /// + private Model _model6len; + + /// + /// Create a new Decompressor from a Stream + /// + /// Stream to decompress + /// Number of bits in the sliding window + public Decompressor(Stream input, uint windowBits) + { + // If we have an invalid stream + if (input == null || !input.CanRead || !input.CanSeek) + throw new ArgumentException(nameof(input)); + + // If we have an invalid value for the window bits + if (windowBits < 10 || windowBits > 21) + throw new ArgumentOutOfRangeException(nameof(windowBits)); + + // Wrap the stream in a BitStream + _bitStream = new BitStream(input); + + // Initialize literal models + this._model0 = CreateModel(0, 64); + this._model1 = CreateModel(64, 64); + this._model2 = CreateModel(128, 64); + this._model3 = CreateModel(192, 64); + + // Initialize LZ models + int maxBitLength = (int)(windowBits * 2); + this._model4 = CreateModel(0, maxBitLength > 24 ? 24 : maxBitLength); + this._model5 = CreateModel(0, maxBitLength > 36 ? 36 : maxBitLength); + this._model6 = CreateModel(0, maxBitLength); + this._model6len = CreateModel(0, 27); + } + + /// + /// Create and initialize a model base on the start symbol and length + /// + private Model CreateModel(ushort start, int length) + { + // Create the model + var model = new Model + { + Entries = length, + Symbols = new ModelSymbol[length], + TimeToReorder = 4, + }; + + // Populate the symbol array + for (int i = 0; i < length; i++) + { + model.Symbols[i].Symbol = (ushort)(start + i); + model.Symbols[i].CumulativeFrequency = (ushort)(length - 1); + } + + return model; + } + /// /// Get the next symbol from a model /// - public int GetSymbol(Model model) + private int GetSymbol(Model model) { int freq = GetFrequency(model.Symbols[0].CumulativeFrequency);