using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Text; using System.Xml; namespace AppInfo { class Types { public static int TYPE_STRING = 3; public static int TYPE_FLOAT = 2; public static int TYPE_INT = 1; public static int TYPE_FILE = 8; } class Tools { public static MemoryStream ByteToStream(byte[] Array) { MemoryStream ms = new MemoryStream(); ms.Write(Array, 0x00, Array.Length); ms.Seek(0, SeekOrigin.Begin); return ms; } public static bool IsImage(byte[] Bytes) { try { GetBitmap(Bytes); } catch(Exception) { return false; } return true; } public static Bitmap GetBitmap(byte[] BitmapBytes) { MemoryStream ms = ByteToStream(BitmapBytes); Bitmap bmp = new Bitmap(ms); ms.Dispose(); return bmp; } public static String ReadStringAt(Stream ms, int location) { long ogPos = ms.Position; ms.Seek(location, SeekOrigin.Begin); String str = ReadString(ms); ms.Seek(ogPos, SeekOrigin.Begin); return str; } public static int ReadIntAt(Stream ms, int location) { BinaryReader BinReader = new BinaryReader(ms); long ogPos = ms.Position; ms.Seek(location, SeekOrigin.Begin); int i = BinReader.ReadInt32(); ms.Seek(ogPos, SeekOrigin.Begin); return i; } public static int ReadInt(Stream ms) { BinaryReader BinReader = new BinaryReader(ms); int i = BinReader.ReadInt32(); return i; } public static String ReadString(Stream ms) { int i = 0xFF; MemoryStream StringStream = new MemoryStream(); do { i = ms.ReadByte(); if (i == 0) break; StringStream.WriteByte((byte)i); } while (true); byte[] StringData = StringStream.ToArray(); String str = Encoding.UTF8.GetString(StringData); return str; } } class Parser { private static bool _checkMagicNumber() { String Magic = Tools.ReadStringAt(InfoFile, 0x00); if (Magic.StartsWith("PSMA")) { return true; } else if(Magic.StartsWith("RCOF")) { Console.WriteLine("WARNING: .RCO files probably wont work!!\nThis tool was made for PSM's \"app.info\" files."); return true; } else { return false; } } static FileStream InfoFile; static MemoryStream StringTable; static MemoryStream TreeTable; static MemoryStream FileTable; static BinaryReader BinaryTree; static XmlWriter XMLFile; public static void Init(string Path, bool CheckMagic = true) { InfoFile = File.Open(Path, FileMode.Open, FileAccess.Read); if(CheckMagic) { if (!_checkMagicNumber()) { throw new Exception("Incorrect magic number."); } } StringTable = Tools.ByteToStream(GetStringTable()); TreeTable = Tools.ByteToStream(GetTreeTable()); FileTable = Tools.ByteToStream(GetFileTable()); BinaryTree = new BinaryReader(TreeTable); return; } public static void Term() { InfoFile.Close(); StringTable.Close(); TreeTable.Close(); FileTable.Close(); BinaryTree.Dispose(); } public static int GetTableOffset() { return Tools.ReadIntAt(InfoFile,0x8); } public static int GetTableSize() { return Tools.ReadIntAt(InfoFile, 0xC); } public static int GetFileTableOffset() { return Tools.ReadIntAt(InfoFile, 0x48); } public static int GetFileTableSize() { return Tools.ReadIntAt(InfoFile, 0x4C); } public static int GetStringTableOffset() { return Tools.ReadIntAt(InfoFile, 0x20); } public static int GetStringTableSize() { return Tools.ReadIntAt(InfoFile, 0x24); } 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[] GetTreeTable() { int TableOffset = GetTableOffset(); int TableSize = GetTableSize(); InfoFile.Seek(TableOffset, SeekOrigin.Begin); byte[] Table = new byte[TableSize]; InfoFile.Read(Table, 0x00, TableSize); return Table; } 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) { Init(CXMLFile,force); XmlWriterSettings XMLSettings = new XmlWriterSettings(); XMLSettings.Indent = true; XMLFile = XmlWriter.Create(Path.GetFileNameWithoutExtension(CXMLFile)+".xml", XMLSettings); XMLFile.WriteStartDocument(); ReadElement(); XMLFile.WriteEndDocument(); XMLFile.Flush(); Term(); } public static void ReadAttribute() { int AttributePtr = BinaryTree.ReadInt32(); int AttributeType = BinaryTree.ReadInt32(); String AttributeName = Tools.ReadStringAt(StringTable, AttributePtr); object AttributeValue; Console.WriteLine("AttributeType: " + AttributeType); if (AttributeType == Types.TYPE_STRING) { int ValuePtr = BinaryTree.ReadInt32(); AttributeValue = Tools.ReadStringAt(StringTable, ValuePtr); TreeTable.Seek(4, SeekOrigin.Current); } else if(AttributeType == Types.TYPE_FLOAT) { AttributeValue = BinaryTree.ReadSingle(); TreeTable.Seek(4, SeekOrigin.Current); } else if(AttributeType == Types.TYPE_INT) { AttributeValue = BinaryTree.ReadInt32(); TreeTable.Seek(4, SeekOrigin.Current); } else if(AttributeType == Types.TYPE_FILE) { int FilePtr = BinaryTree.ReadInt32(); int FileSz = BinaryTree.ReadInt32(); String FileName = ""; Byte[] FileData = new Byte[FileSz]; FileTable.Seek(FilePtr,SeekOrigin.Begin); FileTable.Read(FileData, 0, FileSz); if (Tools.IsImage(FileData)) FileName = AttributeName + ".png"; else FileName = AttributeName + ".txt"; Console.WriteLine("Writing: " + FileName); File.WriteAllBytes(FileName, FileData); AttributeValue = FileName; } else { Console.WriteLine("ERROR: Unknown Type '"+AttributeType+"' @ " + (TreeTable.Position - 4).ToString()); Environment.Exit(-1); return; } Console.WriteLine(AttributeName + "=" + AttributeValue.ToString()); XMLFile.WriteAttributeString(AttributeName, AttributeValue.ToString()); XMLFile.Flush(); } public static void ReadElement() { int ElementPtr = BinaryTree.ReadInt32(); int NumAttributes = BinaryTree.ReadInt32(); int ParentPtr = BinaryTree.ReadInt32(); int PrevSibling = BinaryTree.ReadInt32(); int NextSibling = BinaryTree.ReadInt32(); int FirstChild = BinaryTree.ReadInt32(); int LastChild = BinaryTree.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(); } } if (FirstChild != -1) { TreeTable.Seek(FirstChild, SeekOrigin.Begin); ReadElement(); } XMLFile.WriteEndElement(); XMLFile.Flush(); if (NextSibling != -1) { TreeTable.Seek(NextSibling, SeekOrigin.Begin); ReadElement(); } } } }