Implement Decompress function fully.

This commit is contained in:
Li 2023-01-07 18:36:33 -08:00
parent b271d97983
commit b3b07228a9
5 changed files with 59 additions and 76 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
Worms4Editor/obj/* Worms4Editor/obj/*
Worms4Editor/bin/* Worms4Editor/bin/*
LibXom/obj/* LibXom/obj/*
LibXom/bin/* LibXom/bin/*
.vs/*

View File

@ -24,7 +24,7 @@ namespace LibXom.Data
return DecompressInt(BitConverter.ToInt32(buffer)); return DecompressInt(BitConverter.ToInt32(buffer));
} }
public static int[] Decompress(byte[] input) internal static int[] decompressBuffer(byte[] input)
{ {
List<int> decompressedData = new List<int>(); List<int> decompressedData = new List<int>();
@ -48,50 +48,21 @@ namespace LibXom.Data
if (unum <= 0xFFFFFFFF) return 4; if (unum <= 0xFFFFFFFF) return 4;
throw new XomException("Number is too large or too small."); throw new XomException("Number is too large or too small.");
} }
private static int decompressInt16(int compressedInt) private static int pow(int val, int pow)
{ {
int mul = (compressedInt >> 8); return Convert.ToInt32(Math.Pow(val, pow));
int add = (compressedInt & 0xFF);
return (mul * 0x80) + (add % 0x80);
} }
private static int decompressInt24(int compressedInt) // TODO: Write the inverse of this; "CompressInt()"
{
int mul = (compressedInt >> 8) & 0xFF;
int mul2 = (compressedInt >> 16);
int add = (compressedInt & 0xFF);
return ((mul2 * 0x80) * mul) + (add % 0x80);
}
private static int decompressInt32(int compressedInt)
{
int mul = (compressedInt >> 8) & 0xFF;
int mul2 = (compressedInt >> 16) & 0xFF;
int mul3 = (compressedInt >> 24);
int add = (compressedInt & 0xFF);
return (((mul3 * 0x80) * mul2 * 0x80) * mul * 0x80) + (add % 0x80);
}
public static int DecompressInt(int compressedInt) public static int DecompressInt(int compressedInt)
{ {
switch (getNumberByteCount(compressedInt)) int b1 = (compressedInt & 0xFF);
{ int b2 = (compressedInt >> 8) & 0xFF;
case 1: int b3 = (compressedInt >> 16) & 0xFF;
return compressedInt; int b4 = (compressedInt >> 24) & 0xFF;
case 2:
return decompressInt16(compressedInt); return (b4 * pow(0x80, 3)) + ((b3 % 0x80) * pow(0x80, 0x2)) + ((b2 % 0x80) * pow(0x80, 1)) + (b1 % 0x80);
case 3:
return decompressInt24(compressedInt);
case 4:
return decompressInt32(compressedInt);
default:
throw new XomException("Number is too large or too small.");
}
} }
public static int NextCompressedInterger(int compressedInt) public static int NextCompressedInterger(int compressedInt)
{ {
// Some parts of XOM follow a particular pattern, // Some parts of XOM follow a particular pattern,

View File

@ -26,25 +26,40 @@ namespace LibXom.Data
return this.fileBelongs.calculateIdForXomFileComponent(this.uuid, fileBelongs.XomContainers); return this.fileBelongs.calculateIdForXomFileComponent(this.uuid, fileBelongs.XomContainers);
} }
} }
public byte[] Data public byte[] GetData()
{ {
get return data;
}
public void SetData(byte[] data)
{
this.Type.ReplaceContainerData(this, data);
}
private byte[] intArrayToByteArray(int[] intArray)
{
using (MemoryStream ms = new MemoryStream())
{ {
return data; foreach (int i in intArray)
} {
set byte[] buf = BitConverter.GetBytes(i);
{ ms.Write(buf, 0, buf.Length);
this.Type.ReplaceContainerData(this, value); }
ms.Seek(0, SeekOrigin.Begin);
return ms.ToArray();
} }
} }
public int[] Decompress() public int[] Decompress()
{ {
byte[] compressedData = new byte[Data.Length - 3]; byte[] compressedData = new byte[data.Length - 3];
Array.ConstrainedCopy(Data, 3, compressedData, 0, compressedData.Length); Array.ConstrainedCopy(data, 3, compressedData, 0, compressedData.Length);
return XomCompressor.Decompress(compressedData); return XomCompressor.decompressBuffer(compressedData);
} }
public byte[] DecompressToBytes()
{
return intArrayToByteArray(this.Decompress());
}
internal XomContainer(XomFile fromFile, string fromType, byte[] data) internal XomContainer(XomFile fromFile, string fromType, byte[] data)
{ {
fileBelongs = fromFile; fileBelongs = fromFile;

View File

@ -42,12 +42,13 @@ namespace LibXom.Data
return xomContainers.ToArray(); return xomContainers.ToArray();
} }
} }
public XomString GetStringById(int stringId)
{
return XomStrings[stringId];
}
public XomContainer GetContainerById(int containerId) public XomContainer GetContainerById(int containerId)
{ {
foreach(XomContainer container in XomContainers) return XomContainers[containerId];
if (container.Id.Equals(containerId)) return container;
throw new XomContainerNotFoundException("No container with id " + containerId + " was found.");
} }
public XomType GetTypeByName(string typeName) public XomType GetTypeByName(string typeName)
{ {
@ -58,13 +59,10 @@ namespace LibXom.Data
} }
internal int calculateIdForXomFileComponent(string searchUuid, XomFileComponent[] components) internal int calculateIdForXomFileComponent(string searchUuid, XomFileComponent[] components)
{ {
int id = 0; for (int i = 0; i < components.Length; i++)
foreach(XomFileComponent component in components) if (components[i].uuid.Equals(searchUuid, StringComparison.CurrentCultureIgnoreCase)) return i;
{
if (component.uuid.Equals(searchUuid, StringComparison.InvariantCultureIgnoreCase)) return id; throw new XomFileComponentNotFoundException("A XOM Components ID could not be found in the Component List.");
id = XomCompressor.NextCompressedInterger(id);
}
return id;
} }
internal XomFile(XomBlock[] xomBlocks) internal XomFile(XomBlock[] xomBlocks)
{ {

View File

@ -2,6 +2,7 @@
using LibXom.Blocks; using LibXom.Blocks;
using LibXom.Data; using LibXom.Data;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text;
namespace Worms4Editor namespace Worms4Editor
{ {
@ -9,28 +10,25 @@ namespace Worms4Editor
{ {
static void Main(string[] args) static void Main(string[] args)
{ {
Console.WriteLine(XomCompressor.DecompressInt(32767).ToString("X")); /* int id = 0;
Console.WriteLine(XomCompressor.DecompressInt(98432).ToString("X")); for (int i = 0; i < 0x7FFFFF; i++) {
Console.WriteLine(XomCompressor.DecompressInt(98433).ToString("X"));
Console.WriteLine(XomCompressor.DecompressInt(8388607).ToString("X"));
int id = 0;
for (int i = 0; i < 0x9000; i++) {
int d = XomCompressor.DecompressInt(id); int d = XomCompressor.DecompressInt(id);
if (d != i) Console.WriteLine("FAIL; " + i.ToString("X") + " id " + id.ToString("X") + " d " + d.ToString("X")); if (d != i) Console.WriteLine("FAIL; " + i.ToString("X") + " id " + id.ToString("X") + " d " + d.ToString("X"));
else Console.WriteLine("PASS; " + i.ToString("X") + " id " + id.ToString("X") + " d " + d.ToString("X")); else Console.WriteLine("PASS; " + i.ToString("X") + " id " + id.ToString("X") + " d " + d.ToString("X"));
id = XomCompressor.NextCompressedInterger(id); id = XomCompressor.NextCompressedInterger(id);
} } */
XomFile xfile = XomReader.ReadXomFile(@"SaveGame.xom"); XomFile xfile = XomReader.ReadXomFile(@"Original.xom");
XomFile ps2file = XomReader.ReadXomFile(@"ps2.xom"); //XomFile ps2file = XomReader.ReadXomFile(@"ps2.xom");
XomType type = xfile.GetTypeByName("StoredStatsCollective"); XomType type = xfile.GetTypeByName("StoredStatsCollective");
File.WriteAllBytes("StoredStatsCollective.bin", type.Containers.First().Data); XomContainer container = type.Containers.First();
File.WriteAllBytes("StoredStatsCollective.bin", container.DecompressToBytes());
/*foreach(int d in data) for(int i = 0; i < xfile.XomStrings.Length; i++)
{ {
Console.WriteLine(d + ": "+ BitConverter.ToString(ps2file.GetContainerById(d).Data).Replace("-", " ")); XomString str = xfile.XomStrings[i];
}*/ Console.WriteLine(str.Id.ToString("X") + ": " + str.Value);
}
} }
} }
} }