70 lines
1.8 KiB
C#
70 lines
1.8 KiB
C#
using System;
|
|
|
|
namespace AssetStudio;
|
|
public class LZ4
|
|
{
|
|
public static LZ4 Instance => new();
|
|
public virtual int Decompress(ReadOnlySpan<byte> cmp, Span<byte> dec)
|
|
{
|
|
int cmpPos = 0;
|
|
int decPos = 0;
|
|
|
|
do
|
|
{
|
|
var (encCount, litCount) = GetLiteralToken(cmp, ref cmpPos);
|
|
|
|
//Copy literal chunk
|
|
litCount = GetLength(litCount, cmp, ref cmpPos);
|
|
|
|
cmp.Slice(cmpPos, litCount).CopyTo(dec.Slice(decPos));
|
|
|
|
cmpPos += litCount;
|
|
decPos += litCount;
|
|
|
|
if (cmpPos >= cmp.Length)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//Copy compressed chunk
|
|
int back = GetChunkEnd(cmp, ref cmpPos);
|
|
|
|
encCount = GetLength(encCount, cmp, ref cmpPos) + 4;
|
|
|
|
int encPos = decPos - back;
|
|
|
|
if (encCount <= back)
|
|
{
|
|
dec.Slice(encPos, encCount).CopyTo(dec.Slice(decPos));
|
|
|
|
decPos += encCount;
|
|
}
|
|
else
|
|
{
|
|
while (encCount-- > 0)
|
|
{
|
|
dec[decPos++] = dec[encPos++];
|
|
}
|
|
}
|
|
} while (cmpPos < cmp.Length &&
|
|
decPos < dec.Length);
|
|
|
|
return decPos;
|
|
}
|
|
protected virtual (int encCount, int litCount) GetLiteralToken(ReadOnlySpan<byte> cmp, ref int cmpPos) => ((cmp[cmpPos] >> 0) & 0xf, (cmp[cmpPos++] >> 4) & 0xf);
|
|
protected virtual int GetChunkEnd(ReadOnlySpan<byte> cmp, ref int cmpPos) => cmp[cmpPos++] << 0 | cmp[cmpPos++] << 8;
|
|
protected virtual int GetLength(int length, ReadOnlySpan<byte> cmp, ref int cmpPos)
|
|
{
|
|
byte sum;
|
|
|
|
if (length == 0xf)
|
|
{
|
|
do
|
|
{
|
|
length += sum = cmp[cmpPos++];
|
|
} while (sum == 0xff);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
} |