From 0aa6de7b9c88cb8b07b5c9be434c7affed2e713a Mon Sep 17 00:00:00 2001 From: Li Date: Sun, 19 Jun 2022 16:29:29 +1200 Subject: [PATCH] Add support for ps3 cxml --- CXMLCli/CXML.cs | 55 ++++ CXMLCli/CXMLBuilder.cs | 397 +++++++++++++++-------------- CXMLCli/CXMLCli.csproj | 2 +- CXMLCli/CXMLCli.csproj.user | 7 + CXMLCli/CXMLReader.cs | 486 ++++++++++++++++++++---------------- CXMLCli/LoopbackHandler.cs | 13 - CXMLCli/Program.cs | 74 +++--- CXMLCli/Tools.cs | 114 ++++++++- 8 files changed, 681 insertions(+), 467 deletions(-) create mode 100644 CXMLCli/CXML.cs create mode 100644 CXMLCli/CXMLCli.csproj.user delete mode 100644 CXMLCli/LoopbackHandler.cs diff --git a/CXMLCli/CXML.cs b/CXMLCli/CXML.cs new file mode 100644 index 0000000..020b50f --- /dev/null +++ b/CXMLCli/CXML.cs @@ -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; + } + +} diff --git a/CXMLCli/CXMLBuilder.cs b/CXMLCli/CXMLBuilder.cs index e0a3d45..42f413a 100644 --- a/CXMLCli/CXMLBuilder.cs +++ b/CXMLCli/CXMLBuilder.cs @@ -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 TreeTableEntries = new List(); List StringTableEntries = new List(); - List CharTableEntries = new List(); - List HashIdTableEntries = new List(); + List WStringTableEntries = new List(); + List HashTableEntries = new List(); List IntArrayTableEntries = new List(); List FloatArrayTableEntries = new List(); List FileTableEntries = new List(); - List StringIDTableEntries = new List(); - List IntIDTableEntries = new List(); + List IDTableEntries = new List(); + List HashIDTableEntries = new List(); 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(); } diff --git a/CXMLCli/CXMLCli.csproj b/CXMLCli/CXMLCli.csproj index cbcae8e..d50b2b6 100644 --- a/CXMLCli/CXMLCli.csproj +++ b/CXMLCli/CXMLCli.csproj @@ -93,10 +93,10 @@ + - diff --git a/CXMLCli/CXMLCli.csproj.user b/CXMLCli/CXMLCli.csproj.user new file mode 100644 index 0000000..2cc53d9 --- /dev/null +++ b/CXMLCli/CXMLCli.csproj.user @@ -0,0 +1,7 @@ + + + + sample\sample.xml sample2.cxml --compile + C:\Users\User\Documents\git\cxml-decompiler\CXMLCli\bin\x64\Debug + + \ No newline at end of file diff --git a/CXMLCli/CXMLReader.cs b/CXMLCli/CXMLReader.cs index 09170d4..b061ca2 100644 --- a/CXMLCli/CXMLReader.cs +++ b/CXMLCli/CXMLReader.cs @@ -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 FileList = new List(); 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 IntList = new List(); 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 StrList = new List(); 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); diff --git a/CXMLCli/LoopbackHandler.cs b/CXMLCli/LoopbackHandler.cs deleted file mode 100644 index fdc356d..0000000 --- a/CXMLCli/LoopbackHandler.cs +++ /dev/null @@ -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; - } -} diff --git a/CXMLCli/Program.cs b/CXMLCli/Program.cs index 337c876..dada6f7 100644 --- a/CXMLCli/Program.cs +++ b/CXMLCli/Program.cs @@ -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"); 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()); } diff --git a/CXMLCli/Tools.cs b/CXMLCli/Tools.cs index 7ab6f7f..8749820 100644 --- a/CXMLCli/Tools.cs +++ b/CXMLCli/Tools.cs @@ -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];