Refactoring

This commit is contained in:
BtbN
2019-04-17 14:59:58 +02:00
parent e731f90030
commit f9f66a9e42
4 changed files with 147 additions and 82 deletions

View File

@@ -77,7 +77,6 @@ namespace eAmuseCore.KBinXML
throw new ArgumentException("Invalid signature", "input");
input = input.Skip(1);
bool compressed;
switch (input.FirstU8())
{
case SIG_COMPRESSED:
@@ -100,20 +99,98 @@ namespace eAmuseCore.KBinXML
encoding = GetEncoding(encodingSig);
uint nodeEnd = input.FirstU32();
int nodeSize = input.FirstS32();
input = input.Skip(4);
IEnumerable<byte> nodeBuf = input.Take((int)nodeEnd);
IEnumerable<byte> dataBuf = input.Skip((int)nodeEnd);
nodeBuf = input.Take(nodeSize);
dataBuf = input.Skip(nodeSize);
dataByteBuf = dataWordBuf = Enumerable.Empty<byte>();
ParseNodes(nodeBuf, dataBuf, compressed);
ParseNodes();
}
private void ParseNodes(IEnumerable<byte> nodeBuf, IEnumerable<byte> dataBuf, bool compressed)
{
IEnumerable<byte> dataByteBuf = Enumerable.Empty<byte>();
IEnumerable<byte> dataWordBuf = Enumerable.Empty<byte>();
private IEnumerable<byte> nodeBuf = Enumerable.Empty<byte>(), dataBuf = Enumerable.Empty<byte>();
private IEnumerable<byte> dataByteBuf = Enumerable.Empty<byte>(), dataWordBuf = Enumerable.Empty<byte>();
bool compressed = false;
IEnumerable<byte> TakeDataAligned(int size, bool isArray)
{
if (size <= 0)
{
return Enumerable.Empty<byte>();
}
else if (size == 1 && !isArray)
{
if (!dataByteBuf.Any())
{
dataByteBuf = dataBuf;
dataBuf = dataBuf.Skip(4);
}
var res = dataByteBuf.Take(1);
dataByteBuf = dataByteBuf.Skip(1);
return res;
}
else if (size == 2 && !isArray)
{
if (!dataWordBuf.Any())
{
dataWordBuf = dataBuf;
dataBuf = dataBuf.Skip(4);
}
var res = dataWordBuf.Take(2);
dataWordBuf = dataWordBuf.Skip(2);
return res;
}
else
{
return EnumHelpers.TakeBytesAligned(ref dataBuf, size);
}
}
void SetNodeValue(XElement node, IEnumerable<byte> data, KValueAttribute nodeAttrs, int varCount, int arrCount)
{
if (nodeAttrs.NodeType == XmlTypes.XmlTypes.BinType)
{
node.SetAttributeValue("__size", varCount);
node.SetValue(XmlTypes.Bin.FromBytes(data));
}
else if (nodeAttrs.NodeType == XmlTypes.XmlTypes.StrType)
{
node.SetValue(XmlTypes.Str.FromBytes(data, encoding));
}
else
{
node.SetValue(XmlTypes.XmlTypes.MakeNodeFromBytes(nodeAttrs, arrCount, data));
}
}
private string GetNodeName(byte nodeType)
{
if (nodeType != XmlTypes.XmlTypes.NodeEndType && nodeType != XmlTypes.XmlTypes.SectionEndType)
{
if (compressed)
{
return SixBit.Unpack(ref nodeBuf);
}
else
{
int length = (nodeBuf.First() & ~64) + 1;
nodeBuf = nodeBuf.Skip(1);
byte[] nameBytes = nodeBuf.Take(length).ToArray();
nodeBuf = nodeBuf.Skip(length);
return encoding.GetString(nameBytes);
}
}
else
{
return "";
}
}
private void ParseNodes()
{
uint dataSize = dataBuf.FirstU32();
dataBuf = dataBuf.Skip(4);
@@ -131,24 +208,7 @@ namespace eAmuseCore.KBinXML
bool isArray = (nodeType & 64) != 0;
nodeType = (byte)(nodeType & ~64);
string name = "";
if (nodeType != XmlTypes.XmlTypes.NodeEndType && nodeType != XmlTypes.XmlTypes.SectionEndType)
{
if (compressed)
{
name = SixBit.Unpack(ref nodeBuf);
}
else
{
int length = (nodeBuf.First() & ~64) + 1;
nodeBuf = nodeBuf.Skip(1);
byte[] nameBytes = nodeBuf.Take(length).ToArray();
nodeBuf = nodeBuf.Skip(length);
name = encoding.GetString(nameBytes);
}
}
string name = GetNodeName(nodeType);
KValueAttribute nodeAttrs = null;
bool startNode = false;
@@ -202,49 +262,9 @@ namespace eAmuseCore.KBinXML
int totCount = arrCount * varCount;
int totSize = totCount * nodeAttrs.Size;
IEnumerable<byte> data = null;
if (isArray || totSize > 2)
{
data = EnumHelpers.TakeBytesAligned(ref dataBuf, totCount * nodeAttrs.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);
}
else if (totSize == 0)
{
continue;
}
IEnumerable<byte> data = TakeDataAligned(totSize, isArray);
if (nodeType == XmlTypes.XmlTypes.BinType)
{
node.SetAttributeValue("__size", totCount);
node.SetValue(XmlTypes.Bin.FromBytes(data));
}
else if (nodeType == XmlTypes.XmlTypes.StrType)
{
node.SetValue(XmlTypes.Str.FromBytes(data, encoding));
}
else
{
node.SetValue(XmlTypes.XmlTypes.MakeNodeFromBytes(nodeType, arrCount, data));
}
SetNodeValue(node, data, nodeAttrs, varCount, arrCount);
}
doc = new XDocument(fakeroot.FirstNode);

View File

@@ -4,8 +4,22 @@ using System.Linq;
namespace eAmuseCore.KBinXML
{
public class KValueList<T> : List<T>
public interface IKValue
{
string ToString();
IEnumerable<byte> ToBytes();
}
public class KValueList<T> : List<T>, IKValue where T : IKValue
{
public IEnumerable<byte> ToBytes()
{
IEnumerable<byte> res = Enumerable.Empty<byte>();
foreach (IKValue val in this)
res = res.Concat(val.ToBytes());
return res;
}
public override string ToString()
{
return string.Join(" ", this.Select(v => v.ToString()));
@@ -32,9 +46,8 @@ namespace eAmuseCore.KBinXML
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>();
private static readonly Dictionary<string, KValueAttribute> nameLookupMap = new Dictionary<string, KValueAttribute>();
private static readonly Dictionary<byte, KValueAttribute> typeLookupMap = new Dictionary<byte, KValueAttribute>();
public static void Register(KValueAttribute attr)
{
@@ -59,7 +72,7 @@ namespace eAmuseCore.KBinXML
}
}
public class KValue<T>
public class KValue<T> : IKValue
{
public T Value { get; set; }
@@ -71,7 +84,29 @@ namespace eAmuseCore.KBinXML
return (Value != null) ? Value.ToString() : "";
}
protected KValueAttribute KValAttr => GetType().GetCustomAttributes(typeof(KValueAttribute), true).First() as KValueAttribute;
public virtual IEnumerable<byte> ToBytes()
{
if (Value == null)
return Enumerable.Empty<byte>();
IEnumerable<byte> res = BitConverter.GetBytes(Convert.ToUInt64(Value));
if (BitConverter.IsLittleEndian)
res = res.Reverse();
return res.Skip(8 - Size);
}
protected KValueAttribute KValAttr
{
get
{
var res = GetType().GetCustomAttributes(typeof(KValueAttribute), true).FirstOrDefault() as KValueAttribute;
if (res == null)
throw new InvalidOperationException("KValue types need KValueAttributes!");
return res;
}
}
public int NodeType => KValAttr.NodeType;

View File

@@ -8,13 +8,16 @@ using System.Collections;
namespace eAmuseCore.KBinXML.XmlTypes
{
#pragma warning disable IDE0060 // Remove unused parameter
[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 FromString(string input) => new Void(null);
static public Void FromBytes(IEnumerable<byte> input) => new Void(null);
}
#pragma warning restore IDE0060
[KValue(2, "s8", Count = 1, Size = 1)]
public class S8 : KValue<sbyte>
@@ -90,6 +93,8 @@ namespace eAmuseCore.KBinXML.XmlTypes
return string.Join("", Value.Select(b => Convert.ToString(b, 16).PadLeft(2, '0')));
}
public override IEnumerable<byte> ToBytes() => Value;
static public Bin FromString(string input)
{
throw new NotImplementedException();
@@ -105,6 +110,8 @@ namespace eAmuseCore.KBinXML.XmlTypes
public override string ToString() => Value;
public override IEnumerable<byte> ToBytes() => Encoding.UTF8.GetBytes(Value);
static public Str FromString(string input) => new Str(input);
static public Str FromBytes(IEnumerable<byte> input, Encoding encoding)
@@ -121,6 +128,8 @@ namespace eAmuseCore.KBinXML.XmlTypes
public override string ToString() => Value.ToString();
public override IEnumerable<byte> ToBytes() => Value.GetAddressBytes();
static public IP4 FromString(string input) => new IP4(IPAddress.Parse(input));
static public IP4 FromBytes(IEnumerable<byte> input) => new IP4(new IPAddress(input.Take(4).ToArray()));
@@ -135,7 +144,7 @@ namespace eAmuseCore.KBinXML.XmlTypes
public const int NodeEndType = 190;
public const int SectionEndType = 191;
private static Dictionary<byte, Type> lookupMap = new Dictionary<byte, Type>();
private static readonly Dictionary<byte, Type> lookupMap = new Dictionary<byte, Type>();
public static void RegisterAll()
{
@@ -171,9 +180,9 @@ namespace eAmuseCore.KBinXML.XmlTypes
return lookupMap[type];
}
public static object MakeNodeFromBytes(byte type, int count, IEnumerable<byte> data)
public static object MakeNodeFromBytes(KValueAttribute attrs, int count, IEnumerable<byte> data)
{
Type valType = GetByType(type);
Type valType = GetByType(attrs.NodeType);
MethodInfo fromBytes = valType.GetMethod("FromBytes", BindingFlags.Static | BindingFlags.Public);
if (count <= 1)
@@ -184,8 +193,7 @@ namespace eAmuseCore.KBinXML.XmlTypes
{
Type listType = typeof(KValueList<>).MakeGenericType(valType);
IList list = (IList)Activator.CreateInstance(listType);
var attr = KValueAttribute.GetAttrByType(type);
int size = attr.Size * attr.Count;
int size = attrs.Size * attrs.Count;
for (int i = 0; i < count; i++)
{

View File

@@ -46,7 +46,9 @@ namespace eAmuseTest
else if (compress != "none")
throw new ArgumentException("Unsupported compression algorithm");
//KBinXML kbinxml = new KBinXML(rawData);
Console.WriteLine(BytesToString(BitConverter.GetBytes((byte)1)));
KBinXML kbinxml = new KBinXML(rawData);
KBinXML testDoc = new KBinXML(ExtractResource("eAmuseTest.testcases_out.kbin"));
}