From e4fda86b333a11a6996e90e7dced884d726d3854 Mon Sep 17 00:00:00 2001 From: BtbN Date: Mon, 15 Apr 2019 21:54:46 +0200 Subject: [PATCH] KBinXML logic fully implemented --- eAmuseCore/KBinXML/Helpers.cs | 13 ++++--- eAmuseCore/KBinXML/KBinXML.cs | 70 ++++++++++++++++++++++++++++++---- eAmuseCore/KBinXML/XmlTypes.cs | 39 +++++++++++-------- eAmuseTest/Program.cs | 2 +- 4 files changed, 96 insertions(+), 28 deletions(-) diff --git a/eAmuseCore/KBinXML/Helpers.cs b/eAmuseCore/KBinXML/Helpers.cs index 93dc378..675bc3b 100644 --- a/eAmuseCore/KBinXML/Helpers.cs +++ b/eAmuseCore/KBinXML/Helpers.cs @@ -168,10 +168,13 @@ namespace eAmuseCore.KBinXML return input.Select(v => (object)v); } - public static IEnumerable TakeByteArrayAligned(ref IEnumerable input) + public static IEnumerable TakeBytesAligned(ref IEnumerable input, int size = -1) { - int size = input.FirstS32(); - input = input.Skip(4); + if (size < 0) + { + size = input.FirstS32(); + input = input.Skip(4); + } var res = input.Take(size); input = input.Skip(size); @@ -183,9 +186,9 @@ namespace eAmuseCore.KBinXML return res; } - public static string TakeStringAligned(ref IEnumerable input, Encoding encoding) + public static string TakeStringAligned(ref IEnumerable input, Encoding encoding, int size = -1) { - byte[] data = TakeByteArrayAligned(ref input).ToArray(); + byte[] data = TakeBytesAligned(ref input, size).ToArray(); return encoding.GetString(data, 0, data.Length - 1); // drop final null byte } } diff --git a/eAmuseCore/KBinXML/KBinXML.cs b/eAmuseCore/KBinXML/KBinXML.cs index 9390a50..1d2c345 100644 --- a/eAmuseCore/KBinXML/KBinXML.cs +++ b/eAmuseCore/KBinXML/KBinXML.cs @@ -89,8 +89,6 @@ namespace eAmuseCore.KBinXML } input = input.Skip(1); - Console.WriteLine("Compressed: " + compressed); - byte encodingSig = input.FirstU8(); input = input.Skip(1); @@ -111,6 +109,9 @@ namespace eAmuseCore.KBinXML private void ParseNodes(IEnumerable nodeBuf, IEnumerable dataBuf, bool compressed) { + IEnumerable dataByteBuf = Enumerable.Empty(); + IEnumerable dataWordBuf = Enumerable.Empty(); + uint dataSize = dataBuf.FirstU32(); dataBuf = dataBuf.Skip(4); @@ -147,9 +148,6 @@ namespace eAmuseCore.KBinXML } } - Console.WriteLine("Name: " + name); - Console.WriteLine("Type: " + nodeType); - XmlTypes.Entry nodeTypeEntry = null; bool startNode = false; @@ -158,7 +156,6 @@ namespace eAmuseCore.KBinXML case XmlTypes.AttrType: string attrVal = EnumHelpers.TakeStringAligned(ref dataBuf, encoding); node.SetAttributeValue(name, attrVal); - Console.WriteLine("Attr val: " + attrVal); break; case XmlTypes.NodeEndType: node = node.Parent; @@ -185,9 +182,68 @@ namespace eAmuseCore.KBinXML if (startNode) continue; + + node.SetAttributeValue("__type", nodeTypeEntry.names[0]); + + int varCount = nodeTypeEntry.count; + int arrCount = 1; + if (varCount < 0) + { + varCount = dataBuf.FirstS32(); + dataBuf = dataBuf.Skip(4); + isArray = true; + } + else if (isArray) + { + arrCount = dataBuf.FirstS32() / (nodeTypeEntry.size * nodeTypeEntry.count); + dataBuf = dataBuf.Skip(4); + node.SetAttributeValue("__count", arrCount); + } + int totCount = arrCount * varCount; + int totSize = totCount * nodeTypeEntry.size; + + IEnumerable data = null; + if (isArray || totSize > 2) + { + data = EnumHelpers.TakeBytesAligned(ref dataBuf, totCount * nodeTypeEntry.size); + } + else if (totSize == 1) + { + if (!dataByteBuf.Any()) + { + dataByteBuf = dataBuf; + dataBuf = dataBuf.Skip(4); + } + data = dataByteBuf.Take(1); + dataByteBuf = dataByteBuf.Skip(1); + } + else if(totSize == 2) + { + if (!dataWordBuf.Any()) + { + dataWordBuf = dataBuf; + dataBuf = dataBuf.Skip(4); + } + data = dataWordBuf.Take(2); + dataWordBuf = dataWordBuf.Skip(2); + } + + if (nodeType == XmlTypes.Bin.nodeType) + { + node.SetAttributeValue("__size", totCount); + node.Value = string.Join("", data.Select(b => Convert.ToString(b, 16).PadLeft(2, '0'))); + } + else if (nodeType == XmlTypes.Str.nodeType) + { + node.Value = encoding.GetString(data.ToArray(), 0, totCount - 1); + } + else + { + node.Value = string.Join(" ", XmlTypes.DataToString(data, nodeTypeEntry)); + } } - doc = new XDocument(fakeroot.Elements().First()); + doc = new XDocument(fakeroot.FirstNode); Console.WriteLine(doc.ToString()); } } diff --git a/eAmuseCore/KBinXML/XmlTypes.cs b/eAmuseCore/KBinXML/XmlTypes.cs index 65f2cec..09e078d 100644 --- a/eAmuseCore/KBinXML/XmlTypes.cs +++ b/eAmuseCore/KBinXML/XmlTypes.cs @@ -20,7 +20,7 @@ namespace eAmuseCore.KBinXML public int size = 0; public int count = 0; public Type type = typeof(object); - public Func, IEnumerable> read = _ => Enumerable.Empty(); + public Func, string> toString; } public static readonly Entry Void = new Entry @@ -36,7 +36,7 @@ namespace eAmuseCore.KBinXML size = 1, count = 1, type = typeof(sbyte), - read = input => input.TakeS8(1).Box(), + toString = input => input.FirstS8().ToString(), }; public static readonly Entry U8 = new Entry @@ -46,7 +46,7 @@ namespace eAmuseCore.KBinXML size = 1, count = 1, type = typeof(byte), - read = input => input.TakeU8(1).Box(), + toString = input => input.FirstU8().ToString(), }; public static readonly Entry S16 = new Entry @@ -56,7 +56,7 @@ namespace eAmuseCore.KBinXML size = 2, count = 1, type = typeof(short), - read = input => input.TakeS16(1).Box(), + toString = input => input.FirstS16().ToString(), }; public static readonly Entry U16 = new Entry @@ -66,7 +66,7 @@ namespace eAmuseCore.KBinXML size = 2, count = 1, type = typeof(ushort), - read = input => input.TakeU16(1).Box(), + toString = input => input.FirstU16().ToString(), }; public static readonly Entry S32 = new Entry @@ -76,7 +76,7 @@ namespace eAmuseCore.KBinXML size = 4, count = 1, type = typeof(int), - read = input => input.TakeS32(1).Box(), + toString = input => input.FirstS32().ToString(), }; public static readonly Entry U32 = new Entry @@ -86,7 +86,7 @@ namespace eAmuseCore.KBinXML size = 4, count = 1, type = typeof(int), - read = input => input.TakeU32(1).Box(), + toString = input => input.FirstU32().ToString(), }; public static readonly Entry S64 = new Entry @@ -96,7 +96,7 @@ namespace eAmuseCore.KBinXML size = 8, count = 1, type = typeof(int), - read = input => input.TakeS64(1).Box(), + toString = input => input.FirstS64().ToString(), }; public static readonly Entry U64 = new Entry @@ -106,27 +106,27 @@ namespace eAmuseCore.KBinXML size = 8, count = 1, type = typeof(int), - read = input => input.TakeU64(1).Box(), + toString = input => input.FirstU64().ToString(), }; public static readonly Entry Bin = new Entry { names = new[] { "bin", "binary" }, nodeType = 10, - size = 4, + size = 1, count = -1, - type = typeof(byte[]), - read = input => input.TakeU64(1).Box(), + type = typeof(byte), + toString = null, // special case, cannot be handled here }; public static readonly Entry Str = new Entry { names = new[] { "str", "string" }, nodeType = 11, - size = 4, + size = 1, count = -1, - type = typeof(byte[]), - read = input => input.TakeU64(1).Box(), + type = typeof(byte), + toString = null, // special case, cannot be handled here }; private static Dictionary nameLookupMap = new Dictionary(); @@ -169,5 +169,14 @@ namespace eAmuseCore.KBinXML return null; } + + public static IEnumerable DataToString(IEnumerable dataBuf, Entry entry) + { + while (dataBuf.Any()) + { + yield return entry.toString(dataBuf); + dataBuf = dataBuf.Skip(entry.size); + } + } } } diff --git a/eAmuseTest/Program.cs b/eAmuseTest/Program.cs index f26feec..5bfaa89 100644 --- a/eAmuseTest/Program.cs +++ b/eAmuseTest/Program.cs @@ -46,7 +46,7 @@ namespace eAmuseTest else if (compress != "none") throw new ArgumentException("Unsupported compression algorithm"); - Console.WriteLine("" + ((3 - 4) % 4)); + Console.WriteLine(BitConverter.ToString(new byte[] { 1, 2, 3, 4 })); KBinXML kbinxml = new KBinXML(rawData); }