mirror of
https://github.com/BtbN/ClanServer.git
synced 2026-09-09 00:45:16 -05:00
Stop using LINQ entirely, it's horribly slow.
This commit is contained in:
311
eAmuseCore/KBinXML/ByteBuffer.cs
Normal file
311
eAmuseCore/KBinXML/ByteBuffer.cs
Normal file
@@ -0,0 +1,311 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace eAmuseCore.KBinXML
|
||||
{
|
||||
public class ByteBuffer
|
||||
{
|
||||
private List<byte> data;
|
||||
private int wordWriteOffset = 0, byteWriteOffset = 0;
|
||||
private int wordReadOffset = 0, byteReadOffset = 0;
|
||||
private int limit = -1;
|
||||
private readonly int align = 4;
|
||||
|
||||
public int Offset { get; set; } = 0;
|
||||
|
||||
public int Length
|
||||
{
|
||||
get => (limit >= 0) ? limit : data.Count;
|
||||
}
|
||||
|
||||
public int Remaining
|
||||
{
|
||||
get => Length - Offset;
|
||||
}
|
||||
|
||||
public bool AtEnd
|
||||
{
|
||||
get => Offset >= Length;
|
||||
}
|
||||
|
||||
public ByteBuffer()
|
||||
{
|
||||
data = new List<byte>();
|
||||
}
|
||||
|
||||
public ByteBuffer(IEnumerable<byte> data)
|
||||
{
|
||||
this.data = new List<byte>(data);
|
||||
}
|
||||
|
||||
public ByteBuffer(ByteBuffer other)
|
||||
{
|
||||
data = other.data;
|
||||
Offset = other.Offset;
|
||||
}
|
||||
|
||||
public byte this[int idx]
|
||||
{
|
||||
get => data[idx];
|
||||
set => data[idx] = value;
|
||||
}
|
||||
|
||||
public void CopyTo(int idx, byte[] arr, int offset, int count)
|
||||
{
|
||||
data.CopyTo(idx, arr, offset, count);
|
||||
}
|
||||
|
||||
public ByteBuffer MakeSub(int offset, int length = -1)
|
||||
{
|
||||
ByteBuffer res = new ByteBuffer(this);
|
||||
res.Offset += offset;
|
||||
if (length >= 0 && offset + length <= Length)
|
||||
res.limit = offset + length;
|
||||
return res;
|
||||
}
|
||||
|
||||
public void RealignReads()
|
||||
{
|
||||
int realign = align - (Offset % align);
|
||||
if (realign == align)
|
||||
return;
|
||||
Offset += realign;
|
||||
}
|
||||
|
||||
public void RealignWrites()
|
||||
{
|
||||
int realign = align - (data.Count % align);
|
||||
if (realign == align)
|
||||
return;
|
||||
while (realign-- > 0)
|
||||
data.Add(0);
|
||||
}
|
||||
|
||||
public byte[] TakeBytes(int count)
|
||||
{
|
||||
byte[] res = new byte[count];
|
||||
data.CopyTo(Offset, res, 0, count);
|
||||
Offset += count;
|
||||
return res;
|
||||
}
|
||||
|
||||
public byte[] TakeBytesSubAligned(int count)
|
||||
{
|
||||
byte[] res = new byte[count];
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
if (byteReadOffset % align == 0)
|
||||
{
|
||||
byteReadOffset = Offset;
|
||||
Offset += align;
|
||||
}
|
||||
data.CopyTo(byteReadOffset, res, 0, 1);
|
||||
byteReadOffset += 1;
|
||||
}
|
||||
else if (count == 2)
|
||||
{
|
||||
if (wordReadOffset % align == 0)
|
||||
{
|
||||
wordReadOffset = Offset;
|
||||
Offset += align;
|
||||
}
|
||||
data.CopyTo(wordReadOffset, res, 0, 2);
|
||||
wordReadOffset += 2;
|
||||
}
|
||||
else if (count >= 3)
|
||||
{
|
||||
data.CopyTo(Offset, res, 0, count);
|
||||
Offset += count;
|
||||
RealignReads();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public byte[] TakeBytesAligned(int count)
|
||||
{
|
||||
byte[] res = TakeBytes(count);
|
||||
RealignReads();
|
||||
return res;
|
||||
}
|
||||
|
||||
public byte[] TakeBytesEndian(int count)
|
||||
{
|
||||
byte[] res = TakeBytes(count);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public byte TakeU8()
|
||||
{
|
||||
return data[Offset++];
|
||||
}
|
||||
|
||||
public sbyte TakeS8()
|
||||
{
|
||||
return unchecked((sbyte)data[Offset++]);
|
||||
}
|
||||
|
||||
public ushort TakeU16()
|
||||
{
|
||||
byte[] bytes = TakeBytesEndian(2);
|
||||
return BitConverter.ToUInt16(bytes, 0);
|
||||
}
|
||||
|
||||
public short TakeS16()
|
||||
{
|
||||
byte[] bytes = TakeBytesEndian(2);
|
||||
return BitConverter.ToInt16(bytes, 0);
|
||||
}
|
||||
|
||||
public uint TakeU32()
|
||||
{
|
||||
byte[] bytes = TakeBytesEndian(4);
|
||||
return BitConverter.ToUInt32(bytes, 0);
|
||||
}
|
||||
|
||||
public int TakeS32()
|
||||
{
|
||||
byte[] bytes = TakeBytesEndian(4);
|
||||
return BitConverter.ToInt32(bytes, 0);
|
||||
}
|
||||
|
||||
public ulong TakeU64()
|
||||
{
|
||||
byte[] bytes = TakeBytesEndian(8);
|
||||
return BitConverter.ToUInt64(bytes, 0);
|
||||
}
|
||||
|
||||
public long TakeS64()
|
||||
{
|
||||
byte[] bytes = TakeBytesEndian(8);
|
||||
return BitConverter.ToInt64(bytes, 0);
|
||||
}
|
||||
|
||||
public float TakeFloat()
|
||||
{
|
||||
byte[] bytes = TakeBytesEndian(4);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
public double TakeDouble()
|
||||
{
|
||||
byte[] bytes = TakeBytesEndian(8);
|
||||
return BitConverter.ToDouble(bytes, 0);
|
||||
}
|
||||
|
||||
public string TakeString(Encoding encoding)
|
||||
{
|
||||
int length = TakeS32();
|
||||
byte[] bytes = TakeBytes(length);
|
||||
return encoding.GetString(bytes, 0, length - 1);
|
||||
}
|
||||
|
||||
public void AddBytes(IEnumerable<byte> bytes)
|
||||
{
|
||||
data.AddRange(bytes);
|
||||
}
|
||||
|
||||
public void AddBytesSubAligned(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length == 1)
|
||||
{
|
||||
if (byteWriteOffset % align == 0)
|
||||
{
|
||||
byteWriteOffset = data.Count;
|
||||
data.AddRange(new byte[align]);
|
||||
}
|
||||
data[byteWriteOffset++] = bytes[0];
|
||||
}
|
||||
else if (bytes.Length == 2)
|
||||
{
|
||||
if (wordWriteOffset % align == 0)
|
||||
{
|
||||
wordWriteOffset = data.Count;
|
||||
data.AddRange(new byte[align]);
|
||||
}
|
||||
data[wordWriteOffset++] = bytes[0];
|
||||
data[wordWriteOffset++] = bytes[1];
|
||||
}
|
||||
else if(bytes.Length >= 3)
|
||||
{
|
||||
data.AddRange(bytes);
|
||||
RealignWrites();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBytesAligned(byte[] bytes)
|
||||
{
|
||||
data.AddRange(bytes);
|
||||
RealignWrites();
|
||||
}
|
||||
|
||||
public void AddBytesEndian(byte[] bytes)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(bytes);
|
||||
data.AddRange(bytes);
|
||||
}
|
||||
|
||||
public void AddU8(byte input)
|
||||
{
|
||||
data.Add(input);
|
||||
}
|
||||
|
||||
public void AddS8(sbyte input)
|
||||
{
|
||||
data.Add(unchecked((byte)input));
|
||||
}
|
||||
|
||||
public void AddU16(ushort input)
|
||||
{
|
||||
AddBytesEndian(BitConverter.GetBytes(input));
|
||||
}
|
||||
|
||||
public void AddS16(short input)
|
||||
{
|
||||
AddBytesEndian(BitConverter.GetBytes(input));
|
||||
}
|
||||
|
||||
public void AddU32(uint input)
|
||||
{
|
||||
AddBytesEndian(BitConverter.GetBytes(input));
|
||||
}
|
||||
|
||||
public void AddS32(int input)
|
||||
{
|
||||
AddBytesEndian(BitConverter.GetBytes(input));
|
||||
}
|
||||
|
||||
public void AddU64(ulong input)
|
||||
{
|
||||
AddBytesEndian(BitConverter.GetBytes(input));
|
||||
}
|
||||
|
||||
public void AddS64(long input)
|
||||
{
|
||||
AddBytesEndian(BitConverter.GetBytes(input));
|
||||
}
|
||||
|
||||
public void AddFloat(float input)
|
||||
{
|
||||
AddBytesEndian(BitConverter.GetBytes(input));
|
||||
}
|
||||
|
||||
public void AddDouble(double input)
|
||||
{
|
||||
AddBytesEndian(BitConverter.GetBytes(input));
|
||||
}
|
||||
|
||||
public void AddString(string input, Encoding encoding)
|
||||
{
|
||||
byte[] bytes = encoding.GetBytes(input);
|
||||
AddS32(bytes.Length + 1);
|
||||
AddBytes(bytes);
|
||||
AddU8(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,222 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace eAmuseCore.KBinXML.Helpers
|
||||
{
|
||||
static class EnumHelpers
|
||||
static class ByteArrayHelpers
|
||||
{
|
||||
public static IEnumerable<ulong> TakeU64(this IEnumerable<byte> input, int count)
|
||||
public static ulong GetU64(this byte[] input, int offset = 0)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
input = input.Take(8);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
input = input.Reverse();
|
||||
yield return BitConverter.ToUInt64(input.ToArray(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<long> TakeS64(this IEnumerable<byte> input, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
input = input.Take(8);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
input = input.Reverse();
|
||||
yield return BitConverter.ToInt64(input.ToArray(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<uint> TakeU32(this IEnumerable<byte> input, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
input = input.Take(4);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
input = input.Reverse();
|
||||
yield return BitConverter.ToUInt32(input.ToArray(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<int> TakeS32(this IEnumerable<byte> input, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
input = input.Take(4);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
input = input.Reverse();
|
||||
yield return BitConverter.ToInt32(input.ToArray(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<ushort> TakeU16(this IEnumerable<byte> input, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
input = input.Take(2);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
input = input.Reverse();
|
||||
yield return BitConverter.ToUInt16(input.ToArray(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<short> TakeS16(this IEnumerable<byte> input, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
input = input.Take(2);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
input = input.Reverse();
|
||||
yield return BitConverter.ToInt16(input.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)
|
||||
{
|
||||
input = input.Take(4);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
input = input.Reverse();
|
||||
yield return BitConverter.ToSingle(input.ToArray(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<double> TakeD(this IEnumerable<byte> input, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
input = input.Take(8);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
input = input.Reverse();
|
||||
yield return BitConverter.ToDouble(input.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)
|
||||
{
|
||||
return input.TakeU16(1).First();
|
||||
}
|
||||
|
||||
public static short FirstS16(this IEnumerable<byte> input)
|
||||
{
|
||||
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 void AddU8(this List<byte> list, byte data)
|
||||
{
|
||||
list.Add(data);
|
||||
}
|
||||
|
||||
public static void AddS8(this List<byte> list, sbyte data)
|
||||
{
|
||||
list.Add(unchecked((byte)data));
|
||||
}
|
||||
|
||||
public static void AddRangeAligned(this List<byte> list, IEnumerable<byte> data, int alignment = 4)
|
||||
{
|
||||
list.AddRange(data);
|
||||
list.Realign(alignment);
|
||||
}
|
||||
|
||||
public static IEnumerable<byte> TakeBytesAligned(ref IEnumerable<byte> input, int size, int alignment = 4)
|
||||
{
|
||||
var res = input.Take(size);
|
||||
input = input.Skip(size);
|
||||
|
||||
int align = alignment - (size % alignment);
|
||||
if (align != alignment)
|
||||
input = input.Skip(align);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static string TakeStringAligned(ref IEnumerable<byte> input, Encoding encoding, int alignment = 4)
|
||||
{
|
||||
int size = input.FirstS32();
|
||||
input = input.Skip(4);
|
||||
byte[] data = TakeBytesAligned(ref input, size, alignment).ToArray();
|
||||
return encoding.GetString(data, 0, data.Length - 1); // drop final null byte
|
||||
}
|
||||
}
|
||||
|
||||
public static class ListHelpers
|
||||
{
|
||||
public static void AddU32(this List<byte> list, uint data)
|
||||
{
|
||||
IEnumerable<byte> bytes = BitConverter.GetBytes(data);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
bytes = bytes.Reverse();
|
||||
list.AddRange(bytes);
|
||||
Array.Reverse(input, offset, 8);
|
||||
return BitConverter.ToUInt64(input, offset);
|
||||
}
|
||||
|
||||
public static void AddS32(this List<byte> list, int data)
|
||||
public static long GetS64(this byte[] input, int offset = 0)
|
||||
{
|
||||
IEnumerable<byte> bytes = BitConverter.GetBytes(data);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
bytes = bytes.Reverse();
|
||||
list.AddRange(bytes);
|
||||
Array.Reverse(input, offset, 8);
|
||||
return BitConverter.ToInt64(input, offset);
|
||||
}
|
||||
|
||||
public static void Realign(this List<byte> list, int alignment = 4)
|
||||
public static uint GetU32(this byte[] input, int offset = 0)
|
||||
{
|
||||
int align = alignment - (list.Count % alignment);
|
||||
if (align == alignment)
|
||||
return;
|
||||
while (align-- > 0)
|
||||
list.Add(0);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(input, offset, 4);
|
||||
return BitConverter.ToUInt32(input, offset);
|
||||
}
|
||||
|
||||
public static int GetS32(this byte[] input, int offset = 0)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(input, offset, 4);
|
||||
return BitConverter.ToInt32(input, offset);
|
||||
}
|
||||
|
||||
public static ushort GetU16(this byte[] input, int offset = 0)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(input, offset, 2);
|
||||
return BitConverter.ToUInt16(input, offset);
|
||||
}
|
||||
|
||||
public static short GetS16(this byte[] input, int offset = 0)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(input, offset, 2);
|
||||
return BitConverter.ToInt16(input, offset);
|
||||
}
|
||||
|
||||
public static byte GetU8(this byte[] input, int offset = 0)
|
||||
{
|
||||
return input[offset];
|
||||
}
|
||||
|
||||
public static sbyte GetS8(this byte[] input, int offset = 0)
|
||||
{
|
||||
return unchecked((sbyte)input[offset]);
|
||||
}
|
||||
|
||||
public static float GetFloat(this byte[] input, int offset = 0)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(input, offset, 4);
|
||||
return BitConverter.ToSingle(input, offset);
|
||||
}
|
||||
|
||||
public static double GetDouble(this byte[] input, int offset = 0)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(input, offset, 8);
|
||||
return BitConverter.ToDouble(input, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using eAmuseCore.KBinXML.Helpers;
|
||||
|
||||
namespace eAmuseCore.KBinXML
|
||||
{
|
||||
@@ -56,9 +52,12 @@ namespace eAmuseCore.KBinXML
|
||||
}
|
||||
|
||||
public XDocument Document { get; private set; }
|
||||
public IEnumerable<byte> Bytes { get; private set; }
|
||||
public byte[] Bytes { get; private set; }
|
||||
public Encoding BinEncoding { get; private set; }
|
||||
|
||||
private ByteBuffer nodeBuf = null, dataBuf = null;
|
||||
bool compressed = false;
|
||||
|
||||
public KBinXML(XDocument doc, Encoding encoding, bool compress = true)
|
||||
{
|
||||
Document = doc;
|
||||
@@ -72,7 +71,7 @@ namespace eAmuseCore.KBinXML
|
||||
:this(doc, Encoding.GetEncoding(932), compress)
|
||||
{ }
|
||||
|
||||
public KBinXML(IEnumerable<byte> input)
|
||||
public KBinXML(byte[] input)
|
||||
{
|
||||
Bytes = input;
|
||||
|
||||
@@ -86,7 +85,7 @@ namespace eAmuseCore.KBinXML
|
||||
|
||||
private void Generate()
|
||||
{
|
||||
List<byte> header = new List<byte>(8);
|
||||
ByteBuffer header = new ByteBuffer();
|
||||
header.AddU8(SIGNATURE);
|
||||
|
||||
if (compressed)
|
||||
@@ -98,26 +97,28 @@ namespace eAmuseCore.KBinXML
|
||||
header.AddU8(encodingSig);
|
||||
header.AddU8((byte)(0xFF ^ encodingSig));
|
||||
|
||||
nodeList = new List<byte>();
|
||||
dataList = new List<byte>();
|
||||
dataByteOffset = dataWordOffset = 0;
|
||||
nodeBuf = new ByteBuffer();
|
||||
dataBuf = new ByteBuffer();
|
||||
|
||||
GenerateNode(Document.Root);
|
||||
|
||||
nodeList.AddU8(XmlType.SectionEndType | 64);
|
||||
nodeList.Realign();
|
||||
nodeBuf.AddU8(XmlType.SectionEndType | 64);
|
||||
nodeBuf.RealignWrites();
|
||||
|
||||
header.AddU32((uint)nodeList.Count);
|
||||
nodeList.AddU32((uint)dataList.Count);
|
||||
header.AddU32((uint)nodeBuf.Length);
|
||||
nodeBuf.AddU32((uint)dataBuf.Length);
|
||||
|
||||
Bytes = header.Concat(nodeList).Concat(dataList).ToArray();
|
||||
byte[] bytes = new byte[header.Length + nodeBuf.Length + dataBuf.Length];
|
||||
|
||||
nodeList = dataList = null;
|
||||
header.CopyTo(0, bytes, 0, header.Length);
|
||||
nodeBuf.CopyTo(0, bytes, header.Length, nodeBuf.Length);
|
||||
dataBuf.CopyTo(0, bytes, header.Length + nodeBuf.Length, dataBuf.Length);
|
||||
|
||||
Bytes = bytes;
|
||||
|
||||
nodeBuf = dataBuf = null;
|
||||
}
|
||||
|
||||
private List<byte> nodeList = null, dataList = null;
|
||||
private int dataByteOffset = 0, dataWordOffset = 0;
|
||||
|
||||
private bool NodeIsMixed(XElement element)
|
||||
{
|
||||
bool text = false;
|
||||
@@ -141,52 +142,16 @@ namespace eAmuseCore.KBinXML
|
||||
{
|
||||
if (compressed)
|
||||
{
|
||||
nodeList.AddRange(SixBit.Pack(name));
|
||||
nodeBuf.AddBytes(SixBit.Pack(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] bytes = BinEncoding.GetBytes(name);
|
||||
nodeList.AddU8((byte)((bytes.Length - 1) | 64));
|
||||
nodeList.AddRange(bytes);
|
||||
nodeBuf.AddU8((byte)((bytes.Length - 1) | 64));
|
||||
nodeBuf.AddBytes(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddDataAligned(byte[] data)
|
||||
{
|
||||
if (data.Length == 1)
|
||||
{
|
||||
if (dataByteOffset % 4 == 0)
|
||||
{
|
||||
dataByteOffset = dataList.Count;
|
||||
dataList.AddU32(0);
|
||||
}
|
||||
dataList[dataByteOffset++] = data[0];
|
||||
}
|
||||
else if (data.Length == 2)
|
||||
{
|
||||
if(dataWordOffset % 4 == 0)
|
||||
{
|
||||
dataWordOffset = dataList.Count;
|
||||
dataList.AddU32(0);
|
||||
}
|
||||
dataList[dataWordOffset++] = data[0];
|
||||
dataList[dataWordOffset++] = data[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
dataList.AddRangeAligned(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddStringAligned(string str)
|
||||
{
|
||||
byte[] bytes = BinEncoding.GetBytes(str);
|
||||
dataList.AddS32(bytes.Length + 1);
|
||||
dataList.AddRange(bytes);
|
||||
dataList.AddU8(0);
|
||||
dataList.Realign();
|
||||
}
|
||||
|
||||
private byte[] GetNodeData(XElement node, byte nodeType, XmlType xmlType, int count)
|
||||
{
|
||||
if (nodeType == XmlType.StrType)
|
||||
@@ -194,7 +159,10 @@ namespace eAmuseCore.KBinXML
|
||||
if (count != 1)
|
||||
throw new FormatException("String value cannot have a count != 1.");
|
||||
|
||||
return BinEncoding.GetBytes(node.Value).Concat(new byte[] { 0 }).ToArray();
|
||||
byte[] res = BinEncoding.GetBytes(node.Value);
|
||||
Array.Resize(ref res, res.Length + 1);
|
||||
res[res.Length - 1] = 0;
|
||||
return res;
|
||||
}
|
||||
else if (nodeType == XmlType.BinType)
|
||||
{
|
||||
@@ -210,20 +178,17 @@ namespace eAmuseCore.KBinXML
|
||||
}
|
||||
else
|
||||
{
|
||||
IEnumerable<string> parts = node.Value.Split(' ');
|
||||
if (parts.Count() != count * xmlType.Count)
|
||||
string[] parts = node.Value.Split(' ');
|
||||
if (parts.Length != count * xmlType.Count)
|
||||
throw new ArgumentException("Node value does not have required amount of fields.", "node");
|
||||
|
||||
IEnumerable<byte> res = Enumerable.Empty<byte>();
|
||||
byte[] res = new byte[xmlType.Size * count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
res = res.Concat(
|
||||
xmlType.KFromString(
|
||||
string.Join(" ", parts.Take(xmlType.Count))));
|
||||
parts = parts.Skip(xmlType.Count);
|
||||
Buffer.BlockCopy(xmlType.KFromString(parts, i * xmlType.Count), 0, res, xmlType.Size * i, xmlType.Size);
|
||||
}
|
||||
|
||||
return res.ToArray();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +222,7 @@ namespace eAmuseCore.KBinXML
|
||||
isArray = true;
|
||||
}
|
||||
|
||||
nodeList.AddU8((byte)(nodeType | (isArray ? 64 : 0)));
|
||||
nodeBuf.AddU8((byte)(nodeType | (isArray ? 64 : 0)));
|
||||
AddNodeName(node.Name.LocalName);
|
||||
|
||||
if (nodeType != XmlType.VoidType)
|
||||
@@ -266,42 +231,42 @@ namespace eAmuseCore.KBinXML
|
||||
|
||||
if (isArray || xmlType.Count < 0)
|
||||
{
|
||||
dataList.AddU32((uint)data.Length);
|
||||
dataList.AddRangeAligned(data);
|
||||
dataBuf.AddS32(data.Length);
|
||||
dataBuf.AddBytesAligned(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddDataAligned(data.ToArray());
|
||||
dataBuf.AddBytesSubAligned(data);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (XAttribute attr in node.Attributes())
|
||||
{
|
||||
if (new[] { "__type", "__size", "__count" }.Contains(attr.Name.LocalName))
|
||||
if (attr.Name.LocalName == "__type" || attr.Name.LocalName == "__size" || attr.Name.LocalName == "__count")
|
||||
continue;
|
||||
|
||||
nodeList.AddU8(XmlType.AttrType);
|
||||
nodeBuf.AddU8(XmlType.AttrType);
|
||||
AddNodeName(attr.Name.LocalName);
|
||||
|
||||
AddStringAligned(attr.Value);
|
||||
dataBuf.AddString(attr.Value, BinEncoding);
|
||||
dataBuf.RealignWrites();
|
||||
}
|
||||
|
||||
foreach (XElement child in node.Elements())
|
||||
GenerateNode(child);
|
||||
|
||||
nodeList.AddU8(XmlType.NodeEndType | 64);
|
||||
nodeBuf.AddU8(XmlType.NodeEndType | 64);
|
||||
}
|
||||
|
||||
private void Parse()
|
||||
{
|
||||
IEnumerable<byte> input = Bytes;
|
||||
ByteBuffer input = new ByteBuffer(Bytes);
|
||||
Document = new XDocument();
|
||||
|
||||
if (input.FirstU8() != SIGNATURE)
|
||||
if (input.TakeU8() != SIGNATURE)
|
||||
throw new ArgumentException("Invalid signature", "input");
|
||||
input = input.Skip(1);
|
||||
|
||||
switch (input.FirstU8())
|
||||
switch (input.TakeU8())
|
||||
{
|
||||
case SIG_COMPRESSED:
|
||||
compressed = true;
|
||||
@@ -312,67 +277,23 @@ namespace eAmuseCore.KBinXML
|
||||
default:
|
||||
throw new ArgumentException("Invalud compression info", "input");
|
||||
}
|
||||
input = input.Skip(1);
|
||||
|
||||
byte encodingSig = input.FirstU8();
|
||||
input = input.Skip(1);
|
||||
byte encodingSig = input.TakeU8();
|
||||
|
||||
if (input.FirstU8() != (0xFF ^ encodingSig))
|
||||
if (input.TakeU8() != (0xFF ^ encodingSig))
|
||||
throw new ArgumentException("Encoding signature failed to verify", "input");
|
||||
input = input.Skip(1);
|
||||
|
||||
|
||||
BinEncoding = GetEncoding(encodingSig);
|
||||
|
||||
uint nodesSize = input.FirstU32();
|
||||
input = input.Skip(4);
|
||||
int nodesSize = input.TakeS32();
|
||||
|
||||
nodeBuf = input.Take((int)nodesSize);
|
||||
dataBuf = input.Skip((int)nodesSize);
|
||||
dataByteBuf = dataWordBuf = Enumerable.Empty<byte>();
|
||||
nodeBuf = input.MakeSub(0, nodesSize);
|
||||
dataBuf = input.MakeSub(nodesSize);
|
||||
|
||||
ParseNodes();
|
||||
|
||||
nodeBuf = dataBuf = null;
|
||||
dataByteBuf = dataWordBuf = null;
|
||||
Bytes = Bytes.ToArray();
|
||||
}
|
||||
|
||||
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.Take(4);
|
||||
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.Take(4);
|
||||
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, byte nodeType, XmlType xmlType, bool isArray)
|
||||
@@ -381,38 +302,43 @@ namespace eAmuseCore.KBinXML
|
||||
int arrCount = 1;
|
||||
if (varCount < 0)
|
||||
{
|
||||
varCount = dataBuf.FirstS32();
|
||||
dataBuf = dataBuf.Skip(4);
|
||||
varCount = dataBuf.TakeS32();
|
||||
isArray = true;
|
||||
}
|
||||
else if (isArray)
|
||||
{
|
||||
arrCount = dataBuf.FirstS32() / (xmlType.Size * xmlType.Count);
|
||||
dataBuf = dataBuf.Skip(4);
|
||||
arrCount = dataBuf.TakeS32() / (xmlType.Size * xmlType.Count);
|
||||
node.SetAttributeValue("__count", arrCount);
|
||||
}
|
||||
int totCount = arrCount * varCount;
|
||||
int totSize = totCount * xmlType.Size;
|
||||
|
||||
IEnumerable<byte> data = TakeDataAligned(totSize, isArray);
|
||||
byte[] data;
|
||||
if (isArray)
|
||||
data = dataBuf.TakeBytesAligned(totSize);
|
||||
else
|
||||
data = dataBuf.TakeBytesSubAligned(totSize);
|
||||
|
||||
if (nodeType == XmlType.BinType)
|
||||
{
|
||||
node.SetAttributeValue("__size", varCount);
|
||||
node.SetValue(string.Join("", data.Select(b => Convert.ToString(b, 16).PadLeft(2, '0'))));
|
||||
node.SetAttributeValue("__size", data.Length);
|
||||
|
||||
StringBuilder sb = new StringBuilder(data.Length * 2);
|
||||
for (int i = 0; i < data.Length; ++i)
|
||||
sb.Append(Convert.ToString(data[i], 16).PadLeft(2, '0'));
|
||||
|
||||
node.SetValue(sb.ToString());
|
||||
}
|
||||
else if (nodeType == XmlType.StrType)
|
||||
{
|
||||
byte[] strData = data.ToArray();
|
||||
node.SetValue(BinEncoding.GetString(strData, 0, strData.Length - 1));
|
||||
node.SetValue(BinEncoding.GetString(data, 0, data.Length - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] parts = new string[arrCount];
|
||||
for (int i = 0; i < arrCount; ++i)
|
||||
{
|
||||
parts[i] = xmlType.KToString(data.Take(xmlType.Size));
|
||||
data = data.Skip(xmlType.Size);
|
||||
parts[i] = xmlType.KToString(data, i * xmlType.Size);
|
||||
}
|
||||
node.SetValue(string.Join(" ", parts));
|
||||
}
|
||||
@@ -424,15 +350,12 @@ namespace eAmuseCore.KBinXML
|
||||
{
|
||||
if (compressed)
|
||||
{
|
||||
return SixBit.Unpack(ref nodeBuf);
|
||||
return SixBit.Unpack(nodeBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
int length = (nodeBuf.First() & ~64) + 1;
|
||||
nodeBuf = nodeBuf.Skip(1);
|
||||
|
||||
byte[] nameBytes = nodeBuf.Take(length).ToArray();
|
||||
nodeBuf = nodeBuf.Skip(length);
|
||||
int length = (nodeBuf.TakeU8() & ~64) + 1;
|
||||
byte[] nameBytes = nodeBuf.TakeBytes(length);
|
||||
|
||||
return BinEncoding.GetString(nameBytes);
|
||||
}
|
||||
@@ -445,19 +368,18 @@ namespace eAmuseCore.KBinXML
|
||||
|
||||
private void ParseNodes()
|
||||
{
|
||||
uint dataSize = dataBuf.FirstU32();
|
||||
dataBuf = dataBuf.Skip(4);
|
||||
uint dataSize = dataBuf.TakeU32();
|
||||
|
||||
XElement fakeroot = new XElement("fakeroot");
|
||||
XElement node = fakeroot;
|
||||
|
||||
bool nodesLeft = true;
|
||||
while (nodesLeft && nodeBuf.Any())
|
||||
while (nodesLeft && !nodeBuf.AtEnd)
|
||||
{
|
||||
nodeBuf = nodeBuf.SkipWhile(b => b == 0);
|
||||
while (nodeBuf[nodeBuf.Offset] == 0)
|
||||
nodeBuf.Offset += 1;
|
||||
|
||||
byte nodeType = nodeBuf.FirstU8();
|
||||
nodeBuf = nodeBuf.Skip(1);
|
||||
byte nodeType = nodeBuf.TakeU8();
|
||||
|
||||
bool isArray = (nodeType & 64) != 0;
|
||||
nodeType = (byte)(nodeType & ~64);
|
||||
@@ -470,7 +392,8 @@ namespace eAmuseCore.KBinXML
|
||||
switch (nodeType)
|
||||
{
|
||||
case XmlType.AttrType:
|
||||
string attrVal = EnumHelpers.TakeStringAligned(ref dataBuf, BinEncoding);
|
||||
string attrVal = dataBuf.TakeString(BinEncoding);
|
||||
dataBuf.RealignReads();
|
||||
node.SetAttributeValue(name, attrVal);
|
||||
break;
|
||||
case XmlType.NodeEndType:
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
using eAmuseCore.KBinXML.Helpers;
|
||||
using System.Text;
|
||||
|
||||
namespace eAmuseCore.KBinXML
|
||||
{
|
||||
public static class SixBit
|
||||
@@ -32,10 +28,10 @@ namespace eAmuseCore.KBinXML
|
||||
|
||||
try
|
||||
{
|
||||
foreach (byte i in input.Select(c => bytemap[c]))
|
||||
foreach (char c in input)
|
||||
{
|
||||
bits <<= 6;
|
||||
bits |= i;
|
||||
bits |= bytemap[c];
|
||||
}
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
@@ -45,27 +41,31 @@ namespace eAmuseCore.KBinXML
|
||||
|
||||
bits <<= padding;
|
||||
|
||||
return bits.ToByteArray().Take(length_bytes).Append((byte)input.Length).Reverse().ToArray();
|
||||
byte[] res = new byte[length_bytes + 1];
|
||||
Buffer.BlockCopy(bits.ToByteArray(), 0, res, 1, length_bytes);
|
||||
Array.Reverse(res, 1, length_bytes);
|
||||
res[0] = (byte)input.Length;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static string Unpack(byte[] data)
|
||||
{
|
||||
IEnumerable<byte> nodeBuf = data.AsEnumerable();
|
||||
return Unpack(ref nodeBuf);
|
||||
return Unpack(new ByteBuffer(data));
|
||||
}
|
||||
|
||||
public static string Unpack(ref IEnumerable<byte> nodeBuf)
|
||||
public static string Unpack(ByteBuffer nodeBuf)
|
||||
{
|
||||
int length = nodeBuf.FirstU8();
|
||||
nodeBuf = nodeBuf.Skip(1);
|
||||
int length = nodeBuf.TakeU8();
|
||||
|
||||
int length_bits = length * 6;
|
||||
int length_bytes = (length_bits + 7) / 8;
|
||||
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.TakeU8(length_bytes).Reverse().ToArray());
|
||||
nodeBuf = nodeBuf.Skip(length_bytes);
|
||||
byte[] bytes = nodeBuf.TakeBytes(length_bytes);
|
||||
Array.Reverse(bytes);
|
||||
BigInteger bits = new BigInteger(bytes);
|
||||
|
||||
bits >>= padding;
|
||||
|
||||
char[] res = new char[length];
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
|
||||
using eAmuseCore.KBinXML.Helpers;
|
||||
|
||||
namespace eAmuseCore.KBinXML
|
||||
{
|
||||
public delegate string KBinToString(IEnumerable<byte> input);
|
||||
public delegate IEnumerable<byte> KBinFromString(string input);
|
||||
public delegate string KBinToString(byte[] input, int offset);
|
||||
public delegate byte[] KBinFromString(string[] input, int offset);
|
||||
|
||||
public class KBinConverter
|
||||
{
|
||||
@@ -24,22 +21,32 @@ namespace eAmuseCore.KBinXML
|
||||
public KBinFromString KFromString { get; }
|
||||
public KBinToString KToString { get; }
|
||||
|
||||
public static KBinConverter S8 = new KBinConverter(s => Convert.ToSByte(s).ToBytes(), b => b.FirstS8().ToString());
|
||||
public static KBinConverter U8 = new KBinConverter(s => Convert.ToByte(s).ToBytes(), b => b.FirstU8().ToString());
|
||||
public static KBinConverter S16 = new KBinConverter(s => Convert.ToInt16(s).ToBytes(), b => b.FirstS16().ToString());
|
||||
public static KBinConverter U16 = new KBinConverter(s => Convert.ToUInt16(s).ToBytes(), b => b.FirstU16().ToString());
|
||||
public static KBinConverter S32 = new KBinConverter(s => Convert.ToInt32(s).ToBytes(), b => b.FirstS32().ToString());
|
||||
public static KBinConverter U32 = new KBinConverter(s => Convert.ToUInt32(s).ToBytes(), b => b.FirstU32().ToString());
|
||||
public static KBinConverter S64 = new KBinConverter(s => Convert.ToInt64(s).ToBytes(), b => b.FirstS64().ToString());
|
||||
public static KBinConverter U64 = new KBinConverter(s => Convert.ToUInt64(s).ToBytes(), b => b.FirstU64().ToString());
|
||||
public static KBinConverter S8 = new KBinConverter((s, o) => Convert.ToSByte(s[o]).ToBytes(), (b, o) => b.GetS8(o).ToString());
|
||||
public static KBinConverter U8 = new KBinConverter((s, o) => Convert.ToByte(s[o]).ToBytes(), (b, o) => b.GetU8(o).ToString());
|
||||
public static KBinConverter S16 = new KBinConverter((s, o) => Convert.ToInt16(s[o]).ToBytes(), (b, o) => b.GetS16(o).ToString());
|
||||
public static KBinConverter U16 = new KBinConverter((s, o) => Convert.ToUInt16(s[o]).ToBytes(), (b, o) => b.GetU16(o).ToString());
|
||||
public static KBinConverter S32 = new KBinConverter((s, o) => Convert.ToInt32(s[o]).ToBytes(), (b, o) => b.GetS32(o).ToString());
|
||||
public static KBinConverter U32 = new KBinConverter((s, o) => Convert.ToUInt32(s[o]).ToBytes(), (b, o) => b.GetU32(o).ToString());
|
||||
public static KBinConverter S64 = new KBinConverter((s, o) => Convert.ToInt64(s[o]).ToBytes(), (b, o) => b.GetS64(o).ToString());
|
||||
public static KBinConverter U64 = new KBinConverter((s, o) => Convert.ToUInt64(s[o]).ToBytes(), (b, o) => b.GetU64(o).ToString());
|
||||
|
||||
public static KBinConverter KFloat = new KBinConverter(s => Convert.ToSingle(s).ToBytes(), b => b.FirstF().ToString());
|
||||
public static KBinConverter KDouble = new KBinConverter(s => Convert.ToDouble(s).ToBytes(), b => b.FirstD().ToString());
|
||||
public static KBinConverter KFloat = new KBinConverter((s, o) => Convert.ToSingle(s[o]).ToBytes(), (b, o) => b.GetFloat(o).ToString());
|
||||
public static KBinConverter KDouble = new KBinConverter((s, o) => Convert.ToDouble(s[o]).ToBytes(), (b, o) => b.GetDouble(o).ToString());
|
||||
|
||||
public static KBinConverter IP4 = new KBinConverter(s => IPAddress.Parse(s).GetAddressBytes(), b => new IPAddress(b.Take(4).ToArray()).ToString());
|
||||
public static KBinConverter Bool = new KBinConverter(s => new byte[] { s.ToBool() ? (byte)1 : (byte)0 }, b => (b.FirstU8() != 0) ? "1" : "0");
|
||||
public static KBinConverter IP4 = new KBinConverter((s, o) => IPAddress.Parse(s[o]).GetAddressBytes(), (b, o) =>
|
||||
{
|
||||
byte[] buf = b;
|
||||
if (buf.Length != 4)
|
||||
{
|
||||
buf = new byte[4];
|
||||
Buffer.BlockCopy(b, o, buf, 0, 4);
|
||||
}
|
||||
return new IPAddress(buf).ToString();
|
||||
});
|
||||
|
||||
public static KBinConverter Invalid = new KBinConverter(s => throw new InvalidOperationException(), b => throw new InvalidOperationException());
|
||||
public static KBinConverter Bool = new KBinConverter((s, o) => new byte[] { s[o].ToBool() ? (byte)1 : (byte)0 }, (b, o) => (b.GetU8(o) != 0) ? "1" : "0");
|
||||
|
||||
public static KBinConverter Invalid = new KBinConverter((s, o) => throw new InvalidOperationException(), (b, o) => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
public class XmlType
|
||||
@@ -82,21 +89,19 @@ namespace eAmuseCore.KBinXML
|
||||
return this;
|
||||
}
|
||||
|
||||
public IEnumerable<byte> KFromString(string input)
|
||||
public byte[] KFromString(string[] input, int offset)
|
||||
{
|
||||
if (input.Length == 0)
|
||||
return new byte[0];
|
||||
return Converter.KFromString(input);
|
||||
return Converter.KFromString(input, offset);
|
||||
}
|
||||
|
||||
public string KToString(IEnumerable<byte> input)
|
||||
public string KToString(byte[] input, int offset)
|
||||
{
|
||||
input = input.Take(Size);
|
||||
ICollection<byte> col = input as ICollection<byte>;
|
||||
if (col != null && col.Count != Size)
|
||||
if (input.Length - offset < Size)
|
||||
throw new ArgumentException("input does not provide enough data", "input");
|
||||
|
||||
return Converter.KToString(input);
|
||||
return Converter.KToString(input, offset);
|
||||
}
|
||||
|
||||
private XmlType Times(int count)
|
||||
@@ -106,30 +111,24 @@ namespace eAmuseCore.KBinXML
|
||||
|
||||
string[] names = Names.Select(name => count.ToString() + name).ToArray();
|
||||
int size = Size * count;
|
||||
KBinFromString fromString = s =>
|
||||
KBinFromString fromString = (s, o) =>
|
||||
{
|
||||
string[] elems = s.Split(' ');
|
||||
if (elems.Length != count)
|
||||
throw new ArgumentException("input does not split into correct element count", "s");
|
||||
if (s.Length - o < count)
|
||||
throw new ArgumentException("input does not contain enough elements");
|
||||
|
||||
byte[] res = new byte[size];
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
Buffer.BlockCopy(Converter.KFromString(s, o + i), 0, res, i * Size, Size);
|
||||
|
||||
IEnumerable<byte> res = Enumerable.Empty<byte>();
|
||||
foreach (string elem in elems)
|
||||
res = res.Concat(Converter.KFromString(elem));
|
||||
return res;
|
||||
};
|
||||
KBinToString toString = b =>
|
||||
KBinToString toString = (b, o) =>
|
||||
{
|
||||
IEnumerable<byte> data = b.Take(size);
|
||||
ICollection<byte> col = data as ICollection<byte>;
|
||||
if (col != null && col.Count != size)
|
||||
throw new ArgumentException("input does not provide enough data for all elements", "b");
|
||||
|
||||
string[] res = new string[count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
res[i] = Converter.KToString(data.Take(Size));
|
||||
data = data.Skip(Size);
|
||||
}
|
||||
res[i] = Converter.KToString(b, i * Size + o);
|
||||
|
||||
return string.Join(" ", res);
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ namespace eAmuseTest
|
||||
|
||||
KBinXML kbinxml = new KBinXML(rawData.ToArray());
|
||||
|
||||
kbinxml = new KBinXML(kbinxml.Document);
|
||||
|
||||
kbinxml = new KBinXML(kbinxml.Bytes);
|
||||
|
||||
Console.WriteLine(kbinxml);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user