346 lines
9.9 KiB
C#
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();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|