diff --git a/Quantum/Decoder.cs b/Quantum/Decompressor.cs similarity index 59% rename from Quantum/Decoder.cs rename to Quantum/Decompressor.cs index f9c29b8..63fb55b 100644 --- a/Quantum/Decoder.cs +++ b/Quantum/Decompressor.cs @@ -4,13 +4,81 @@ using SabreTools.Models.Compression.Quantum; namespace SabreTools.Compression.Quantum { /// - public class Quantum + public class Decompressor { + /// + /// Internal bitstream to use for decompression + /// + private BitStream _bitStream; + // TODO: Figure out what these values are private uint CS_H; private uint CS_L; private uint CS_C; + /// + /// Get the next symbol from a model + /// + public int GetSymbol(Model model) + { + int i; + int sym; + + int freq = GetFrequency(model.Symbols[0].CumulativeFrequency); + for (i = 1; i < model.Entries; i++) + { + if (model.Symbols[i].CumulativeFrequency <= freq) + break; + } + + sym = model.Symbols[i - 1].Symbol; + + GetCode(model.Symbols[i - 1].CumulativeFrequency, + model.Symbols[i].CumulativeFrequency, + model.Symbols[0].CumulativeFrequency); + + UpdateModel(model, i); + + return sym; + } + + /// + /// Get the next code based on the frequencies + /// + private int GetCode(int prevFrequency, int currentFrequency, int totalFrequency) + { + int uf; + + uint range = (CS_H - CS_L) + 1; + CS_H = CS_L + (uint)((prevFrequency * range) / totalFrequency) - 1; + CS_L = CS_L + (uint)((currentFrequency * range) / totalFrequency); + + while (true) + { + if ((CS_L & 0x8000) != (CS_H & 0x8000)) + { + if ((CS_L & 0x4000) != 0 && (CS_H & 0x4000) == 0) + { + // Underflow case + CS_C ^= 0x4000; + CS_L &= 0x3FFF; + CS_H |= 0x4000; + } + else + { + break; + } + } + + CS_L <<= 1; + CS_H = (CS_H << 1) | 1; + CS_C = (CS_C << 1) | _bitStream.ReadBit() ?? 0; + } + + // TODO: Incomplete implementation? + return 0; + } + /// /// Update the model after an encode or decode step ///