Add support for ps3 cxml

This commit is contained in:
Li 2022-06-19 16:29:29 +12:00
parent a6fcc971a9
commit 0aa6de7b9c
8 changed files with 681 additions and 467 deletions

55
CXMLCli/CXML.cs Normal file
View File

@ -0,0 +1,55 @@
using System;
namespace CXML
{
public enum AttributeTypePs3
{
TYPE_NONE = 0,
TYPE_INT = 1,
TYPE_FLOAT = 2,
TYPE_STRING = 3,
TYPE_INTEGER_ARRAY = 4,
TYPE_FLOAT_ARRAY = 5,
TYPE_FILE = 6,
TYPE_ID_REF = 7,
TYPE_ID = 8,
};
public enum AttributeType
{
TYPE_NONE = 0,
TYPE_INT = 1,
TYPE_FLOAT = 2,
TYPE_STRING = 3,
TYPE_WSTRING = 4,
TYPE_HASH = 5,
TYPE_INTEGER_ARRAY = 6,
TYPE_FLOAT_ARRAY = 7,
TYPE_FILE = 8,
TYPE_ID_REF = 9,
TYPE_ID = 10,
TYPE_ID_HASH_REF = 11,
TYPE_ID_HASH = 12
};
enum Version
{
PS3 = 0x10010000,
PSVITA = 0x110,
PSM = 0x100,
UNKNOWN
};
public class TypingInformation
{
public string key;
public string value;
}
public class LoopbackHandler
{
public String FileName;
public String OldFileName;
public String ReplacePattern;
public byte[] FileData;
public Int64 FilePointer;
}
}

View File

