using System; using System.Collections.Generic; using System.Diagnostics; using General; using System.IO; using System.Text; using System.Xml; namespace CXML { enum AttributeType { TYPE_NONE, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_CHAR, TYPE_STYLE_ID, TYPE_INTEGER_ARRAY, TYPE_FLOAT_ARRAY, TYPE_FILE, TYPE_ID_STRING_LOOPBACK, TYPE_ID_STRING, TYPE_ID_INT_LOOPBACK, TYPE_ID_INT }; class CXMLParser { private static bool _checkMagicNumber() { String Magic = Tools.ReadStringAt(InfoFile, 0x00); if (Magic.StartsWith("PSMA")) { return true; } else if(Magic.StartsWith("RCOF")) { return true; } else if (Magic.StartsWith("RCSF")) { return true; } else { return false; } } private static string _lastFileName = ""; static String MainDir = ""; static String FileDir = ""; static String XMLFilename = ""; static FileStream InfoFile; static MemoryStream TreeTable; static MemoryStream StringIDTable; static MemoryStream IntIDTable; static MemoryStream StringTable; static MemoryStream CharTable; static MemoryStream StylesIDTable; static MemoryStream IntArrayTable; static MemoryStream FloatArrayTable; static MemoryStream FileTable; static BinaryReader bTreeTable; static BinaryReader bIntIDTable; static BinaryReader bFloatArrayTable; static BinaryReader bIntArrayTable; static BinaryReader bStylesIDTable; static BinaryReader bStringIDTable; static XmlWriter XMLFile; public static void Init(string path, bool CheckMagic = true, string outputDir = "") { InfoFile = File.Open(path, FileMode.Open, FileAccess.Read); if(CheckMagic) { if (!_checkMagicNumber()) { throw new Exception("Incorrect magic number."); } } TreeTable = Tools.ByteToStream(GetTreeTable()); StringIDTable = Tools.ByteToStream(GetStringIDTable()); IntIDTable = Tools.ByteToStream(GetIntIDTable()); StringTable = Tools.ByteToStream(GetStringTable()); CharTable = Tools.ByteToStream(GetCharTable()); StylesIDTable = Tools.ByteToStream(GetStyleIDTable()); IntArrayTable = Tools.ByteToStream(GetIntArrayTable()); FloatArrayTable = Tools.ByteToStream(GetFloatArrayTable()); FileTable = Tools.ByteToStream(GetFileTable()); bTreeTable = new BinaryReader(TreeTable); bIntIDTable = new BinaryReader(IntIDTable); bFloatArrayTable = new BinaryReader(FloatArrayTable); bIntArrayTable = new BinaryReader(IntArrayTable); bStylesIDTable = new BinaryReader(StylesIDTable); bStringIDTable = new BinaryReader(StringIDTable); MainDir = outputDir + Path.GetFileNameWithoutExtension(path); FileDir = Path.Combine(MainDir, "files"); XMLFilename = Path.GetFileNameWithoutExtension(path) + ".xml"; try { if (Directory.Exists(MainDir)) Directory.Delete(MainDir, true); if (!Directory.Exists(FileDir)) Directory.CreateDirectory(FileDir); } catch (Exception) { }; } public static void Term() { InfoFile.Close(); TreeTable.Close(); StringIDTable.Close(); IntIDTable.Close(); StringTable.Close(); CharTable.Close(); StylesIDTable.Close(); IntArrayTable.Close(); FloatArrayTable.Close(); FileTable.Close(); bTreeTable.Close(); bIntIDTable.Close(); bFloatArrayTable.Close(); bIntArrayTable.Close(); bStylesIDTable.Close(); } public static int GetTreeTableOffset() { return Tools.ReadIntAt(InfoFile,0x8); } public static int GetTreeTableSize() { return Tools.ReadIntAt(InfoFile, 0xC); } public static int GetIDStringTableOffset() { return Tools.ReadIntAt(InfoFile, 0x10); } public static int GetIDStringTableSize() { return Tools.ReadIntAt(InfoFile, 0x14); } public static int GetIDIntTableOffset() { return Tools.ReadIntAt(InfoFile, 0x18); } public static int GetIDIntTableSize() { return Tools.ReadIntAt(InfoFile, 0x1C); } public static int GetStringTableOffset() { return Tools.ReadIntAt(InfoFile, 0x20); } public static int GetStringTableSize() { return Tools.ReadIntAt(InfoFile, 0x24); } public static int GetCharTableOffset() { return Tools.ReadIntAt(InfoFile, 0x28); } public static int GetCharTableSize() { return Tools.ReadIntAt(InfoFile, 0x2C); } public static int GetStyleIDTableOffset() { return Tools.ReadIntAt(InfoFile, 0x30); } public static int GetStyleIDTableSize() { return Tools.ReadIntAt(InfoFile, 0x34); } public static int GetIntArrayTableOffset() { return Tools.ReadIntAt(InfoFile, 0x38); } public static int GetIntArrayTableSize() { return Tools.ReadIntAt(InfoFile, 0x3C); } public static int GetFloatArrayTableOffset() { return Tools.ReadIntAt(InfoFile, 0x40); } public static int GetFloatArrayTableSize() { return Tools.ReadIntAt(InfoFile, 0x44); } public static int GetFileTableOffset() { return Tools.ReadIntAt(InfoFile, 0x48); } public static int GetFileTableSize() { return Tools.ReadIntAt(InfoFile, 0x4C); } public static byte[] GetTreeTable() { int TableOffset = GetTreeTableOffset(); int TableSize = GetTreeTableSize(); InfoFile.Seek(TableOffset, SeekOrigin.Begin); byte[] Table = new byte[TableSize]; InfoFile.Read(Table, 0x00, TableSize); return Table; } public static byte[] GetStringIDTable() { int IDStrTableOffset = GetIDStringTableOffset(); int IDStrTableSize = GetIDStringTableSize(); InfoFile.Seek(IDStrTableOffset, SeekOrigin.Begin); byte[] IDStringTable = new byte[IDStrTableSize]; InfoFile.Read(IDStringTable, 0x00, IDStrTableSize); return IDStringTable; } public static byte[] GetIntIDTable() { int IDIntTableOffset = GetIDIntTableOffset(); int IDIntTableSize = GetIDIntTableSize(); InfoFile.Seek(IDIntTableOffset, SeekOrigin.Begin); byte[] IDIntTable = new byte[IDIntTableSize]; InfoFile.Read(IDIntTable, 0x00, IDIntTableSize); return IDIntTable; } public static byte[] GetStringTable() { int StringTableOffset = GetStringTableOffset(); int StringTableSize = GetStringTableSize(); InfoFile.Seek(StringTableOffset, SeekOrigin.Begin); byte[] StringTable = new byte[StringTableSize]; InfoFile.Read(StringTable, 0x00, StringTableSize); return StringTable; } public static byte[] GetCharTable() { int CharTableOffset = GetCharTableOffset(); int CharTableSize = GetCharTableSize(); InfoFile.Seek(CharTableOffset, SeekOrigin.Begin); byte[] CharTable = new byte[CharTableSize]; InfoFile.Read(CharTable, 0x00, CharTableSize); return CharTable; } public static byte[] GetStyleIDTable() { int StyleIDTableOffset = GetStyleIDTableOffset(); int StyleIDTableSize = GetStyleIDTableSize(); InfoFile.Seek(StyleIDTableOffset, SeekOrigin.Begin); byte[] StyleIDTable = new byte[StyleIDTableSize]; InfoFile.Read(StyleIDTable, 0x00, StyleIDTableSize); return StyleIDTable; } public static byte[] GetIntArrayTable() { int IntArrayTableOffset = GetIntArrayTableOffset(); int IntArrayTableSize = GetIntArrayTableSize(); InfoFile.Seek(IntArrayTableOffset, SeekOrigin.Begin); byte[] IntArrayTable = new byte[IntArrayTableSize]; InfoFile.Read(IntArrayTable, 0x00, IntArrayTableSize); return IntArrayTable; } public static byte[] GetFloatArrayTable() { int FloatArrayTableOffset = GetFloatArrayTableOffset(); int FloatArrayTableSize = GetFloatArrayTableSize(); InfoFile.Seek(FloatArrayTableOffset, SeekOrigin.Begin); byte[] FloatArrayTable = new byte[FloatArrayTableSize]; InfoFile.Read(FloatArrayTable, 0x00, FloatArrayTableSize); return FloatArrayTable; } public static byte[] GetFileTable() { int DataOffset = GetFileTableOffset(); int DataLength = GetFileTableSize(); InfoFile.Seek(DataOffset, SeekOrigin.Begin); byte[] FileTable = new byte[DataLength]; InfoFile.Read(FileTable, 0x00, DataLength); return FileTable; } public static void DecompileCXML(String CXMLFile, bool force = false, String outputDir = "") { try { Term(); } catch (Exception) { }; Init(CXMLFile,force,outputDir); Directory.CreateDirectory(MainDir); XmlWriterSettings XMLSettings = new XmlWriterSettings(); XMLSettings.Indent = true; XMLFile = XmlWriter.Create(Path.Combine(MainDir, XMLFilename), XMLSettings); XMLFile.WriteStartDocument(); ReadElements(); XMLFile.WriteEndDocument(); XMLFile.Flush(); XMLFile.Close(); Term(); } public static void ReadAttribute(String ElementName = "") { int AttributePtr = bTreeTable.ReadInt32(); AttributeType Type = (AttributeType)bTreeTable.ReadInt32(); String AttributeName = Tools.ReadStringAt(StringTable, AttributePtr); object AttributeValue = ""; Console.WriteLine("AttributeType: " + Type.ToString() + " - "+ TreeTable.Position.ToString()); switch (Type) { case AttributeType.TYPE_NONE: Console.WriteLine("UNSUPPORTED TYPE @ " + TreeTable.Position); Console.ReadKey(); break; case AttributeType.TYPE_INT: AttributeValue = bTreeTable.ReadInt32(); TreeTable.Seek(4, SeekOrigin.Current); break; case AttributeType.TYPE_FLOAT: float FloatValue = bTreeTable.ReadSingle(); AttributeValue = Tools.RemoveDecimals(FloatValue); TreeTable.Seek(4, SeekOrigin.Current); break; case AttributeType.TYPE_STRING: int StringOffset = bTreeTable.ReadInt32(); int StringLen = bTreeTable.ReadInt32(); byte[] StringBytes = new byte[StringLen]; StringTable.Seek(StringOffset, 0x00); StringTable.Read(StringBytes, 0x00, StringLen); AttributeValue = Encoding.UTF8.GetString(StringBytes); break; case AttributeType.TYPE_CHAR: int CharOffset = bTreeTable.ReadInt32() * 2; int CharLen = bTreeTable.ReadInt32(); byte[] CharBytes = new byte[CharLen]; CharTable.Seek(CharOffset, 0x00); CharTable.Read(CharBytes, 0x00, CharLen); AttributeValue = Encoding.Unicode.GetString(CharBytes); break; case AttributeType.TYPE_STYLE_ID: int StyleTableOffset = bTreeTable.ReadInt32(); int StyleTableSize = bTreeTable.ReadInt32(); byte[] StyleTableData = new byte[StyleTableSize]; StylesIDTable.Seek(StyleTableOffset, SeekOrigin.Begin); StylesIDTable.Read(StyleTableData, 0x00, StyleTableSize); AttributeValue = BitConverter.ToString(StyleTableData).Replace("-",""); break; case AttributeType.TYPE_INTEGER_ARRAY: int IntArrayOffset = bTreeTable.ReadInt32(); int IntArraySize = bTreeTable.ReadInt32(); IntArrayTable.Seek(IntArrayOffset, SeekOrigin.Begin); List IntList = new List(); for (int i = 0; i < IntArraySize; i++) { int IntValue = bIntArrayTable.ReadInt32(); IntList.Add(IntValue); } int[] IntArray = IntList.ToArray(); AttributeValue = String.Join(", ", IntArray); break; case AttributeType.TYPE_FLOAT_ARRAY: int FloatArrayOffset = bTreeTable.ReadInt32(); int FloatArraySize = bTreeTable.ReadInt32(); FloatArrayTable.Seek(FloatArrayOffset, SeekOrigin.Begin); List StrList = new List(); for(int i = 0; i < FloatArraySize; i++) { FloatValue = bFloatArrayTable.ReadSingle(); StrList.Add(Tools.RemoveDecimals(FloatValue)); } string[] StrArray = StrList.ToArray(); AttributeValue = String.Join(", ", StrArray); break; case AttributeType.TYPE_FILE: int FilePtr = bTreeTable.ReadInt32(); int FileSz = bTreeTable.ReadInt32(); String FileName = ""; Byte[] FileData = new Byte[FileSz]; FileTable.Seek(FilePtr, SeekOrigin.Begin); FileTable.Read(FileData, 0, FileSz); int count = 0; string CounterStr = count.ToString(); do { String Extension = Tools.GetFileExtension(FileData); CounterStr = count.ToString(); if (count == 0) CounterStr = ""; FileName = Path.Combine(FileDir , ElementName , AttributeName + CounterStr + Extension); count++; } while (File.Exists(FileName)); Console.WriteLine("Writing: " + FileName); if (!Directory.Exists(Path.GetDirectoryName(FileName))) Directory.CreateDirectory(Path.GetDirectoryName(FileName)); File.WriteAllBytes(FileName, FileData); AttributeValue = FileName; break; case AttributeType.TYPE_ID_STRING_LOOPBACK: int StringIdTableOffset = bTreeTable.ReadInt32(); StringIDTable.Seek(StringIdTableOffset, SeekOrigin.Begin); int LoopbackPtr = bStringIDTable.ReadInt32(); int StringPtr = Tools.ReadIntAt(TreeTable, LoopbackPtr); string LoopbackAttribute = Tools.ReadStringAt(StringTable, StringPtr); Console.WriteLine("Loopback: " + LoopbackAttribute); AttributeValue = Tools.ReadString(StringIDTable); TreeTable.Seek(4, SeekOrigin.Current); break; case AttributeType.TYPE_ID_STRING: Console.WriteLine("UNSUPPORTED TYPE @ " + TreeTable.Position); Console.ReadKey(); break; case AttributeType.TYPE_ID_INT_LOOPBACK: int IntIdTableOffset = bTreeTable.ReadInt32(); IntIDTable.Seek(IntIdTableOffset, SeekOrigin.Begin); LoopbackPtr = bIntIDTable.ReadInt32(); StringPtr = Tools.ReadIntAt(TreeTable, LoopbackPtr); int IDValue = bIntIDTable.ReadInt32(); LoopbackAttribute = Tools.ReadStringAt(StringTable, StringPtr); Console.WriteLine("Loopback: " + LoopbackAttribute); AttributeValue = IDValue.ToString("X8"); TreeTable.Seek(4, SeekOrigin.Current); break; case AttributeType.TYPE_ID_INT: IntIdTableOffset = bTreeTable.ReadInt32(); IntIDTable.Seek(IntIdTableOffset + 4, SeekOrigin.Begin); IDValue = bIntIDTable.ReadInt32(); AttributeValue = IDValue.ToString("X8"); TreeTable.Seek(4, SeekOrigin.Current); break; default: Console.WriteLine("UNKNOWN TYPE @ " + TreeTable.Position); break; }; Console.WriteLine(AttributeName + "=" + AttributeValue.ToString()); XMLFile.WriteAttributeString(AttributeName, AttributeValue.ToString()); XMLFile.Flush(); } public static void ReadElements() { int ElementPtr = bTreeTable.ReadInt32(); int NumAttributes = bTreeTable.ReadInt32(); int ParentPtr = bTreeTable.ReadInt32(); int PrevSibling = bTreeTable.ReadInt32(); int NextSibling = bTreeTable.ReadInt32(); int FirstChild = bTreeTable.ReadInt32(); int LastChild = bTreeTable.ReadInt32(); String ElementName = Tools.ReadStringAt(StringTable, ElementPtr); Console.WriteLine("Creating Element: " + ElementName); Console.WriteLine("Attribute Count: " + NumAttributes); Console.WriteLine("ParentPtr: " + ParentPtr); Console.WriteLine("PrevSibling: " + PrevSibling); Console.WriteLine("NextSibling: " + NextSibling); Console.WriteLine("FirstChild: " + FirstChild); Console.WriteLine("LastChild: " + LastChild); XMLFile.WriteStartElement(ElementName); if(NumAttributes > 0) { for (int i = 0; i < NumAttributes; i++) { ReadAttribute(ElementName); } } if (FirstChild != -1) { TreeTable.Seek(FirstChild, SeekOrigin.Begin); ReadElements(); } XMLFile.WriteEndElement(); XMLFile.Flush(); if (NextSibling != -1) { TreeTable.Seek(NextSibling, SeekOrigin.Begin); ReadElements(); } } } }