using LibXom.Exceptions; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.Intrinsics; using System.Text; using System.Threading.Tasks; namespace LibXom.Data { public class XomCompressor { internal static int getNumberByteCount(int num) { uint unum = Convert.ToUInt32(num); if (unum <= 0xFF) return 1; if (unum <= 0xFFFF) return 2; if (unum <= 0xFFFFFF) return 3; if (unum <= 0xFFFFFFFF) return 4; throw new XomException("Number is too large or too small."); } public static int ReadCompressedIntFromStream(Stream ms) { byte[] buffer = new byte[4]; for (int i = 0; i < 4; i++) { int b = ms.ReadByte(); buffer[i] = Convert.ToByte(b); if (b > 0x7F) continue; else break; } return DecompressInt(BitConverter.ToInt32(buffer)); } internal static void compressIntAndWriteToStream(Stream s, int uncompressedInt) { int c = XomCompressor.CompressInt(uncompressedInt); int sz = XomCompressor.getNumberByteCount(c); byte[] buffer = BitConverter.GetBytes(c); s.Write(buffer, 0x00, sz); } internal static byte[] compressBuffer(int[] input) { using(MemoryStream ms = new MemoryStream()) { foreach(int enc in input) { compressIntAndWriteToStream(ms, enc); } ms.Seek(0, SeekOrigin.Begin); return ms.ToArray(); } } internal static int[] decompressBuffer(byte[] input) { List decompressedData = new List(); using (MemoryStream inputStream = new MemoryStream(input)) { while (inputStream.Position < inputStream.Length) { int n = ReadCompressedIntFromStream(inputStream); decompressedData.Add(n); } } return decompressedData.ToArray(); } private static int pow(int val, int pow) { return Convert.ToInt32(Math.Pow(val, pow)); } private static int floor(double val) { return Convert.ToInt32(Math.Floor(val)); } private static int minusButNot0(int val, int minus) { int nval = val - minus; if (nval < 0) nval = 0; return nval; } public static int CompressInt(int decompressedInt) { int val = decompressedInt; // Calculate each byte int b4 = floor(val / pow(0x80, 3)); val -= minusButNot0(b4, 1) * pow(0x80, 3); int b3 = floor(val / pow(0x80, 2)); val -= minusButNot0(b3, 1) * pow(0x80, 2); int b2 = floor(val / pow(0x80, 1)); val -= minusButNot0(b2, 1) * pow(0x80, 1); int b1 = val; // rebuild int from bytes int compressedInt = 0; compressedInt = (compressedInt << 8) | b4; compressedInt = (compressedInt << 8) | b3; compressedInt = (compressedInt << 8) | b2; compressedInt = (compressedInt << 8) | b1; return compressedInt; } public static int DecompressInt(int compressedInt) { // Extract each byte from the int int b1 = (compressedInt >> 0) & 0xFF; int b2 = (compressedInt >> 8) & 0xFF; int b3 = (compressedInt >> 16) & 0xFF; int b4 = (compressedInt >> 24) & 0xFF; // calculate full number from bytes return (b4 * pow(0x80, 3)) + ((b3 % 0x80) * pow(0x80, 0x2)) + ((b2 % 0x80) * pow(0x80, 0x1)) + (b1 % 0x80); } } }