mirror of
https://github.com/SabreTools/SabreTools.Compression.git
synced 2026-07-08 18:06:34 +00:00
Make Blast like others
This commit is contained in:
@@ -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
|
||||
/// <summary>
|
||||
/// 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").
|
||||
/// </summary>
|
||||
public unsafe class Decompressor
|
||||
{
|
||||
#region Huffman Encoding
|
||||
|
||||
/// <summary>
|
||||
/// Literal code
|
||||
/// </summary>
|
||||
private static readonly Huffman litcode = new(MAXBITS + 1, 256);
|
||||
private readonly Huffman litcode = new(MAXBITS + 1, 256);
|
||||
|
||||
/// <summary>
|
||||
/// Length code
|
||||
/// </summary>
|
||||
private static readonly Huffman lencode = new(MAXBITS + 1, 16);
|
||||
private readonly Huffman lencode = new(MAXBITS + 1, 16);
|
||||
|
||||
/// <summary>
|
||||
/// Distance code
|
||||
/// </summary>
|
||||
private static readonly Huffman distcode = new(MAXBITS + 1, 64);
|
||||
private readonly Huffman distcode = new(MAXBITS + 1, 64);
|
||||
|
||||
/// <summary>
|
||||
/// Base for length codes
|
||||
@@ -72,10 +83,12 @@ namespace SabreTools.Compression.Blast
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor
|
||||
/// Create a Blast decompressor
|
||||
/// </summary>
|
||||
static BlastDecoder()
|
||||
private Decompressor()
|
||||
{
|
||||
// Repeated code lengths of literal codes
|
||||
byte[] litlen =
|
||||
@@ -105,20 +118,29 @@ namespace SabreTools.Compression.Blast
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public static int Blast(byte[] inhow, List<byte> outhow)
|
||||
public static Decompressor Create() => new();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Decompress source data to an output stream
|
||||
/// </summary>
|
||||
public bool CopyTo(byte[] source, Stream dest)
|
||||
=> CopyTo(new MemoryStream(source), dest);
|
||||
|
||||
/// <summary>
|
||||
/// Decompress source data to an output stream
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -176,7 +198,7 @@ namespace SabreTools.Compression.Blast
|
||||
/// ignoring whether the length is greater than the distance or not implements
|
||||
/// this correctly.
|
||||
/// </remarks>
|
||||
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;
|
||||
}
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// Opaque information passed to InputFunction()
|
||||
/// </summary>
|
||||
public byte[] InHow { get; set; }
|
||||
public Stream Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Next input location
|
||||
/// </summary>
|
||||
public List<byte> Input { get; set; }
|
||||
public byte[] Input { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to the next input location
|
||||
@@ -48,7 +48,7 @@ namespace SabreTools.Compression.Blast
|
||||
/// <summary>
|
||||
/// Opaque information passed to OutputFunction()
|
||||
/// </summary>
|
||||
public List<byte> OutHow { get; set; }
|
||||
public Stream Dest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Index of next write location in out[]
|
||||
@@ -63,7 +63,7 @@ namespace SabreTools.Compression.Blast
|
||||
/// <summary>
|
||||
/// Output buffer and sliding window
|
||||
/// </summary>
|
||||
public byte[] Output { get; set; } = new byte[MAXWIN];
|
||||
public readonly byte[] Output = new byte[MAXWIN];
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to the next output location
|
||||
@@ -75,18 +75,16 @@ namespace SabreTools.Compression.Blast
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="inhow">Input byte array</param>
|
||||
/// <param name="outhow">Output byte list</param>
|
||||
public State(byte[] inhow, List<byte> outhow)
|
||||
public State(Stream source, Stream dest)
|
||||
{
|
||||
InHow = inhow;
|
||||
Input = new List<byte>();
|
||||
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
|
||||
/// <returns>Amount of data in Input</returns>
|
||||
public uint ProcessInput()
|
||||
{
|
||||
Input = [.. InHow];
|
||||
return (uint)Input.Count;
|
||||
int read = Source.Read(Input, 0, 4096);
|
||||
return (uint)read;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user