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 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 buffer = new List(); 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 xomBlocks = new List(); 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); } } }