Medusa.net/Medusa.Core/Utils/LZ77.cs

97 lines
2.9 KiB
C#

namespace Medusa.Core.Utils
{
public class LZ77
{
public static byte[] Decompress(byte[] data)
{
// init a buffer, size comes from eamuemu
byte[] res = new byte[0x190000];
// current data location
int p = 0;
// current output location
int r = 0;
// traceback location
int t = 0;
// bitmask location
int b = 8; // read next bitmask byte on start
byte mask = 0;
while(true)
{
// read bitmask on block end
if(b == 8)
{
mask = data[p];
p += 1;
b = 0;
}
// get mask for next byte
if((mask & 1) == 1)
{ // not coded
// copy the byte from data to result
res[r] = data[p];
r += 1;
p += 1;
}
else
{ // coded
// read descriptors
int distance = data[p];
int count = data[p + 1];
// EOF mark
if(distance == 0 && count == 0)
{
break;
}
p += 2;
// shift to correct location
distance <<= 4;
distance |= count >> 4;
count = (count & 0x0F) + 3;
// copy earlier result bytes to the end
t = r - distance; // initialize traceback location
for(int i = 0; i < count; i++)
{
res[r] = t < 0 ? (byte)0x00 : res[t];
r += 1;
t += 1;
}
}
// shift mask
mask >>= 1;
b += 1;
}
// r = result length
byte[] output = new byte[r];
Array.Copy(res, output, r);
return output;
}
public static byte[] CompressEmpty(byte[] data)
{
byte[] res = new byte[data.Length + data.Length / 8 + 3];
int p = 0;
for(int i = 0; i < data.Length; i++)
{
if(i % 8 == 0)
{
if(data.Length - i < 8)
{
res[p] = (byte)(Math.Pow(2, data.Length - i) - 1);
}
else
{
res[p] = 255;
}
p += 1;
}
res[p] = data[i];
p += 1;
}
res[p] = 0;
res[p + 1] = 0;
return res;
}
}
}