mirror of
https://github.com/BtbN/ClanServer.git
synced 2026-09-07 16:05:14 -05:00
Restructure parsing logic
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace eAmuseCore.KBinXML
|
||||
@@ -15,6 +16,7 @@ namespace eAmuseCore.KBinXML
|
||||
static KBinXML()
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
XmlTypes.XmlTypes.RegisterAll();
|
||||
}
|
||||
|
||||
private static Encoding GetEncoding(byte sig)
|
||||
@@ -130,7 +132,7 @@ namespace eAmuseCore.KBinXML
|
||||
nodeType = (byte)(nodeType & ~64);
|
||||
|
||||
string name = "";
|
||||
if (nodeType != XmlTypes.NodeEndType && nodeType != XmlTypes.SectionEndType)
|
||||
if (nodeType != XmlTypes.XmlTypes.NodeEndType && nodeType != XmlTypes.XmlTypes.SectionEndType)
|
||||
{
|
||||
if (compressed)
|
||||
{
|
||||
@@ -148,32 +150,30 @@ namespace eAmuseCore.KBinXML
|
||||
}
|
||||
}
|
||||
|
||||
XmlTypes.Entry nodeTypeEntry = null;
|
||||
KValueAttribute nodeAttrs = null;
|
||||
bool startNode = false;
|
||||
|
||||
switch (nodeType)
|
||||
{
|
||||
case XmlTypes.AttrType:
|
||||
case XmlTypes.XmlTypes.AttrType:
|
||||
string attrVal = EnumHelpers.TakeStringAligned(ref dataBuf, encoding);
|
||||
node.SetAttributeValue(name, attrVal);
|
||||
break;
|
||||
case XmlTypes.NodeEndType:
|
||||
case XmlTypes.XmlTypes.NodeEndType:
|
||||
node = node.Parent;
|
||||
break;
|
||||
case XmlTypes.SectionEndType:
|
||||
case XmlTypes.XmlTypes.SectionEndType:
|
||||
nodesLeft = false;
|
||||
break;
|
||||
case XmlTypes.NodeStartType:
|
||||
case XmlTypes.XmlTypes.NodeStartType:
|
||||
startNode = true;
|
||||
break;
|
||||
default:
|
||||
nodeTypeEntry = XmlTypes.GetEntryByType(nodeType);
|
||||
if (nodeTypeEntry == null)
|
||||
throw new NotImplementedException("nodeType " + nodeType + " is not implemented");
|
||||
nodeAttrs = KValueAttribute.GetAttrByType(nodeType);
|
||||
break;
|
||||
}
|
||||
|
||||
if (nodeTypeEntry == null && !startNode)
|
||||
if (nodeAttrs == null && !startNode)
|
||||
continue;
|
||||
|
||||
XElement child = new XElement(name);
|
||||
@@ -183,9 +183,9 @@ namespace eAmuseCore.KBinXML
|
||||
if (startNode)
|
||||
continue;
|
||||
|
||||
node.SetAttributeValue("__type", nodeTypeEntry.names[0]);
|
||||
node.SetAttributeValue("__type", nodeAttrs.Name);
|
||||
|
||||
int varCount = nodeTypeEntry.count;
|
||||
int varCount = nodeAttrs.Count;
|
||||
int arrCount = 1;
|
||||
if (varCount < 0)
|
||||
{
|
||||
@@ -195,17 +195,17 @@ namespace eAmuseCore.KBinXML
|
||||
}
|
||||
else if (isArray)
|
||||
{
|
||||
arrCount = dataBuf.FirstS32() / (nodeTypeEntry.size * nodeTypeEntry.count);
|
||||
arrCount = dataBuf.FirstS32() / (nodeAttrs.Size * nodeAttrs.Count);
|
||||
dataBuf = dataBuf.Skip(4);
|
||||
node.SetAttributeValue("__count", arrCount);
|
||||
}
|
||||
int totCount = arrCount * varCount;
|
||||
int totSize = totCount * nodeTypeEntry.size;
|
||||
int totSize = totCount * nodeAttrs.Size;
|
||||
|
||||
IEnumerable<byte> data = null;
|
||||
if (isArray || totSize > 2)
|
||||
{
|
||||
data = EnumHelpers.TakeBytesAligned(ref dataBuf, totCount * nodeTypeEntry.size);
|
||||
data = EnumHelpers.TakeBytesAligned(ref dataBuf, totCount * nodeAttrs.Size);
|
||||
}
|
||||
else if (totSize == 1)
|
||||
{
|
||||
@@ -232,18 +232,18 @@ namespace eAmuseCore.KBinXML
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nodeType == XmlTypes.Bin.nodeType)
|
||||
if (nodeType == XmlTypes.XmlTypes.BinType)
|
||||
{
|
||||
node.SetAttributeValue("__size", totCount);
|
||||
node.Value = string.Join("", data.Select(b => Convert.ToString(b, 16).PadLeft(2, '0')));
|
||||
node.SetValue(XmlTypes.Bin.FromBytes(data));
|
||||
}
|
||||
else if (nodeType == XmlTypes.Str.nodeType)
|
||||
else if (nodeType == XmlTypes.XmlTypes.StrType)
|
||||
{
|
||||
node.Value = encoding.GetString(data.ToArray(), 0, totCount - 1);
|
||||
node.SetValue(XmlTypes.Str.FromBytes(data, encoding));
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Value = string.Join(" ", XmlTypes.DataToString(data, nodeTypeEntry));
|
||||
node.SetValue(XmlTypes.XmlTypes.MakeNodeFromBytes(nodeType, data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
88
eAmuseCore/KBinXML/TypeHelpers.cs
Normal file
88
eAmuseCore/KBinXML/TypeHelpers.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace eAmuseCore.KBinXML
|
||||
{
|
||||
public class KValueList<T> : List<T>
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(" ", this.Select(v => v.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=false)]
|
||||
public class KValueAttribute : Attribute
|
||||
{
|
||||
public KValueAttribute(byte nodeType, params string[] names)
|
||||
{
|
||||
NodeType = nodeType;
|
||||
Names = names;
|
||||
}
|
||||
|
||||
public byte NodeType { get; }
|
||||
|
||||
public string[] Names { get; }
|
||||
|
||||
public string Name => Names[0];
|
||||
|
||||
public int Count { get; set; }
|
||||
|
||||
public int Size { get; set; }
|
||||
|
||||
|
||||
private static Dictionary<string, KValueAttribute> nameLookupMap = new Dictionary<string, KValueAttribute>();
|
||||
private static Dictionary<byte, KValueAttribute> typeLookupMap = new Dictionary<byte, KValueAttribute>();
|
||||
private static Dictionary<byte, Type> classLookupMap = new Dictionary<byte, Type>();
|
||||
|
||||
public static void Register(KValueAttribute attr)
|
||||
{
|
||||
typeLookupMap[attr.NodeType] = attr;
|
||||
|
||||
foreach (string name in attr.Names)
|
||||
nameLookupMap[name] = attr;
|
||||
}
|
||||
|
||||
public static KValueAttribute GetAttrByName(string name)
|
||||
{
|
||||
if (!nameLookupMap.ContainsKey(name))
|
||||
throw new NotImplementedException("KValue name not implemented: " + name);
|
||||
return nameLookupMap[name];
|
||||
}
|
||||
|
||||
public static KValueAttribute GetAttrByType(byte type)
|
||||
{
|
||||
if (!typeLookupMap.ContainsKey(type))
|
||||
throw new NotImplementedException("KValue type not implemented: " + type);
|
||||
return typeLookupMap[type];
|
||||
}
|
||||
}
|
||||
|
||||
public class KValue<T>
|
||||
{
|
||||
public T Value { get; set; }
|
||||
|
||||
public KValue() { }
|
||||
public KValue(T value) => Value = value;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return (Value != null) ? Value.ToString() : "";
|
||||
}
|
||||
|
||||
protected KValueAttribute KValAttr => GetType().GetCustomAttributes(typeof(KValueAttribute), true).First() as KValueAttribute;
|
||||
|
||||
public int NodeType => KValAttr.NodeType;
|
||||
|
||||
public string[] Names => KValAttr.Names;
|
||||
|
||||
public string Name => KValAttr.Name;
|
||||
|
||||
public int Count => KValAttr.Count;
|
||||
|
||||
public int Size => KValAttr.Size;
|
||||
|
||||
public Type ValueType => typeof(T);
|
||||
}
|
||||
}
|
||||
@@ -4,179 +4,163 @@ using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace eAmuseCore.KBinXML
|
||||
namespace eAmuseCore.KBinXML.XmlTypes
|
||||
{
|
||||
[KValue(1, "void", Count = 1, Size = 0)]
|
||||
public class Void : KValue<object>
|
||||
{
|
||||
public Void(object _) => Value = null;
|
||||
static public Void FromString(object _) => new Void(null);
|
||||
static public Void FromBytes(IEnumerable<byte> input) => new Void(null);
|
||||
}
|
||||
|
||||
[KValue(2, "s8", Count = 1, Size = 1)]
|
||||
public class S8 : KValue<sbyte>
|
||||
{
|
||||
public S8(sbyte value) => Value = value;
|
||||
static public S8 FromString(string input) => new S8(Convert.ToSByte(input));
|
||||
static public S8 FromBytes(IEnumerable<byte> input) => new S8(input.FirstS8());
|
||||
}
|
||||
|
||||
[KValue(3, "u8", Count = 1, Size = 1)]
|
||||
public class U8 : KValue<byte>
|
||||
{
|
||||
public U8(byte value) => Value = value;
|
||||
static public U8 FromString(string input) => new U8(Convert.ToByte(input));
|
||||
static public U8 FromBytes(IEnumerable<byte> input) => new U8(input.FirstU8());
|
||||
}
|
||||
|
||||
[KValue(4, "s16", Count = 1, Size = 2)]
|
||||
public class S16 : KValue<short>
|
||||
{
|
||||
public S16(short value) => Value = value;
|
||||
static public S16 FromString(string input) => new S16(Convert.ToInt16(input));
|
||||
static public S16 FromBytes(IEnumerable<byte> input) => new S16(input.FirstS16());
|
||||
}
|
||||
|
||||
[KValue(5, "u16", Count = 1, Size = 2)]
|
||||
public class U16 : KValue<ushort>
|
||||
{
|
||||
public U16(ushort value) => Value = value;
|
||||
static public U16 FromString(string input) => new U16(Convert.ToUInt16(input));
|
||||
static public U16 FromBytes(IEnumerable<byte> input) => new U16(input.FirstU16());
|
||||
}
|
||||
|
||||
[KValue(6, "s32", Count = 1, Size = 4)]
|
||||
public class S32 : KValue<int>
|
||||
{
|
||||
public S32(int value) => Value = value;
|
||||
static public S32 FromString(string input) => new S32(Convert.ToInt32(input));
|
||||
static public S32 FromBytes(IEnumerable<byte> input) => new S32(input.FirstS32());
|
||||
}
|
||||
|
||||
[KValue(7, "u32", Count = 1, Size = 4)]
|
||||
public class U32 : KValue<uint>
|
||||
{
|
||||
public U32(uint value) => Value = value;
|
||||
static public U32 FromString(string input) => new U32(Convert.ToUInt32(input));
|
||||
static public U32 FromBytes(IEnumerable<byte> input) => new U32(input.FirstU32());
|
||||
}
|
||||
|
||||
[KValue(8, "s64", Count = 1, Size = 8)]
|
||||
public class S64 : KValue<long>
|
||||
{
|
||||
public S64(long value) => Value = value;
|
||||
static public S64 FromString(string input) => new S64(Convert.ToInt64(input));
|
||||
static public S64 FromBytes(IEnumerable<byte> input) => new S64(input.FirstS64());
|
||||
}
|
||||
|
||||
[KValue(9, "u64", Count = 1, Size = 8)]
|
||||
public class U64 : KValue<ulong>
|
||||
{
|
||||
public U64(ulong value) => Value = value;
|
||||
static public U64 FromString(string input) => new U64(Convert.ToUInt64(input));
|
||||
static public U64 FromBytes(IEnumerable<byte> input) => new U64(input.FirstU64());
|
||||
}
|
||||
|
||||
[KValue(10, "bin", "binary", Count = -1, Size = 1)]
|
||||
public class Bin : KValue<byte[]>
|
||||
{
|
||||
public Bin(byte[] value) => Value = value;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join("", Value.Select(b => Convert.ToString(b, 16).PadLeft(2, '0')));
|
||||
}
|
||||
|
||||
static public Bin FromString(string input)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
static public Bin FromBytes(IEnumerable<byte> input) => new Bin(input.ToArray());
|
||||
}
|
||||
|
||||
[KValue(11, "str", "string", Count = -1, Size = 1)]
|
||||
public class Str : KValue<string>
|
||||
{
|
||||
public Str(string value) => Value = value;
|
||||
|
||||
public override string ToString() => Value;
|
||||
|
||||
static public Str FromString(string input) => new Str(input);
|
||||
|
||||
static public Str FromBytes(IEnumerable<byte> input, Encoding encoding)
|
||||
{
|
||||
byte[] data = input.ToArray();
|
||||
return new Str(encoding.GetString(data, 0, data.Length - 1));
|
||||
}
|
||||
}
|
||||
|
||||
public static class XmlTypes
|
||||
{
|
||||
public const int NodeStartType = 1;
|
||||
public const int BinType = 10;
|
||||
public const int StrType = 11;
|
||||
public const int AttrType = 46;
|
||||
public const int NodeEndType = 190;
|
||||
public const int SectionEndType = 191;
|
||||
|
||||
public class Entry
|
||||
private static Dictionary<byte, Type> lookupMap = new Dictionary<byte, Type>();
|
||||
|
||||
public static void RegisterAll()
|
||||
{
|
||||
public string[] names = null;
|
||||
public byte nodeType = 0;
|
||||
public int size = 0;
|
||||
public int count = 0;
|
||||
public Type type = typeof(object);
|
||||
public Func<IEnumerable<byte>, string> toString;
|
||||
Type[] types = new[]
|
||||
{
|
||||
typeof(Void),
|
||||
typeof(S8),
|
||||
typeof(U8),
|
||||
typeof(S16),
|
||||
typeof(U16),
|
||||
typeof(S32),
|
||||
typeof(U32),
|
||||
typeof(S64),
|
||||
typeof(U64),
|
||||
typeof(Bin),
|
||||
typeof(Str),
|
||||
};
|
||||
|
||||
foreach (Type type in types)
|
||||
{
|
||||
KValueAttribute attr = type.GetCustomAttributes(typeof(KValueAttribute), true).First() as KValueAttribute;
|
||||
|
||||
lookupMap[attr.NodeType] = type;
|
||||
KValueAttribute.Register(attr);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly Entry Void = new Entry
|
||||
public static Type GetByType(byte type)
|
||||
{
|
||||
names = new[] { "void" },
|
||||
nodeType = 1,
|
||||
};
|
||||
|
||||
public static readonly Entry S8 = new Entry
|
||||
{
|
||||
names = new[] { "s8" },
|
||||
nodeType = 2,
|
||||
size = 1,
|
||||
count = 1,
|
||||
type = typeof(sbyte),
|
||||
toString = input => input.FirstS8().ToString(),
|
||||
};
|
||||
|
||||
public static readonly Entry U8 = new Entry
|
||||
{
|
||||
names = new[] { "u8" },
|
||||
nodeType = 3,
|
||||
size = 1,
|
||||
count = 1,
|
||||
type = typeof(byte),
|
||||
toString = input => input.FirstU8().ToString(),
|
||||
};
|
||||
|
||||
public static readonly Entry S16 = new Entry
|
||||
{
|
||||
names = new[] { "s16" },
|
||||
nodeType = 4,
|
||||
size = 2,
|
||||
count = 1,
|
||||
type = typeof(short),
|
||||
toString = input => input.FirstS16().ToString(),
|
||||
};
|
||||
|
||||
public static readonly Entry U16 = new Entry
|
||||
{
|
||||
names = new[] { "u16" },
|
||||
nodeType = 5,
|
||||
size = 2,
|
||||
count = 1,
|
||||
type = typeof(ushort),
|
||||
toString = input => input.FirstU16().ToString(),
|
||||
};
|
||||
|
||||
public static readonly Entry S32 = new Entry
|
||||
{
|
||||
names = new[] { "s32" },
|
||||
nodeType = 6,
|
||||
size = 4,
|
||||
count = 1,
|
||||
type = typeof(int),
|
||||
toString = input => input.FirstS32().ToString(),
|
||||
};
|
||||
|
||||
public static readonly Entry U32 = new Entry
|
||||
{
|
||||
names = new[] { "u32" },
|
||||
nodeType = 7,
|
||||
size = 4,
|
||||
count = 1,
|
||||
type = typeof(int),
|
||||
toString = input => input.FirstU32().ToString(),
|
||||
};
|
||||
|
||||
public static readonly Entry S64 = new Entry
|
||||
{
|
||||
names = new[] { "s64" },
|
||||
nodeType = 8,
|
||||
size = 8,
|
||||
count = 1,
|
||||
type = typeof(int),
|
||||
toString = input => input.FirstS64().ToString(),
|
||||
};
|
||||
|
||||
public static readonly Entry U64 = new Entry
|
||||
{
|
||||
names = new[] { "u64" },
|
||||
nodeType = 9,
|
||||
size = 8,
|
||||
count = 1,
|
||||
type = typeof(int),
|
||||
toString = input => input.FirstU64().ToString(),
|
||||
};
|
||||
|
||||
public static readonly Entry Bin = new Entry
|
||||
{
|
||||
names = new[] { "bin", "binary" },
|
||||
nodeType = 10,
|
||||
size = 1,
|
||||
count = -1,
|
||||
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 = 1,
|
||||
count = -1,
|
||||
type = typeof(byte),
|
||||
toString = null, // special case, cannot be handled here
|
||||
};
|
||||
|
||||
private static Dictionary<string, Entry> nameLookupMap = new Dictionary<string, Entry>();
|
||||
private static Dictionary<byte, Entry> typeLookupMap = new Dictionary<byte, Entry>();
|
||||
|
||||
public static Entry GetEntryByName(string name)
|
||||
{
|
||||
if (nameLookupMap.ContainsKey(name))
|
||||
return nameLookupMap[name];
|
||||
|
||||
foreach (FieldInfo info in typeof(XmlTypes).GetFields())
|
||||
{
|
||||
if (!info.IsStatic)
|
||||
continue;
|
||||
Entry res = info.GetValue(null) as Entry;
|
||||
if (res == null || !res.names.Contains(name))
|
||||
continue;
|
||||
nameLookupMap[name] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
return null;
|
||||
if (!lookupMap.ContainsKey(type))
|
||||
throw new NotImplementedException("KValue type not implemented: " + type);
|
||||
return lookupMap[type];
|
||||
}
|
||||
|
||||
public static Entry GetEntryByType(byte type)
|
||||
public static object MakeNodeFromBytes(byte type, IEnumerable<byte> data)
|
||||
{
|
||||
if (typeLookupMap.ContainsKey(type))
|
||||
return typeLookupMap[type];
|
||||
|
||||
foreach (FieldInfo info in typeof(XmlTypes).GetFields())
|
||||
{
|
||||
if (!info.IsStatic)
|
||||
continue;
|
||||
Entry res = info.GetValue(null) as Entry;
|
||||
if (res == null || res.nodeType != type)
|
||||
continue;
|
||||
typeLookupMap[type] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> DataToString(IEnumerable<byte> dataBuf, Entry entry)
|
||||
{
|
||||
while (dataBuf.Any())
|
||||
{
|
||||
yield return entry.toString(dataBuf);
|
||||
dataBuf = dataBuf.Skip(entry.size);
|
||||
}
|
||||
return GetByType(type)
|
||||
.GetMethod("FromBytes", BindingFlags.Static | BindingFlags.Public)
|
||||
.Invoke(null, new object[] { data });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user