From 7ca1f8489b8354d243aca1c9ae7b1d3e60b45ff5 Mon Sep 17 00:00:00 2001 From: BtbN Date: Fri, 14 Jun 2019 21:25:45 +0200 Subject: [PATCH] Rewrite LZ77 decompression as well --- ClanServer/Data/L44/ClanMusicInfo.cs | 4 +- .../Formatters/EamuseXrpcInputFormatter.cs | 2 +- .../Formatters/EamuseXrpcOutputFormatter.cs | 2 +- eAmuseCore/Compression/LZ77.cs | 111 +++++------------- eAmuseTest/Program.cs | 2 +- 5 files changed, 33 insertions(+), 88 deletions(-) diff --git a/ClanServer/Data/L44/ClanMusicInfo.cs b/ClanServer/Data/L44/ClanMusicInfo.cs index da2aecc..22f60a9 100644 --- a/ClanServer/Data/L44/ClanMusicInfo.cs +++ b/ClanServer/Data/L44/ClanMusicInfo.cs @@ -27,9 +27,7 @@ namespace ClanServer.Data.L44 stream.CopyTo(ms); return new ClanMusicInfo( new KBinXML( - LZ77.Decompress( - ms.ToArray() - ).ToArray() + LZ77.Decompress(ms.ToArray()) ).Document ); } diff --git a/ClanServer/Formatters/EamuseXrpcInputFormatter.cs b/ClanServer/Formatters/EamuseXrpcInputFormatter.cs index 62b01ca..42a27cb 100644 --- a/ClanServer/Formatters/EamuseXrpcInputFormatter.cs +++ b/ClanServer/Formatters/EamuseXrpcInputFormatter.cs @@ -89,7 +89,7 @@ namespace ClanServer.Formatters switch (compAlgo.ToLower()) { case "lz77": - return LZ77.Decompress(data).ToArray(); + return LZ77.Decompress(data); case "none": return data; default: diff --git a/ClanServer/Formatters/EamuseXrpcOutputFormatter.cs b/ClanServer/Formatters/EamuseXrpcOutputFormatter.cs index bed43d3..4482928 100644 --- a/ClanServer/Formatters/EamuseXrpcOutputFormatter.cs +++ b/ClanServer/Formatters/EamuseXrpcOutputFormatter.cs @@ -39,7 +39,7 @@ namespace ClanServer.Formatters string algo = "none"; - byte[] compressed = LZ77.Compress(resData); + byte[] compressed = LZ77.Compress(resData, 32); if (compressed.Length < resData.Length) { resData = compressed; diff --git a/eAmuseCore/Compression/LZ77.cs b/eAmuseCore/Compression/LZ77.cs index 392ea60..43bc370 100644 --- a/eAmuseCore/Compression/LZ77.cs +++ b/eAmuseCore/Compression/LZ77.cs @@ -1,103 +1,50 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; namespace eAmuseCore.Compression { - public class RepeatingRingBuffer - { - private readonly byte[] buf; - private readonly int mod; - private int pos; - - public RepeatingRingBuffer(int size) - { - if (size == 0 || (size & (size - 1)) != 0) - throw new ArgumentException("Size is not a power of two.", "size"); - - buf = new byte[size]; - mod = size - 1; - pos = 0; - } - - public byte this[int index] - { - get => buf[(pos + index) & mod]; - set => buf[(pos + index) & mod] = value; - } - - public int Size - { - get => buf.Length; - } - - public void Append(byte b) - { - buf[pos++ & mod] = b; - } - - public IEnumerable Slice(int start, int end) - { - for (int i = start; i < end; ++i) - { - if (start < 0 && i >= 0) - yield return this[start + (i % start)]; - else - yield return this[i]; - } - } - } - public static class LZ77 { private const int minLength = 3; - public static IEnumerable Decompress(IEnumerable data) + public static byte[] Decompress(byte[] data) { - RepeatingRingBuffer buffer = new RepeatingRingBuffer(0x1000); + List res = new List(); + + int pos = 0; int state = 0; - using (var iter = data.GetEnumerator()) + while (pos < data.Length) { - while (iter.MoveNext()) + state >>= 1; + if (state <= 1) + state = data[pos++] | 0x100; + + if ((state & 1) != 0) { - state >>= 1; - if (state <= 1) + res.Add(data[pos++]); + } + else + { + byte byte1 = data[pos++]; + byte byte2 = data[pos++]; + + int length = (byte2 & 0xf) + minLength; + int distance = (byte1 << 4) | (byte2 >> 4); + + if (distance == 0) + break; + + int resPos = res.Count; + for (int i = 0; i < length; ++i) { - state = iter.Current | 0x100; - if (!iter.MoveNext()) - yield break; - } - - if ((state & 1) != 0) - { - yield return iter.Current; - buffer.Append(iter.Current); - } - else - { - byte byte1 = iter.Current; - if (!iter.MoveNext()) - yield break; - byte byte2 = iter.Current; - - int length = (byte2 & 0xf) + minLength; - int distance = (byte1 << 4) | (byte2 >> 4); - - if (distance == 0) - yield break; - - for (int i = 0; i < length; ++i) - { - byte b = buffer[-distance]; - yield return b; - buffer.Append(b); - } + int o = resPos - distance + i; + res.Add((o < 0) ? (byte)0 : res[o]); } } } + + return res.ToArray(); } private struct Match diff --git a/eAmuseTest/Program.cs b/eAmuseTest/Program.cs index b82aec1..bd1cabf 100644 --- a/eAmuseTest/Program.cs +++ b/eAmuseTest/Program.cs @@ -27,7 +27,7 @@ namespace eAmuseTest byte[] rawData = data; if (compress == "lz77") - rawData = LZ77.Decompress(data).ToArray(); + rawData = LZ77.Decompress(data); else if (compress != "none") throw new ArgumentException("Unsupported compression algorithm");