mirror of
https://github.com/SabreTools/SabreTools.Compression.git
synced 2026-09-22 14:54:59 +00:00
Better modernization of Blast
This commit is contained in:
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user