cxml-decompiler/AppInfoCli/AppInfo.cs

346 lines
9.9 KiB
C#

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