diff --git a/eAmuseCore/KBinXML/Helpers.cs b/eAmuseCore/KBinXML/Helpers.cs index 24dd40a..93dc378 100644 --- a/eAmuseCore/KBinXML/Helpers.cs +++ b/eAmuseCore/KBinXML/Helpers.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; namespace eAmuseCore.KBinXML { @@ -166,5 +167,26 @@ namespace eAmuseCore.KBinXML { return input.Select(v => (object)v); } + + public static IEnumerable TakeByteArrayAligned(ref IEnumerable input) + { + int size = input.FirstS32(); + input = input.Skip(4); + + var res = input.Take(size); + input = input.Skip(size); + + int align = 4 - (size % 4); + if (align != 4) + input = input.Skip(align); + + return res; + } + + public static string TakeStringAligned(ref IEnumerable input, Encoding encoding) + { + byte[] data = TakeByteArrayAligned(ref input).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 7a97021..9390a50 100644 --- a/eAmuseCore/KBinXML/KBinXML.cs +++ b/eAmuseCore/KBinXML/KBinXML.cs @@ -114,9 +114,11 @@ namespace eAmuseCore.KBinXML uint dataSize = dataBuf.FirstU32(); dataBuf = dataBuf.Skip(4); - XElement node = doc.Root; + XElement fakeroot = new XElement("fakeroot"); + XElement node = fakeroot; - while (nodeBuf.Any()) + bool nodesLeft = true; + while (nodesLeft && nodeBuf.Any()) { nodeBuf = nodeBuf.SkipWhile(b => b == 0); @@ -126,10 +128,8 @@ namespace eAmuseCore.KBinXML bool isArray = (nodeType & 64) != 0; nodeType = (byte)(nodeType & ~64); - XmlTypes.Entry nodeTypeEntry = XmlTypes.GetEntryByType(nodeType); - - string name = null; - if (nodeType != XmlTypes.NodeEnd.nodeType && nodeType != XmlTypes.EndSection.nodeType) + string name = ""; + if (nodeType != XmlTypes.NodeEndType && nodeType != XmlTypes.SectionEndType) { if (compressed) { @@ -148,15 +148,47 @@ namespace eAmuseCore.KBinXML } Console.WriteLine("Name: " + name); + Console.WriteLine("Type: " + nodeType); - bool skip = true; + XmlTypes.Entry nodeTypeEntry = null; + bool startNode = false; - if (nodeType == XmlTypes.EndSection.nodeType) - break; + switch (nodeType) + { + 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; + break; + case XmlTypes.SectionEndType: + nodesLeft = false; + break; + case XmlTypes.NodeStartType: + startNode = true; + break; + default: + nodeTypeEntry = XmlTypes.GetEntryByType(nodeType); + if (nodeTypeEntry == null) + throw new NotImplementedException("nodeType " + nodeType + " is not implemented"); + break; + } - if (skip) + if (nodeTypeEntry == null && !startNode) + continue; + + XElement child = new XElement(name); + node.Add(child); + node = child; + + if (startNode) continue; } + + doc = new XDocument(fakeroot.Elements().First()); + Console.WriteLine(doc.ToString()); } } } diff --git a/eAmuseCore/KBinXML/XmlTypes.cs b/eAmuseCore/KBinXML/XmlTypes.cs index 6fbbd13..65f2cec 100644 --- a/eAmuseCore/KBinXML/XmlTypes.cs +++ b/eAmuseCore/KBinXML/XmlTypes.cs @@ -8,6 +8,11 @@ namespace eAmuseCore.KBinXML { public static class XmlTypes { + public const int NodeStartType = 1; + public const int AttrType = 46; + public const int NodeEndType = 190; + public const int SectionEndType = 191; + public class Entry { public string[] names = null; @@ -16,16 +21,8 @@ namespace eAmuseCore.KBinXML public int count = 0; public Type type = typeof(object); public Func, IEnumerable> read = _ => Enumerable.Empty(); - public bool isVirtual = false; } - public static readonly Entry NodeStart = new Entry - { - names = new[] { "nodeStart" }, - nodeType = 1, - isVirtual = true, - }; - public static readonly Entry Void = new Entry { names = new[] { "void" }, @@ -116,30 +113,20 @@ namespace eAmuseCore.KBinXML { names = new[] { "bin", "binary" }, nodeType = 10, - size = 1, + size = 4, count = -1, type = typeof(byte[]), read = input => input.TakeU64(1).Box(), }; - public static readonly Entry Attr = new Entry + public static readonly Entry Str = new Entry { - names = new[] { "attr" }, - nodeType = 46, - }; - - public static readonly Entry NodeEnd = new Entry - { - names = new[] { "nodeEnd" }, - nodeType = 190, - isVirtual = true, - }; - - public static readonly Entry EndSection = new Entry - { - names = new[] { "endSection" }, - nodeType = 191, - isVirtual = true, + names = new[] { "str", "string" }, + nodeType = 11, + size = 4, + count = -1, + type = typeof(byte[]), + read = input => input.TakeU64(1).Box(), }; private static Dictionary nameLookupMap = new Dictionary(); @@ -174,7 +161,7 @@ namespace eAmuseCore.KBinXML if (!info.IsStatic) continue; Entry res = info.GetValue(null) as Entry; - if (res == null || res.nodeType != type || res.isVirtual) + if (res == null || res.nodeType != type) continue; typeLookupMap[type] = res; return res; diff --git a/eAmuseTest/Program.cs b/eAmuseTest/Program.cs index ceee509..f26feec 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(BytesToString(rawData)); + Console.WriteLine("" + ((3 - 4) % 4)); KBinXML kbinxml = new KBinXML(rawData); }