From aa22ca34a92c8c8d3ec401baaa1e5a056ac672fa Mon Sep 17 00:00:00 2001 From: Peter Dolkens Date: Fri, 26 Feb 2016 09:31:17 +0000 Subject: [PATCH 1/5] Work on reversing Data Forge --- .gitignore | 1 + .../{BinaryNode.cs => CryXmlNode.cs} | 2 +- ...{BinaryReference.cs => CryXmlReference.cs} | 2 +- HoloXPLOR.DataForge/CryXmlSerializer.cs | 220 +++++++ .../{BinaryValue.cs => CryXmlValue.cs} | 2 +- HoloXPLOR.DataForge/DataForge.cs | 582 ++++++++++++------ HoloXPLOR.DataForge/DataForgeSerializable.cs | 190 ++++++ .../HoloXPLOR.DataForge.csproj | 13 +- HoloXPLOR.DataForge/Program.cs | 476 +++++++++++++- HoloXPLOR/Scripts.cs | 10 +- 10 files changed, 1291 insertions(+), 207 deletions(-) rename HoloXPLOR.DataForge/{BinaryNode.cs => CryXmlNode.cs} (95%) rename HoloXPLOR.DataForge/{BinaryReference.cs => CryXmlReference.cs} (88%) create mode 100644 HoloXPLOR.DataForge/CryXmlSerializer.cs rename HoloXPLOR.DataForge/{BinaryValue.cs => CryXmlValue.cs} (89%) create mode 100644 HoloXPLOR.DataForge/DataForgeSerializable.cs diff --git a/.gitignore b/.gitignore index dac0ced..db3f3eb 100644 --- a/.gitignore +++ b/.gitignore @@ -202,5 +202,6 @@ publish *.xpi *.crx +*.dcb App_Data smtp.config \ No newline at end of file diff --git a/HoloXPLOR.DataForge/BinaryNode.cs b/HoloXPLOR.DataForge/CryXmlNode.cs similarity index 95% rename from HoloXPLOR.DataForge/BinaryNode.cs rename to HoloXPLOR.DataForge/CryXmlNode.cs index d329ed9..c393ab3 100644 --- a/HoloXPLOR.DataForge/BinaryNode.cs +++ b/HoloXPLOR.DataForge/CryXmlNode.cs @@ -6,7 +6,7 @@ namespace HoloXPLOR.DataForge { - public class BinaryNode + public class CryXmlNode { public Int32 NodeID { get; set; } public Int32 NodeNameOffset { get; set; } diff --git a/HoloXPLOR.DataForge/BinaryReference.cs b/HoloXPLOR.DataForge/CryXmlReference.cs similarity index 88% rename from HoloXPLOR.DataForge/BinaryReference.cs rename to HoloXPLOR.DataForge/CryXmlReference.cs index d044ee4..66df403 100644 --- a/HoloXPLOR.DataForge/BinaryReference.cs +++ b/HoloXPLOR.DataForge/CryXmlReference.cs @@ -6,7 +6,7 @@ namespace HoloXPLOR.DataForge { - public class BinaryReference + public class CryXmlReference { public Int32 NameOffset { get; set; } public Int32 ValueOffset { get; set; } diff --git a/HoloXPLOR.DataForge/CryXmlSerializer.cs b/HoloXPLOR.DataForge/CryXmlSerializer.cs new file mode 100644 index 0000000..bc3796a --- /dev/null +++ b/HoloXPLOR.DataForge/CryXmlSerializer.cs @@ -0,0 +1,220 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using System.Xml.Serialization; + +namespace HoloXPLOR.DataForge +{ + public static class CryXmlSerializer + { + public static XmlDocument ReadFile(String inFile, Boolean writeLog = false) + { + using (BinaryReader br = new BinaryReader(File.OpenRead(inFile))) + { + String header = br.ReadCString(); + + if (header != "CryXmlB") + { + throw new Exception("Unknown File Format"); + } + + var headerLength = br.BaseStream.Position; + var fileLength = br.ReadInt32(); + + var nodeTableOffset = br.ReadInt32(); + var nodeTableCount = br.ReadInt32(); + var nodeTableSize = 28; + + var referenceTableOffset = br.ReadInt32(); + var referenceTableCount = br.ReadInt32(); + var referenceTableSize = 8; + + var offset3 = br.ReadInt32(); + var count3 = br.ReadInt32(); + var length3 = 4; + + var contentOffset = br.ReadInt32(); + var contentLength = br.ReadInt32(); + + if (writeLog) + { + // Regex byteFormatter = new Regex("([0-9A-F]{8})"); + Console.WriteLine("Header"); + Console.WriteLine("0x{0:X6}: {1}", 0x00, header); + Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x00, fileLength); + Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x04, nodeTableOffset); + Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x08, nodeTableCount); + Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x12, referenceTableOffset); + Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x16, referenceTableCount); + Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x20, offset3); + Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x24, count3); + Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x28, contentOffset); + Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x32, contentLength); + Console.WriteLine(""); + Console.WriteLine("Node Table"); + } + + List nodeTable = new List { }; + br.BaseStream.Seek(nodeTableOffset, SeekOrigin.Begin); + Int32 nodeID = 0; + while (br.BaseStream.Position < nodeTableOffset + nodeTableCount * nodeTableSize) + { + var position = br.BaseStream.Position; + var value = new CryXmlNode + { + NodeID = nodeID++, + NodeNameOffset = br.ReadInt32(), + ItemType = br.ReadInt32(), + AttributeCount = br.ReadInt16(), + ChildCount = br.ReadInt16(), + ParentNodeID = br.ReadInt32(), + FirstAttributeIndex = br.ReadInt32(), + FirstChildIndex = br.ReadInt32(), + Reserved = br.ReadInt32(), + }; + + nodeTable.Add(value); + if (writeLog) + { + Console.WriteLine( + "0x{0:X6}: {1:X8} {2:X8} {3:X4} {4:X4} {5:X8} {6:X8} {7:X8} {8:X8}", + position, + value.NodeNameOffset, + value.ItemType, + value.AttributeCount, + value.ChildCount, + value.ParentNodeID, + value.FirstAttributeIndex, + value.FirstChildIndex, + value.Reserved); + } + } + + if (writeLog) + { + Console.WriteLine(""); + Console.WriteLine("Reference Table"); + } + + List attributeTable = new List { }; + br.BaseStream.Seek(referenceTableOffset, SeekOrigin.Begin); + while (br.BaseStream.Position < referenceTableOffset + referenceTableCount * referenceTableSize) + { + var position = br.BaseStream.Position; + var value = new CryXmlReference + { + NameOffset = br.ReadInt32(), + ValueOffset = br.ReadInt32() + }; + + attributeTable.Add(value); + if (writeLog) + { + Console.WriteLine("0x{0:X6}: {1:X8} {2:X8}", position, value.NameOffset, value.ValueOffset); + } + } + if (writeLog) + { + Console.WriteLine(""); + Console.WriteLine("Order Table"); + } + + List table3 = new List { }; + br.BaseStream.Seek(offset3, SeekOrigin.Begin); + while (br.BaseStream.Position < offset3 + count3 * length3) + { + var position = br.BaseStream.Position; + var value = br.ReadInt32(); + + table3.Add(value); + if (writeLog) + { + Console.WriteLine("0x{0:X6}: {1:X8}", position, value); + } + } + + if (writeLog) + { + Console.WriteLine(""); + Console.WriteLine("Dynamic Dictionary"); + } + + List dataTable = new List { }; + br.BaseStream.Seek(contentOffset, SeekOrigin.Begin); + while (br.BaseStream.Position < br.BaseStream.Length) + { + var position = br.BaseStream.Position; + var value = new CryXmlValue + { + Offset = (Int32)position - contentOffset, + Value = br.ReadCString(), + }; + dataTable.Add(value); + if (writeLog) + { + Console.WriteLine("0x{0:X6}: {1:X8} {2}", position, value.Offset, value.Value); + } + } + + var dataMap = dataTable.ToDictionary(k => k.Offset, v => v.Value); + + var attributeIndex = 0; + + var xmlDoc = new XmlDocument(); + + var bugged = false; + + Dictionary xmlMap = new Dictionary { }; + foreach (var node in nodeTable) + { + XmlElement element = xmlDoc.CreateElement(dataMap[node.NodeNameOffset]); + + for (Int32 i = 0, j = node.AttributeCount; i < j; i++) + { + if (dataMap.ContainsKey(attributeTable[attributeIndex].ValueOffset)) + { + element.SetAttribute(dataMap[attributeTable[attributeIndex].NameOffset], dataMap[attributeTable[attributeIndex].ValueOffset]); + } + else + { + bugged = true; + element.SetAttribute(dataMap[attributeTable[attributeIndex].NameOffset], "BUGGED"); + } + attributeIndex++; + } + + xmlMap[node.NodeID] = element; + if (xmlMap.ContainsKey(node.ParentNodeID)) + xmlMap[node.ParentNodeID].AppendChild(element); + else + xmlDoc.AppendChild(element); + } + + return xmlDoc; + } + } + + public static TObject Deserialize(String inFile) where TObject : class + { + using (MemoryStream ms = new MemoryStream()) + { + var xmlDoc = CryXmlSerializer.ReadFile(inFile); + + xmlDoc.Save(ms); + + ms.Seek(0, SeekOrigin.Begin); + + XmlSerializer xs = new XmlSerializer(typeof(TObject)); + + return xs.Deserialize(ms) as TObject; + } + } + } +} \ No newline at end of file diff --git a/HoloXPLOR.DataForge/BinaryValue.cs b/HoloXPLOR.DataForge/CryXmlValue.cs similarity index 89% rename from HoloXPLOR.DataForge/BinaryValue.cs rename to HoloXPLOR.DataForge/CryXmlValue.cs index 153c020..6fc0044 100644 --- a/HoloXPLOR.DataForge/BinaryValue.cs +++ b/HoloXPLOR.DataForge/CryXmlValue.cs @@ -6,7 +6,7 @@ namespace HoloXPLOR.DataForge { - public class BinaryValue + public class CryXmlValue { public Int32 Offset { get; set; } public String Value { get; set; } diff --git a/HoloXPLOR.DataForge/DataForge.cs b/HoloXPLOR.DataForge/DataForge.cs index e291b05..dc957c8 100644 --- a/HoloXPLOR.DataForge/DataForge.cs +++ b/HoloXPLOR.DataForge/DataForge.cs @@ -1,214 +1,412 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Text; -using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Xml; -using System.Xml.Linq; -using System.Xml.Serialization; namespace HoloXPLOR.DataForge { - public static class DataForgeSerializer + public class DataForge : DataForgeSerializable { - public static XmlDocument ReadFile(String inFile, Boolean writeLog = false) + public Int64 FileVersion { get; set; } + public DataForgeTypeDefinition[] TypeDefinitionTable { get; set; } + public DataForgePropertyDefinition[] PropertyDefinitionTable { get; set; } + public DataForgeEnumDefinition[] EnumDefinitionTable { get; set; } + public DataForgeRecord4[] RecordTable4 { get; set; } + public DataForgeSchema[] SchemaTable { get; set; } + public DataForgeStringLookup[] EnumValueTable { get; set; } + public DataForgeString[] ValueTable { get; set; } + + public DataForge(BinaryReader br) + : base(br) { - using (BinaryReader br = new BinaryReader(File.OpenRead(inFile))) + this.FileVersion = br.ReadInt64(); + + var numRecords1 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords2 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords3 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords4 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords5 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords6 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords7 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords8 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords9 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords10 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords11 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords12 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords13 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords14 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords15 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords16 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords17 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords18 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords19 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords20 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords21 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords22 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords23 = br.ReadUInt16(); br.ReadUInt16(); + var numRecords24 = br.ReadUInt16(); br.ReadUInt16(); + var totalLength25 = br.ReadUInt32(); + + br.BaseStream.Seek(0x0000006c, SeekOrigin.Begin); + + this.TypeDefinitionTable = this.ReadArray(numRecords1); + this.PropertyDefinitionTable = this.ReadArray(numRecords2); + this.EnumDefinitionTable = this.ReadArray(numRecords3); + this.RecordTable4 = this.ReadArray(numRecords4); + this.SchemaTable = this.ReadArray(numRecords5); + + var temp6 = this.ReadArray(numRecords6); + var temp7 = this.ReadArray(numRecords7); + var temp8 = this.ReadArray(numRecords8); + var temp9 = this.ReadArray(numRecords9); + var temp10 = this.ReadArray(numRecords10); + var temp11 = this.ReadArray(numRecords11); + var temp12 = this.ReadArray(numRecords12); + var temp13 = this.ReadArray(numRecords13); + var temp14 = this.ReadArray(numRecords14); + var temp15 = this.ReadArray(numRecords15); + var temp16 = this.ReadArray(numRecords16); + var temp17 = this.ReadArray(numRecords17); + var temp18 = this.ReadArray(numRecords18); + var temp19 = this.ReadArray(numRecords19); + var temp20 = this.ReadArray(numRecords20); + var temp21 = this.ReadArray(numRecords21); + var temp22 = this.ReadArray(numRecords22); + + var wrong = br.BaseStream.Position - 0x0002e4d4; + + // HACK: Skip unknown tables at this stage + br.BaseStream.Seek(0x0002e4d4, SeekOrigin.Begin); + + var temp23 = this.ReadArray(numRecords23); + + br.BaseStream.Seek(0x0002e7cc, SeekOrigin.Begin); + + this.EnumValueTable = this.ReadArray(numRecords24); + + var buffer = new List { }; + var maxPosition = br.BaseStream.Position + totalLength25; + while (br.BaseStream.Position < maxPosition) { - String header = br.ReadCString(); - var headerLength = br.BaseStream.Position; - var fileLength = br.ReadInt32(); - - var nodeTableOffset = br.ReadInt32(); - var nodeTableCount = br.ReadInt32(); - var nodeTableSize = 28; - - var referenceTableOffset = br.ReadInt32(); - var referenceTableCount = br.ReadInt32(); - var referenceTableSize = 8; - - var offset3 = br.ReadInt32(); - var count3 = br.ReadInt32(); - var length3 = 4; - - var contentOffset = br.ReadInt32(); - var contentLength = br.ReadInt32(); - - if (writeLog) - { - // Regex byteFormatter = new Regex("([0-9A-F]{8})"); - Console.WriteLine("Header"); - Console.WriteLine("0x{0:X6}: {1}", 0x00, header); - Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x00, fileLength); - Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x04, nodeTableOffset); - Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x08, nodeTableCount); - Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x12, referenceTableOffset); - Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x16, referenceTableCount); - Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x20, offset3); - Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x24, count3); - Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x28, contentOffset); - Console.WriteLine("0x{0:X6}: {1:X8} (Dec: {1:D8})", headerLength + 0x32, contentLength); - Console.WriteLine(""); - Console.WriteLine("Node Table"); - } - - List nodeTable = new List { }; - br.BaseStream.Seek(nodeTableOffset, SeekOrigin.Begin); - Int32 nodeID = 0; - while (br.BaseStream.Position < nodeTableOffset + nodeTableCount * nodeTableSize) - { - var position = br.BaseStream.Position; - var value = new BinaryNode - { - NodeID = nodeID++, - NodeNameOffset = br.ReadInt32(), - ItemType = br.ReadInt32(), - AttributeCount = br.ReadInt16(), - ChildCount = br.ReadInt16(), - ParentNodeID = br.ReadInt32(), - FirstAttributeIndex = br.ReadInt32(), - FirstChildIndex = br.ReadInt32(), - Reserved = br.ReadInt32(), - }; - - nodeTable.Add(value); - if (writeLog) - { - Console.WriteLine( - "0x{0:X6}: {1:X8} {2:X8} {3:X4} {4:X4} {5:X8} {6:X8} {7:X8} {8:X8}", - position, - value.NodeNameOffset, - value.ItemType, - value.AttributeCount, - value.ChildCount, - value.ParentNodeID, - value.FirstAttributeIndex, - value.FirstChildIndex, - value.Reserved); - } - } - - if (writeLog) - { - Console.WriteLine(""); - Console.WriteLine("Reference Table"); - } - - List attributeTable = new List { }; - br.BaseStream.Seek(referenceTableOffset, SeekOrigin.Begin); - while (br.BaseStream.Position < referenceTableOffset + referenceTableCount * referenceTableSize) - { - var position = br.BaseStream.Position; - var value = new BinaryReference - { - NameOffset = br.ReadInt32(), - ValueOffset = br.ReadInt32() - }; - - attributeTable.Add(value); - if (writeLog) - { - Console.WriteLine("0x{0:X6}: {1:X8} {2:X8}", position, value.NameOffset, value.ValueOffset); - } - } - if (writeLog) - { - Console.WriteLine(""); - Console.WriteLine("Order Table"); - } - - List table3 = new List { }; - br.BaseStream.Seek(offset3, SeekOrigin.Begin); - while (br.BaseStream.Position < offset3 + count3 * length3) - { - var position = br.BaseStream.Position; - var value = br.ReadInt32(); - - table3.Add(value); - if (writeLog) - { - Console.WriteLine("0x{0:X6}: {1:X8}", position, value); - } - } - - if (writeLog) - { - Console.WriteLine(""); - Console.WriteLine("Dynamic Dictionary"); - } - - List dataTable = new List { }; - br.BaseStream.Seek(contentOffset, SeekOrigin.Begin); - while (br.BaseStream.Position < br.BaseStream.Length) - { - var position = br.BaseStream.Position; - var value = new BinaryValue - { - Offset = (Int32)position - contentOffset, - Value = br.ReadCString(), - }; - dataTable.Add(value); - if (writeLog) - { - Console.WriteLine("0x{0:X6}: {1:X8} {2}", position, value.Offset, value.Value); - } - } - - var dataMap = dataTable.ToDictionary(k => k.Offset, v => v.Value); - - var attributeIndex = 0; - - var xmlDoc = new XmlDocument(); - - var bugged = false; - - Dictionary xmlMap = new Dictionary { }; - foreach (var node in nodeTable) - { - XmlElement element = xmlDoc.CreateElement(dataMap[node.NodeNameOffset]); - - for (Int32 i = 0, j = node.AttributeCount; i < j; i++) - { - if (dataMap.ContainsKey(attributeTable[attributeIndex].ValueOffset)) - { - element.SetAttribute(dataMap[attributeTable[attributeIndex].NameOffset], dataMap[attributeTable[attributeIndex].ValueOffset]); - } - else - { - bugged = true; - element.SetAttribute(dataMap[attributeTable[attributeIndex].NameOffset], "BUGGED"); - } - attributeIndex++; - } - - xmlMap[node.NodeID] = element; - if (xmlMap.ContainsKey(node.ParentNodeID)) - xmlMap[node.ParentNodeID].AppendChild(element); - else - xmlDoc.AppendChild(element); - } - - return xmlDoc; + buffer.Add(new DataForgeString(br)); } + this.ValueTable = buffer.ToArray(); } + } - public static TObject Deserialize(String inFile) where TObject : class + // TODO: Verify this + public class DataForgeTypeDefinition : DataForgeSerializable + { + public String Name { get; set; } + public UInt32 ParentTypeIndex { get; set; } + public UInt16 AttributeCount { get; set; } + public UInt16 FirstAttributeIndex { get; set; } + public UInt32 NodeType { get; set; } + + public DataForgeTypeDefinition(BinaryReader br) + : base(br) { - using (MemoryStream ms = new MemoryStream()) - { - var xmlDoc = DataForgeSerializer.ReadFile(inFile); + this.Name = this.ReadString(); + this.ParentTypeIndex = br.ReadUInt32(); + this.AttributeCount = br.ReadUInt16(); + this.FirstAttributeIndex = br.ReadUInt16(); + this.NodeType = br.ReadUInt32(); + } + } - xmlDoc.Save(ms); + public enum EDataType : ushort + { + varString = 0x000A, + varInteger = 0x000B, + nodeRequired = 0x0010, + nodeOptional = 0x0110, + } - ms.Seek(0, SeekOrigin.Begin); + public enum EConversionType : ushort + { + varSingle = 0x6900, + varChild = 0x6901, + varArray = 0x6902, + } - XmlSerializer xs = new XmlSerializer(typeof(TObject)); + // TODO: Verify this + public class DataForgePropertyDefinition : DataForgeSerializable + { + public String Name { get; set; } + public UInt16 ChildType { get; set; } + public EDataType DataType { get; set; } + public EConversionType ConversionType { get; set; } + public UInt16 Unknown { get; set; } - return xs.Deserialize(ms) as TObject; - } + public DataForgePropertyDefinition(BinaryReader br) + : base(br) + { + this.Name = this.ReadString(); + this.ChildType = br.ReadUInt16(); + this.DataType = (EDataType)br.ReadUInt16(); + this.ConversionType = (EConversionType)br.ReadUInt16(); + this.Unknown = br.ReadUInt16(); + } + } + + public class DataForgeEnumDefinition : DataForgeSerializable + { + public String Name { get; set; } + public UInt16 ValueCount { get; set; } + public UInt16 FirstValueIndex { get; set; } + + public DataForgeEnumDefinition(BinaryReader br) + : base(br) + { + this.Name = this.ReadString(); + this.ValueCount = br.ReadUInt16(); + this.FirstValueIndex = br.ReadUInt16(); + } + } + + public class DataForgeRecord4 : DataForgeSerializable + { + public UInt16 Item1 { get; set; } + public UInt16 Item2 { get; set; } + + public DataForgeRecord4(BinaryReader br) + : base(br) + { + this.Item1 = br.ReadUInt16(); + this.Item2 = br.ReadUInt16(); + } + } + + public class DataForgeSchema : DataForgeSerializable + { + public String Name { get; set; } + public UInt32 TypeIndex { get; set; } + public Guid? Hash { get; set; } + + public UInt16 VariantIndex { get; set; } + public UInt16 Item1 { get; set; } + + public DataForgeSchema(BinaryReader br) + : base(br) + { + this.Name = this.ReadString(); + this.TypeIndex = br.ReadUInt32(); + this.Hash = this.ReadGuid(false); + + this.VariantIndex = br.ReadUInt16(); + this.Item1 = br.ReadUInt16(); + } + } + + public class DataForgeRecord23 : DataForgeSerializable + { + public UInt32 Item1 { get; set; } + public UInt32 Item2 { get; set; } + public UInt32 Item3 { get; set; } + public UInt32 Item4 { get; set; } + public UInt32 Item5 { get; set; } + + public DataForgeRecord23(BinaryReader br) + : base(br) + { + this.Item1 = br.ReadUInt32(); + this.Item2 = br.ReadUInt32(); + this.Item3 = br.ReadUInt32(); + this.Item4 = br.ReadUInt32(); + this.Item5 = br.ReadUInt32(); + } + + public override String ToString() + { + return String.Format("0x{0:X8} 0x{1:X8} 0x{2:X8} 0x{3:X8} 0x{4:X8}", this.Item1, this.Item2, this.Item3, this.Item4, this.Item5); + } + } + + public class DataForgeStringLookup : DataForgeSerializable + { + public String Value { get; set; } + + public DataForgeStringLookup(BinaryReader br) + : base(br) + { + this.Value = this.ReadString(); + } + + public override String ToString() + { + return this.Value; + } + } + + public class DataForgeUInt32 : DataForgeSerializable + { + public UInt32 Value { get; set; } + + public DataForgeUInt32(BinaryReader br) + : base(br) + { + this.Value = br.ReadUInt32(); + } + + public override String ToString() + { + return String.Format("0x{0:X8}", this.Value); + } + } + + public class DataForgeString : DataForgeSerializable + { + public String Value { get; set; } + + public DataForgeString(BinaryReader br) + : base(br) + { + this.Value = br.ReadCString(); + } + + public override String ToString() + { + return this.Value; + } + } + + public class DataForgeTuple : DataForgeSerializable + { + public UInt32 Item1 { get; set; } + public UInt32 Item2 { get; set; } + + public DataForgeTuple(BinaryReader br) + : base(br) + { + this.Item1 = br.ReadUInt32(); + this.Item2 = br.ReadUInt32(); + } + + public override String ToString() + { + return String.Format("0x{0:X8} 0x{1:X8}", this.Item1, this.Item2); + } + } + + public class DataForgeRecord6 : DataForgeSerializable + { + public UInt32 Item1 { get; set; } + public UInt32 Item2 { get; set; } + public UInt32 Item3 { get; set; } + public UInt32 Item4 { get; set; } + public UInt32 Item5 { get; set; } + public UInt32 Item6 { get; set; } + public UInt32 Item7 { get; set; } + public UInt32 Item8 { get; set; } + + public DataForgeRecord6(BinaryReader br) + : base(br) + { + this.Item1 = br.ReadUInt32(); + this.Item2 = br.ReadUInt32(); + this.Item3 = br.ReadUInt32(); + this.Item4 = br.ReadUInt32(); + this.Item5 = br.ReadUInt32(); + this.Item6 = br.ReadUInt32(); + this.Item7 = br.ReadUInt32(); + this.Item8 = br.ReadUInt32(); + } + + public override String ToString() + { + return String.Format("0x{0:X8} 0x{1:X8} 0x{2:X8} 0x{3:X8} 0x{4:X8} 0x{5:X8} 0x{6:X8} 0x{7:X8}", this.Item1, this.Item2, this.Item3, this.Item4, this.Item5, this.Item6, this.Item7, this.Item8); + } + } + + public class DataForgeRecord7 : DataForgeSerializable + { + public UInt32 Item1 { get; set; } + public UInt32 Item2 { get; set; } + public UInt32 Item3 { get; set; } + public UInt32 Item4 { get; set; } + public UInt32 Item5 { get; set; } + public UInt32 Item6 { get; set; } + public UInt32 Item7 { get; set; } + public UInt32 Item8 { get; set; } + + public DataForgeRecord7(BinaryReader br) + : base(br) + { + this.Item1 = br.ReadUInt32(); + this.Item2 = br.ReadUInt32(); + this.Item3 = br.ReadUInt32(); + this.Item4 = br.ReadUInt32(); + this.Item5 = br.ReadUInt32(); + this.Item6 = br.ReadUInt32(); + this.Item7 = br.ReadUInt32(); + this.Item8 = br.ReadUInt32(); + } + + public override String ToString() + { + return String.Format("0x{0:X8} 0x{1:X8} 0x{2:X8} 0x{3:X8} 0x{4:X8} 0x{5:X8} 0x{6:X8} 0x{7:X8}", this.Item1, this.Item2, this.Item3, this.Item4, this.Item5, this.Item6, this.Item7, this.Item8); + } + } + + public class DataForgeRecord8 : DataForgeSerializable + { + public UInt32 Item1 { get; set; } + public UInt32 Item2 { get; set; } + public UInt32 Item3 { get; set; } + public UInt32 Item4 { get; set; } + public UInt32 Item5 { get; set; } + public UInt32 Item6 { get; set; } + public UInt32 Item7 { get; set; } + public UInt32 Item8 { get; set; } + + public DataForgeRecord8(BinaryReader br) + : base(br) + { + this.Item1 = br.ReadUInt32(); + this.Item2 = br.ReadUInt32(); + this.Item3 = br.ReadUInt32(); + this.Item4 = br.ReadUInt32(); + this.Item5 = br.ReadUInt32(); + this.Item6 = br.ReadUInt32(); + this.Item7 = br.ReadUInt32(); + this.Item8 = br.ReadUInt32(); + } + + public override String ToString() + { + return String.Format("0x{0:X8} 0x{1:X8} 0x{2:X8} 0x{3:X8} 0x{4:X8} 0x{5:X8} 0x{6:X8} 0x{7:X8}", this.Item1, this.Item2, this.Item3, this.Item4, this.Item5, this.Item6, this.Item7, this.Item8); + } + } + + public class DataForgeRecord9 : DataForgeSerializable + { + public UInt32 Item1 { get; set; } + public UInt32 Item2 { get; set; } + public UInt32 Item3 { get; set; } + public UInt32 Item4 { get; set; } + public UInt32 Item5 { get; set; } + public UInt32 Item6 { get; set; } + public UInt32 Item7 { get; set; } + public UInt32 Item8 { get; set; } + + public DataForgeRecord9(BinaryReader br) + : base(br) + { + this.Item1 = br.ReadUInt32(); + this.Item2 = br.ReadUInt32(); + this.Item3 = br.ReadUInt32(); + this.Item4 = br.ReadUInt32(); + this.Item5 = br.ReadUInt32(); + this.Item6 = br.ReadUInt32(); + this.Item7 = br.ReadUInt32(); + this.Item8 = br.ReadUInt32(); + } + + public override String ToString() + { + return String.Format("0x{0:X8} 0x{1:X8} 0x{2:X8} 0x{3:X8} 0x{4:X8} 0x{5:X8} 0x{6:X8} 0x{7:X8}", this.Item1, this.Item2, this.Item3, this.Item4, this.Item5, this.Item6, this.Item7, this.Item8); } } -} \ No newline at end of file +} diff --git a/HoloXPLOR.DataForge/DataForgeSerializable.cs b/HoloXPLOR.DataForge/DataForgeSerializable.cs new file mode 100644 index 0000000..20d5f49 --- /dev/null +++ b/HoloXPLOR.DataForge/DataForgeSerializable.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HoloXPLOR.DataForge +{ + public abstract class DataForgeSerializable + { + private BinaryReader _br; + private Int64 _offset; + private Int64[] _signature; + + public DataForgeSerializable(BinaryReader br) + { + this._br = br; + this._offset = this._br.BaseStream.Position; + this._signature = this._signature ?? new Int64[] { this._br.BaseStream.Length, 0x04 }; + } + + public void Deserialize() + { + var i = 1; + while (this._br.BaseStream.Position < this._signature[0] && this._br.BaseStream.Position < this._br.BaseStream.Length) + { + if (i >= this._signature.Length) i = 1; + + var width = this._signature[i]; + var isNull = false; + var format = ""; + Object data = null; + + if ((width & 0x20) == 0x20) + { + isNull = _br.ReadInt32() == -1; + } + + switch (width) + { + case 0x00: + format = "| "; + data = ""; + break; + case 0x80: + format = @"""{0}"" "; + data = (_br.ReadCString() ?? String.Empty).Replace("\r", "\\r").Replace("\n", "\\n"); + break; + case 0x81: + case 0x01: + format = "0x{0:X2} "; + data = _br.ReadByte(); + break; + case 0x82: + case 0x02: + format = "0x{0:X4} "; + data = _br.ReadInt16(); + break; + case 0x03: + format = "#{0} "; + data = String.Format("{0:X2}{1:X2}{2:X2}", _br.ReadByte(), _br.ReadByte(), _br.ReadByte()); + break; + case 0x84: + case 0x04: + format = "0x{0:X8} "; + data = _br.ReadInt32(); + break; + case 0x44: + format = "{0} "; + data = _br.ReadSingle(); + break; + case 0x88: + case 0x08: + format = "0x{0:X16} "; + data = _br.ReadInt64(); + break; + case 0x48: + format = "{0} "; + data = _br.ReadDouble(); + break; + case 0x26: + case 0x16: + format = "{0} "; + var p3 = _br.ReadInt16(); + var p2 = _br.ReadInt16(); + var p1 = _br.ReadInt32(); + var p4 = _br.ReadByte(); + var p5 = _br.ReadByte(); + var p6 = _br.ReadByte(); + var p7 = _br.ReadByte(); + var p8 = _br.ReadByte(); + var p9 = _br.ReadByte(); + var p10 = _br.ReadByte(); + var p11 = _br.ReadByte(); + data = new Guid(p1, p2, p3, p11, p10, p9, p8, p7, p6, p5, p4); + break; + } + + if (isNull) + { + data = null; + } + + if ((width & 0x80) == 0x80 && (width != 0x80)) + { + var stringOffset = (data as Int64? ?? data as Int32? ?? data as Int16? ?? -1); + + if (stringOffset <= 0x00066E19 && + stringOffset >= 0x00000000) + { + var oldPos = _br.BaseStream.Position; + _br.BaseStream.Seek(stringOffset + 0x0002F1DC, SeekOrigin.Begin); + Console.Write(@"[{0}] ", (_br.ReadCString() ?? String.Empty).Replace("\r", "\\r").Replace("\n", "\\n")); + _br.BaseStream.Seek(oldPos, SeekOrigin.Begin); + } + else if (stringOffset == -1) + { + Console.Write("[__NULL__] "); + } + else + { + Console.Write("[__{0:X8}__] ", data); + } + } + else + { + Console.Write(format, data ?? "NULL"); + } + } + } + + public String ReadString() + { + var stringOffset = this._br.ReadUInt32(); + + var oldPos = this._br.BaseStream.Position; + + this._br.BaseStream.Seek(0x0002F1DC + stringOffset, SeekOrigin.Begin); + + String buffer = this._br.ReadCString(); + + this._br.BaseStream.Seek(oldPos, SeekOrigin.Begin); + + return buffer; + } + + public Guid? ReadGuid(Boolean nullable = true) + { + var isNull = nullable && this._br.ReadInt32() == -1; + + var c = this._br.ReadInt16(); + var b = this._br.ReadInt16(); + var a = this._br.ReadInt32(); + var k = this._br.ReadByte(); + var j = this._br.ReadByte(); + var i = this._br.ReadByte(); + var h = this._br.ReadByte(); + var g = this._br.ReadByte(); + var f = this._br.ReadByte(); + var e = this._br.ReadByte(); + var d = this._br.ReadByte(); + + if (isNull) return null; + + return new Guid(a, b, c, d, e, f, g, h, i, j, k); + } + + public U[] ReadArray(UInt32? arraySize = null) where U : DataForgeSerializable + { + if (!arraySize.HasValue) + { + arraySize = this._br.ReadUInt32(); + + if (arraySize == 0xFFFFFFFF) + { + return null; + } + } + + if (arraySize == 0xFFFFFFFF) + { + return null; + } + + return (from i in Enumerable.Range(0, (Int32)arraySize.Value) + select (U)Activator.CreateInstance(typeof(U), this._br)).ToArray(); + } + } +} diff --git a/HoloXPLOR.DataForge/HoloXPLOR.DataForge.csproj b/HoloXPLOR.DataForge/HoloXPLOR.DataForge.csproj index c8828e9..175e530 100644 --- a/HoloXPLOR.DataForge/HoloXPLOR.DataForge.csproj +++ b/HoloXPLOR.DataForge/HoloXPLOR.DataForge.csproj @@ -48,18 +48,23 @@ - - - + + + + + Code - + + + Always +