2019-07-25 20:49:04 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.IO.Compression;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Toolbox.Library.IO;
|
|
|
|
|
using K4os.Compression.LZ4.Streams;
|
|
|
|
|
|
|
|
|
|
namespace Toolbox.Library
|
|
|
|
|
{
|
|
|
|
|
//From https://github.com/xdanieldzd/N3DSCmbViewer/blob/3c3f66cf40d9122f8d0ebeab07c4db659b426b8b/N3DSCmbViewer/LZSS.cs
|
|
|
|
|
//and https://github.com/lue/MM3D/blob/master/src/lzs.cpp
|
|
|
|
|
public class LZSS : ICompressionFormat
|
|
|
|
|
{
|
|
|
|
|
public string[] Description { get; set; } = new string[] { "LZSS Compression" };
|
|
|
|
|
public string[] Extension { get; set; } = new string[] { "*.lzs", "*.lzss" };
|
|
|
|
|
|
2019-10-19 21:36:16 +00:00
|
|
|
|
private bool hasMagic = false;
|
|
|
|
|
|
2019-09-15 23:13:01 +00:00
|
|
|
|
public bool Identify(Stream stream, string fileName)
|
2019-07-25 20:49:04 +00:00
|
|
|
|
{
|
|
|
|
|
using (var reader = new FileReader(stream, true))
|
|
|
|
|
{
|
2019-10-19 21:36:16 +00:00
|
|
|
|
hasMagic = reader.CheckSignature(4, "LzS\x01");
|
2020-01-22 22:13:54 +00:00
|
|
|
|
return hasMagic || Utils.GetExtension(fileName) == ".lzs";
|
2019-07-25 20:49:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool CanCompress { get; } = true;
|
|
|
|
|
|
|
|
|
|
public Stream Decompress(Stream stream)
|
|
|
|
|
{
|
|
|
|
|
byte[] arcdata = stream.ToArray();
|
|
|
|
|
|
2019-10-19 21:36:16 +00:00
|
|
|
|
uint decompressedSize = 0;
|
|
|
|
|
uint compressedSize = 0;
|
|
|
|
|
|
|
|
|
|
if (hasMagic)
|
|
|
|
|
{
|
|
|
|
|
string tag = Encoding.ASCII.GetString(arcdata, 0, 4);
|
|
|
|
|
uint unknown = BitConverter.ToUInt32(arcdata, 4);
|
|
|
|
|
decompressedSize = BitConverter.ToUInt32(arcdata, 8);
|
|
|
|
|
compressedSize = BitConverter.ToUInt32(arcdata, 12);
|
2020-01-22 22:13:54 +00:00
|
|
|
|
|
|
|
|
|
if (arcdata.Length != compressedSize + 0x10) throw new Exception("compressed size mismatch");
|
2019-10-19 21:36:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
decompressedSize = BitConverter.ToUInt32(arcdata, 0);
|
|
|
|
|
}
|
2019-07-25 20:49:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<byte> outdata = new List<byte>();
|
|
|
|
|
byte[] BUFFER = new byte[4096];
|
|
|
|
|
for (int i = 0; i < BUFFER.Length; i++) BUFFER[i] = 0;
|
|
|
|
|
byte flags8 = 0;
|
|
|
|
|
ushort writeidx = 0xFEE;
|
|
|
|
|
ushort readidx = 0;
|
|
|
|
|
uint fidx = 0x10;
|
2020-01-22 22:13:54 +00:00
|
|
|
|
if (!hasMagic)
|
|
|
|
|
fidx = 4;
|
2019-07-25 20:49:04 +00:00
|
|
|
|
|
|
|
|
|
while (fidx < arcdata.Length)
|
|
|
|
|
{
|
|
|
|
|
flags8 = arcdata[fidx];
|
|
|
|
|
fidx++;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
|
{
|
|
|
|
|
if ((flags8 & 1) != 0)
|
|
|
|
|
{
|
|
|
|
|
outdata.Add(arcdata[fidx]);
|
|
|
|
|
BUFFER[writeidx] = arcdata[fidx];
|
|
|
|
|
writeidx++; writeidx %= 4096;
|
|
|
|
|
fidx++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
readidx = arcdata[fidx];
|
|
|
|
|
fidx++;
|
|
|
|
|
readidx |= (ushort)((arcdata[fidx] & 0xF0) << 4);
|
|
|
|
|
for (int j = 0; j < (arcdata[fidx] & 0x0F) + 3; j++)
|
|
|
|
|
{
|
|
|
|
|
outdata.Add(BUFFER[readidx]);
|
|
|
|
|
BUFFER[writeidx] = BUFFER[readidx];
|
|
|
|
|
readidx++; readidx %= 4096;
|
|
|
|
|
writeidx++; writeidx %= 4096;
|
|
|
|
|
}
|
|
|
|
|
fidx++;
|
|
|
|
|
}
|
|
|
|
|
flags8 >>= 1;
|
|
|
|
|
if (fidx >= arcdata.Length) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (decompressedSize != outdata.Count)
|
|
|
|
|
throw new Exception(string.Format("Size mismatch: got {0} bytes after decompression, expected {1}.\n", outdata.Count, decompressedSize));
|
|
|
|
|
|
|
|
|
|
return new MemoryStream(outdata.ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Stream Compress(Stream stream)
|
|
|
|
|
{
|
|
|
|
|
var mem = new MemoryStream();
|
|
|
|
|
return stream;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|