207 lines
5.8 KiB
C#
207 lines
5.8 KiB
C#
using LibXom.Blocks;
|
|
using LibXom.Data;
|
|
using System.Text;
|
|
|
|
namespace LibXom
|
|
{
|
|
public class XomReader
|
|
{
|
|
private Stream xomStream;
|
|
private byte[] readBytes(int amt)
|
|
{
|
|
byte[] buffer = new byte[amt];
|
|
xomStream.Read(buffer, 0, amt);
|
|
return buffer;
|
|
}
|
|
private byte readByte()
|
|
{
|
|
return Convert.ToByte(xomStream.ReadByte());
|
|
}
|
|
private string readStrLen(int len)
|
|
{
|
|
byte[] buf = readBytes(len);
|
|
|
|
int rlen = 0;
|
|
for (rlen = 0; rlen < len; rlen++)
|
|
if (buf[rlen] == 0) break;
|
|
|
|
return Encoding.UTF8.GetString(buf, 0, rlen);
|
|
}
|
|
private string readCStr()
|
|
{
|
|
StringBuilder cstr = new StringBuilder();
|
|
|
|
while (true)
|
|
{
|
|
char c = (char)readByte();
|
|
if (c == 0) break;
|
|
cstr.Append(c);
|
|
}
|
|
|
|
return cstr.ToString();
|
|
}
|
|
private int readInt32BE()
|
|
{
|
|
byte[] buffer = readBytes(0x4);
|
|
buffer.Reverse();
|
|
return BitConverter.ToInt32(buffer);
|
|
}
|
|
private void skip(int amt)
|
|
{
|
|
xomStream.Seek(amt, SeekOrigin.Current);
|
|
}
|
|
private int readInt32()
|
|
{
|
|
return BitConverter.ToInt32(readBytes(0x4));
|
|
}
|
|
|
|
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>();
|
|
while (xomStream.Position < xomStream.Length)
|
|
{
|
|
buffer.Add(readByte());
|
|
if (bufferEndsWith(buffer, Encoding.UTF8.GetBytes("CTNR")))
|
|
{
|
|
skip(-4);
|
|
int i = buffer.Count - 1;
|
|
int endAt = i - 4;
|
|
for (; i != endAt; i--)
|
|
buffer.RemoveAt(i);
|
|
return new CtnrBlock(buffer.ToArray());
|
|
}
|
|
}
|
|
return new CtnrBlock(buffer.ToArray());
|
|
}
|
|
|
|
public MoikBlock readMoik()
|
|
{
|
|
int version = readInt32BE();
|
|
skip(0x10);
|
|
int numTypes = readInt32();
|
|
int numCtnr = readInt32();
|
|
int numCtnr2 = readInt32();
|
|
skip(0x1C);
|
|
return new MoikBlock(version, numCtnr, numTypes);
|
|
}
|
|
public TypeBlock readType()
|
|
{
|
|
skip(0x4);
|
|
int numCtnr = readInt32();
|
|
skip(0x4);
|
|
byte[] md5 = readBytes(0x10);
|
|
string typeName = readStrLen(0x20);
|
|
return new TypeBlock(numCtnr, md5, typeName);
|
|
}
|
|
public SchmBlock readSchm()
|
|
{
|
|
int unk0 = readInt32();
|
|
int unk1 = readInt32();
|
|
int unk2 = readInt32();
|
|
return new SchmBlock(unk0, unk1, unk2);
|
|
}
|
|
public GuidBlock readGuid()
|
|
{
|
|
int unk0 = readInt32();
|
|
int unk1 = readInt32();
|
|
int unk2 = readInt32();
|
|
return new GuidBlock(unk0, unk1, unk2);
|
|
}
|
|
public StrsBlock readStrs()
|
|
{
|
|
int numStrs = readInt32();
|
|
int strsSz = readInt32();
|
|
|
|
int[] offsets = new int[numStrs];
|
|
string[] strings = new string[numStrs];
|
|
|
|
for (int i = 0; i < numStrs; i++)
|
|
{
|
|
offsets[i] = readInt32();
|
|
}
|
|
for (int i = 0; i < numStrs; i++)
|
|
{
|
|
strings[i] = readCStr();
|
|
}
|
|
return new StrsBlock(numStrs, strsSz, offsets, strings); ;
|
|
}
|
|
public XomBlock? readBlock()
|
|
{
|
|
string hdr = readStrLen(0x4);
|
|
|
|
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>();
|
|
while (xomStream.Position < xomStream.Length)
|
|
{
|
|
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)
|
|
{
|
|
this.xomStream = xom;
|
|
}
|
|
}
|
|
}
|