@ -16,15 +16,20 @@ namespace CXMLDecompiler
String MainDir = "";
String XMLFilename = "";
String MagicNumber = "";
Endainness FileEndainness;
bool ps3;
Tools tools;
Int32 Version;
FileStream InfoFile;
MemoryStream TreeTable;
MemoryStream StringIDTable;
MemoryStream IntIDTable;
MemoryStream StringTable;
MemoryStream CharTable;
MemoryStream IDTable;
MemoryStream HashIDTable;
MemoryStream StringTable;
MemoryStream WStringTable;
MemoryStream HashTable;
MemoryStream IntArrayTable;
MemoryStream FloatArrayTable;
MemoryStream FileTable;
@ -32,41 +37,34 @@ namespace CXMLDecompiler
Boolean IsInitalized = false;
public Boolean HashStrings = false;
BinaryWriter bInfoFile;
BinaryWriter bTreeTable;
BinaryWriter bIntIDTable;
BinaryWriter bFloatArrayTable;
BinaryWriter bIntArrayTable;
BinaryWriter bHashIDTable;
BinaryWriter bStringIDTable;
String SilicaTypingInformation = "";
public void Init(string XMLFile, string CxmlFile)
{
GetSilicaTypingInformation(XMLFile);
MagicNumber = GetTypingInformation("MAGIC");
Version = Int32.Parse(GetTypingInformation("VERSION"), CultureInfo.InvariantCulture);
Version = Int32.Parse(GetTypingInformation("VERSION").Replace("0x", ""), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
// Determine filetype.
FileEndainness = (Endainness)Enum.Parse(typeof(Endainness), GetTypingInformation("ENDAINESS"));
ps3 = GetTypingInformation("PS3") == "true";
tools = new Tools((FileEndainness == Endainness.BIG_ENDAIN));
InfoFile = File.Open(CxmlFile, FileMode.OpenOrCreate, FileAccess.ReadWrite);
InfoFile.SetLength(0);
TreeTable = new MemoryStream();
StringIDTable = new MemoryStream();
IntIDTable = new MemoryStream();
IDTable = new MemoryStream();
StringTable = new MemoryStream();
CharTable = new MemoryStream();
HashIDTable = new MemoryStream();
IntArrayTable = new MemoryStream();
FloatArrayTable = new MemoryStream();
FileTable = new MemoryStream();
bInfoFile = new BinaryWriter(InfoFile);
bTreeTable = new BinaryWriter(TreeTable);
bIntIDTable = new BinaryWriter(IntIDTable);
bFloatArrayTable = new BinaryWriter(FloatArrayTable);
bIntArrayTable = new BinaryWriter(IntArrayTable);
bHashIDTable = new BinaryWriter(HashIDTable);
bStringIDTable = new BinaryWriter(StringIDTable);
WStringTable = new MemoryStream();
HashIDTable = new MemoryStream();
HashTable = new MemoryStream();
XMLFilename = XMLFile;
MainDir = Path.GetDirectoryName(XMLFilename);
@ -106,18 +104,18 @@ namespace CXMLDecompiler
public int offset;
public string name;
}
public class IntTableEntry
public class HashTableEntry
{
public int offset;
public int value;
}
public class StringIDTableEntry
public class IDTableEntry
{
public int offset;
public string value;
public int loopbackOffset;
}
public class IntIDTableEntry
public class HashIDTableEntry
{
public int offset;
public int value;
@ -131,13 +129,13 @@ namespace CXMLDecompiler
}
List<TreeTableEntry> TreeTableEntries = new List<TreeTableEntry>();
List<StringTableEntry> StringTableEntries = new List<StringTableEntry>();
List<StringTableEntry> CharTableEntries = new List<StringTableEntry>();
List<IntTableEntry> HashIdTableEntries = new List<IntTableEntry>();
List<StringTableEntry> WStringTableEntries = new List<StringTableEntry>();
List<HashTableEntry> HashTableEntries = new List<HashTableEntry>();
List<Int32> IntArrayTableEntries = new List<Int32>();
List<Single> FloatArrayTableEntries = new List<Single>();
List<StringTableEntry> FileTableEntries = new List<StringTableEntry>();
List<StringIDTableEntry> StringIDTableEntries = new List<StringIDTableEntry>();
List<IntIDTableEntry> IntIDTableEntries = new List<IntIDTableEntry>();
List<IDTableEntry> IDTableEntries = new List<IDTableEntry>();
List<HashIDTableEntry> HashIDTableEntries = new List<HashIDTableEntry>();
public int AddGetTreeTable(XmlNode node)
{
if (!(node.NodeType == XmlNodeType.Element || node.NodeType == XmlNodeType.EndElement || node.NodeType == XmlNodeType.Attribute))
@ -155,9 +153,9 @@ namespace CXMLDecompiler
return ent.offset;
}
public int AddGetIntIdTable(int value, int loopbackPtr)
public int AddGetHashIdTable(int value, int loopbackPtr)
{
foreach (IntIDTableEntry entry in IntIDTableEntries)
foreach (HashIDTableEntry entry in HashIDTableEntries)
{
if (entry.loopbackOffset == loopbackPtr && loopbackPtr != -1)
@ -169,27 +167,27 @@ namespace CXMLDecompiler
if (loopbackPtr == -1)
return entry.offset;
entry.loopbackOffset = loopbackPtr;
long position1 = IntIDTable.Position;
IntIDTable.Seek(entry.offset, SeekOrigin.Begin);
bIntIDTable.Write(loopbackPtr);
IntIDTable.Seek(position1, SeekOrigin.Begin);
long position1 = HashIDTable.Position;
HashIDTable.Seek(entry.offset, SeekOrigin.Begin);
tools.WriteInt32(HashIDTable, loopbackPtr);
HashIDTable.Seek(position1, SeekOrigin.Begin);
return entry.offset;
}
}
IntIDTableEntry ent = new IntIDTableEntry();
HashIDTableEntry ent = new HashIDTableEntry();
ent.value = value;
ent.loopbackOffset = loopbackPtr;
ent.offset = Convert.ToInt32(IntIDTable.Position);
IntIDTableEntries.Add(ent);
ent.offset = Convert.ToInt32(HashIDTable.Position);
HashIDTableEntries.Add(ent);
bIntIDTable.Write((int)loopbackPtr);
bIntIDTable.Write((int)value);
tools.WriteInt32(HashIDTable, loopbackPtr);
tools.WriteInt32(HashIDTable, value);
return ent.offset;
}
public int AddGetStringIdTable(string value, int loopbackPtr)
public int AddGetIdTable(string value, int loopbackPtr)
{
foreach (StringIDTableEntry entry in StringIDTableEntries)
foreach (IDTableEntry entry in IDTableEntries)
{
if (entry.loopbackOffset == loopbackPtr && loopbackPtr != -1)
{
@ -200,27 +198,27 @@ namespace CXMLDecompiler
if (loopbackPtr == -1)
return entry.offset;
entry.loopbackOffset = loopbackPtr;
long position1 = StringIDTable.Position;
StringIDTable.Seek(entry.offset, SeekOrigin.Begin);
bStringIDTable.Write(loopbackPtr);
StringIDTable.Seek(position1, SeekOrigin.Begin);
long position1 = IDTable.Position;
IDTable.Seek(entry.offset, SeekOrigin.Begin);
tools.WriteInt32(IDTable, loopbackPtr);
IDTable.Seek(position1, SeekOrigin.Begin);
return entry.offset;
}
}
StringIDTableEntry ent = new StringIDTableEntry();
IDTableEntry ent = new IDTableEntry();
ent.value = value;
ent.loopbackOffset = loopbackPtr;
ent.offset = Convert.ToInt32(StringIDTable.Position);
StringIDTableEntries.Add(ent);
bStringIDTable.Write(loopbackPtr);
Tools.WriteStringToStream(StringIDTable, value);
StringIDTable.WriteByte(0x00);
ent.offset = Convert.ToInt32(IDTable.Position);
IDTableEntries.Add(ent);
tools.WriteInt32(IDTable, loopbackPtr);
Tools.WriteStringToStream(IDTable, value);
IDTable.WriteByte(0x00);
if (loopbackPtr != -1)
if (loopbackPtr != -1 && !ps3)
{
Align(StringIDTable, 4);
Align(IDTable, 4);
}
return ent.offset;
@ -257,7 +255,7 @@ namespace CXMLDecompiler
foreach (float i in value)
{
bFloatArrayTable.Write((float)i);
tools.WriteSingle(FloatArrayTable, i);
FloatArrayTableEntries.Add(i);
}
@ -279,24 +277,24 @@ namespace CXMLDecompiler
foreach (int i in value)
{
bIntArrayTable.Write((int)i);
tools.WriteInt32(IntArrayTable, i);
IntArrayTableEntries.Add(i);
}
return offset;
}
public int AddGetHashIdTable(int value)
public int AddGetHashTable(int value)
{
foreach (IntTableEntry entry in HashIdTableEntries)
foreach (HashTableEntry entry in HashTableEntries)
if (entry.value == value)
return entry.offset/4;
IntTableEntry ent = new IntTableEntry();
HashTableEntry ent = new HashTableEntry();
ent.value = value;
ent.offset = Convert.ToInt32(HashIDTable.Position);
HashIdTableEntries.Add(ent);
ent.offset = Convert.ToInt32(HashTable.Position);
HashTableEntries.Add(ent);
bHashIDTable.Write((int)value);
tools.WriteInt32(HashTable, value);
return ent.offset/4;
}
@ -316,34 +314,40 @@ namespace CXMLDecompiler
return ent.offset;
}
public int AddGetCharTable(string elementName)
public int AddGetWstringTable(string elementName)
{
foreach (StringTableEntry entry in CharTableEntries)
foreach (StringTableEntry entry in WStringTableEntries)
if (entry.name == elementName)
return entry.offset;
StringTableEntry ent = new StringTableEntry();
ent.name = elementName;
ent.offset = Convert.ToInt32(CharTable.Position)/2;
CharTableEntries.Add(ent);
ent.offset = Convert.ToInt32(WStringTable.Position)/2;
WStringTableEntries.Add(ent);
Tools.WriteUtf16StringToStream(CharTable, elementName);
CharTable.WriteByte(0x00);
CharTable.WriteByte(0x00);
Tools.WriteUtf16StringToStream(WStringTable, elementName);
WStringTable.WriteByte(0x00);
WStringTable.WriteByte(0x00);
return ent.offset;
}
public int ConvertAttributeTypeToInt(AttributeType type)
{
if (!ps3)
return (int) type;
else
return (int) (AttributeTypePs3)Enum.Parse(typeof(AttributeTypePs3), type.ToString());
}
public AttributeType DetermineType(string ElementName, string AttributeName)
{
return (AttributeType)Int32.Parse(GetTypingInformation(ElementName + ":" + AttributeName), CultureInfo.InvariantCulture);
return (AttributeType)Enum.Parse(typeof(AttributeType), GetTypingInformation(ElementName + ":" + AttributeName));
}
public void WriteAttribute(XmlAttribute attribute, MemoryStream WorkRam, BinaryWriter bWorkRam, string ElementName)
public void WriteAttribute(XmlAttribute attribute, MemoryStream WorkRam, string ElementName)
{
int AttributePtr = AddGetStringTable(attribute.Name);
AttributeType Type = DetermineType(ElementName, attribute.Name);
bWorkRam.Write(AttributePtr);
bWorkRam.Write((int)Type);
tools.WriteInt32(WorkRam, AttributePtr);
tools.WriteInt32(WorkRam, ConvertAttributeTypeToInt(Type));
Console.WriteLine("AttributeType: " + Type.ToString());
switch (Type)
{
@ -353,40 +357,40 @@ namespace CXMLDecompiler
break;
case AttributeType.TYPE_INT:
int intWrite = Int32.Parse(attribute.Value, CultureInfo.InvariantCulture);
bWorkRam.Write((int)intWrite);
bWorkRam.Write((int)0x00);
tools.WriteInt32(WorkRam, intWrite);
tools.WriteInt32(WorkRam, 0x00);
Console.WriteLine("Int - Value: " + intWrite.ToString());
break;
case AttributeType.TYPE_FLOAT:
float FloatValue = Single.Parse(attribute.Value.Substring(0, attribute.Value.Length - 1), CultureInfo.InvariantCulture);
bWorkRam.Write((float)FloatValue);
bWorkRam.Write((int)0x00);
tools.WriteSingle(WorkRam, FloatValue);
tools.WriteInt32(WorkRam, 0x00);
Console.WriteLine("Float - Value: " + FloatValue.ToString());
break;
case AttributeType.TYPE_STRING:
int StringOffset = AddGetStringTable(attribute.Value);
int StringLen = Encoding.UTF8.GetBytes(attribute.Value).Length;
bWorkRam.Write(StringOffset);
bWorkRam.Write(StringLen);
tools.WriteInt32(WorkRam, StringOffset);
tools.WriteInt32(WorkRam, StringLen);
Console.WriteLine("String: " + attribute.Value);
break;
case AttributeType.TYPE_CHAR:
int CharOffset = AddGetCharTable(attribute.Value);
int CharLen = Encoding.Unicode.GetBytes(attribute.Value).Length;
bWorkRam.Write(CharOffset);
bWorkRam.Write(CharLen);
Console.WriteLine("Char: " + attribute.Value);
case AttributeType.TYPE_WSTRING:
int WStringOffset = AddGetWstringTable(attribute.Value);
int WStringLength = Encoding.Unicode.GetBytes(attribute.Value).Length;
tools.WriteInt32(WorkRam, WStringOffset);
tools.WriteInt32(WorkRam, WStringLength);
Console.WriteLine("WString: " + attribute.Value);
break;
case AttributeType.TYPE_HASH_ID:
case AttributeType.TYPE_HASH:
int hashId = Int32.Parse(attribute.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
if (HashStrings)
hashId = Int32.Parse(Tools.GenerateShortHash(Encoding.UTF8.GetBytes(attribute.Value)), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
int HashTableOffset = AddGetHashIdTable(hashId);
int HashTableOffset = AddGetHashTable(hashId);
int HashTableSize = 4;
bWorkRam.Write(HashTableOffset);
bWorkRam.Write(HashTableSize);
tools.WriteInt32(WorkRam, HashTableOffset);
tools.WriteInt32(WorkRam, HashTableSize);
Console.WriteLine("Hash ID Offset:" + HashTableOffset.ToString() + " size: " + HashTableSize);
break;
case AttributeType.TYPE_INTEGER_ARRAY:
@ -397,8 +401,8 @@ namespace CXMLDecompiler
int IntArrayOffset = AddGetIntArrayTable(intArr);
int IntArraySize = intArr.Length;
bWorkRam.Write(IntArrayOffset);
bWorkRam.Write(IntArraySize);
tools.WriteInt32(WorkRam, IntArrayOffset);
tools.WriteInt32(WorkRam, IntArraySize);
Console.WriteLine("Int Array: " + attribute.Value);
break;
@ -410,8 +414,8 @@ namespace CXMLDecompiler
int FloatArrayOffset = AddGetFloatArrayTable(floatArr);
int FloatArraySize = floatArr.Length;
bWorkRam.Write(FloatArrayOffset);
bWorkRam.Write(FloatArraySize);
tools.WriteInt32(WorkRam, FloatArrayOffset);
tools.WriteInt32(WorkRam, FloatArraySize);
Console.WriteLine("Float Array: " + attribute.Value);
break;
@ -420,41 +424,41 @@ namespace CXMLDecompiler
byte[] data = File.ReadAllBytes(fPath);
int FilePtr = AddGetFileTable(data, Path.Combine(Environment.CurrentDirectory, fPath));
int FileSz = data.Length;
bWorkRam.Write(FilePtr);
bWorkRam.Write(FileSz);
tools.WriteInt32(WorkRam, FilePtr);
tools.WriteInt32(WorkRam, FileSz);
Console.WriteLine("Reading File: " + fPath);
break;
case AttributeType.TYPE_ID_STRING_LOOPBACK:
int StringIdTableOffset = AddGetStringIdTable(attribute.Value, Convert.ToInt32(TreeTable.Position));
bWorkRam.Write(StringIdTableOffset);
bWorkRam.Write((int)0x00);
case AttributeType.TYPE_ID_REF:
int IdTableOffset = AddGetIdTable(attribute.Value, Convert.ToInt32(TreeTable.Position));
tools.WriteInt32(WorkRam, IdTableOffset);
tools.WriteInt32(WorkRam, 0x00);
Console.WriteLine("String Loopback: " + ElementName + " " + TreeTable.Position.ToString("X") + " (" + TreeTable.Position.ToString("X") + ")");
Console.WriteLine("Loopback ID String: " + StringIdTableOffset + " sz: 0");
Console.WriteLine("Loopback ID String: " + IdTableOffset + " sz: 0");
break;
case AttributeType.TYPE_ID_STRING:
StringIdTableOffset = AddGetStringIdTable(attribute.Value, -1);
bWorkRam.Write(StringIdTableOffset);
bWorkRam.Write((int)0x00);
Console.WriteLine("ID String: " + StringIdTableOffset + " sz: 0");
case AttributeType.TYPE_ID:
IdTableOffset = AddGetIdTable(attribute.Value, -1);
tools.WriteInt32(WorkRam, IdTableOffset);
tools.WriteInt32(WorkRam, 0x00);
Console.WriteLine("ID String: " + IdTableOffset + " sz: 0");
break;
case AttributeType.TYPE_ID_INT_LOOPBACK:
case AttributeType.TYPE_ID_HASH_REF:
int hash = Int32.Parse(attribute.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
if (HashStrings)
hash = Int32.Parse(Tools.GenerateShortHash(Encoding.UTF8.GetBytes(attribute.Value)), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
int IntIdTableOffset = AddGetIntIdTable(hash, Convert.ToInt32(TreeTable.Position));
bWorkRam.Write(IntIdTableOffset);
bWorkRam.Write((int)0x00);
int IntIdTableOffset = AddGetHashIdTable(hash, Convert.ToInt32(TreeTable.Position));
tools.WriteInt32(WorkRam, IntIdTableOffset);
tools.WriteInt32(WorkRam, 0x00);
Console.WriteLine("Int Loopback: " + ElementName + " " + TreeTable.Position.ToString("X") + " (" + TreeTable.Position.ToString("X") + ")");
Console.WriteLine("Loopback ID Int: " + IntIdTableOffset + " sz: 0");
break;
case AttributeType.TYPE_ID_INT:
case AttributeType.TYPE_ID_HASH:
hash = Int32.Parse(attribute.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
if (HashStrings)
hash = Int32.Parse(Tools.GenerateShortHash(Encoding.UTF8.GetBytes(attribute.Value)), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
IntIdTableOffset = AddGetIntIdTable(hash, -1);
IntIdTableOffset = AddGetHashIdTable(hash, -1);
bWorkRam.Write(IntIdTableOffset);
bWorkRam.Write((int)0x00);
tools.WriteInt32(WorkRam, IntIdTableOffset);
tools.WriteInt32(WorkRam, 0x00);
Console.WriteLine("Int Id: " + IntIdTableOffset + " sz: 0");
break;
default:
@ -467,7 +471,7 @@ namespace CXMLDecompiler
public void WriteElement(XmlNode node)
{
MemoryStream WorkRam = new MemoryStream();
BinaryWriter bWorkRam = new BinaryWriter(WorkRam);
//BinaryWriter bWorkRam = new BinaryWriter(WorkRam);
int ElementPtr = AddGetStringTable(node.Name);
int NumAttributes = 0;
int ParentPtr = -1;
@ -477,17 +481,17 @@ namespace CXMLDecompiler
int FirstChild = -1;
int LastChild = -1;
long Position = TreeTable.Position;
bWorkRam.Write(ElementPtr);
bWorkRam.Write(NumAttributes);
bWorkRam.Write(ParentPtr);
bWorkRam.Write(PrevSibling);
bWorkRam.Write(NextSibling);
bWorkRam.Write(FirstChild);
bWorkRam.Write(LastChild);
tools.WriteInt32(WorkRam, ElementPtr);
tools.WriteInt32(WorkRam, NumAttributes);
tools.WriteInt32(WorkRam, ParentPtr);
tools.WriteInt32(WorkRam, PrevSibling);
tools.WriteInt32(WorkRam, NextSibling);
tools.WriteInt32(WorkRam, FirstChild);
tools.WriteInt32(WorkRam, LastChild);
foreach (XmlAttribute attribute in node.Attributes)
{
WriteAttribute(attribute, WorkRam, bWorkRam, node.Name);
WriteAttribute(attribute, WorkRam, node.Name);
}
@ -515,14 +519,14 @@ namespace CXMLDecompiler
LastChild = AddGetTreeTable(node.LastChild);
long Position2 = TreeTable.Position;
TreeTable.Seek(Position, SeekOrigin.Begin);
bTreeTable.Write(ElementPtr);
bTreeTable.Write(NumAttributes);
bTreeTable.Write(ParentPtr);
bTreeTable.Write(PrevSibling);
bTreeTable.Write(NextSibling);
bTreeTable.Write(FirstChild);
bTreeTable.Write(LastChild);
TreeTable.Seek(Position, SeekOrigin.Begin);
tools.WriteInt32(TreeTable, ElementPtr);
tools.WriteInt32(TreeTable, NumAttributes);
tools.WriteInt32(TreeTable, ParentPtr);
tools.WriteInt32(TreeTable, PrevSibling);
tools.WriteInt32(TreeTable, NextSibling);
tools.WriteInt32(TreeTable, FirstChild);
tools.WriteInt32(TreeTable, LastChild);
TreeTable.Seek(Position2, SeekOrigin.Begin);
}
@ -545,30 +549,25 @@ namespace CXMLDecompiler
{
InfoFile.Close();
TreeTable.Close();
StringIDTable.Close();
IntIDTable.Close();
StringTable.Close();
CharTable.Close();
IDTable.Close();
HashIDTable.Close();
StringTable.Close();
WStringTable.Close();
HashTable.Close();
IntArrayTable.Close();
FloatArrayTable.Close();
FileTable.Close();
bTreeTable.Close();
bIntIDTable.Close();
bFloatArrayTable.Close();
bIntArrayTable.Close();
bHashIDTable.Close();
TreeTableEntries.Clear();
StringTableEntries.Clear();
CharTableEntries.Clear();
HashIdTableEntries.Clear();
WStringTableEntries.Clear();
HashTableEntries.Clear();
IntArrayTableEntries.Clear();
FloatArrayTableEntries.Clear();
FileTableEntries.Clear();
StringIDTableEntries.Clear();
IntIDTableEntries.Clear();
IDTableEntries.Clear();
HashIDTableEntries.Clear();
IsInitalized = false;
}
@ -584,11 +583,17 @@ namespace CXMLDecompiler
XMLFile.Load(XmlFile);
Tools.WriteStringToStream(InfoFile, MagicNumber);
bInfoFile.Write((Int32)Version);
byte[] headerPlaceholder = new byte[0x48];
Tools.WriteLittleEndainInt(InfoFile, Version);
byte[] headerPlaceholder;
if (!ps3)
headerPlaceholder = new byte[0x48];
else
headerPlaceholder = new byte[0x30];
InfoFile.Write(headerPlaceholder, 0x00, headerPlaceholder.Length);
Align(InfoFile, 0x10);
foreach(XmlNode childNode in XMLFile.ChildNodes)
foreach (XmlNode childNode in XMLFile.ChildNodes)
{
AddGetTreeTable(childNode);
}
@ -600,29 +605,11 @@ namespace CXMLDecompiler
TreeTable.CopyTo(InfoFile);
int StringIdOffset = Convert.ToInt32(InfoFile.Position);
int StringIdSize = Convert.ToInt32(StringIDTable.Length);
Align(StringIDTable, 0x10);
StringIDTable.Seek(0x00, SeekOrigin.Begin);
StringIDTable.CopyTo(InfoFile);
int IntIdOffset = Convert.ToInt32(InfoFile.Position);
int IntIdSize = Convert.ToInt32(IntIDTable.Length);
Align(IntIDTable, 0x10);
IntIDTable.Seek(0x00, SeekOrigin.Begin);
IntIDTable.CopyTo(InfoFile);
int StringTableOffset = Convert.ToInt32(InfoFile.Position);
int StringTableSize = Convert.ToInt32(StringTable.Length);
Align(StringTable, 0x10);
StringTable.Seek(0x00, SeekOrigin.Begin);
StringTable.CopyTo(InfoFile);
int CharTableOffset = Convert.ToInt32(InfoFile.Position);
int CharTableSize = Convert.ToInt32(CharTable.Length);
Align(CharTable, 0x10);
CharTable.Seek(0x00, SeekOrigin.Begin);
CharTable.CopyTo(InfoFile);
int IdTableOffset = Convert.ToInt32(InfoFile.Position);
int IdTableSize = Convert.ToInt32(IDTable.Length);
Align(IDTable, 0x10);
IDTable.Seek(0x00, SeekOrigin.Begin);
IDTable.CopyTo(InfoFile);
int HashIdTableOffset = Convert.ToInt32(InfoFile.Position);
int HashIdTableSize = Convert.ToInt32(HashIDTable.Length);
@ -630,6 +617,24 @@ namespace CXMLDecompiler
HashIDTable.Seek(0x00, SeekOrigin.Begin);
HashIDTable.CopyTo(InfoFile);
int StringTableOffset = Convert.ToInt32(InfoFile.Position);
int StringTableSize = Convert.ToInt32(StringTable.Length);
Align(StringTable, 0x10);
StringTable.Seek(0x00, SeekOrigin.Begin);
StringTable.CopyTo(InfoFile);
int WStringTableOffset = Convert.ToInt32(InfoFile.Position);
int WStringTableSize = Convert.ToInt32(WStringTable.Length);
Align(WStringTable, 0x10);
WStringTable.Seek(0x00, SeekOrigin.Begin);
WStringTable.CopyTo(InfoFile);
int HashTableOffset = Convert.ToInt32(InfoFile.Position);
int HashTableSize = Convert.ToInt32(HashTable.Length);
Align(HashTable, 0x10);
HashTable.Seek(0x00, SeekOrigin.Begin);
HashTable.CopyTo(InfoFile);
int IntArrayTableOffset = Convert.ToInt32(InfoFile.Position);
int IntArrayTableSize = Convert.ToInt32(IntArrayTable.Length);
Align(IntArrayTable, 0x10);
@ -659,24 +664,34 @@ namespace CXMLDecompiler
}
InfoFile.Seek(0x8, SeekOrigin.Begin);
bInfoFile.Write(TreeTableOffset);
bInfoFile.Write(TreeTableSize);
bInfoFile.Write(StringIdOffset);
bInfoFile.Write(StringIdSize);
bInfoFile.Write(IntIdOffset);
bInfoFile.Write(IntIdSize);
bInfoFile.Write(StringTableOffset);
bInfoFile.Write(StringTableSize);
bInfoFile.Write(CharTableOffset);
bInfoFile.Write(CharTableSize);
bInfoFile.Write(HashIdTableOffset);
bInfoFile.Write(HashIdTableSize);
bInfoFile.Write(IntArrayTableOffset);
bInfoFile.Write(IntArrayTableSize);
bInfoFile.Write(FloatArrayTableOffset);
bInfoFile.Write(FloatArrayTableSize);
bInfoFile.Write(FileTableOffset);
bInfoFile.Write(FileTableSize);
tools.WriteInt32(InfoFile, TreeTableOffset);
tools.WriteInt32(InfoFile, TreeTableSize);
tools.WriteInt32(InfoFile, IdTableOffset);
tools.WriteInt32(InfoFile, IdTableSize);
if (!ps3)
{
tools.WriteInt32(InfoFile, HashIdTableOffset);
tools.WriteInt32(InfoFile, HashIdTableSize);
}
tools.WriteInt32(InfoFile, StringTableOffset);
tools.WriteInt32(InfoFile, StringTableSize);
if (!ps3)
{
tools.WriteInt32(InfoFile, WStringTableOffset);
tools.WriteInt32(InfoFile, WStringTableSize);
tools.WriteInt32(InfoFile, HashTableOffset);
tools.WriteInt32(InfoFile, HashTableSize);
}
tools.WriteInt32(InfoFile, IntArrayTableOffset);
tools.WriteInt32(InfoFile, IntArrayTableSize);
tools.WriteInt32(InfoFile, FloatArrayTableOffset);
tools.WriteInt32(InfoFile, FloatArrayTableSize);
tools.WriteInt32(InfoFile, FileTableOffset);
tools.WriteInt32(InfoFile, FileTableSize);
Term();
}

View File

@ -93,10 +93,10 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CXML.cs" />
<Compile Include="CXMLReader.cs" />
<Compile Include="CXMLBuilder.cs" />
<Compile Include="GimConv.cs" />
<Compile Include="LoopbackHandler.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tools.cs" />

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<StartArguments>sample\sample.xml sample2.cxml --compile</StartArguments>
<StartWorkingDirectory>C:\Users\User\Documents\git\cxml-decompiler\CXMLCli\bin\x64\Debug</StartWorkingDirectory>
</PropertyGroup>
</Project>

View File

@ -1,5 +1,6 @@
using Ionic.Zlib;
using General;
using CXML;
using System;
using System.Collections.Generic;
@ -7,46 +8,35 @@ using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Globalization;
using System.Globalization;
namespace CXML
namespace CXMLDecompiler
{
enum AttributeType
class CXMLReader
{
TYPE_NONE,
TYPE_INT,
TYPE_FLOAT,
TYPE_STRING,
TYPE_CHAR,
TYPE_HASH_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 bool _checkMagicNumber()
{
String Magic = Tools.ReadStringAt(InfoFile, 0x00);
MagicNumber = Magic.Substring(0,4);
if (Magic.StartsWith("PSMA"))
if (Magic.StartsWith("PSMA")) // PlayStation Mobile "app.info"
{
return true;
}
else if(Magic.StartsWith("RCOF"))
else if(Magic.StartsWith("RCOF")) // Vita/Ps4/Ps3 RCO
{
return true;
}
else if (Magic.StartsWith("RCSF"))
else if (Magic.StartsWith("RCSF")) // Found inside RCO
{
return true;
}
else if (Magic.StartsWith("CXML")) // cxml.py default
{
return true;
}
else if (Magic.StartsWith("TEST")) // ps3 cxml tools example
{
return true;
}
@ -54,13 +44,9 @@ namespace CXML
{
return false;
}
}
}
public class TypingInformation
{
public string key;
public string value;
}
String MainDir = "";
String FileDir = "";
String XMLFilename = "";
@ -73,32 +59,32 @@ namespace CXML
FileStream InfoFile;
MemoryStream TreeTable;
MemoryStream StringIDTable;
MemoryStream IntIDTable;
MemoryStream StringTable;
MemoryStream CharTable;
MemoryStream IDTable;
MemoryStream HashIDTable;
MemoryStream StringTable;
MemoryStream WStringTable;
MemoryStream HashTable;
MemoryStream IntArrayTable;
MemoryStream FloatArrayTable;
MemoryStream FileTable;
Tools tools;
Boolean IsInitalized = false;
BinaryReader bTreeTable;
BinaryReader bIntIDTable;
BinaryReader bFloatArrayTable;
BinaryReader bIntArrayTable;
BinaryReader bHashIDTable;
BinaryReader bStringIDTable;
CXML.Version FileVersion;
public Endainness FileEndainness = Endainness.LITTLE_ENDAIN;
List<LoopbackHandler> FileList = new List<LoopbackHandler>();
XmlWriter XMLWriter;
public bool ps3 = false;
public bool ProcessFiles = false;
public bool WaitExit = false;
public bool NoRecursive = false;
public void Init(string path, bool CheckMagic = true)
public void Init(string path, bool CheckMagic = true, bool forcePs3 = false, Endainness forceEndainness = Endainness.UNCHANGED)
{
InfoFile = File.Open(path, FileMode.Open, FileAccess.Read);
bool MagicValid = _checkMagicNumber();
@ -110,24 +96,47 @@ namespace CXML
}
}
// This is a bit of a hack, but what can you do?
FileVersion = ReadVersionEnum();
if (FileVersion == CXML.Version.PS3)
{
ps3 = true;
FileEndainness = Endainness.BIG_ENDAIN;
}
else
{
FileEndainness = Endainness.LITTLE_ENDAIN;
}
if (forcePs3)
ps3 = true;
if (forceEndainness != Endainness.UNCHANGED)
FileEndainness = forceEndainness;
tools = new Tools(FileEndainness == Endainness.BIG_ENDAIN);
TreeTable = Tools.ByteToStream(GetTreeTable());
StringIDTable = Tools.ByteToStream(GetStringIDTable());
IntIDTable = Tools.ByteToStream(GetIntIDTable());
StringTable = Tools.ByteToStream(GetStringTable());
CharTable = Tools.ByteToStream(GetCharTable());
HashIDTable = Tools.ByteToStream(GetHashIDTable());
IntArrayTable = Tools.ByteToStream(GetIntArrayTable());
FloatArrayTable = Tools.ByteToStream(GetFloatArrayTable());
IDTable = Tools.ByteToStream(GetIDTable());
FileTable = Tools.ByteToStream(GetFileTable());
bTreeTable = new BinaryReader(TreeTable);
bIntIDTable = new BinaryReader(IntIDTable);
bFloatArrayTable = new BinaryReader(FloatArrayTable);
bIntArrayTable = new BinaryReader(IntArrayTable);
bHashIDTable = new BinaryReader(HashIDTable);
bStringIDTable = new BinaryReader(StringIDTable);
// psvita, ps4 exclusive
if (!ps3)
{
HashTable = Tools.ByteToStream(GetHashTable());
HashIDTable = Tools.ByteToStream(GetHashIDTable());
WStringTable = Tools.ByteToStream(GetWStringTable());
}
else
{
HashTable = new MemoryStream();
HashIDTable = new MemoryStream();
WStringTable = new MemoryStream();
}
MainDir = Path.GetFileNameWithoutExtension(path);
FileDir = Path.Combine(MainDir, "files");
XMLFilename = Path.GetFileNameWithoutExtension(path) + ".xml";
@ -141,113 +150,130 @@ namespace CXML
{
InfoFile.Close();
TreeTable.Close();
StringIDTable.Close();
IntIDTable.Close();
StringTable.Close();
CharTable.Close();
IDTable.Close();
HashIDTable.Close();
StringTable.Close();
WStringTable.Close();
HashTable.Close();
IntArrayTable.Close();
FloatArrayTable.Close();
FileTable.Close();
bTreeTable.Close();
bIntIDTable.Close();
bFloatArrayTable.Close();
bIntArrayTable.Close();
bHashIDTable.Close();
FileList.Clear();
IsInitalized = false;
}
public int GetTreeTableOffset()
{
return Tools.ReadIntAt(InfoFile,0x8);
return tools.ReadIntAt(InfoFile,0x8);
}
public int GetTreeTableSize()
{
return Tools.ReadIntAt(InfoFile, 0xC);
return tools.ReadIntAt(InfoFile, 0xC);
}
public int GetIDStringTableOffset()
public int GetIDTableOffset()
{
return Tools.ReadIntAt(InfoFile, 0x10);
return tools.ReadIntAt(InfoFile, 0x10);
}
public int GetIDStringTableSize()
public int GetIDTableSize()
{
return Tools.ReadIntAt(InfoFile, 0x14);
}
public int GetIDIntTableOffset()
{
return Tools.ReadIntAt(InfoFile, 0x18);
}
public int GetIDIntTableSize()
{
return Tools.ReadIntAt(InfoFile, 0x1C);
}
public int GetStringTableOffset()
{
return Tools.ReadIntAt(InfoFile, 0x20);
}
public int GetStringTableSize()
{
return Tools.ReadIntAt(InfoFile, 0x24);
}
public int GetCharTableOffset()
{
return Tools.ReadIntAt(InfoFile, 0x28);
}
public int GetCharTableSize()
{
return Tools.ReadIntAt(InfoFile, 0x2C);
return tools.ReadIntAt(InfoFile, 0x14);
}
public int GetHashIDTableOffset()
{
return Tools.ReadIntAt(InfoFile, 0x30);
return tools.ReadIntAt(InfoFile, 0x18);
}
public int GetHashIDTableSize()
{
return Tools.ReadIntAt(InfoFile, 0x34);
return tools.ReadIntAt(InfoFile, 0x1C);
}
public int GetStringTableOffset()
{
if (ps3)
return tools.ReadIntAt(InfoFile, 0x18);
else
return tools.ReadIntAt(InfoFile, 0x20);
}
public int GetStringTableSize()
{
if (ps3)
return tools.ReadIntAt(InfoFile, 0x1C);
else
return tools.ReadIntAt(InfoFile, 0x24);
}
public int GetWStringTableOffset()
{
return tools.ReadIntAt(InfoFile, 0x28);
}
public int GetWStringTableSize()
{
return tools.ReadIntAt(InfoFile, 0x2C);
}
public int GetHashTableOffset()
{
return tools.ReadIntAt(InfoFile, 0x30);
}
public int GetHashTableSize()
{
return tools.ReadIntAt(InfoFile, 0x34);
}
public int GetIntArrayTableOffset()
{
return Tools.ReadIntAt(InfoFile, 0x38);
if(ps3)
return tools.ReadIntAt(InfoFile, 0x20);
else
return tools.ReadIntAt(InfoFile, 0x38);
}
public int GetIntArrayTableSize()
{
return Tools.ReadIntAt(InfoFile, 0x3C);
if (ps3)
return tools.ReadIntAt(InfoFile, 0x24);
else
return tools.ReadIntAt(InfoFile, 0x3C);
}
public int GetFloatArrayTableOffset()
{
return Tools.ReadIntAt(InfoFile, 0x40);
if (ps3)
return tools.ReadIntAt(InfoFile, 0x28);
else
return tools.ReadIntAt(InfoFile, 0x40);
}
public int GetFloatArrayTableSize()
{
return Tools.ReadIntAt(InfoFile, 0x44);
if (ps3)
return tools.ReadIntAt(InfoFile, 0x2C);
else
return tools.ReadIntAt(InfoFile, 0x44);
}
public int GetFileTableOffset()
{
return Tools.ReadIntAt(InfoFile, 0x48);
{
if (ps3)
return tools.ReadIntAt(InfoFile, 0x30);
else
return tools.ReadIntAt(InfoFile, 0x48);
}
public int GetFileTableSize()
{
return Tools.ReadIntAt(InfoFile, 0x4C);
{
if (ps3)
return tools.ReadIntAt(InfoFile, 0x34);
else
return tools.ReadIntAt(InfoFile, 0x4C);
}
public byte[] GetTreeTable()
@ -260,24 +286,24 @@ namespace CXML
return Table;
}
public byte[] GetStringIDTable()
public byte[] GetIDTable()
{
int IDStrTableOffset = GetIDStringTableOffset();
int IDStrTableSize = GetIDStringTableSize();
InfoFile.Seek(IDStrTableOffset, SeekOrigin.Begin);
byte[] IDStringTable = new byte[IDStrTableSize];
InfoFile.Read(IDStringTable, 0x00, IDStrTableSize);
return IDStringTable;
int IDOffset = GetIDTableOffset();
int IDTableSize = GetIDTableSize();
InfoFile.Seek(IDOffset, SeekOrigin.Begin);
byte[] IDTable = new byte[IDTableSize];
InfoFile.Read(IDTable, 0x00, IDTableSize);
return IDTable;
}
public byte[] GetIntIDTable()
public byte[] GetHashIDTable()
{
int IDIntTableOffset = GetIDIntTableOffset();
int IDIntTableSize = GetIDIntTableSize();
InfoFile.Seek(IDIntTableOffset, SeekOrigin.Begin);
byte[] IDIntTable = new byte[IDIntTableSize];
InfoFile.Read(IDIntTable, 0x00, IDIntTableSize);
return IDIntTable;
int HashIDTableOffset = GetHashIDTableOffset();
int HashIDTableSize = GetHashIDTableSize();
InfoFile.Seek(HashIDTableOffset, SeekOrigin.Begin);
byte[] HashIDTable = new byte[HashIDTableSize];
InfoFile.Read(HashIDTable, 0x00, HashIDTableSize);
return HashIDTable;
}
public byte[] GetStringTable()
@ -290,24 +316,24 @@ namespace CXML
return StringTable;
}
public byte[] GetCharTable()
public byte[] GetWStringTable()
{
int CharTableOffset = GetCharTableOffset();
int CharTableSize = GetCharTableSize();
int CharTableOffset = GetWStringTableOffset();
int CharTableSize = GetWStringTableSize();
InfoFile.Seek(CharTableOffset, SeekOrigin.Begin);
byte[] CharTable = new byte[CharTableSize];
InfoFile.Read(CharTable, 0x00, CharTableSize);
return CharTable;
}
public byte[] GetHashIDTable()
public byte[] GetHashTable()
{
int HashIDTableOffset = GetHashIDTableOffset();
int HashIDTableSize = GetHashIDTableSize();
InfoFile.Seek(HashIDTableOffset, SeekOrigin.Begin);
byte[] HashIDTable = new byte[HashIDTableSize];
InfoFile.Read(HashIDTable, 0x00, HashIDTableSize);
return HashIDTable;
int HashTableOffset = GetHashTableOffset();
int HashTableSize = GetHashTableSize();
InfoFile.Seek(HashTableOffset, SeekOrigin.Begin);
byte[] HashTable = new byte[HashTableSize];
InfoFile.Read(HashTable, 0x00, HashTableSize);
return HashTable;
}
public byte[] GetIntArrayTable()
@ -339,9 +365,20 @@ namespace CXML
InfoFile.Read(FileTable, 0x00, DataLength);
return FileTable;
}
public int ReadVersion()
public CXML.Version ReadVersionEnum()
{
try
{
return (CXML.Version)ReadVersionInt();
}
catch (Exception)
{
return CXML.Version.UNKNOWN;
}
}
public int ReadVersionInt()
{
return Tools.ReadIntAt(InfoFile, 0x4);
return Tools.ReadLittleEndainIntAt(InfoFile, 0x4);
}
public void AddTypingInfo(string key, object value)
{
@ -405,7 +442,9 @@ namespace CXML
XMLWriter.WriteStartDocument();
XMLWriter.WriteComment(MagicReplacePattern);
AddTypingInfo("MAGIC", MagicNumber);
AddTypingInfo("VERSION", ReadVersion());
AddTypingInfo("VERSION", "0x"+ReadVersionInt().ToString("X"));
AddTypingInfo("ENDAINESS", FileEndainness.ToString());
AddTypingInfo("PS3", ps3 ? "true" : "false");
ReadElements();
XMLWriter.WriteEndDocument();
XMLWriter.Flush();
@ -508,7 +547,7 @@ namespace CXML
try
{
CXMLParser cxmlParser = new CXMLParser();
CXMLReader cxmlParser = new CXMLReader();
cxmlParser.Init(FileName);
cxmlParser.ProcessFiles = this.ProcessFiles;
cxmlParser.MainDir = DirectoryName;
@ -613,11 +652,24 @@ namespace CXML
FileList.Add(lpHandler);
return;
}
public AttributeType ReadAttributeType(Stream ms)
{
if(!ps3)
{
AttributeType type = (AttributeType)tools.ReadInt32(ms);
return type;
}
else
{
AttributeTypePs3 type = (AttributeTypePs3)tools.ReadInt32(ms);
return (AttributeType)Enum.Parse(typeof(AttributeType), type.ToString());
}
}
public void ReadAttribute(String ElementName = "", Int64 ElementPtr = 0)
{
int AttributePtr = bTreeTable.ReadInt32();
AttributeType Type = (AttributeType)bTreeTable.ReadInt32();
int AttributePtr = tools.ReadInt32(TreeTable);
AttributeType Type = ReadAttributeType(TreeTable);
String AttributeName = Tools.ReadStringAt(StringTable, AttributePtr);
object AttributeValue = "";
@ -625,24 +677,23 @@ namespace CXML
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();
int sz = bTreeTable.ReadInt32();
AttributeValue = tools.ReadInt32(TreeTable);
int sz = tools.ReadInt32(TreeTable);
Console.WriteLine("Int - Value: " + AttributeValue.ToString() + " sz:" + sz);
break;
case AttributeType.TYPE_FLOAT:
float FloatValue = bTreeTable.ReadSingle();
AttributeValue = FloatValue.ToString("G9", CultureInfo.InvariantCulture) + "f";
sz = bTreeTable.ReadInt32();
Console.WriteLine("Float - Value: " + AttributeValue.ToString() + " sz:" + sz);
float FloatValue = tools.ReadSingle(TreeTable);
string FloatStr = FloatValue.ToString("G9", CultureInfo.InvariantCulture);
if (!FloatStr.Contains("."))
FloatStr += ".0";
AttributeValue = FloatStr;
sz = tools.ReadInt32(TreeTable);
Console.WriteLine("Float: " + AttributeValue.ToString() + " sz:" + sz);
break;
case AttributeType.TYPE_STRING:
int StringOffset = bTreeTable.ReadInt32();
int StringLen = bTreeTable.ReadInt32();
int StringOffset = tools.ReadInt32(TreeTable);
int StringLen = tools.ReadInt32(TreeTable);
byte[] StringBytes = new byte[StringLen];
StringTable.Seek(StringOffset, 0x00);
@ -651,63 +702,66 @@ namespace CXML
AttributeValue = Encoding.UTF8.GetString(StringBytes);
Console.WriteLine("String: " + AttributeValue);
break;
case AttributeType.TYPE_CHAR:
int CharOffset = bTreeTable.ReadInt32() * 2;
int CharLen = bTreeTable.ReadInt32();
case AttributeType.TYPE_WSTRING:
int WStrOffset = tools.ReadInt32(TreeTable) * 2;
int WStrLen = tools.ReadInt32(TreeTable);
byte[] CharBytes = new byte[CharLen];
CharTable.Seek(CharOffset, 0x00);
CharTable.Read(CharBytes, 0x00, CharLen);
byte[] WStrBytes = new byte[WStrLen];
WStringTable.Seek(WStrOffset, 0x00);
WStringTable.Read(WStrBytes, 0x00, WStrLen);
AttributeValue = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(Encoding.Unicode.GetString(CharBytes)));
Console.WriteLine("Char: " + AttributeValue);
AttributeValue = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(Encoding.Unicode.GetString(WStrBytes)));
Console.WriteLine("WString: " + AttributeValue);
break;
case AttributeType.TYPE_HASH_ID:
int HashTableOffset = bTreeTable.ReadInt32();
int HashTableSize = bTreeTable.ReadInt32();
HashIDTable.Seek(HashTableOffset * 4, SeekOrigin.Begin);
Console.WriteLine("Hash ID Offset:" + HashTableOffset.ToString(CultureInfo.InvariantCulture) + " size: " + HashTableSize);
case AttributeType.TYPE_HASH:
int HashTableOffset = tools.ReadInt32(TreeTable);
int HashTableSize = tools.ReadInt32(TreeTable);
HashTable.Seek(HashTableOffset * 4, SeekOrigin.Begin);
int HashId = bHashIDTable.ReadInt32();
int Hash = tools.ReadInt32(HashTable);
AttributeValue = HashId.ToString("X8", CultureInfo.InvariantCulture);
AttributeValue = Hash.ToString("X8", CultureInfo.InvariantCulture);
Console.WriteLine("Hash: " + AttributeValue.ToString() + " sz: " + HashTableSize);
break;
case AttributeType.TYPE_INTEGER_ARRAY:
int IntArrayOffset = bTreeTable.ReadInt32();
int IntArraySize = bTreeTable.ReadInt32();
int IntArrayOffset = tools.ReadInt32(TreeTable);
int IntArraySize = tools.ReadInt32(TreeTable);
IntArrayTable.Seek(IntArrayOffset*4, SeekOrigin.Begin);
List<int> IntList = new List<int>();
for (int i = 0; i < IntArraySize; i++)
{
int IntValue = bIntArrayTable.ReadInt32();
int IntValue = tools.ReadInt32(IntArrayTable);
IntList.Add(IntValue);
}
int[] IntArray = IntList.ToArray();
AttributeValue = "[" + String.Join(", ", IntArray) + "]";
AttributeValue = String.Join(",", IntArray);
Console.WriteLine("Int Array: " + AttributeValue.ToString());
break;
case AttributeType.TYPE_FLOAT_ARRAY:
int FloatArrayOffset = bTreeTable.ReadInt32();
int FloatArraySize = bTreeTable.ReadInt32();
int FloatArrayOffset = tools.ReadInt32(TreeTable);
int FloatArraySize = tools.ReadInt32(TreeTable);
FloatArrayTable.Seek(FloatArrayOffset*4, SeekOrigin.Begin);
List<string> StrList = new List<string>();
for(int i = 0; i < FloatArraySize; i++)
{
FloatValue = bFloatArrayTable.ReadSingle();
StrList.Add(FloatValue.ToString("G9", CultureInfo.InvariantCulture) +"f");
FloatValue = tools.ReadSingle(FloatArrayTable);
FloatStr = FloatValue.ToString("G9", CultureInfo.InvariantCulture);
if (!FloatStr.Contains("."))
FloatStr += ".0";
StrList.Add(FloatStr);
}
string[] StrArray = StrList.ToArray();
AttributeValue = "[" + String.Join(", ", StrArray) + "]";
AttributeValue = String.Join(", ", StrArray);
Console.WriteLine("Float Array: " + AttributeValue.ToString());
break;
case AttributeType.TYPE_FILE:
int FilePtr = bTreeTable.ReadInt32();
int FileSz = bTreeTable.ReadInt32();
int FilePtr = tools.ReadInt32(TreeTable);
int FileSz = tools.ReadInt32(TreeTable);
Byte[] FileData = new Byte[FileSz];
FileTable.Seek(FilePtr, SeekOrigin.Begin);
@ -725,40 +779,40 @@ namespace CXML
AttributeValue = ReplacePattern;
break;
case AttributeType.TYPE_ID_STRING_LOOPBACK:
int StringIdTableOffset = bTreeTable.ReadInt32();
StringIDTable.Seek(StringIdTableOffset, SeekOrigin.Begin);
case AttributeType.TYPE_ID_REF:
int StringIdTableOffset = tools.ReadInt32(TreeTable);
IDTable.Seek(StringIdTableOffset, SeekOrigin.Begin);
int LoopbackPtr = bStringIDTable.ReadInt32();
int StringPtr = Tools.ReadIntAt(TreeTable, LoopbackPtr);
int LoopbackPtr = tools.ReadInt32(IDTable);
int StringPtr = tools.ReadIntAt(TreeTable, LoopbackPtr);
string LoopbackAttribute = Tools.ReadStringAt(StringTable, StringPtr);
Console.WriteLine("Loopback: " + LoopbackAttribute +" "+ LoopbackPtr.ToString("X")+" ("+ElementPtr.ToString("X")+")");
AttributeValue = Tools.ReadString(StringIDTable);
AttributeValue = Tools.ReadString(IDTable);
RegisterFile(LoopbackPtr, AttributeValue.ToString(), false);
sz = bTreeTable.ReadInt32();
sz = tools.ReadInt32(TreeTable);
Console.WriteLine("Loopback ID String: " + StringIdTableOffset + " sz: " + sz);
Console.WriteLine("ID Ref: " + StringIdTableOffset + " sz: " + sz);
break;
case AttributeType.TYPE_ID_STRING: // This is probably right, tbh
StringIdTableOffset = bTreeTable.ReadInt32();
StringIDTable.Seek(StringIdTableOffset + 4, SeekOrigin.Begin);
case AttributeType.TYPE_ID:
StringIdTableOffset = tools.ReadInt32(TreeTable);
IDTable.Seek(StringIdTableOffset + 4, SeekOrigin.Begin);
AttributeValue = Tools.ReadString(StringIDTable);
AttributeValue = Tools.ReadString(IDTable);
sz = bTreeTable.ReadInt32();
Console.WriteLine("ID String: " + StringIdTableOffset + " sz: " + sz);
sz = tools.ReadInt32(TreeTable);
Console.WriteLine("ID : " + StringIdTableOffset + " sz: " + sz);
break;
case AttributeType.TYPE_ID_INT_LOOPBACK:
int IntIdTableOffset = bTreeTable.ReadInt32();
IntIDTable.Seek(IntIdTableOffset, SeekOrigin.Begin);
case AttributeType.TYPE_ID_HASH_REF:
int IntIdTableOffset = tools.ReadInt32(TreeTable);
HashIDTable.Seek(IntIdTableOffset, SeekOrigin.Begin);
LoopbackPtr = bIntIDTable.ReadInt32();
StringPtr = Tools.ReadIntAt(TreeTable, LoopbackPtr);
LoopbackPtr = tools.ReadInt32(HashIDTable);
StringPtr = tools.ReadIntAt(TreeTable, LoopbackPtr);
int IDValue = bIntIDTable.ReadInt32();
int IDValue = tools.ReadInt32(HashIDTable);
LoopbackAttribute = Tools.ReadStringAt(StringTable, StringPtr);
Console.WriteLine("Int Loopback: " + LoopbackAttribute + " " + LoopbackPtr.ToString("X", CultureInfo.InvariantCulture) + " (" + ElementPtr.ToString("X") + ")");
@ -766,25 +820,25 @@ namespace CXML
AttributeValue = IDValue.ToString("X8", CultureInfo.InvariantCulture);
RegisterFile(LoopbackPtr, AttributeValue.ToString(), false);
sz = bTreeTable.ReadInt32();
Console.WriteLine("Loopback Int: " + IntIdTableOffset + " sz: " + sz);
sz = tools.ReadInt32(TreeTable);
Console.WriteLine("Hash Ref: " + IntIdTableOffset + " sz: " + sz);
break;
case AttributeType.TYPE_ID_INT:
IntIdTableOffset = bTreeTable.ReadInt32();
IntIDTable.Seek(IntIdTableOffset + 4, SeekOrigin.Begin);
IDValue = bIntIDTable.ReadInt32();
case AttributeType.TYPE_ID_HASH:
IntIdTableOffset = tools.ReadInt32(TreeTable);
HashIDTable.Seek(IntIdTableOffset + 4, SeekOrigin.Begin);
IDValue = tools.ReadInt32(HashIDTable);
AttributeValue = IDValue.ToString("X8", CultureInfo.InvariantCulture);
sz = bTreeTable.ReadInt32();
Console.WriteLine("Int Id: " + IntIdTableOffset + " sz: " + sz);
break;
sz = tools.ReadInt32(TreeTable);
Console.WriteLine("Hash Id: " + IntIdTableOffset + " sz: " + sz);
break;
case AttributeType.TYPE_NONE:
default:
Console.WriteLine("UNKNOWN TYPE @ " + TreeTable.Position);
Console.ReadKey();
new NotImplementedException("UNKNOWN TYPE @ " + TreeTable.Position);
break;
};
AddTypingInfo(ElementName + ":" + AttributeName, ((int)Type).ToString(CultureInfo.InvariantCulture));
AddTypingInfo(ElementName + ":" + AttributeName, Type.ToString());
Console.WriteLine(AttributeName + "=" + AttributeValue.ToString());
XMLWriter.WriteAttributeString(AttributeName, AttributeValue.ToString());
XMLWriter.Flush();
@ -793,15 +847,15 @@ namespace CXML
public void ReadElements()
{
Int64 ElementLocation = TreeTable.Position;
int ElementPtr = bTreeTable.ReadInt32();
int NumAttributes = bTreeTable.ReadInt32();
int ElementPtr = tools.ReadInt32(TreeTable);
int NumAttributes = tools.ReadInt32(TreeTable);
int ParentPtr = bTreeTable.ReadInt32();
int PrevSibling = bTreeTable.ReadInt32();
int NextSibling = bTreeTable.ReadInt32();
int ParentPtr = tools.ReadInt32(TreeTable);
int PrevSibling = tools.ReadInt32(TreeTable);
int NextSibling = tools.ReadInt32(TreeTable);
int FirstChild = bTreeTable.ReadInt32();
int LastChild = bTreeTable.ReadInt32();
int FirstChild = tools.ReadInt32(TreeTable);
int LastChild = tools.ReadInt32(TreeTable);
String ElementName = Tools.ReadStringAt(StringTable, ElementPtr);
Console.WriteLine("Creating Element: " + ElementName);

View File

@ -1,13 +0,0 @@
using System;
namespace CXML
{
public class LoopbackHandler
{
public String FileName;
public String OldFileName;
public String ReplacePattern;
public byte[] FileData;
public Int64 FilePointer;
}
}

View File

@ -48,31 +48,33 @@ namespace CXMLCli
if (args.Length == 0)
{
Console.WriteLine("-- app.info/CXML Decompiler --");
Console.WriteLine("I like to see girls die :3");
Console.WriteLine("-- CXML Decompiler --");
Console.WriteLine("Required Arguments:");
Console.WriteLine("\t<input_filename>");
Console.WriteLine("Optional Arguments:");
Console.WriteLine("\t-iv --is-vag File is HE-VAG audio and NOT CXML");
Console.WriteLine("\t-dc --decompress Decompress .Z File");
Console.WriteLine("\t-cc --compress Compress back to .Z File");
Console.WriteLine("\t-f --force Dont check magic number.");
Console.WriteLine("\t-dt --dump-tables Dump ALL tables.");
Console.WriteLine("\t-tt --dump-tree Dump tree table.");
Console.WriteLine("\t-ist --dump-string-id Dump string ID table.");
Console.WriteLine("\t-iit --dump-int-id Dump int ID table.");
Console.WriteLine("\t-st --dump-string Dump string table.");
Console.WriteLine("\t-ct --dump-char Dump char table.");
Console.WriteLine("\t-hit --dump-hash-id Dump hash ID table.");
Console.WriteLine("\t-iat --dump-int-array Dump int array table.");
Console.WriteLine("\t-fat --dump-float-array Dump float array table.");
Console.WriteLine("\t-ft --dump-file Dump file table.");
Console.WriteLine("\t-p --process-files Process Extracted Files");
Console.WriteLine("\t-nr --no-recursive Do not recursively decompile .RCS to XML");
Console.WriteLine("\t-w --wait-exit Wait for keypress before exiting");
Console.WriteLine("\t-d --decompile Decompile CXML to XML.");
Console.WriteLine("\t-c --compile Compile XML to CXML");
Console.WriteLine("\t-h --hash-string When Compiling, Generate new hashes");
Console.WriteLine("\t-iv --is-vag File is HE-VAG audio and NOT CXML");
Console.WriteLine("\t-dc --decompress Decompress .Z File");
Console.WriteLine("\t-cc --compress Compress back to .Z File");
Console.WriteLine("\t-f --force Dont check magic number.");
Console.WriteLine("\t-dt --dump-tables Dump ALL tables.");
Console.WriteLine("\t-tt --dump-tree Dump tree table.");
Console.WriteLine("\t-idt --dump-id Dump id ID table.");
Console.WriteLine("\t-iht --dump-hash-id Dump hash ID table.");
Console.WriteLine("\t-st --dump-string Dump string table.");
Console.WriteLine("\t-wt --dump-wstring Dump wstring table.");
Console.WriteLine("\t-ht --dump-hash Dump hash table.");
Console.WriteLine("\t-iat --dump-int-array Dump int array table.");
Console.WriteLine("\t-fat --dump-float-array Dump float array table.");
Console.WriteLine("\t-ft --dump-file Dump file table.");
Console.WriteLine("\t-le --little-endain De/Encode ints as Little Endain");
Console.WriteLine("\t-be --big-endain De/Encode ints as Big Endain");
Console.WriteLine("\t-ps3 --playstation-3 Use the old CXML Format used back on PS3.");
Console.WriteLine("\t-p --process-files Process Extracted Files");
Console.WriteLine("\t-nr --no-recursive Do not recursively decompile .RCS to XML");
Console.WriteLine("\t-w --wait-exit Wait for keypress before exiting");
Console.WriteLine("\t-d --decompile Decompile CXML to XML.");
Console.WriteLine("\t-c --compile Compile XML to CXML");
Console.WriteLine("\t-h --hash-string When Compiling, Generate new hashes");
Console.WriteLine("Example Decompile: " + Path.GetFileName(Assembly.GetEntryAssembly().Location) + " app.info -d -p");
Console.WriteLine("Example Compile: " + Path.GetFileName(Assembly.GetEntryAssembly().Location) + " app.xml app.info -c");
Console.WriteLine("Default functonality is to Decompile,\nThis is canceled if any other arguments passed.");
@ -118,7 +120,7 @@ namespace CXMLCli
return 0;
}
CXML.CXMLParser cxmlParser = new CXML.CXMLParser();
CXMLReader cxmlParser = new CXMLReader();
if(!HasArg(ArgsFull, "-c") && !HasArg(ArgsFull, "--compile"))
{
Console.WriteLine("Initalizing: " + path);
@ -133,7 +135,7 @@ namespace CXMLCli
if (HasArg(ArgsFull, "-dt") || HasArg(ArgsFull, "--dump-tables"))
{
ArgsFull += " -tt -ist -iit -st -ct -sit -iat -fat -ft";
ArgsFull += " --dump-tree --dump-id --dump-hash-id --dump-string --dump-wstring --dump-hash --dump-int-array --dump-float-array --dump-file ";
}
if (HasArg(ArgsFull, "-tt") || HasArg(ArgsFull, "--dump-tree"))
@ -143,17 +145,17 @@ namespace CXMLCli
}
if (HasArg(ArgsFull, "-ist") || HasArg(ArgsFull, "--dump-string-id"))
if (HasArg(ArgsFull, "-idt") || HasArg(ArgsFull, "--dump-id"))
{
Console.WriteLine("Dumping string ID table.");
File.WriteAllBytes("string-id-table.bin", cxmlParser.GetStringIDTable());
Console.WriteLine("Dumping ID table.");
File.WriteAllBytes("id-table.bin", cxmlParser.GetIDTable());
}
if (HasArg(ArgsFull, "-iit") || HasArg(ArgsFull, "--dump-int-id"))
if (HasArg(ArgsFull, "-iht") || HasArg(ArgsFull, "--dump-hash-id"))
{
Console.WriteLine("Dumping int ID table.");
File.WriteAllBytes("int-id-table.bin", cxmlParser.GetIntIDTable());
Console.WriteLine("Dumping hash ID table.");
File.WriteAllBytes("hash-id-table.bin", cxmlParser.GetHashIDTable());
}
if (HasArg(ArgsFull, "-st") || HasArg(ArgsFull, "--dump-string"))
@ -163,16 +165,16 @@ namespace CXMLCli
}
if (HasArg(ArgsFull, "-ct") || HasArg(ArgsFull, "--dump-char"))
if (HasArg(ArgsFull, "-wt") || HasArg(ArgsFull, "--dump-wstring"))
{
Console.WriteLine("Dumping char table.");
File.WriteAllBytes("char-table.bin", cxmlParser.GetCharTable());
Console.WriteLine("Dumping wstring table.");
File.WriteAllBytes("wstring-table.bin", cxmlParser.GetWStringTable());
}
if ((HasArg(ArgsFull, "-sit") || HasArg(ArgsFull, "--dump-style-id")) /*kept for backwards comp*/ || (HasArg(ArgsFull, "-hit") || HasArg(ArgsFull, "--dump-hash-id")))
if (HasArg(ArgsFull, "-ht") || HasArg(ArgsFull, "--dump-hash"))
{
Console.WriteLine("Dumping hash ID table.");
File.WriteAllBytes("hash-id-table.bin", cxmlParser.GetHashIDTable());
Console.WriteLine("Dumping hash table.");
File.WriteAllBytes("hash-table.bin", cxmlParser.GetHashTable());
}

View File

@ -6,9 +6,21 @@ using System.Security.Cryptography;
using System.Text;
namespace General
{
{
enum Endainness
{
LITTLE_ENDAIN,
BIG_ENDAIN,
UNCHANGED
};
class Tools
{
public Tools(bool bigEndain)
{
BigEndain = bigEndain;
}
public bool BigEndain = false;
public static byte[] bmp = Encoding.ASCII.GetBytes("BM"); // BMP
public static byte[] gif = Encoding.ASCII.GetBytes("GIF"); // GIF
@ -197,24 +209,59 @@ namespace General
return str;
}
public static int ReadIntAt(Stream ms, int location)
public static int ReadLittleEndainIntAt(Stream ms, int location)
{
BinaryReader BinReader = new BinaryReader(ms);
long ogPos = ms.Position;
ms.Seek(location, SeekOrigin.Begin);
int i = BinReader.ReadInt32();
int i = ReadLittleEndainInt(ms);
ms.Seek(ogPos, SeekOrigin.Begin);
return i;
}
public int ReadIntAt(Stream ms, int location)
{
long ogPos = ms.Position;
ms.Seek(location, SeekOrigin.Begin);
int i = ReadInt32(ms);
ms.Seek(ogPos, SeekOrigin.Begin);
return i;
}
public static bool HasBinaryContent(string content)
{
return content.Any(ch => char.IsControl(ch) && ch != '\r' && ch != '\n');
}
public static int ReadInt(Stream ms)
}
public void WriteInt32(Stream ms, int val)
{
BinaryReader BinReader = new BinaryReader(ms);
int i = BinReader.ReadInt32();
return i;
if (BigEndain)
WriteBigEndainInt(ms, val);
else
WriteLittleEndainInt(ms, val);
}
public void WriteSingle(Stream ms, Single val)
{
if (BigEndain)
WriteBigEndainSingle(ms, val);
else
WriteLittleEndainSingle(ms, val);
}
public int ReadInt32(Stream ms)
{
if (BigEndain)
return ReadBigEndainInt(ms);
else
return ReadLittleEndainInt(ms);
}
public Single ReadSingle(Stream ms)
{
if (BigEndain)
return ReadBigEndainSingle(ms);
else
return ReadLittleEndainSingle(ms);
}
public static int ReadBigEndainIntAt(Stream ms, int location)
@ -225,7 +272,54 @@ namespace General
ms.Seek(ogPos, SeekOrigin.Begin);
return i;
}
public static Single ReadBigEndainSingle(Stream ms)
{
byte[] SingleBytes = new byte[4];
ms.Read(SingleBytes, 0x00, 4);
SingleBytes = SingleBytes.Reverse().ToArray();
Single val = BitConverter.ToSingle(SingleBytes, 0x00);
return val;
}
public static Single ReadLittleEndainSingle(Stream ms)
{
byte[] SingleBytes = new byte[4];
ms.Read(SingleBytes, 0x00, 4);
SingleBytes = SingleBytes.ToArray();
Single val = BitConverter.ToSingle(SingleBytes, 0x00);
return val;
}
public static void WriteLittleEndainSingle(Stream ms, Single val)
{
byte[] SingleBytes = BitConverter.GetBytes(val);
ms.Write(SingleBytes, 0x00, SingleBytes.Length);
}
public static void WriteBigEndainSingle(Stream ms, Single val)
{
byte[] SingleBytes = BitConverter.GetBytes(val);
SingleBytes = SingleBytes.Reverse().ToArray();
ms.Write(SingleBytes, 0x00, SingleBytes.Length);
}
public static void WriteLittleEndainInt(Stream ms, int val)
{
byte[] IntBytes = BitConverter.GetBytes(val);
ms.Write(IntBytes, 0x00, IntBytes.Length);
}
public static void WriteBigEndainInt(Stream ms, int val)
{
byte[] IntBytes = BitConverter.GetBytes(val);
IntBytes = IntBytes.Reverse().ToArray();
ms.Write(IntBytes, 0x00, IntBytes.Length);
}
public static int ReadLittleEndainInt(Stream ms)
{
byte[] IntBytes = new byte[4];
ms.Read(IntBytes, 0x00, 4);
IntBytes = IntBytes.ToArray();
int i = BitConverter.ToInt32(IntBytes, 0x00);
return i;
}
public static int ReadBigEndainInt(Stream ms)
{
byte[] IntBytes = new byte[4];