2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-09-13 12:43:17 +00:00
Files
esiur-dotnet/Esiur/Data/TransmissionDataUnit.cs
2025-09-03 13:01:28 +03:00

338 lines
12 KiB
C#

using Esiur.Net.IIP;
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
namespace Esiur.Data;
public struct TransmissionDataUnit
{
public TransmissionDataUnitIdentifier Identifier;
public int Index;
public TransmissionDataUnitClass Class;
public uint Offset;
public ulong ContentLength;
public byte Exponent;
public byte[] Data;
public byte[] Metadata;
public ulong Size;
public TransmissionDataUnit(TransmissionDataUnitIdentifier identifier,
byte[] data, uint offset,
ulong length, byte[] metadata = null,
byte exponent = 0)
{
Identifier = identifier;
Index = (byte)identifier & 0x7;
Class = (TransmissionDataUnitClass)((byte)identifier >> 6);
Offset = offset;
ContentLength = length;
Exponent = exponent;
Data = data;
Metadata = metadata;
Size = Class == TransmissionDataUnitClass.Fixed ? 1 + length: 1 + length +
}
public byte[] GetTypeMetadata()
{
if (Class != TransmissionDataUnitClass.Typed)
throw new Exception("Class has no metadata.");
var size = Data[Offset];
return Data.Clip(Offset + 1, size);
}
public bool MatchType(TransmissionDataUnit with)
{
if (Identifier != with.Identifier)
return false;
if (Class == TransmissionDataUnitClass.Typed)
if (!Metadata.SequenceEqual(with.Metadata))
return false;
return true;
}
public byte[] Compose()
{
return null;
}
public static byte[] Compose(TransmissionDataUnitIdentifier identifier, byte[] data, byte[] typeMetadata)
{
if (data == null || data.Length == 0)
return new byte[] { (byte)identifier };
var cls = (TransmissionDataUnitClass)((int)identifier >> 6);
if (cls == TransmissionDataUnitClass.Fixed)
{
return DC.Combine(new byte[] { (byte)identifier }, 0, 1, data, 0, (uint)data.Length);
}
else if (cls == TransmissionDataUnitClass.Dynamic
|| cls == TransmissionDataUnitClass.Extension)
{
var len = (ulong)data.LongLength;
if (len == 0)
{
return new byte[1] { (byte)identifier };
}
else if (len <= 0xFF)
{
var rt = new byte[2 + len];
rt[0] = (byte)((byte)identifier | 0x8);
rt[1] = (byte)len;
Buffer.BlockCopy(data, 0, rt, 2, (int)len);
return rt;
}
else if (len <= 0xFF_FF)
{
var rt = new byte[3 + len];
rt[0] = (byte)((byte)identifier | 0x10);
rt[1] = (byte)((len >> 8) & 0xFF);
rt[2] = (byte)(len & 0xFF);
Buffer.BlockCopy(data, 0, rt, 3, (int)len);
return rt;
}
else if (len <= 0xFF_FF_FF)
{
var rt = new byte[4 + len];
rt[0] = (byte)((byte)identifier | 0x18);
rt[1] = (byte)((len >> 16) & 0xFF);
rt[2] = (byte)((len >> 8) & 0xFF);
rt[3] = (byte)(len & 0xFF);
Buffer.BlockCopy(data, 0, rt, 4, (int)len);
return rt;
}
else if (len <= 0xFF_FF_FF_FF)
{
var rt = new byte[5 + len];
rt[0] = (byte)((byte)identifier | 0x20);
rt[1] = (byte)((len >> 24) & 0xFF);
rt[2] = (byte)((len >> 16) & 0xFF);
rt[3] = (byte)((len >> 8) & 0xFF);
rt[4] = (byte)(len & 0xFF);
Buffer.BlockCopy(data, 0, rt, 5, (int)len);
return rt;
}
else if (len <= 0xFF_FF_FF_FF_FF)
{
var rt = new byte[6 + len];
rt[0] = (byte)((byte)identifier | 0x28);
rt[1] = (byte)((len >> 32) & 0xFF);
rt[2] = (byte)((len >> 24) & 0xFF);
rt[3] = (byte)((len >> 16) & 0xFF);
rt[4] = (byte)((len >> 8) & 0xFF);
rt[5] = (byte)(len & 0xFF);
Buffer.BlockCopy(data, 0, rt, 6, (int)len);
return rt;
}
else if (len <= 0xFF_FF_FF_FF_FF_FF)
{
var rt = new byte[7 + len];
rt[0] = (byte)((byte)identifier | 0x30);
rt[1] = (byte)((len >> 40) & 0xFF);
rt[2] = (byte)((len >> 32) & 0xFF);
rt[3] = (byte)((len >> 24) & 0xFF);
rt[4] = (byte)((len >> 16) & 0xFF);
rt[5] = (byte)((len >> 8) & 0xFF);
rt[6] = (byte)(len & 0xFF);
Buffer.BlockCopy(data, 0, rt, 7, (int)len);
return rt;
}
else //if (len <= 0xFF_FF_FF_FF_FF_FF_FF)
{
var rt = new byte[8 + len];
rt[0] = (byte)((byte)identifier | 0x38);
rt[1] = (byte)((len >> 48) & 0xFF);
rt[2] = (byte)((len >> 40) & 0xFF);
rt[3] = (byte)((len >> 32) & 0xFF);
rt[4] = (byte)((len >> 24) & 0xFF);
rt[5] = (byte)((len >> 16) & 0xFF);
rt[6] = (byte)((len >> 8) & 0xFF);
rt[7] = (byte)(len & 0xFF);
Buffer.BlockCopy(data, 0, rt, 8, (int)len);
return rt;
}
}
else if (cls == TransmissionDataUnitClass.Typed)
{
var len = 1 + (ulong)typeMetadata.LongLength + (ulong)data.LongLength;
if (len == 0)
{
return new byte[1] { (byte)identifier };
}
else if (len <= 0xFF)
{
var rt = new byte[2 + len];
rt[0] = (byte)((byte)identifier | 0x8);
rt[1] = (byte)len;
Buffer.BlockCopy(typeMetadata, 0, rt, 2, typeMetadata.Length);
Buffer.BlockCopy(data, 0, rt, 2 + typeMetadata.Length, data.Length);
return rt;
}
else if (len <= 0xFF_FF)
{
var rt = new byte[3 + len];
rt[0] = (byte)((byte)identifier | 0x10);
rt[1] = (byte)((len >> 8) & 0xFF);
rt[2] = (byte)(len & 0xFF);
Buffer.BlockCopy(typeMetadata, 0, rt, 3, typeMetadata.Length);
Buffer.BlockCopy(data, 0, rt, 3 + typeMetadata.Length, data.Length);
return rt;
}
else if (len <= 0xFF_FF_FF)
{
var rt = new byte[4 + len];
rt[0] = (byte)((byte)identifier | 0x18);
rt[1] = (byte)((len >> 16) & 0xFF);
rt[2] = (byte)((len >> 8) & 0xFF);
rt[3] = (byte)(len & 0xFF);
Buffer.BlockCopy(typeMetadata, 0, rt, 4, typeMetadata.Length);
Buffer.BlockCopy(data, 0, rt, 4 + typeMetadata.Length, data.Length);
return rt;
}
else if (len <= 0xFF_FF_FF_FF)
{
var rt = new byte[5 + len];
rt[0] = (byte)((byte)identifier | 0x20);
rt[1] = (byte)((len >> 24) & 0xFF);
rt[2] = (byte)((len >> 16) & 0xFF);
rt[3] = (byte)((len >> 8) & 0xFF);
rt[4] = (byte)(len & 0xFF);
Buffer.BlockCopy(typeMetadata, 0, rt, 5, typeMetadata.Length);
Buffer.BlockCopy(data, 0, rt, 5 + typeMetadata.Length, data.Length);
return rt;
}
else if (len <= 0xFF_FF_FF_FF_FF)
{
var rt = new byte[6 + len];
rt[0] = (byte)((byte)identifier | 0x28);
rt[1] = (byte)((len >> 32) & 0xFF);
rt[2] = (byte)((len >> 24) & 0xFF);
rt[3] = (byte)((len >> 16) & 0xFF);
rt[4] = (byte)((len >> 8) & 0xFF);
rt[5] = (byte)(len & 0xFF);
Buffer.BlockCopy(typeMetadata, 0, rt, 6, typeMetadata.Length);
Buffer.BlockCopy(data, 0, rt, 6 + typeMetadata.Length, data.Length);
return rt;
}
else if (len <= 0xFF_FF_FF_FF_FF_FF)
{
var rt = new byte[7 + len];
rt[0] = (byte)((byte)identifier | 0x30);
rt[1] = (byte)((len >> 40) & 0xFF);
rt[2] = (byte)((len >> 32) & 0xFF);
rt[3] = (byte)((len >> 24) & 0xFF);
rt[4] = (byte)((len >> 16) & 0xFF);
rt[5] = (byte)((len >> 8) & 0xFF);
rt[6] = (byte)(len & 0xFF);
Buffer.BlockCopy(typeMetadata, 0, rt, 7, typeMetadata.Length);
Buffer.BlockCopy(data, 0, rt, 7 + typeMetadata.Length, data.Length);
return rt;
}
else //if (len <= 0xFF_FF_FF_FF_FF_FF_FF)
{
var rt = new byte[8 + len];
rt[0] = (byte)((byte)identifier | 0x38);
rt[1] = (byte)((len >> 48) & 0xFF);
rt[2] = (byte)((len >> 40) & 0xFF);
rt[3] = (byte)((len >> 32) & 0xFF);
rt[4] = (byte)((len >> 24) & 0xFF);
rt[5] = (byte)((len >> 16) & 0xFF);
rt[6] = (byte)((len >> 8) & 0xFF);
rt[7] = (byte)(len & 0xFF);
Buffer.BlockCopy(typeMetadata, 0, rt, 8, typeMetadata.Length);
Buffer.BlockCopy(data, 0, rt, 8 + typeMetadata.Length, data.Length);
return rt;
}
}
throw new Exception("Not supported class type.");
}
public static (ulong, TransmissionDataUnit?) Parse(byte[] data, uint offset, uint ends)
{
var h = data[offset++];
var cls = (TransmissionDataUnitClass)(h >> 6);
if (cls == TransmissionDataUnitClass.Fixed)
{
var exp = (h & 0x38) >> 3;
if (exp == 0)
return (1, new TransmissionDataUnit((TransmissionDataUnitIdentifier)h, data, offset, 0));
ulong cl = (ulong)(1 << (exp - 1));
if (ends - offset < cl)
return (cl - (ends - offset), null);
//offset += (uint)cl;
return (1 + cl, new TransmissionDataUnit((TransmissionDataUnitIdentifier)h, data, offset, cl, null, (byte)exp));
}
else if (cls == TransmissionDataUnitClass.Typed)
{
ulong cll = (ulong)(h >> 3) & 0x7;
if (ends - offset < cll)
return (cll - (ends - offset), null);
ulong cl = 0;
for (uint i = 0; i < cll; i++)
cl = cl << 8 | data[offset++];
if (ends - offset < cl)
return (cl - (ends - offset), null);
var metaData = DC.Clip(data, offset + 1, data[offset]);
offset += data[offset];
return (1 + cl + cll, new TransmissionDataUnit((TransmissionDataUnitIdentifier)(h & 0xC7), data, offset, cl, metaData));
}
else
{
ulong cll = (ulong)(h >> 3) & 0x7;
if (ends - offset < cll)
return (cll - (ends - offset), null);
ulong cl = 0;
for (uint i = 0; i < cll; i++)
cl = cl << 8 | data[offset++];
if (ends - offset < cl)
return (cl - (ends - offset), null);
return (1 + cl + cll, new TransmissionDataUnit((TransmissionDataUnitIdentifier)(h & 0xC7), data, offset, cl));
}
}
}