Worms4Editor/LibXom/XomReader.cs

166 lines
5.1 KiB
C#

using LibXom.Blocks;
using LibXom.Data;
using LibXom.Streams;
using System.IO;
using System.Text;
namespace LibXom
{
public class XomReader
{
private XomStreamReader xomStream;
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.BaseStream.Position < xomStream.BaseStream.Length)
{
buffer.Add(xomStream.ReadByte());
if (bufferEndsWith(buffer, Encoding.UTF8.GetBytes("CTNR")))
{
xomStream.Skip(-4);
int i = buffer.Count - 1;
int endAt = i - 4;
for (; i != endAt; i--)
buffer.RemoveAt(i);
return new CtnrBlock(buffer.ToArray());
}
}
// remove last 2 for EOF
buffer.RemoveAt(buffer.Count-1);
buffer.RemoveAt(buffer.Count-1);
return new CtnrBlock(buffer.ToArray());
}
public MoikBlock readMoik()
{
int version = xomStream.ReadInt32BE();
xomStream.Skip(0x10);
int numTypes = xomStream.ReadInt32();
int numCtnr = xomStream.ReadInt32();
int numCtnr2 = xomStream.ReadInt32();
xomStream.Skip(0x1C);
return new MoikBlock(version, numCtnr, numTypes);
}
public TypeBlock readType()
{
xomStream.Skip(0x4);
int numCtnr = xomStream.ReadInt32();
xomStream.Skip(0x4);
byte[] md5 = xomStream.ReadBytes(0x10);
string typeName = xomStream.ReadStrLen(0x20);
return new TypeBlock(numCtnr, md5, typeName);
}
public SchmBlock readSchm()
{
int unk0 = xomStream.ReadInt32();
int unk1 = xomStream.ReadInt32();
int unk2 = xomStream.ReadInt32();
return new SchmBlock(unk0, unk1, unk2);
}
public GuidBlock readGuid()
{
int unk0 = xomStream.ReadInt32();
int unk1 = xomStream.ReadInt32();
int unk2 = xomStream.ReadInt32();
return new GuidBlock(unk0, unk1, unk2);
}
public StrsBlock readStrs()
{
int numStrs = xomStream.ReadInt32();
int strsSz = xomStream.ReadInt32();
int[] offsets = new int[numStrs];
string[] strings = new string[numStrs];
for (int i = 0; i < numStrs; i++)
{
offsets[i] = xomStream.ReadInt32();
}
for (int i = 0; i < numStrs; i++)
{
strings[i] = xomStream.ReadCStr();
}
return new StrsBlock(numStrs, strsSz, offsets, strings);
}
public XomBlock? readBlock()
{
string hdr = xomStream.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.BaseStream.Position < xomStream.BaseStream.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 = new XomStreamReader(xom);
}
}
}