2023-01-07 09:36:13 +00:00
|
|
|
|
using LibXom.Blocks;
|
|
|
|
|
using LibXom.Data;
|
2023-01-09 13:18:25 +00:00
|
|
|
|
using LibXom.Streams;
|
|
|
|
|
using System.IO;
|
2023-01-07 09:36:13 +00:00
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace LibXom
|
|
|
|
|
{
|
|
|
|
|
public class XomReader
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
private XomStreamReader xomStream;
|
2023-01-07 09:36:13 +00:00
|
|
|
|
public bool bufferEndsWith(List<byte> buffer, byte[] search)
|
|
|
|
|
{
|
|
|
|
|
int len = search.Length;
|
|
|
|
|
|
|
|
|
|
if (buffer.Count < len) return false;
|
|
|
|
|
|
|
|
|
|
byte[] lastSection = new byte[len];
|
|
|
|
|
|
|
|
|
|
int ii = 0;
|
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
int pos = (buffer.Count - len) + i;
|
|
|
|
|
lastSection[ii] = buffer[pos];
|
|
|
|
|
ii++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lastSection.SequenceEqual(search))
|
|
|
|
|
return true;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
public CtnrBlock readCtnr()
|
|
|
|
|
{
|
|
|
|
|
List<byte> buffer = new List<byte>();
|
2023-01-09 13:18:25 +00:00
|
|
|
|
while (xomStream.BaseStream.Position < xomStream.BaseStream.Length)
|
2023-01-07 09:36:13 +00:00
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
buffer.Add(xomStream.ReadByte());
|
2023-01-07 09:36:13 +00:00
|
|
|
|
if (bufferEndsWith(buffer, Encoding.UTF8.GetBytes("CTNR")))
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
xomStream.Skip(-4);
|
2023-01-07 09:36:13 +00:00
|
|
|
|
int i = buffer.Count - 1;
|
|
|
|
|
int endAt = i - 4;
|
|
|
|
|
for (; i != endAt; i--)
|
|
|
|
|
buffer.RemoveAt(i);
|
|
|
|
|
return new CtnrBlock(buffer.ToArray());
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-23 09:43:15 +00:00
|
|
|
|
|
|
|
|
|
// remove last 2 for EOF
|
|
|
|
|
buffer.RemoveAt(buffer.Count-1);
|
|
|
|
|
buffer.RemoveAt(buffer.Count-1);
|
|
|
|
|
|
2023-01-07 09:36:13 +00:00
|
|
|
|
return new CtnrBlock(buffer.ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MoikBlock readMoik()
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
int version = xomStream.ReadInt32BE();
|
|
|
|
|
xomStream.Skip(0x10);
|
|
|
|
|
int numTypes = xomStream.ReadInt32();
|
|
|
|
|
int numCtnr = xomStream.ReadInt32();
|
|
|
|
|
int numCtnr2 = xomStream.ReadInt32();
|
|
|
|
|
xomStream.Skip(0x1C);
|
2023-01-07 09:36:13 +00:00
|
|
|
|
return new MoikBlock(version, numCtnr, numTypes);
|
|
|
|
|
}
|
|
|
|
|
public TypeBlock readType()
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
xomStream.Skip(0x4);
|
|
|
|
|
int numCtnr = xomStream.ReadInt32();
|
|
|
|
|
xomStream.Skip(0x4);
|
|
|
|
|
byte[] md5 = xomStream.ReadBytes(0x10);
|
|
|
|
|
string typeName = xomStream.ReadStrLen(0x20);
|
2023-01-07 09:36:13 +00:00
|
|
|
|
return new TypeBlock(numCtnr, md5, typeName);
|
|
|
|
|
}
|
|
|
|
|
public SchmBlock readSchm()
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
int unk0 = xomStream.ReadInt32();
|
|
|
|
|
int unk1 = xomStream.ReadInt32();
|
|
|
|
|
int unk2 = xomStream.ReadInt32();
|
2023-01-07 09:36:13 +00:00
|
|
|
|
return new SchmBlock(unk0, unk1, unk2);
|
|
|
|
|
}
|
|
|
|
|
public GuidBlock readGuid()
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
int unk0 = xomStream.ReadInt32();
|
|
|
|
|
int unk1 = xomStream.ReadInt32();
|
|
|
|
|
int unk2 = xomStream.ReadInt32();
|
2023-01-07 09:36:13 +00:00
|
|
|
|
return new GuidBlock(unk0, unk1, unk2);
|
|
|
|
|
}
|
|
|
|
|
public StrsBlock readStrs()
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
int numStrs = xomStream.ReadInt32();
|
|
|
|
|
int strsSz = xomStream.ReadInt32();
|
2023-01-07 09:36:13 +00:00
|
|
|
|
|
|
|
|
|
int[] offsets = new int[numStrs];
|
|
|
|
|
string[] strings = new string[numStrs];
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numStrs; i++)
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
offsets[i] = xomStream.ReadInt32();
|
2023-01-07 09:36:13 +00:00
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < numStrs; i++)
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
strings[i] = xomStream.ReadCStr();
|
2023-01-07 09:36:13 +00:00
|
|
|
|
}
|
2023-01-11 09:22:45 +00:00
|
|
|
|
return new StrsBlock(numStrs, strsSz, offsets, strings);
|
2023-01-07 09:36:13 +00:00
|
|
|
|
}
|
|
|
|
|
public XomBlock? readBlock()
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
string hdr = xomStream.ReadStrLen(0x4);
|
2023-01-07 09:36:13 +00:00
|
|
|
|
|
|
|
|
|
switch (hdr)
|
|
|
|
|
{
|
|
|
|
|
case "MOIK":
|
|
|
|
|
return readMoik();
|
|
|
|
|
case "TYPE":
|
|
|
|
|
return readType();
|
|
|
|
|
case "SCHM":
|
|
|
|
|
return readSchm();
|
|
|
|
|
case "GUID":
|
|
|
|
|
return readGuid();
|
|
|
|
|
case "STRS":
|
|
|
|
|
return readStrs();
|
|
|
|
|
case "CTNR":
|
|
|
|
|
return readCtnr();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
private XomBlock[] readAllBlocks()
|
|
|
|
|
{
|
|
|
|
|
List<XomBlock> xomBlocks = new List<XomBlock>();
|
2023-01-09 13:18:25 +00:00
|
|
|
|
while (xomStream.BaseStream.Position < xomStream.BaseStream.Length)
|
2023-01-07 09:36:13 +00:00
|
|
|
|
{
|
|
|
|
|
XomBlock? block = readBlock();
|
|
|
|
|
if (block == null) break;
|
|
|
|
|
xomBlocks.Add(block);
|
|
|
|
|
}
|
|
|
|
|
return xomBlocks.ToArray();
|
|
|
|
|
}
|
|
|
|
|
public static XomFile ReadXomFile(string xomFilename)
|
|
|
|
|
{
|
|
|
|
|
using(MemoryStream ms = new MemoryStream())
|
|
|
|
|
{
|
|
|
|
|
using(FileStream fs = File.OpenRead(xomFilename))
|
|
|
|
|
fs.CopyTo(ms);
|
|
|
|
|
|
|
|
|
|
ms.Seek(0, SeekOrigin.Begin);
|
|
|
|
|
return ReadXomFile(ms);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public static XomFile ReadXomFile(Stream xomStream)
|
|
|
|
|
{
|
|
|
|
|
XomReader reader = new XomReader(xomStream);
|
|
|
|
|
// Read all blocks
|
|
|
|
|
XomBlock[] xomBlocks = reader.readAllBlocks();
|
|
|
|
|
// Create the file object
|
|
|
|
|
return new XomFile(xomBlocks);
|
|
|
|
|
}
|
|
|
|
|
internal XomReader(Stream xom)
|
|
|
|
|
{
|
2023-01-09 13:18:25 +00:00
|
|
|
|
this.xomStream = new XomStreamReader(xom);
|
2023-01-07 09:36:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|