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; } }