From 97a83b42ee0022fa652acf89aac4d78f747098ba Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Wed, 11 Dec 2024 09:20:14 -0500 Subject: [PATCH] Make Blast like others --- .../{BlastDecoder.cs => Decompressor.cs} | 67 ++++++++++++------- SabreTools.Compression/Blast/State.cs | 29 ++++---- 2 files changed, 58 insertions(+), 38 deletions(-) rename SabreTools.Compression/Blast/{BlastDecoder.cs => Decompressor.cs} (83%) diff --git a/SabreTools.Compression/Blast/BlastDecoder.cs b/SabreTools.Compression/Blast/Decompressor.cs similarity index 83% rename from SabreTools.Compression/Blast/BlastDecoder.cs rename to SabreTools.Compression/Blast/Decompressor.cs index 1c12080..721710d 100644 --- a/SabreTools.Compression/Blast/BlastDecoder.cs +++ b/SabreTools.Compression/Blast/Decompressor.cs @@ -30,29 +30,40 @@ */ using System; -using System.Collections.Generic; +using System.IO; using static SabreTools.Compression.Blast.Constants; namespace SabreTools.Compression.Blast { - public unsafe static class BlastDecoder + /// + /// blast() decompresses the PKWare Data Compression Library (DCL) compressed + /// format. It provides the same functionality as the explode() function in + /// that library. (Note: PKWare overused the "implode" verb, and the format + /// used by their library implode() function is completely different and + /// incompatible with the implode compression method supported by PKZIP.) + /// + /// The binary mode for stdio functions should be used to assure that the + /// compressed data is not corrupted when read or written. For example: + /// fopen(..., "rb") and fopen(..., "wb"). + /// + public unsafe class Decompressor { #region Huffman Encoding /// /// Literal code /// - private static readonly Huffman litcode = new(MAXBITS + 1, 256); + private readonly Huffman litcode = new(MAXBITS + 1, 256); /// /// Length code /// - private static readonly Huffman lencode = new(MAXBITS + 1, 16); + private readonly Huffman lencode = new(MAXBITS + 1, 16); /// /// Distance code /// - private static readonly Huffman distcode = new(MAXBITS + 1, 64); + private readonly Huffman distcode = new(MAXBITS + 1, 64); /// /// Base for length codes @@ -72,10 +83,12 @@ namespace SabreTools.Compression.Blast #endregion + #region Constructors + /// - /// Static constructor + /// Create a Blast decompressor /// - static BlastDecoder() + private Decompressor() { // Repeated code lengths of literal codes byte[] litlen = @@ -105,20 +118,29 @@ namespace SabreTools.Compression.Blast } /// - /// blast() decompresses the PKWare Data Compression Library (DCL) compressed - /// format. It provides the same functionality as the explode() function in - /// that library. (Note: PKWare overused the "implode" verb, and the format - /// used by their library implode() function is completely different and - /// incompatible with the implode compression method supported by PKZIP.) - /// - /// The binary mode for stdio functions should be used to assure that the - /// compressed data is not corrupted when read or written. For example: - /// fopen(..., "rb") and fopen(..., "wb"). + /// Create a Blast decompressor /// - public static int Blast(byte[] inhow, List outhow) + public static Decompressor Create() => new(); + + #endregion + + /// + /// Decompress source data to an output stream + /// + public bool CopyTo(byte[] source, Stream dest) + => CopyTo(new MemoryStream(source), dest); + + /// + /// Decompress source data to an output stream + /// + public bool CopyTo(Stream source, Stream dest) { + // Ignore unwritable streams + if (!dest.CanWrite) + return false; + // Input/output state - var state = new State(inhow, outhow); + var state = new State(source, dest); // Attempt to decompress using the above state int err; @@ -136,7 +158,7 @@ namespace SabreTools.Compression.Blast if (err != 1 && state.Next != 0 && !state.ProcessOutput() && err == 0) err = 1; - return err; + return err == 0; } /// @@ -176,7 +198,7 @@ namespace SabreTools.Compression.Blast /// ignoring whether the length is greater than the distance or not implements /// this correctly. /// - private static int Decomp(State state) + private int Decomp(State state) { int symbol; // decoded symbol, extra bits for distance int len; // length for copy @@ -194,7 +216,7 @@ namespace SabreTools.Compression.Blast return -2; // Decode literals and length/distance pairs - do + while (true) { if (state.Bits(1) != 0) { @@ -256,13 +278,12 @@ namespace SabreTools.Compression.Blast { if (!state.ProcessOutput()) return 1; - + state.Next = 0; state.First = false; } } } - while (true); return 0; } diff --git a/SabreTools.Compression/Blast/State.cs b/SabreTools.Compression/Blast/State.cs index 86e42d6..73641e3 100644 --- a/SabreTools.Compression/Blast/State.cs +++ b/SabreTools.Compression/Blast/State.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.IO; using static SabreTools.Compression.Blast.Constants; namespace SabreTools.Compression.Blast @@ -14,12 +14,12 @@ namespace SabreTools.Compression.Blast /// /// Opaque information passed to InputFunction() /// - public byte[] InHow { get; set; } + public Stream Source { get; set; } /// /// Next input location /// - public List Input { get; set; } + public byte[] Input { get; set; } /// /// Pointer to the next input location @@ -48,7 +48,7 @@ namespace SabreTools.Compression.Blast /// /// Opaque information passed to OutputFunction() /// - public List OutHow { get; set; } + public Stream Dest { get; set; } /// /// Index of next write location in out[] @@ -63,7 +63,7 @@ namespace SabreTools.Compression.Blast /// /// Output buffer and sliding window /// - public byte[] Output { get; set; } = new byte[MAXWIN]; + public readonly byte[] Output = new byte[MAXWIN]; /// /// Pointer to the next output location @@ -75,18 +75,16 @@ namespace SabreTools.Compression.Blast /// /// Constructor /// - /// Input byte array - /// Output byte list - public State(byte[] inhow, List outhow) + public State(Stream source, Stream dest) { - InHow = inhow; - Input = new List(); + Source = source; + Input = []; InputPtr = 0; Left = 0; BitBuf = 0; BitCnt = 0; - OutHow = outhow; + Dest = dest; Next = 0; First = true; } @@ -116,7 +114,7 @@ namespace SabreTools.Compression.Blast } // Load eight bits - val |= (int)(Input[InputPtr++]) << BitCnt; + val |= Input[InputPtr++] << BitCnt; Left--; BitCnt += 8; } @@ -135,8 +133,8 @@ namespace SabreTools.Compression.Blast /// Amount of data in Input public uint ProcessInput() { - Input = [.. InHow]; - return (uint)Input.Count; + int read = Source.Read(Input, 0, 4096); + return (uint)read; } /// @@ -149,7 +147,8 @@ namespace SabreTools.Compression.Blast { byte[] next = new byte[Next]; Array.Copy(Output, next, next.Length); - OutHow.AddRange(next); + Dest.Write(next); + Dest.Flush(); return true; } catch