From c5fa090426b81afac057f17a8b01d06febbca34e Mon Sep 17 00:00:00 2001 From: BtbN Date: Mon, 15 Apr 2019 16:17:59 +0200 Subject: [PATCH] More work on kbinxml --- eAmuseCore/KBinXML/Helpers.cs | 167 +++++++++++++++++++++++++++++---- eAmuseCore/KBinXML/KBinXML.cs | 14 +-- eAmuseCore/KBinXML/SixBit.cs | 4 +- eAmuseCore/KBinXML/XmlTypes.cs | 124 ++++++++++++++++++++++-- eAmuseTest/Program.cs | 5 - 5 files changed, 272 insertions(+), 42 deletions(-) diff --git a/eAmuseCore/KBinXML/Helpers.cs b/eAmuseCore/KBinXML/Helpers.cs index 214ec7e..6d2e498 100644 --- a/eAmuseCore/KBinXML/Helpers.cs +++ b/eAmuseCore/KBinXML/Helpers.cs @@ -6,36 +6,165 @@ namespace eAmuseCore.KBinXML { static class EnumHelpers { - public static uint FirstU32(this IEnumerable input) + public static IEnumerable TakeU64(this IEnumerable input, int count) { - input = input.Take(4); - if (BitConverter.IsLittleEndian) - input = input.Reverse(); - return BitConverter.ToUInt32(input.ToArray(), 0); + for (int i = 0; i < count; ++i) + { + var state = input.Take(8); + if (BitConverter.IsLittleEndian) + state = state.Reverse(); + input = input.Skip(8); + yield return BitConverter.ToUInt64(state.ToArray(), 0); + } } - public static int FirstI32(this IEnumerable input) + public static IEnumerable TakeS64(this IEnumerable input, int count) { - input = input.Take(4); - if (BitConverter.IsLittleEndian) - input = input.Reverse(); - return BitConverter.ToInt32(input.ToArray(), 0); + for (int i = 0; i < count; ++i) + { + var state = input.Take(8); + if (BitConverter.IsLittleEndian) + state = state.Reverse(); + input = input.Skip(8); + yield return BitConverter.ToInt64(state.ToArray(), 0); + } + } + + public static IEnumerable TakeU32(this IEnumerable input, int count) + { + for (int i = 0; i < count; ++i) + { + var state = input.Take(4); + if (BitConverter.IsLittleEndian) + state = state.Reverse(); + input = input.Skip(4); + yield return BitConverter.ToUInt32(state.ToArray(), 0); + } + } + + public static IEnumerable TakeS32(this IEnumerable input, int count) + { + for (int i = 0; i < count; ++i) + { + var state = input.Take(4); + if (BitConverter.IsLittleEndian) + state = state.Reverse(); + input = input.Skip(4); + yield return BitConverter.ToInt32(state.ToArray(), 0); + } + } + + public static IEnumerable TakeU16(this IEnumerable input, int count) + { + for (int i = 0; i < count; ++i) + { + var state = input.Take(2); + if (BitConverter.IsLittleEndian) + state = state.Reverse(); + input = input.Skip(2); + yield return BitConverter.ToUInt16(state.ToArray(), 0); + } + } + + public static IEnumerable TakeS16(this IEnumerable input, int count) + { + for (int i = 0; i < count; ++i) + { + var state = input.Take(2); + if (BitConverter.IsLittleEndian) + state = state.Reverse(); + input = input.Skip(2); + yield return BitConverter.ToInt16(state.ToArray(), 0); + } + } + + public static IEnumerable TakeU8(this IEnumerable input, int count) + { + return input.Take(count); + } + + public static IEnumerable TakeS8(this IEnumerable input, int count) + { + return input.Take(count).Select(b => unchecked((sbyte)b)); + } + + public static IEnumerable TakeF(this IEnumerable input, int count) + { + for (int i = 0; i < count; ++i) + { + var state = input.Take(4); + if (BitConverter.IsLittleEndian) + state = state.Reverse(); + input = input.Skip(4); + yield return BitConverter.ToSingle(state.ToArray(), 0); + } + } + + public static IEnumerable TakeD(this IEnumerable input, int count) + { + for (int i = 0; i < count; ++i) + { + var state = input.Take(8); + if (BitConverter.IsLittleEndian) + state = state.Reverse(); + input = input.Skip(8); + yield return BitConverter.ToDouble(state.ToArray(), 0); + } + } + + public static ulong FirstU64(this IEnumerable input) + { + return input.TakeU64(1).First(); + } + + public static long FirstS64(this IEnumerable input) + { + return input.TakeS64(1).First(); + } + + public static uint FirstU32(this IEnumerable input) + { + return input.TakeU32(1).First(); + } + + public static int FirstS32(this IEnumerable input) + { + return input.TakeS32(1).First(); } public static ushort FirstU16(this IEnumerable input) { - input = input.Take(2); - if (BitConverter.IsLittleEndian) - input = input.Reverse(); - return BitConverter.ToUInt16(input.ToArray(), 0); + return input.TakeU16(1).First(); } - public static short FirstI16(this IEnumerable input) + public static short FirstS16(this IEnumerable input) { - input = input.Take(2); - if (BitConverter.IsLittleEndian) - input = input.Reverse(); - return BitConverter.ToInt16(input.ToArray(), 0); + return input.TakeS16(1).First(); + } + + public static byte FirstU8(this IEnumerable input) + { + return input.TakeU8(1).First(); + } + + public static sbyte FirstS8(this IEnumerable input) + { + return input.TakeS8(1).First(); + } + + public static float FirstF(this IEnumerable input) + { + return input.TakeF(1).First(); + } + + public static double FirstD(this IEnumerable input) + { + return input.TakeD(1).First(); + } + + public static IEnumerable Box(this IEnumerable input) + { + return input.Select(v => (object)v); } } } diff --git a/eAmuseCore/KBinXML/KBinXML.cs b/eAmuseCore/KBinXML/KBinXML.cs index 4a0c2fd..7a97021 100644 --- a/eAmuseCore/KBinXML/KBinXML.cs +++ b/eAmuseCore/KBinXML/KBinXML.cs @@ -71,12 +71,12 @@ namespace eAmuseCore.KBinXML { doc = new XDocument(); - if (input.First() != SIGNATURE) + if (input.FirstU8() != SIGNATURE) throw new ArgumentException("Invalid signature", "input"); input = input.Skip(1); bool compressed; - switch (input.First()) + switch (input.FirstU8()) { case SIG_COMPRESSED: compressed = true; @@ -91,10 +91,10 @@ namespace eAmuseCore.KBinXML Console.WriteLine("Compressed: " + compressed); - byte encodingSig = input.First(); + byte encodingSig = input.FirstU8(); input = input.Skip(1); - if (input.First() != (0xFF ^ encodingSig)) + if (input.FirstU8() != (0xFF ^ encodingSig)) throw new ArgumentException("Encoding signature failed to verify", "input"); input = input.Skip(1); @@ -120,7 +120,7 @@ namespace eAmuseCore.KBinXML { nodeBuf = nodeBuf.SkipWhile(b => b == 0); - byte nodeType = nodeBuf.First(); + byte nodeType = nodeBuf.FirstU8(); nodeBuf = nodeBuf.Skip(1); bool isArray = (nodeType & 64) != 0; @@ -129,7 +129,7 @@ namespace eAmuseCore.KBinXML XmlTypes.Entry nodeTypeEntry = XmlTypes.GetEntryByType(nodeType); string name = null; - if (nodeType != XmlTypes.NodeEnd.type && nodeType != XmlTypes.EndSection.type) + if (nodeType != XmlTypes.NodeEnd.nodeType && nodeType != XmlTypes.EndSection.nodeType) { if (compressed) { @@ -151,7 +151,7 @@ namespace eAmuseCore.KBinXML bool skip = true; - if (nodeType == XmlTypes.EndSection.type) + if (nodeType == XmlTypes.EndSection.nodeType) break; if (skip) diff --git a/eAmuseCore/KBinXML/SixBit.cs b/eAmuseCore/KBinXML/SixBit.cs index 1c0e669..c16c2b0 100644 --- a/eAmuseCore/KBinXML/SixBit.cs +++ b/eAmuseCore/KBinXML/SixBit.cs @@ -52,7 +52,7 @@ namespace eAmuseCore.KBinXML public static string Unpack(ref IEnumerable nodeBuf) { - int length = nodeBuf.First(); + int length = nodeBuf.FirstU8(); nodeBuf = nodeBuf.Skip(1); int length_bits = length * 6; @@ -60,7 +60,7 @@ namespace eAmuseCore.KBinXML int padding = (8 - (length_bits % 8)) % 8; // bytes are in big endian order, BigInteger expects little endian, hence .Reverse() it. - BigInteger bits = new BigInteger(nodeBuf.Take(length_bytes).Reverse().ToArray()); + BigInteger bits = new BigInteger(nodeBuf.TakeU8(length_bytes).Reverse().ToArray()); nodeBuf = nodeBuf.Skip(length_bytes); bits >>= padding; diff --git a/eAmuseCore/KBinXML/XmlTypes.cs b/eAmuseCore/KBinXML/XmlTypes.cs index daafd5b..6fbbd13 100644 --- a/eAmuseCore/KBinXML/XmlTypes.cs +++ b/eAmuseCore/KBinXML/XmlTypes.cs @@ -10,30 +10,136 @@ namespace eAmuseCore.KBinXML { public class Entry { - public byte type; - public int size; - public int count; - public string[] names; + public string[] names = null; + public byte nodeType = 0; + public int size = 0; + 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 { - type = 1 + names = new[] { "nodeStart" }, + nodeType = 1, + isVirtual = true, + }; + + public static readonly Entry Void = new Entry + { + names = new[] { "void" }, + nodeType = 1, + }; + + public static readonly Entry S8 = new Entry + { + names = new[] { "s8" }, + nodeType = 2, + size = 1, + count = 1, + type = typeof(sbyte), + read = input => input.TakeS8(1).Box(), + }; + + public static readonly Entry U8 = new Entry + { + names = new[] { "u8" }, + nodeType = 3, + size = 1, + count = 1, + type = typeof(byte), + read = input => input.TakeU8(1).Box(), + }; + + public static readonly Entry S16 = new Entry + { + names = new[] { "s16" }, + nodeType = 4, + size = 2, + count = 1, + type = typeof(short), + read = input => input.TakeS16(1).Box(), + }; + + public static readonly Entry U16 = new Entry + { + names = new[] { "u16" }, + nodeType = 5, + size = 2, + count = 1, + type = typeof(ushort), + read = input => input.TakeU16(1).Box(), + }; + + public static readonly Entry S32 = new Entry + { + names = new[] { "s32" }, + nodeType = 6, + size = 4, + count = 1, + type = typeof(int), + read = input => input.TakeS32(1).Box(), + }; + + public static readonly Entry U32 = new Entry + { + names = new[] { "u32" }, + nodeType = 7, + size = 4, + count = 1, + type = typeof(int), + read = input => input.TakeU32(1).Box(), + }; + + public static readonly Entry S64 = new Entry + { + names = new[] { "s64" }, + nodeType = 8, + size = 8, + count = 1, + type = typeof(int), + read = input => input.TakeS64(1).Box(), + }; + + public static readonly Entry U64 = new Entry + { + names = new[] { "u64" }, + nodeType = 9, + size = 8, + count = 1, + type = typeof(int), + read = input => input.TakeU64(1).Box(), + }; + + public static readonly Entry Bin = new Entry + { + names = new[] { "bin", "binary" }, + nodeType = 10, + size = 1, + count = -1, + type = typeof(byte[]), + read = input => input.TakeU64(1).Box(), }; public static readonly Entry Attr = new Entry { - type = 46 + names = new[] { "attr" }, + nodeType = 46, }; public static readonly Entry NodeEnd = new Entry { - type = 190 + names = new[] { "nodeEnd" }, + nodeType = 190, + isVirtual = true, }; public static readonly Entry EndSection = new Entry { - type = 191 + names = new[] { "endSection" }, + nodeType = 191, + isVirtual = true, }; private static Dictionary nameLookupMap = new Dictionary(); @@ -68,7 +174,7 @@ namespace eAmuseCore.KBinXML if (!info.IsStatic) continue; Entry res = info.GetValue(null) as Entry; - if (res == null || res.type != type) + if (res == null || res.nodeType != type || res.isVirtual) continue; typeLookupMap[type] = res; return res; diff --git a/eAmuseTest/Program.cs b/eAmuseTest/Program.cs index 0747853..ceee509 100644 --- a/eAmuseTest/Program.cs +++ b/eAmuseTest/Program.cs @@ -49,11 +49,6 @@ namespace eAmuseTest Console.WriteLine(BytesToString(rawData)); KBinXML kbinxml = new KBinXML(rawData); - - Dictionary dd = new Dictionary(); - dd[2] = 3; - Console.WriteLine("" + dd[2]); - Console.WriteLine("" + dd[1]); } private static string BytesToString(IEnumerable bytes)