122 lines
3.9 KiB
C#
122 lines
3.9 KiB
C#
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<int> decompressedData = new List<int>();
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|