Worms4Editor/LibXom/XomReader.cs

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;
}
}
}