Better modernization of Blast

This commit is contained in:
Matt Nadareski
2024-12-11 09:45:03 -05:00
parent 97a83b42ee
commit 8fc071d4d8
3 changed files with 77 additions and 66 deletions

View File

@@ -146,7 +146,7 @@ namespace SabreTools.Compression.Blast
int err;
try
{
err = Decomp(state);
err = Decompress(state);
}
catch (IndexOutOfRangeException)
{
@@ -198,7 +198,7 @@ namespace SabreTools.Compression.Blast
/// ignoring whether the length is greater than the distance or not implements
/// this correctly.
/// </remarks>
private int Decomp(State state)
private int Decompress(State state)
{
int symbol; // decoded symbol, extra bits for distance
int len; // length for copy
@@ -207,29 +207,29 @@ namespace SabreTools.Compression.Blast
int from, to; // copy pointers
// Read header
int lit = state.Bits(8); // true if literals are coded
int lit = state.ReadBits(8); // true if literals are coded
if (lit > 1)
return -1;
int dict = state.Bits(8); // log2(dictionary size) - 6
int dict = state.ReadBits(8); // log2(dictionary size) - 6
if (dict < 4 || dict > 6)
return -2;
// Decode literals and length/distance pairs
while (true)
{
if (state.Bits(1) != 0)
if (state.ReadBits(1) != 0)
{
// Get length
symbol = lencode.Decode(state);
len = baseLength[symbol] + state.Bits(extra[symbol]);
len = baseLength[symbol] + state.ReadBits(extra[symbol]);
if (len == 519)
break; // end code
// Get distance
symbol = len == 2 ? 2 : dict;
dist = (uint)(distcode.Decode(state) << symbol);
dist += (uint)state.Bits(symbol);
dist += (uint)state.ReadBits(symbol);
dist++;
if (state.First && dist > state.Next)
return -3; //distance too far back
@@ -237,7 +237,7 @@ namespace SabreTools.Compression.Blast
// Copy length bytes from distance bytes back
do
{
to = (int)(state.OutputPtr + state.Next);
to = (int)state.Next;
from = (int)(to - dist);
copy = MAXWIN;
if (state.Next < dist)
@@ -252,11 +252,7 @@ namespace SabreTools.Compression.Blast
len -= copy;
state.Next += (uint)copy;
do
{
state.Output[to++] = state.Output[from++];
}
while (--copy != 0);
state.CopyOutputBytes(to, from, copy);
if (state.Next == MAXWIN)
{
@@ -272,8 +268,8 @@ namespace SabreTools.Compression.Blast
else
{
// Get literal and write it
symbol = lit != 0 ? litcode.Decode(state) : state.Bits(8);
state.Output[state.Next++] = (byte)symbol;
symbol = lit != 0 ? litcode.Decode(state) : state.ReadBits(8);
state.WriteToOutput((byte)symbol);
if (state.Next == MAXWIN)
{
if (!state.ProcessOutput())

View File

@@ -1,4 +1,3 @@
using System;
using static SabreTools.Compression.Blast.Constants;
namespace SabreTools.Compression.Blast
@@ -187,15 +186,7 @@ namespace SabreTools.Compression.Blast
if (left == 0)
break;
if (state.Left == 0)
{
state.Left = state.ProcessInput();
if (state.Left == 0)
throw new IndexOutOfRangeException();
}
bitbuf = state.Input[state.InputPtr++];
state.Left--;
bitbuf = state.ReadNextByte();
if (left > 8)
left = 8;
}

View File

@@ -14,22 +14,22 @@ namespace SabreTools.Compression.Blast
/// <summary>
/// Opaque information passed to InputFunction()
/// </summary>
public Stream Source { get; set; }
private readonly Stream _source;
/// <summary>
/// Next input location
/// </summary>
public byte[] Input { get; set; }
private readonly byte[] _input = new byte[MAXWIN];
/// <summary>
/// Pointer to the next input location
/// </summary>
public int InputPtr { get; set; }
private int _inputPtr;
/// <summary>
/// Available input at in
/// </summary>
public uint Left { get; set; }
private uint _available;
/// <summary>
/// Bit buffer
@@ -48,7 +48,7 @@ namespace SabreTools.Compression.Blast
/// <summary>
/// Opaque information passed to OutputFunction()
/// </summary>
public Stream Dest { get; set; }
private readonly Stream _dest;
/// <summary>
/// Index of next write location in out[]
@@ -63,12 +63,7 @@ namespace SabreTools.Compression.Blast
/// <summary>
/// Output buffer and sliding window
/// </summary>
public readonly byte[] Output = new byte[MAXWIN];
/// <summary>
/// Pointer to the next output location
/// </summary>
public int OutputPtr { get; set; }
private readonly byte[] _output = new byte[MAXWIN];
#endregion
@@ -77,18 +72,29 @@ namespace SabreTools.Compression.Blast
/// </summary>
public State(Stream source, Stream dest)
{
Source = source;
Input = [];
InputPtr = 0;
Left = 0;
_source = source;
_inputPtr = 0;
_available = 0;
BitBuf = 0;
BitCnt = 0;
Dest = dest;
_dest = dest;
Next = 0;
First = true;
}
/// <summary>
/// Copy bytes in the output buffer between locations
/// </summary>
public void CopyOutputBytes(int to, int from, int len)
{
do
{
_output[to++] = _output[from++];
}
while (--len > 0);
}
/// <summary>
/// Return need bits from the input stream. This always leaves less than
/// eight bits in the buffer. bits() works properly for need == 0.
@@ -100,22 +106,16 @@ namespace SabreTools.Compression.Blast
/// buffer, using shift right, and new bytes are appended to the top of the
/// bit buffer, using shift left.
/// </remarks>
public int Bits(int need)
public int ReadBits(int need)
{
// Load at least need bits into val
int val = BitBuf;
while (BitCnt < need)
{
if (Left == 0)
{
Left = ProcessInput();
if (Left == 0)
throw new IndexOutOfRangeException();
}
// Load eight bits
val |= Input[InputPtr++] << BitCnt;
Left--;
EnsureAvailable();
val |= _input[_inputPtr++] << BitCnt;
_available--;
BitCnt += 8;
}
@@ -127,16 +127,6 @@ namespace SabreTools.Compression.Blast
return val & ((1 << need) - 1);
}
/// <summary>
/// Process input for the current state
/// </summary>
/// <returns>Amount of data in Input</returns>
public uint ProcessInput()
{
int read = Source.Read(Input, 0, 4096);
return (uint)read;
}
/// <summary>
/// Process output for the current state
/// </summary>
@@ -145,10 +135,10 @@ namespace SabreTools.Compression.Blast
{
try
{
byte[] next = new byte[Next];
Array.Copy(Output, next, next.Length);
Dest.Write(next);
Dest.Flush();
_dest.Write(_output, 0, (int)Next);
_dest.Flush();
Next = 0;
return true;
}
catch
@@ -156,5 +146,39 @@ namespace SabreTools.Compression.Blast
return false;
}
}
/// <summary>
/// Read the next byte from the input buffer
/// </summary>
public byte ReadNextByte()
{
EnsureAvailable();
return _input[_inputPtr++];
}
/// <summary>
/// Write a byte value to the output buffer
/// </summary>
public void WriteToOutput(byte value)
=> _output[Next++] = value;
/// <summary>
/// Ensure there are bytes available, if possible
/// </summary>
/// <exception cref="IndexOutOfRangeException"></exception>
private void EnsureAvailable()
{
// If there are bytes
if (_inputPtr < _available)
return;
// Read the next block
_available = (uint)_source.Read(_input, 0, MAXWIN);
if (_available == 0)
throw new IndexOutOfRangeException();
// Reset the pointer
_inputPtr = 0;
}
}
}