mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-10-29 07:10:29 +00:00
Encoding
This commit is contained in:
@@ -189,42 +189,53 @@ public static class Codec
|
||||
/// <param name="connection">DistributedConnection is required in case a structure in the array holds items at the other end.</param>
|
||||
/// <param name="dataType">DataType, in case the data is not prepended with DataType</param>
|
||||
/// <returns>Value</returns>
|
||||
public static (uint, object) ParseAsync(byte[] data, uint offset, DistributedConnection connection, uint[] requestSequence, ParsedTDU? dataType = null)
|
||||
public static (uint, object) ParseAsync(byte[] data, uint offset, DistributedConnection connection, uint[] requestSequence)
|
||||
{
|
||||
uint len = 0;
|
||||
|
||||
if (dataType == null)
|
||||
{
|
||||
(var longLen, dataType) = ParsedTDU.Parse(data, offset, (uint)data.Length);
|
||||
var tdu = ParsedTDU.Parse(data, offset, (uint)data.Length);
|
||||
|
||||
if (dataType == null)
|
||||
if (tdu.Class == TDUClass.Invalid)
|
||||
throw new NullReferenceException("DataType can't be parsed.");
|
||||
|
||||
len = (uint)longLen;
|
||||
offset = dataType.Value.Offset;
|
||||
if (tdu.Class == TDUClass.Fixed)
|
||||
{
|
||||
return ((uint)tdu.TotalLength, FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence));
|
||||
}
|
||||
else
|
||||
len = (uint)dataType.Value.ContentLength;
|
||||
else if (tdu.Class == TDUClass.Dynamic)
|
||||
{
|
||||
return ((uint)tdu.TotalLength, DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
||||
}
|
||||
else if (tdu.Class == TDUClass.Typed)
|
||||
{
|
||||
return ((uint)tdu.TotalLength, TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
||||
}
|
||||
else // if (tt.Class == TDUClass.Extension)
|
||||
{
|
||||
return ((uint)tdu.TotalLength, ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
||||
|
||||
var tt = dataType.Value;
|
||||
}
|
||||
}
|
||||
|
||||
//Console.WriteLine("Parsing " + tt.Class + " " + tt.Identifier);
|
||||
public static (uint, object) ParseAsync(ParsedTDU tdu, DistributedConnection connection, uint[] requestSequence)
|
||||
{
|
||||
if (tdu.Class == TDUClass.Invalid)
|
||||
throw new NullReferenceException("DataType can't be parsed.");
|
||||
|
||||
if (tt.Class == TDUClass.Fixed)
|
||||
if (tdu.Class == TDUClass.Fixed)
|
||||
{
|
||||
return (len, FixedAsyncParsers[tt.Exponent][tt.Index](tt, connection, requestSequence));
|
||||
return ((uint)tdu.TotalLength, FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence));
|
||||
}
|
||||
else if (tt.Class == TDUClass.Dynamic)
|
||||
else if (tdu.Class == TDUClass.Dynamic)
|
||||
{
|
||||
return (len, DynamicAsyncParsers[tt.Index](tt, connection, requestSequence));
|
||||
return ((uint)tdu.TotalLength, DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
||||
}
|
||||
else if (tt.Class == TDUClass.Typed)
|
||||
else if (tdu.Class == TDUClass.Typed)
|
||||
{
|
||||
return (len, TypedAsyncParsers[tt.Index](tt, connection, requestSequence));
|
||||
return ((uint)tdu.TotalLength, TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
||||
}
|
||||
else if (tt.Class == TDUClass.Extension)
|
||||
else // if (tt.Class == TDUClass.Extension)
|
||||
{
|
||||
return (len, ExtendedAsyncParsers[tt.Index](tt, connection, requestSequence));
|
||||
return ((uint)tdu.TotalLength, ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -252,34 +263,27 @@ public static class Codec
|
||||
|
||||
public static (uint, object) ParseSync(byte[] data, uint offset, Warehouse warehouse)
|
||||
{
|
||||
uint len = 0;
|
||||
var tdu = ParsedTDU.Parse(data, offset, (uint)data.Length);
|
||||
|
||||
|
||||
var (longLen, dataType) = ParsedTDU.Parse(data, offset, (uint)data.Length);
|
||||
|
||||
if (dataType == null)
|
||||
if (tdu.Class == TDUClass.Invalid)
|
||||
throw new NullReferenceException("DataType can't be parsed.");
|
||||
|
||||
len = (uint)longLen;
|
||||
offset = dataType.Value.Offset;
|
||||
|
||||
var tt = dataType.Value;
|
||||
|
||||
if (tt.Class == TDUClass.Fixed)
|
||||
if (tdu.Class == TDUClass.Fixed)
|
||||
{
|
||||
return (len, FixedParsers[tt.Exponent][tt.Index](tt, warehouse));
|
||||
return ((uint)tdu.TotalLength, FixedParsers[tdu.Exponent][tdu.Index](tdu, warehouse));
|
||||
}
|
||||
else if (tt.Class == TDUClass.Dynamic)
|
||||
else if (tdu.Class == TDUClass.Dynamic)
|
||||
{
|
||||
return (len, DynamicParsers[tt.Index](tt, warehouse));
|
||||
return ((uint)tdu.TotalLength, DynamicParsers[tdu.Index](tdu, warehouse));
|
||||
}
|
||||
else if (tt.Class == TDUClass.Typed)
|
||||
else if (tdu.Class == TDUClass.Typed)
|
||||
{
|
||||
return (len, TypedParsers[tt.Index](tt, warehouse));
|
||||
return ((uint)tdu.TotalLength, TypedParsers[tdu.Index](tdu, warehouse));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (len, ExtendedParsers[tt.Index](tt, warehouse));
|
||||
return ((uint)tdu.TotalLength, ExtendedParsers[tdu.Index](tdu, warehouse));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@@ -326,8 +330,8 @@ public static class Codec
|
||||
[typeof(float?)] = DataSerializer.Float32Composer,
|
||||
[typeof(long)] = DataSerializer.Int64Composer,
|
||||
[typeof(long?)] = DataSerializer.Int64Composer,
|
||||
[typeof(ulong)] = DataSerializer.UIn64Composer,
|
||||
[typeof(ulong?)] = DataSerializer.UIn64Composer,
|
||||
[typeof(ulong)] = DataSerializer.UInt64Composer,
|
||||
[typeof(ulong?)] = DataSerializer.UInt64Composer,
|
||||
[typeof(double)] = DataSerializer.Float64Composer,
|
||||
[typeof(double?)] = DataSerializer.Float64Composer,
|
||||
[typeof(DateTime)] = DataSerializer.DateTimeComposer,
|
||||
|
||||
@@ -828,8 +828,9 @@ public static class DataDeserializer
|
||||
|
||||
public static AsyncReply TupleParserAsync(ParsedTDU tdu, DistributedConnection connection, uint[] requestSequence)
|
||||
{
|
||||
var rt = new AsyncReply();
|
||||
|
||||
var results = new List<object>();
|
||||
var results = new AsyncBag<object>();
|
||||
var tupleSize = tdu.Metadata[0];
|
||||
|
||||
var types = new List<Type>();
|
||||
@@ -977,20 +978,37 @@ public static class DataDeserializer
|
||||
var rt = new AsyncBag<object>();
|
||||
|
||||
// get the type
|
||||
var (hdrCs, rep) = RepresentationType.Parse(data, offset);
|
||||
var (hdrCs, rep) = RepresentationType.Parse(tdu.Metadata, 0);
|
||||
|
||||
offset += hdrCs;
|
||||
length -= hdrCs;
|
||||
|
||||
var runtimeType = rep.GetRuntimeType(connection.Instance.Warehouse);
|
||||
|
||||
rt.ArrayType = runtimeType;
|
||||
|
||||
ParsedTDU current;
|
||||
ParsedTDU? previous = null;
|
||||
|
||||
var offset = tdu.Offset;
|
||||
var length = tdu.ContentLength;
|
||||
var ends = offset + (uint)length;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
var (cs, reply) = Codec.ParseAsync(data, offset, connection, requestSequence);
|
||||
|
||||
current = ParsedTDU.Parse(tdu.Data, offset, ends);
|
||||
|
||||
if (current.Class == TDUClass.Invalid)
|
||||
throw new Exception("Unknown type.");
|
||||
|
||||
|
||||
if (current.Identifier == TDUIdentifier.TypeContinuation)
|
||||
{
|
||||
current.Class = previous.Value.Class;
|
||||
current.Identifier = previous.Value.Identifier;
|
||||
current.Metadata = previous.Value.Metadata;
|
||||
}
|
||||
|
||||
var (cs, reply) = Codec.ParseAsync(tdu.Data, offset, connection, requestSequence);
|
||||
|
||||
rt.Add(reply);
|
||||
|
||||
@@ -1021,7 +1039,7 @@ public static class DataDeserializer
|
||||
|
||||
var list = new List<object>();
|
||||
|
||||
ParsedTDU? current;
|
||||
ParsedTDU current;
|
||||
ParsedTDU? previous = null;
|
||||
|
||||
var offset = tdu.Offset;
|
||||
@@ -1030,21 +1048,20 @@ public static class DataDeserializer
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
(var longLen, current) = ParsedTDU.Parse(tdu.Data, offset, ends);
|
||||
current = ParsedTDU.Parse(tdu.Data, offset, ends);
|
||||
|
||||
if (current == null)
|
||||
if (current.Class == TDUClass.Invalid)
|
||||
throw new Exception("Unknown type.");
|
||||
|
||||
var cur = (ParsedTDU)current.Value;
|
||||
|
||||
if (cur.Identifier == TDUIdentifier.TypeContinuation)
|
||||
if (current.Identifier == TDUIdentifier.TypeContinuation)
|
||||
{
|
||||
cur.Class = previous.Value.Class;
|
||||
cur.Identifier = previous.Value.Identifier;
|
||||
cur.Metadata = previous.Value.Metadata;
|
||||
current.Class = previous.Value.Class;
|
||||
current.Identifier = previous.Value.Identifier;
|
||||
current.Metadata = previous.Value.Metadata;
|
||||
}
|
||||
|
||||
var (cs, reply) = Codec.ParseSync(cur, warehouse);
|
||||
var (cs, reply) = Codec.ParseSync(current, warehouse);
|
||||
|
||||
list.Add(reply);
|
||||
|
||||
@@ -1052,7 +1069,7 @@ public static class DataDeserializer
|
||||
{
|
||||
offset += (uint)cs;
|
||||
length -= (uint)cs;
|
||||
previous = cur;
|
||||
previous = current;
|
||||
}
|
||||
else
|
||||
throw new Exception("Error while parsing structured data");
|
||||
@@ -1070,7 +1087,8 @@ public static class DataDeserializer
|
||||
var rt = new AsyncBag<PropertyValue>();
|
||||
|
||||
|
||||
ListParserAsync(data, offset, length, connection, requestSequence).Then(x =>
|
||||
ListParserAsync(new ParsedTDU() { Data = data, Offset = offset, ContentLength = length }
|
||||
, connection, requestSequence).Then(x =>
|
||||
{
|
||||
var ar = (object[])x;
|
||||
var pvs = new List<PropertyValue>();
|
||||
|
||||
@@ -3,6 +3,7 @@ using Esiur.Net.IIP;
|
||||
using Esiur.Resource;
|
||||
using Esiur.Resource.Template;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -17,78 +18,272 @@ public static class DataSerializer
|
||||
public static unsafe TDU Int32Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var v = (int)value;
|
||||
|
||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||
{
|
||||
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
||||
}
|
||||
else if (v >= short.MinValue && v <= short.MaxValue)
|
||||
{
|
||||
// Fits in 2 bytes
|
||||
var rt = new byte[2];
|
||||
fixed (byte* ptr = rt)
|
||||
*((short*)ptr) = (short)v;
|
||||
|
||||
return new TDU(TDUIdentifier.Int16, rt, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use full 4 bytes
|
||||
var rt = new byte[4];
|
||||
fixed (byte* ptr = rt)
|
||||
*((int*)ptr) = v;
|
||||
return new TDU(TDUIdentifier.Int32, rt, 4);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe TDU UInt32Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var v = (uint)value;
|
||||
|
||||
if (v <= byte.MaxValue)
|
||||
{
|
||||
// Fits in 1 byte
|
||||
return new TDU(TDUIdentifier.UInt8, new byte[] { (byte)v }, 1);
|
||||
}
|
||||
else if (v <= ushort.MaxValue)
|
||||
{
|
||||
// Fits in 2 bytes
|
||||
var rt = new byte[2];
|
||||
fixed (byte* ptr = rt)
|
||||
*((ushort*)ptr) = (ushort)v;
|
||||
|
||||
return new TDU(TDUIdentifier.UInt16, rt, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use full 4 bytes
|
||||
var rt = new byte[4];
|
||||
fixed (byte* ptr = rt)
|
||||
*((uint*)ptr) = v;
|
||||
|
||||
return new TDU(TDUIdentifier.UInt32, rt, 4);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe TDU Int16Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var v = (short)value;
|
||||
|
||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||
{
|
||||
// Fits in 1 byte
|
||||
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use full 2 bytes
|
||||
var rt = new byte[2];
|
||||
fixed (byte* ptr = rt)
|
||||
*((short*)ptr) = v;
|
||||
|
||||
return new TDU(TDUIdentifier.Int16, rt, 2);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe TDU UInt16Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var v = (ushort)value;
|
||||
|
||||
if (v <= byte.MaxValue)
|
||||
{
|
||||
// Fits in 1 byte
|
||||
return new TDU(TDUIdentifier.UInt8, new byte[] { (byte)v }, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use full 2 bytes
|
||||
var rt = new byte[2];
|
||||
fixed (byte* ptr = rt)
|
||||
*((ushort*)ptr) = v;
|
||||
|
||||
return new TDU(TDUIdentifier.UInt16, rt, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static unsafe TDU Float32Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var v = (float)value;
|
||||
float v = (float)value;
|
||||
|
||||
// Special IEEE-754 values
|
||||
if (float.IsNaN(v) || float.IsInfinity(v))
|
||||
{
|
||||
return new TDU(TDUIdentifier.Infinity, new byte[0], 0);
|
||||
}
|
||||
|
||||
// If v is an exact integer, prefer smallest signed width up to Int32
|
||||
if (v == Math.Truncate(v))
|
||||
{
|
||||
// Note: casts are safe because we check bounds first.
|
||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||
{
|
||||
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
||||
}
|
||||
|
||||
if (v >= short.MinValue && v <= short.MaxValue)
|
||||
{
|
||||
var rt = new byte[2];
|
||||
fixed (byte* ptr = rt)
|
||||
*((short*)ptr) = (short)v;
|
||||
return new TDU(TDUIdentifier.Int16, rt, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Default: Float32
|
||||
{
|
||||
var rt = new byte[4];
|
||||
fixed (byte* ptr = rt)
|
||||
*((float*)ptr) = v;
|
||||
return new TDU(TDUIdentifier.Float32, rt, 4);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe TDU Float64Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
|
||||
public unsafe static TDU Float64Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
double v = (double)value;
|
||||
|
||||
// Special IEEE-754 values
|
||||
if (double.IsNaN(v) || double.IsInfinity(v))
|
||||
{
|
||||
return new TDU(TDUIdentifier.Infinity, new byte[0], 0);
|
||||
}
|
||||
|
||||
// If v is an exact integer, choose the smallest signed width
|
||||
if (v == Math.Truncate(v))
|
||||
{
|
||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
||||
|
||||
if (v >= short.MinValue && v <= short.MaxValue)
|
||||
{
|
||||
var rt = new byte[2];
|
||||
|
||||
fixed (byte* ptr = rt)
|
||||
*((short*)ptr) = (short)v;
|
||||
|
||||
return new TDU(TDUIdentifier.Int16, rt, 2);
|
||||
}
|
||||
|
||||
if (v >= int.MinValue && v <= int.MaxValue)
|
||||
{
|
||||
var rt = new byte[4];
|
||||
|
||||
fixed (byte* ptr = rt)
|
||||
*((int*)ptr) = (int)v;
|
||||
|
||||
return new TDU(TDUIdentifier.Int32, rt, 4);
|
||||
}
|
||||
|
||||
// If it's integral but outside Int64 range, fall through to Float64.
|
||||
}
|
||||
|
||||
// Try exact Float32 (decimal subset of doubles)
|
||||
var f = (float)v;
|
||||
if ((double)f == v)
|
||||
{
|
||||
var rt = new byte[4];
|
||||
|
||||
fixed (byte* ptr = rt)
|
||||
*((float*)ptr) = (byte)v;
|
||||
|
||||
return new TDU(TDUIdentifier.Float32, rt, 4);
|
||||
}
|
||||
|
||||
// Default: Float64
|
||||
{
|
||||
var v = (double)value;
|
||||
var rt = new byte[8];
|
||||
fixed (byte* ptr = rt)
|
||||
*((double*)ptr) = v;
|
||||
return new TDU(TDUIdentifier.Float64, rt, 8);
|
||||
}
|
||||
|
||||
}
|
||||
public static unsafe TDU Int64Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var v = (long)value;
|
||||
|
||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||
{
|
||||
// Fits in 1 byte
|
||||
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
||||
}
|
||||
else if (v >= short.MinValue && v <= short.MaxValue)
|
||||
{
|
||||
// Fits in 2 bytes
|
||||
var rt = new byte[2];
|
||||
fixed (byte* ptr = rt)
|
||||
*((short*)ptr) = (short)v;
|
||||
|
||||
return new TDU(TDUIdentifier.Int16, rt, 2);
|
||||
}
|
||||
else if (v >= int.MinValue && v <= int.MaxValue)
|
||||
{
|
||||
// Fits in 4 bytes
|
||||
var rt = new byte[4];
|
||||
fixed (byte* ptr = rt)
|
||||
*((int*)ptr) = (int)v;
|
||||
|
||||
return new TDU(TDUIdentifier.Int32, rt, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use full 8 bytes
|
||||
var rt = new byte[8];
|
||||
fixed (byte* ptr = rt)
|
||||
*((long*)ptr) = v;
|
||||
|
||||
return new TDU(TDUIdentifier.Int64, rt, 8);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe TDU UIn64Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
public static unsafe TDU UInt64Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var v = (ulong)value;
|
||||
|
||||
if (v <= byte.MaxValue)
|
||||
{
|
||||
// Fits in 1 byte
|
||||
return new TDU(TDUIdentifier.UInt8, new byte[] { (byte)v }, 1);
|
||||
}
|
||||
else if (v <= ushort.MaxValue)
|
||||
{
|
||||
// Fits in 2 bytes
|
||||
var rt = new byte[2];
|
||||
fixed (byte* ptr = rt)
|
||||
*((ushort*)ptr) = (ushort)v;
|
||||
|
||||
return new TDU(TDUIdentifier.UInt16, rt, 2);
|
||||
}
|
||||
else if (v <= uint.MaxValue)
|
||||
{
|
||||
// Fits in 4 bytes
|
||||
var rt = new byte[4];
|
||||
fixed (byte* ptr = rt)
|
||||
*((uint*)ptr) = (uint)v;
|
||||
|
||||
return new TDU(TDUIdentifier.UInt32, rt, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use full 8 bytes
|
||||
var rt = new byte[8];
|
||||
fixed (byte* ptr = rt)
|
||||
*((ulong*)ptr) = v;
|
||||
|
||||
return new TDU(TDUIdentifier.UInt64, rt, 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static unsafe TDU DateTimeComposer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
@@ -101,17 +296,88 @@ public static class DataSerializer
|
||||
return new TDU(TDUIdentifier.DateTime, rt, 8);
|
||||
}
|
||||
|
||||
//public static unsafe TDU Decimal128Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
//{
|
||||
// var v = (decimal)value;
|
||||
// var rt = new byte[16];
|
||||
// fixed (byte* ptr = rt)
|
||||
// *((decimal*)ptr) = v;
|
||||
|
||||
// return new TDU(TDUIdentifier.Decimal128, rt, 16);
|
||||
//}
|
||||
|
||||
public static unsafe TDU Decimal128Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var v = (decimal)value;
|
||||
|
||||
// Prefer smallest exact signed integer if no fractional part
|
||||
int[] bits = decimal.GetBits(v);
|
||||
int flags = bits[3];
|
||||
int scale = (flags >> 16) & 0x7F;
|
||||
|
||||
if (scale == 0)
|
||||
{
|
||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
|
||||
|
||||
if (v >= short.MinValue && v <= short.MaxValue)
|
||||
{
|
||||
var b = new byte[2];
|
||||
BinaryPrimitives.WriteInt16LittleEndian(b, (short)v);
|
||||
return new TDU(TDUIdentifier.Int16, b, 2);
|
||||
}
|
||||
|
||||
if (v >= int.MinValue && v <= int.MaxValue)
|
||||
{
|
||||
var b = new byte[4];
|
||||
BinaryPrimitives.WriteInt32LittleEndian(b, (int)v);
|
||||
return new TDU(TDUIdentifier.Int32, b, 4);
|
||||
}
|
||||
|
||||
if (v >= long.MinValue && v <= long.MaxValue)
|
||||
{
|
||||
var b = new byte[8];
|
||||
BinaryPrimitives.WriteInt64LittleEndian(b, (long)v);
|
||||
return new TDU(TDUIdentifier.Int64, b, 8);
|
||||
}
|
||||
// else fall through (needs 96+ bits)
|
||||
}
|
||||
|
||||
// Try exact Float32 (4 bytes)
|
||||
// Exactness test: decimal -> float -> decimal must equal original
|
||||
float f = (float)v;
|
||||
if ((decimal)f == v)
|
||||
{
|
||||
var rt = new byte[4];
|
||||
|
||||
fixed (byte* ptr = rt)
|
||||
*((float*)ptr) = f;
|
||||
|
||||
return new TDU(TDUIdentifier.Float32, rt, 4);
|
||||
}
|
||||
|
||||
// Try exact Float64 (8 bytes)
|
||||
double d = (double)v;
|
||||
if ((decimal)d == v)
|
||||
{
|
||||
var rt = new byte[4];
|
||||
|
||||
fixed (byte* ptr = rt)
|
||||
*((double*)ptr) = d;
|
||||
|
||||
return new TDU(TDUIdentifier.Float64, rt, 8);
|
||||
}
|
||||
|
||||
{
|
||||
// Fallback: full .NET decimal (16 bytes): lo, mid, hi, flags (scale/sign)
|
||||
var rt = new byte[16];
|
||||
|
||||
fixed (byte* ptr = rt)
|
||||
*((decimal*)ptr) = v;
|
||||
|
||||
return new TDU(TDUIdentifier.Decimal128, rt, 16);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static TDU StringComposer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
@@ -228,8 +494,6 @@ public static class DataSerializer
|
||||
{
|
||||
var composed = ArrayComposer((IEnumerable)value, warehouse, connection);
|
||||
|
||||
Console.WriteLine(composed.ToHex());
|
||||
|
||||
if (composed == null)
|
||||
return new TDU(TDUIdentifier.Null, new byte[0], 0);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Esiur.Data
|
||||
public ulong TotalLength;
|
||||
public byte[] Metadata;
|
||||
|
||||
public static (ulong, ParsedTDU?) Parse(byte[] data, uint offset, uint ends)
|
||||
public static ParsedTDU Parse(byte[] data, uint offset, uint ends)
|
||||
{
|
||||
var h = data[offset++];
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Esiur.Data
|
||||
var exp = (h & 0x38) >> 3;
|
||||
|
||||
if (exp == 0)
|
||||
return (1, new ParsedTDU()
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Identifier = (TDUIdentifier)h,
|
||||
Data = data,
|
||||
@@ -37,16 +37,20 @@ namespace Esiur.Data
|
||||
Index = (byte)h & 0x7,
|
||||
ContentLength = 0,
|
||||
TotalLength = 1,
|
||||
});
|
||||
};
|
||||
|
||||
ulong cl = (ulong)(1 << (exp - 1));
|
||||
|
||||
if (ends - offset < cl)
|
||||
return (cl - (ends - offset), null);
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Class = TDUClass.Invalid,
|
||||
TotalLength = (cl - (ends - offset))
|
||||
};
|
||||
|
||||
//offset += (uint)cl;
|
||||
|
||||
return (1 + cl, new ParsedTDU()
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Identifier = (TDUIdentifier)h,
|
||||
Data = data,
|
||||
@@ -56,14 +60,18 @@ namespace Esiur.Data
|
||||
TotalLength = 1 + cl,
|
||||
Exponent = (byte)exp,
|
||||
Index = (byte)h & 0x7,
|
||||
});
|
||||
};
|
||||
}
|
||||
else if (cls == TDUClass.Typed)
|
||||
{
|
||||
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||
|
||||
if (ends - offset < cll)
|
||||
return (cll - (ends - offset), null);
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Class = TDUClass.Invalid,
|
||||
TotalLength = (cll - (ends - offset))
|
||||
};
|
||||
|
||||
ulong cl = 0;
|
||||
|
||||
@@ -71,13 +79,17 @@ namespace Esiur.Data
|
||||
cl = cl << 8 | data[offset++];
|
||||
|
||||
if (ends - offset < cl)
|
||||
return (cl - (ends - offset), null);
|
||||
return new ParsedTDU()
|
||||
{
|
||||
TotalLength = (cl - (ends - offset)),
|
||||
Class = TDUClass.Invalid,
|
||||
};
|
||||
|
||||
var metaData = DC.Clip(data, offset + 1, data[offset]);
|
||||
offset += data[offset] + (uint)1;
|
||||
|
||||
|
||||
return (1 + cl + cll, new ParsedTDU()
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Identifier = (TDUIdentifier)(h & 0xC7),
|
||||
Data = data,
|
||||
@@ -87,14 +99,18 @@ namespace Esiur.Data
|
||||
TotalLength = 1 + cl + cll,
|
||||
Index = (byte)h & 0x7,
|
||||
Metadata = metaData,
|
||||
});
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||
|
||||
if (ends - offset < cll)
|
||||
return (cll - (ends - offset), null);
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Class = TDUClass.Invalid,
|
||||
TotalLength = (cll - (ends - offset))
|
||||
};
|
||||
|
||||
ulong cl = 0;
|
||||
|
||||
@@ -102,10 +118,14 @@ namespace Esiur.Data
|
||||
cl = cl << 8 | data[offset++];
|
||||
|
||||
if (ends - offset < cl)
|
||||
return (cl - (ends - offset), null);
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Class = TDUClass.Invalid,
|
||||
TotalLength = (cl - (ends - offset))
|
||||
};
|
||||
|
||||
|
||||
return (1 + cl + cll,
|
||||
return
|
||||
new ParsedTDU()
|
||||
{
|
||||
Identifier = (TDUIdentifier)(h & 0xC7),
|
||||
@@ -115,7 +135,7 @@ namespace Esiur.Data
|
||||
ContentLength = cl,
|
||||
TotalLength = 1 + cl + cll,
|
||||
Index = (byte)h & 0x7
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Esiur.Data
|
||||
Fixed = 0x0,
|
||||
Dynamic = 0x1,
|
||||
Typed = 0x2,
|
||||
Extension = 0x3
|
||||
Extension = 0x3,
|
||||
Invalid
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Esiur.Data
|
||||
False = 0x1,
|
||||
True = 0x2,
|
||||
NotModified = 0x3,
|
||||
Infinity = 0x4,
|
||||
UInt8 = 0x8,
|
||||
Int8 = 0x9,
|
||||
Char8 = 0xA,
|
||||
|
||||
@@ -438,7 +438,7 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
||||
{
|
||||
// Invoke
|
||||
case IIPPacketNotification.PropertyModified:
|
||||
IIPNotificationPropertyModified(dt, msg);
|
||||
IIPNotificationPropertyModified(dt);
|
||||
break;
|
||||
case IIPPacketNotification.EventOccurred:
|
||||
IIPNotificationEventOccurred(dt, msg);
|
||||
@@ -448,7 +448,7 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
||||
IIPNotificationResourceDestroyed(dt, msg);
|
||||
break;
|
||||
case IIPPacketNotification.ResourceReassigned:
|
||||
IIPNotificationResourceReassigned(dt, msg);
|
||||
IIPNotificationResourceReassigned(dt);
|
||||
break;
|
||||
case IIPPacketNotification.ResourceMoved:
|
||||
IIPNotificationResourceMoved(dt, msg);
|
||||
@@ -537,7 +537,7 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
||||
switch (packet.Reply)
|
||||
{
|
||||
case IIPPacketReply.Completed:
|
||||
IIPReplyCompleted(packet.CallbackId, dt, msg);
|
||||
IIPReplyCompleted(packet.CallbackId, dt);
|
||||
break;
|
||||
case IIPPacketReply.Propagated:
|
||||
IIPReplyPropagated(packet.CallbackId, dt, msg);
|
||||
@@ -554,7 +554,7 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
||||
break;
|
||||
|
||||
case IIPPacketReply.Chunk:
|
||||
IIPReplyChunk(packet.CallbackId, dt, msg);
|
||||
IIPReplyChunk(packet.CallbackId, dt);
|
||||
break;
|
||||
|
||||
case IIPPacketReply.Warning:
|
||||
@@ -1344,7 +1344,6 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
||||
|
||||
protected override void DataReceived(NetworkBuffer data)
|
||||
{
|
||||
//Console.WriteLine("DR " + data.Available + " " + RemoteEndPoint.ToString());
|
||||
var msg = data.Read();
|
||||
uint offset = 0;
|
||||
uint ends = (uint)msg.Length;
|
||||
@@ -1353,8 +1352,6 @@ public partial class DistributedConnection : NetworkConnection, IStore
|
||||
|
||||
var chunkId = (new Random()).Next(1000, 1000000);
|
||||
|
||||
//var list = new List<Map<string, object>>();// double, IIPPacketCommand>();
|
||||
|
||||
|
||||
this.Socket.Hold();
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ partial class DistributedConnection
|
||||
SendReply(IIPPacketReply.Chunk, callbackId, chunk);
|
||||
}
|
||||
|
||||
void IIPReplyCompleted(uint callbackId, ParsedTDU dataType, byte[] data)
|
||||
void IIPReplyCompleted(uint callbackId, ParsedTDU dataType)
|
||||
{
|
||||
var req = requests.Take(callbackId);
|
||||
|
||||
@@ -272,7 +272,7 @@ partial class DistributedConnection
|
||||
return;
|
||||
}
|
||||
|
||||
var (_, parsed) = Codec.ParseAsync(data, 0, this, null, dataType);
|
||||
var (_, parsed) = Codec.ParseAsync(dataType, this, null);
|
||||
if (parsed is AsyncReply reply)
|
||||
{
|
||||
reply.Then(result =>
|
||||
@@ -374,14 +374,14 @@ partial class DistributedConnection
|
||||
|
||||
|
||||
|
||||
void IIPReplyChunk(uint callbackId, ParsedTDU dataType, byte[] data)
|
||||
void IIPReplyChunk(uint callbackId, ParsedTDU dataType)
|
||||
{
|
||||
var req = requests[callbackId];
|
||||
|
||||
if (req == null)
|
||||
return;
|
||||
|
||||
var (_, parsed) = Codec.ParseAsync(data, dataType.Offset, this, null, dataType);
|
||||
var (_, parsed) = Codec.ParseAsync(dataType, this, null);
|
||||
|
||||
if (parsed is AsyncReply reply)
|
||||
reply.Then(result => req.TriggerChunk(result));
|
||||
@@ -389,7 +389,7 @@ partial class DistributedConnection
|
||||
req.TriggerChunk(parsed);
|
||||
}
|
||||
|
||||
void IIPNotificationResourceReassigned(ParsedTDU dataType, byte[] data)
|
||||
void IIPNotificationResourceReassigned(ParsedTDU dataType)
|
||||
{
|
||||
// uint resourceId, uint newResourceId
|
||||
}
|
||||
@@ -429,11 +429,11 @@ partial class DistributedConnection
|
||||
|
||||
}
|
||||
|
||||
void IIPNotificationPropertyModified(ParsedTDU dataType, byte[] data)
|
||||
void IIPNotificationPropertyModified(ParsedTDU dataType)
|
||||
{
|
||||
// resourceId, index, value
|
||||
var (valueOffset, valueSize, args) =
|
||||
DataDeserializer.LimitedCountListParser(data, dataType.Offset, dataType.ContentLength, Instance.Warehouse, 2);
|
||||
DataDeserializer.LimitedCountListParser(dataType.Data, dataType.Offset, dataType.ContentLength, Instance.Warehouse, 2);
|
||||
|
||||
var rid = (uint)args[0];
|
||||
var index = (byte)args[1];
|
||||
@@ -447,7 +447,7 @@ partial class DistributedConnection
|
||||
var item = new AsyncReply<DistributedResourceQueueItem>();
|
||||
queue.Add(item);
|
||||
|
||||
var (_, parsed) = Codec.ParseAsync(data, valueOffset, this, null);
|
||||
var (_, parsed) = Codec.ParseAsync(dataType.Data, valueOffset, this, null);
|
||||
|
||||
if (parsed is AsyncReply)
|
||||
{
|
||||
@@ -663,7 +663,7 @@ partial class DistributedConnection
|
||||
|
||||
void IIPRequestCreateResource(uint callback, ParsedTDU dataType, byte[] data)
|
||||
{
|
||||
var (_, parsed) = Codec.ParseAsync(data, 0, this, null, dataType);
|
||||
var (_, parsed) = Codec.ParseAsync(dataType, this, null);
|
||||
|
||||
var args = (object[])parsed;
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ public abstract class NetworkServer<TConnection> : IDestructible where TConnecti
|
||||
|
||||
if (s == null)
|
||||
{
|
||||
Console.Write("sock == null");
|
||||
Global.Log("NetworkServer", LogType.Error, "sock == null");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,13 +188,13 @@ public class IIPAuthPacket : Packet
|
||||
if (NotEnough(offset, ends, 1))
|
||||
return -dataLengthNeeded;
|
||||
|
||||
(var size, DataType) = ParsedTDU.Parse(data, offset, ends);
|
||||
DataType = ParsedTDU.Parse(data, offset, ends);
|
||||
|
||||
if (DataType == null)
|
||||
return -(int)size;
|
||||
if (DataType.Value.Class == TDUClass.Invalid)
|
||||
return -(int)DataType.Value.TotalLength;
|
||||
|
||||
|
||||
offset += (uint)size;
|
||||
offset += (uint)DataType.Value.TotalLength;
|
||||
|
||||
}
|
||||
else if (Command == IIPAuthPacketCommand.Acknowledge)
|
||||
@@ -208,13 +208,13 @@ public class IIPAuthPacket : Packet
|
||||
if (NotEnough(offset, ends, 1))
|
||||
return -dataLengthNeeded;
|
||||
|
||||
(var size, DataType) = ParsedTDU.Parse(data, offset, ends);
|
||||
DataType = ParsedTDU.Parse(data, offset, ends);
|
||||
|
||||
if (DataType == null)
|
||||
return -(int)size;
|
||||
if (DataType.Value.Class == TDUClass.Invalid)
|
||||
return -(int)DataType.Value.TotalLength;
|
||||
|
||||
|
||||
offset += (uint)size;
|
||||
offset += (uint)DataType.Value.TotalLength;
|
||||
}
|
||||
else if (Command == IIPAuthPacketCommand.Action)
|
||||
{
|
||||
@@ -280,12 +280,12 @@ public class IIPAuthPacket : Packet
|
||||
Reference = data.GetUInt32(offset, Endian.Little);
|
||||
offset += 4;
|
||||
|
||||
(var size, DataType) = ParsedTDU.Parse(data, offset, ends);
|
||||
DataType = ParsedTDU.Parse(data, offset, ends);
|
||||
|
||||
if (DataType == null)
|
||||
return -(int)size;
|
||||
if (DataType.Value.Class == TDUClass.Invalid)
|
||||
return -(int)DataType.Value.TotalLength;
|
||||
|
||||
offset += (uint)size;
|
||||
offset += (uint)DataType.Value.TotalLength;
|
||||
|
||||
}
|
||||
else if (Action == IIPAuthPacketAction.IAuthHashed)
|
||||
@@ -445,12 +445,12 @@ public class IIPAuthPacket : Packet
|
||||
if (NotEnough(offset, ends, 1))
|
||||
return -dataLengthNeeded;
|
||||
|
||||
(var size, DataType) = ParsedTDU.Parse(data, offset, ends);
|
||||
DataType = ParsedTDU.Parse(data, offset, ends);
|
||||
|
||||
if (DataType == null)
|
||||
return -(int)size;
|
||||
if (DataType.Value.Class == TDUClass.Invalid)
|
||||
return -(int)DataType.Value.TotalLength;
|
||||
|
||||
offset += (uint)size;
|
||||
offset += (uint)DataType.Value.TotalLength;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,12 +124,12 @@ class IIPPacket : Packet
|
||||
if (NotEnough(offset, ends, 1))
|
||||
return -dataLengthNeeded;
|
||||
|
||||
(var size, DataType) = ParsedTDU.Parse(data, offset, ends);
|
||||
DataType = ParsedTDU.Parse(data, offset, ends);
|
||||
|
||||
if (DataType == null)
|
||||
return -(int)size;
|
||||
if (DataType.Value.Class == TDUClass.Invalid)
|
||||
return -(int)DataType.Value.TotalLength;
|
||||
|
||||
offset += (uint)size;
|
||||
offset += (uint)DataType.Value.TotalLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user