using System; namespace AssetStudio; public class LZ4 { public static LZ4 Instance => new(); public virtual int Decompress(ReadOnlySpan cmp, Span 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 cmp, ref int cmpPos) => ((cmp[cmpPos] >> 0) & 0xf, (cmp[cmpPos++] >> 4) & 0xf); protected virtual int GetChunkEnd(ReadOnlySpan cmp, ref int cmpPos) => cmp[cmpPos++] << 0 | cmp[cmpPos++] << 8; protected virtual int GetLength(int length, ReadOnlySpan cmp, ref int cmpPos) { byte sum; if (length == 0xf) { do { length += sum = cmp[cmpPos++]; } while (sum == 0xff); } return length; } }