438 lines
11 KiB
C#
438 lines
11 KiB
C#
using System;
|
|||
|
|
|
||
|
|
namespace Crysome.Common.Compression;
|
||
|
|
|
||
|
|
public static class QuickLZ
|
||
|
|
{
|
||
|
|
public const int QLZ_VERSION_MAJOR = 1;
|
||
|
|
|
||
|
|
public const int QLZ_VERSION_MINOR = 5;
|
||
|
|
|
||
|
|
public const int QLZ_VERSION_REVISION = 0;
|
||
|
|
|
||
|
|
public const int QLZ_STREAMING_BUFFER = 0;
|
||
|
|
|
||
|
|
public const int QLZ_MEMORY_SAFE = 0;
|
||
|
|
|
||
|
|
private const int HASH_VALUES = 4096;
|
||
|
|
|
||
|
|
private const int MINOFFSET = 2;
|
||
|
|
|
||
|
|
private const int UNCONDITIONAL_MATCHLEN = 6;
|
||
|
|
|
||
|
|
private const int UNCOMPRESSED_END = 4;
|
||
|
|
|
||
|
|
private const int CWORD_LEN = 4;
|
||
|
|
|
||
|
|
private const int DEFAULT_HEADERLEN = 9;
|
||
|
|
|
||
|
|
private const int QLZ_POINTERS_1 = 1;
|
||
|
|
|
||
|
|
private const int QLZ_POINTERS_3 = 16;
|
||
|
|
|
||
|
|
private static int HeaderLen(byte[] source)
|
||
|
|
{
|
||
|
|
if ((source[0] & 2) != 2)
|
||
|
|
{
|
||
|
|
return 3;
|
||
|
|
}
|
||
|
|
return 9;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static int SizeDecompressed(byte[] source)
|
||
|
|
{
|
||
|
|
if (HeaderLen(source) == 9)
|
||
|
|
{
|
||
|
|
return source[5] | (source[6] << 8) | (source[7] << 16) | (source[8] << 24);
|
||
|
|
}
|
||
|
|
return source[2];
|
||
|
|
}
|
||
|
|
|
||
|
|
public static int SizeCompressed(byte[] source)
|
||
|
|
{
|
||
|
|
if (HeaderLen(source) == 9)
|
||
|
|
{
|
||
|
|
return source[1] | (source[2] << 8) | (source[3] << 16) | (source[4] << 24);
|
||
|
|
}
|
||
|
|
return source[1];
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void WriteHeader(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed)
|
||
|
|
{
|
||
|
|
dst[0] = (byte)(2u | (compressible ? 1u : 0u));
|
||
|
|
dst[0] |= (byte)(level << 2);
|
||
|
|
dst[0] |= 64;
|
||
|
|
dst[0] |= 0;
|
||
|
|
FastWrite(dst, 1, size_decompressed, 4);
|
||
|
|
FastWrite(dst, 5, size_compressed, 4);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static byte[] Compress(byte[] source, int level)
|
||
|
|
{
|
||
|
|
int i = 0;
|
||
|
|
int num = 13;
|
||
|
|
uint num2 = 2147483648u;
|
||
|
|
int i2 = 9;
|
||
|
|
byte[] array = new byte[source.Length + 400];
|
||
|
|
int[] array2 = new int[4096];
|
||
|
|
byte[] array3 = new byte[4096];
|
||
|
|
int num3 = 0;
|
||
|
|
int num4 = source.Length - 6 - 4 - 1;
|
||
|
|
int num5 = 0;
|
||
|
|
if (level != 1 && level != 3)
|
||
|
|
{
|
||
|
|
throw new ArgumentException("C# version only supports level 1 and 3");
|
||
|
|
}
|
||
|
|
int[,] array4 = ((level != 1) ? new int[4096, 16] : new int[4096, 1]);
|
||
|
|
if (source.Length == 0)
|
||
|
|
{
|
||
|
|
return new byte[0];
|
||
|
|
}
|
||
|
|
if (i <= num4)
|
||
|
|
{
|
||
|
|
num3 = source[i] | (source[i + 1] << 8) | (source[i + 2] << 16);
|
||
|
|
}
|
||
|
|
byte[] array5;
|
||
|
|
while (i <= num4)
|
||
|
|
{
|
||
|
|
if ((num2 & 1) == 1)
|
||
|
|
{
|
||
|
|
if (i > source.Length >> 1 && num > i - (i >> 5))
|
||
|
|
{
|
||
|
|
array5 = new byte[source.Length + 9];
|
||
|
|
WriteHeader(array5, level, compressible: false, source.Length, source.Length + 9);
|
||
|
|
Array.Copy(source, 0, array5, 9, source.Length);
|
||
|
|
return array5;
|
||
|
|
}
|
||
|
|
FastWrite(array, i2, (int)(num2 >> 1) | int.MinValue, 4);
|
||
|
|
i2 = num;
|
||
|
|
num += 4;
|
||
|
|
num2 = 2147483648u;
|
||
|
|
}
|
||
|
|
if (level == 1)
|
||
|
|
{
|
||
|
|
int num6 = ((num3 >> 12) ^ num3) & 0xFFF;
|
||
|
|
int num7 = array4[num6, 0];
|
||
|
|
int num8 = array2[num6] ^ num3;
|
||
|
|
array2[num6] = num3;
|
||
|
|
array4[num6, 0] = i;
|
||
|
|
if (num8 == 0 && array3[num6] != 0 && (i - num7 > 2 || (i == num7 + 1 && num5 >= 3 && i > 3 && source[i] == source[i - 3] && source[i] == source[i - 2] && source[i] == source[i - 1] && source[i] == source[i + 1] && source[i] == source[i + 2])))
|
||
|
|
{
|
||
|
|
num2 = (num2 >> 1) | 0x80000000u;
|
||
|
|
if (source[num7 + 3] != source[i + 3])
|
||
|
|
{
|
||
|
|
int num9 = 1 | (num6 << 4);
|
||
|
|
array[num] = (byte)num9;
|
||
|
|
array[num + 1] = (byte)(num9 >> 8);
|
||
|
|
i += 3;
|
||
|
|
num += 2;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
int num10 = i;
|
||
|
|
int num11 = ((source.Length - 4 - i + 1 - 1 > 255) ? 255 : (source.Length - 4 - i + 1 - 1));
|
||
|
|
i += 4;
|
||
|
|
if (source[num7 + i - num10] == source[i])
|
||
|
|
{
|
||
|
|
i++;
|
||
|
|
if (source[num7 + i - num10] == source[i])
|
||
|
|
{
|
||
|
|
for (i++; source[num7 + (i - num10)] == source[i] && i - num10 < num11; i++)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
int num12 = i - num10;
|
||
|
|
num6 <<= 4;
|
||
|
|
if (num12 < 18)
|
||
|
|
{
|
||
|
|
int num13 = num6 | (num12 - 2);
|
||
|
|
array[num] = (byte)num13;
|
||
|
|
array[num + 1] = (byte)(num13 >> 8);
|
||
|
|
num += 2;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
FastWrite(array, num, num6 | (num12 << 16), 3);
|
||
|
|
num += 3;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
num3 = source[i] | (source[i + 1] << 8) | (source[i + 2] << 16);
|
||
|
|
num5 = 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
num5++;
|
||
|
|
array3[num6] = 1;
|
||
|
|
array[num] = source[i];
|
||
|
|
num2 >>= 1;
|
||
|
|
i++;
|
||
|
|
num++;
|
||
|
|
num3 = ((num3 >> 8) & 0xFFFF) | (source[i + 2] << 16);
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
num3 = source[i] | (source[i + 1] << 8) | (source[i + 2] << 16);
|
||
|
|
int num14 = ((source.Length - 4 - i + 1 - 1 > 255) ? 255 : (source.Length - 4 - i + 1 - 1));
|
||
|
|
int num15 = ((num3 >> 12) ^ num3) & 0xFFF;
|
||
|
|
byte b = array3[num15];
|
||
|
|
int num16 = 0;
|
||
|
|
int num17 = 0;
|
||
|
|
int num18;
|
||
|
|
for (int j = 0; j < 16 && b > j; j++)
|
||
|
|
{
|
||
|
|
num18 = array4[num15, j];
|
||
|
|
if ((byte)num3 == source[num18] && (byte)(num3 >> 8) == source[num18 + 1] && (byte)(num3 >> 16) == source[num18 + 2] && num18 < i - 2)
|
||
|
|
{
|
||
|
|
int k;
|
||
|
|
for (k = 3; source[num18 + k] == source[i + k] && k < num14; k++)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
if (k > num16 || (k == num16 && num18 > num17))
|
||
|
|
{
|
||
|
|
num17 = num18;
|
||
|
|
num16 = k;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
num18 = num17;
|
||
|
|
array4[num15, b & 0xF] = i;
|
||
|
|
b++;
|
||
|
|
array3[num15] = b;
|
||
|
|
if (num16 >= 3 && i - num18 < 131071)
|
||
|
|
{
|
||
|
|
int num19 = i - num18;
|
||
|
|
for (int l = 1; l < num16; l++)
|
||
|
|
{
|
||
|
|
num3 = source[i + l] | (source[i + l + 1] << 8) | (source[i + l + 2] << 16);
|
||
|
|
num15 = ((num3 >> 12) ^ num3) & 0xFFF;
|
||
|
|
array4[num15, array3[num15]++ & 0xF] = i + l;
|
||
|
|
}
|
||
|
|
i += num16;
|
||
|
|
num2 = (num2 >> 1) | 0x80000000u;
|
||
|
|
if (num16 == 3 && num19 <= 63)
|
||
|
|
{
|
||
|
|
FastWrite(array, num, num19 << 2, 1);
|
||
|
|
num++;
|
||
|
|
}
|
||
|
|
else if (num16 == 3 && num19 <= 16383)
|
||
|
|
{
|
||
|
|
FastWrite(array, num, (num19 << 2) | 1, 2);
|
||
|
|
num += 2;
|
||
|
|
}
|
||
|
|
else if (num16 <= 18 && num19 <= 1023)
|
||
|
|
{
|
||
|
|
FastWrite(array, num, (num16 - 3 << 2) | (num19 << 6) | 2, 2);
|
||
|
|
num += 2;
|
||
|
|
}
|
||
|
|
else if (num16 <= 33)
|
||
|
|
{
|
||
|
|
FastWrite(array, num, (num16 - 2 << 2) | (num19 << 7) | 3, 3);
|
||
|
|
num += 3;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
FastWrite(array, num, (num16 - 3 << 7) | (num19 << 15) | 3, 4);
|
||
|
|
num += 4;
|
||
|
|
}
|
||
|
|
num5 = 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
array[num] = source[i];
|
||
|
|
num2 >>= 1;
|
||
|
|
i++;
|
||
|
|
num++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
while (i <= source.Length - 1)
|
||
|
|
{
|
||
|
|
if ((num2 & 1) == 1)
|
||
|
|
{
|
||
|
|
FastWrite(array, i2, (int)(num2 >> 1) | int.MinValue, 4);
|
||
|
|
i2 = num;
|
||
|
|
num += 4;
|
||
|
|
num2 = 2147483648u;
|
||
|
|
}
|
||
|
|
array[num] = source[i];
|
||
|
|
i++;
|
||
|
|
num++;
|
||
|
|
num2 >>= 1;
|
||
|
|
}
|
||
|
|
while ((num2 & 1) != 1)
|
||
|
|
{
|
||
|
|
num2 >>= 1;
|
||
|
|
}
|
||
|
|
FastWrite(array, i2, (int)(num2 >> 1) | int.MinValue, 4);
|
||
|
|
WriteHeader(array, level, compressible: true, source.Length, num);
|
||
|
|
array5 = new byte[num];
|
||
|
|
Array.Copy(array, array5, num);
|
||
|
|
return array5;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void FastWrite(byte[] a, int i, int value, int numbytes)
|
||
|
|
{
|
||
|
|
for (int j = 0; j < numbytes; j++)
|
||
|
|
{
|
||
|
|
a[i + j] = (byte)(value >> j * 8);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public static byte[] Decompress(byte[] source)
|
||
|
|
{
|
||
|
|
int num = SizeDecompressed(source);
|
||
|
|
int num2 = HeaderLen(source);
|
||
|
|
int num3 = 0;
|
||
|
|
uint num4 = 1u;
|
||
|
|
byte[] array = new byte[num];
|
||
|
|
int[] array2 = new int[4096];
|
||
|
|
byte[] array3 = new byte[4096];
|
||
|
|
int num5 = num - 6 - 4 - 1;
|
||
|
|
int num6 = -1;
|
||
|
|
uint num7 = 0u;
|
||
|
|
int num8 = (source[0] >> 2) & 3;
|
||
|
|
if (num8 != 1 && num8 != 3)
|
||
|
|
{
|
||
|
|
throw new ArgumentException("C# version only supports level 1 and 3");
|
||
|
|
}
|
||
|
|
if ((source[0] & 1) != 1)
|
||
|
|
{
|
||
|
|
byte[] array4 = new byte[num];
|
||
|
|
Array.Copy(source, HeaderLen(source), array4, 0, num);
|
||
|
|
return array4;
|
||
|
|
}
|
||
|
|
while (true)
|
||
|
|
{
|
||
|
|
if (num4 == 1)
|
||
|
|
{
|
||
|
|
num4 = (uint)(source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16) | (source[num2 + 3] << 24));
|
||
|
|
num2 += 4;
|
||
|
|
if (num3 <= num5)
|
||
|
|
{
|
||
|
|
num7 = (uint)((num8 != 1) ? (source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16) | (source[num2 + 3] << 24)) : (source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ((num4 & 1) == 1)
|
||
|
|
{
|
||
|
|
num4 >>= 1;
|
||
|
|
uint num10;
|
||
|
|
uint num11;
|
||
|
|
if (num8 == 1)
|
||
|
|
{
|
||
|
|
int num9 = ((int)num7 >> 4) & 0xFFF;
|
||
|
|
num10 = (uint)array2[num9];
|
||
|
|
if ((num7 & 0xF) != 0)
|
||
|
|
{
|
||
|
|
num11 = (num7 & 0xF) + 2;
|
||
|
|
num2 += 2;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
num11 = source[num2 + 2];
|
||
|
|
num2 += 3;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
uint num12;
|
||
|
|
if ((num7 & 3) == 0)
|
||
|
|
{
|
||
|
|
num12 = (num7 & 0xFF) >> 2;
|
||
|
|
num11 = 3u;
|
||
|
|
num2++;
|
||
|
|
}
|
||
|
|
else if ((num7 & 2) == 0)
|
||
|
|
{
|
||
|
|
num12 = (num7 & 0xFFFF) >> 2;
|
||
|
|
num11 = 3u;
|
||
|
|
num2 += 2;
|
||
|
|
}
|
||
|
|
else if ((num7 & 1) == 0)
|
||
|
|
{
|
||
|
|
num12 = (num7 & 0xFFFF) >> 6;
|
||
|
|
num11 = ((num7 >> 2) & 0xF) + 3;
|
||
|
|
num2 += 2;
|
||
|
|
}
|
||
|
|
else if ((num7 & 0x7F) != 3)
|
||
|
|
{
|
||
|
|
num12 = (num7 >> 7) & 0x1FFFF;
|
||
|
|
num11 = ((num7 >> 2) & 0x1F) + 2;
|
||
|
|
num2 += 3;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
num12 = num7 >> 15;
|
||
|
|
num11 = ((num7 >> 7) & 0xFF) + 3;
|
||
|
|
num2 += 4;
|
||
|
|
}
|
||
|
|
num10 = (uint)(num3 - num12);
|
||
|
|
}
|
||
|
|
array[num3] = array[num10];
|
||
|
|
array[num3 + 1] = array[num10 + 1];
|
||
|
|
array[num3 + 2] = array[num10 + 2];
|
||
|
|
for (int i = 3; i < num11; i++)
|
||
|
|
{
|
||
|
|
array[num3 + i] = array[num10 + i];
|
||
|
|
}
|
||
|
|
num3 += (int)num11;
|
||
|
|
if (num8 == 1)
|
||
|
|
{
|
||
|
|
num7 = (uint)(array[num6 + 1] | (array[num6 + 2] << 8) | (array[num6 + 3] << 16));
|
||
|
|
while (num6 < num3 - num11)
|
||
|
|
{
|
||
|
|
num6++;
|
||
|
|
int num9 = (int)(((num7 >> 12) ^ num7) & 0xFFF);
|
||
|
|
array2[num9] = num6;
|
||
|
|
array3[num9] = 1;
|
||
|
|
num7 = (uint)(((num7 >> 8) & 0xFFFF) | (array[num6 + 3] << 16));
|
||
|
|
}
|
||
|
|
num7 = (uint)(source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
num7 = (uint)(source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16) | (source[num2 + 3] << 24));
|
||
|
|
}
|
||
|
|
num6 = num3 - 1;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (num3 > num5)
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
array[num3] = source[num2];
|
||
|
|
num3++;
|
||
|
|
num2++;
|
||
|
|
num4 >>= 1;
|
||
|
|
if (num8 == 1)
|
||
|
|
{
|
||
|
|
while (num6 < num3 - 3)
|
||
|
|
{
|
||
|
|
num6++;
|
||
|
|
int num13 = array[num6] | (array[num6 + 1] << 8) | (array[num6 + 2] << 16);
|
||
|
|
int num9 = ((num13 >> 12) ^ num13) & 0xFFF;
|
||
|
|
array2[num9] = num6;
|
||
|
|
array3[num9] = 1;
|
||
|
|
}
|
||
|
|
num7 = (uint)(((num7 >> 8) & 0xFFFF) | (source[num2 + 2] << 16));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
num7 = (uint)(((num7 >> 8) & 0xFFFF) | (source[num2 + 2] << 16) | (source[num2 + 3] << 24));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
while (num3 <= num - 1)
|
||
|
|
{
|
||
|
|
if (num4 == 1)
|
||
|
|
{
|
||
|
|
num2 += 4;
|
||
|
|
num4 = 2147483648u;
|
||
|
|
}
|
||
|
|
array[num3] = source[num2];
|
||
|
|
num3++;
|
||
|
|
num2++;
|
||
|
|
num4 >>= 1;
|
||
|
|
}
|
||
|
|
return array;
|
||
|
|
}
|
||
|
|
}
|