More work on kbinxml

This commit is contained in:
BtbN
2019-04-15 16:17:59 +02:00
parent ed3d2ba40e
commit c5fa090426
5 changed files with 272 additions and 42 deletions

View File

@@ -6,36 +6,165 @@ namespace eAmuseCore.KBinXML
{
static class EnumHelpers
{
public static uint FirstU32(this IEnumerable<byte> input)
public static IEnumerable<ulong> TakeU64(this IEnumerable<byte> 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<byte> input)
public static IEnumerable<long> TakeS64(this IEnumerable<byte> 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<uint> TakeU32(this IEnumerable<byte> 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<int> TakeS32(this IEnumerable<byte> 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<ushort> TakeU16(this IEnumerable<byte> 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<short> TakeS16(this IEnumerable<byte> 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<byte> TakeU8(this IEnumerable<byte> input, int count)
{
return input.Take(count);
}
public static IEnumerable<sbyte> TakeS8(this IEnumerable<byte> input, int count)
{
return input.Take(count).Select(b => unchecked((sbyte)b));
}
public static IEnumerable<float> TakeF(this IEnumerable<byte> 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<double> TakeD(this IEnumerable<byte> 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<byte> input)
{
return input.TakeU64(1).First();
}
public static long FirstS64(this IEnumerable<byte> input)
{
return input.TakeS64(1).First();
}
public static uint FirstU32(this IEnumerable<byte> input)
{
return input.TakeU32(1).First();
}
public static int FirstS32(this IEnumerable<byte> input)
{
return input.TakeS32(1).First();
}
public static ushort FirstU16(this IEnumerable<byte> 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<byte> input)
public static short FirstS16(this IEnumerable<byte> 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<byte> input)
{
return input.TakeU8(1).First();
}
public static sbyte FirstS8(this IEnumerable<byte> input)
{
return input.TakeS8(1).First();
}
public static float FirstF(this IEnumerable<byte> input)
{
return input.TakeF(1).First();
}
public static double FirstD(this IEnumerable<byte> input)
{
return input.TakeD(1).First();
}
public static IEnumerable<object> Box<T>(this IEnumerable<T> input)
{
return input.Select(v => (object)v);
}
}
}

View File

@@ -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)

View File

@@ -52,7 +52,7 @@ namespace eAmuseCore.KBinXML
public static string Unpack(ref IEnumerable<byte> 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;

View File

@@ -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<byte>, IEnumerable<object>> read = _ => Enumerable.Empty<object>();
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<string, Entry> nameLookupMap = new Dictionary<string, Entry>();
@@ -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;

View File

@@ -49,11 +49,6 @@ namespace eAmuseTest
Console.WriteLine(BytesToString(rawData));
KBinXML kbinxml = new KBinXML(rawData);
Dictionary<int, int> dd = new Dictionary<int, int>();
dd[2] = 3;
Console.WriteLine("" + dd[2]);
Console.WriteLine("" + dd[1]);
}
private static string BytesToString(IEnumerable<byte> bytes)