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