Skip to content

Commit

Permalink
Added new value types to ExtensionObject and added a generic extensio…
Browse files Browse the repository at this point in the history
…n to ExtensionObject to allow for more easy access to inner value.

Also added posibility to extend the encoding and decoding types for ExtensionObject from external library/code.
  • Loading branch information
bjornfe committed Mar 2, 2024
1 parent fb7c049 commit debb00d
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 72 deletions.
74 changes: 3 additions & 71 deletions NET Core/LibUA/MemoryBufferExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1665,90 +1665,22 @@ public static bool Decode(this MemoryBuffer mem, out ExtensionObject obj)
if (!mem.DecodeUAByteString(out byte[] str)) { return false; }
obj.Body = str;

var tmp = new MemoryBuffer(str);
return obj.TryDecodeByteString();

switch (obj.TypeId.NumericIdentifier)
{
case (uint)UAConst.ObjectAttributes_Encoding_DefaultBinary:
ObjectAttributes oa;
if (!tmp.Decode(out oa)) { return false; }
obj.Payload = oa;
break;
case (uint)UAConst.ObjectTypeAttributes_Encoding_DefaultBinary:
ObjectTypeAttributes ota;
if (!tmp.Decode(out ota)) { return false; }
obj.Payload = ota;
break;
case (uint)UAConst.VariableAttributes_Encoding_DefaultBinary:
VariableAttributes va;
if (!tmp.Decode(out va)) { return false; }
obj.Payload = va;
break;
case (uint)UAConst.VariableTypeAttributes_Encoding_DefaultBinary:
VariableTypeAttributes vta;
if (!tmp.Decode(out vta)) { return false; }
obj.Payload = vta;
break;
case (uint)UAConst.Argument_Encoding_DefaultBinary:
Argument arg;
if (!tmp.Decode(out arg)) { return false; }
obj.Payload = arg;
break;
default:
break;
}

return true;

}

return true;
}

public static bool Encode(this MemoryBuffer mem, ExtensionObject obj)
{
if (obj == null)
if (obj == null || !obj.TryEncodeByteString(mem.Capacity))
{
if (!mem.Encode(NodeId.Zero)) { return false; }
return mem.Encode((byte)ExtensionObjectBodyType.None);
}

if (obj.Payload != null)
{
var tmp = new MemoryBuffer(mem.Capacity);
UAConst payloadType = 0;
switch (obj.Payload)
{
case ObjectAttributes oa:
payloadType = UAConst.ObjectAttributes_Encoding_DefaultBinary;
if (!tmp.Encode(oa)) { return false; }
break;
case ObjectTypeAttributes ota:
payloadType = UAConst.ObjectTypeAttributes_Encoding_DefaultBinary;
if (!tmp.Encode(ota)) { return false; }
break;
case VariableAttributes va:
payloadType = UAConst.VariableAttributes_Encoding_DefaultBinary;
if (!tmp.Encode(va)) { return false; }
break;
case VariableTypeAttributes vta:
payloadType = UAConst.VariableTypeAttributes_Encoding_DefaultBinary;
if (!tmp.Encode(vta)) { return false; }
break;
case Argument arg:
payloadType = UAConst.Argument_Encoding_DefaultBinary;
if (!tmp.Encode(arg)) { return false; }
break;
default:
break;
}
if (payloadType != 0)
{
obj.TypeId = new NodeId(payloadType);
obj.Body = new byte[tmp.Position];
Array.Copy(tmp.Buffer, obj.Body, obj.Body.Length);
}
}

if (!mem.Encode(obj.TypeId)) { return false; }

if (obj.Body == null)
Expand Down
155 changes: 154 additions & 1 deletion NET Core/LibUA/Types.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using LibUA.ValueTypes;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -5800,10 +5801,162 @@ public override string ToString()

public class ExtensionObject
{
private static ConcurrentDictionary<Type, Func<MemoryBuffer, NodeId>> _objectEncoders = new();
private static ConcurrentDictionary<NodeId, Func<MemoryBuffer, object>> _objectDecoders = new();
public static void RegisterEncoder<TObject>(Func<MemoryBuffer,NodeId> encoder)
{
_objectEncoders[typeof(TObject)] = encoder;
}

public static void RegisterDecoder<TObject>(NodeId TypeId, Func<MemoryBuffer, TObject> decoder) where TObject : class
{
_objectDecoders[TypeId] = decoder;
}



public NodeId TypeId { get; set; }
public byte[] Body { get; set; }

public object Payload { get; set; }

public bool TryEncodeByteString(int BufferCapacity)
{
TypeId = null;
if (Payload != null)
{
var buffer = new MemoryBuffer(BufferCapacity);
UAConst payloadType = 0;

if(_objectEncoders.TryGetValue(Payload.GetType(), out var encoder))
{
TypeId = encoder(buffer);
if (TypeId == null)
return false;
}
else
{
switch (Payload)
{
case ObjectAttributes oa:
payloadType = UAConst.ObjectAttributes_Encoding_DefaultBinary;
if (!buffer.Encode(oa)) { return false; }
break;
case ObjectTypeAttributes ota:
payloadType = UAConst.ObjectTypeAttributes_Encoding_DefaultBinary;
if (!buffer.Encode(ota)) { return false; }
break;
case VariableAttributes va:
payloadType = UAConst.VariableAttributes_Encoding_DefaultBinary;
if (!buffer.Encode(va)) { return false; }
break;
case VariableTypeAttributes vta:
payloadType = UAConst.VariableTypeAttributes_Encoding_DefaultBinary;
if (!buffer.Encode(vta)) { return false; }
break;
case Argument arg:
payloadType = UAConst.Argument_Encoding_DefaultBinary;
if (!buffer.Encode(arg)) { return false; }
break;
case EUInformation eui:
payloadType = UAConst.EUInformation;
if(!buffer.Encode(eui)) { return false; }
break;
case OpcRange range:
payloadType = UAConst.Range;
if(!buffer.Encode(range)) { return false; }
break;
default:
break;
}

if (payloadType != 0)
{
TypeId = new NodeId(payloadType);
}
}

if(TypeId != null)
{
Body = new byte[buffer.Position];
Array.Copy(buffer.Buffer, Body, Body.Length);
return true;
}

return false;
}

return false;
}

public bool TryDecodeByteString()
{
var tmp = new MemoryBuffer(Body);

if(_objectDecoders.TryGetValue(TypeId, out var decoder))
{
Payload = decoder(tmp);
if (Payload != null)
return true;
}

switch (TypeId.NumericIdentifier)
{
case (uint)UAConst.ObjectAttributes_Encoding_DefaultBinary:
ObjectAttributes oa;
if (!tmp.Decode(out oa)) { return false; }
Payload = oa;
break;
case (uint)UAConst.ObjectTypeAttributes_Encoding_DefaultBinary:
ObjectTypeAttributes ota;
if (!tmp.Decode(out ota)) { return false; }
Payload = ota;
break;
case (uint)UAConst.VariableAttributes_Encoding_DefaultBinary:
VariableAttributes va;
if (!tmp.Decode(out va)) { return false; }
Payload = va;
break;
case (uint)UAConst.VariableTypeAttributes_Encoding_DefaultBinary:
VariableTypeAttributes vta;
if (!tmp.Decode(out vta)) { return false; }
Payload = vta;
break;
case (uint)UAConst.Argument_Encoding_DefaultBinary:
Argument arg;
if (!tmp.Decode(out arg)) { return false; }
Payload = arg;
break;
case (uint)UAConst.EUInformation:
EUInformation eui;
if(!tmp.Decode(out eui)) { return false; }
Payload = eui;
break;
case (uint)UAConst.Range:
OpcRange range;
if(!tmp.Decode(out range)) { return false; }
Payload = range;
break;
default:
break;
}

return Payload != null;
}
}

public class ExtensionObject<TPayload> : ExtensionObject
{
public TPayload Value
{
get
{
if (Payload != null && Payload is TPayload tPayload)
return tPayload;
return default;
}
set => Payload = value;
}
}

public class DataValue
Expand Down

0 comments on commit debb00d

Please sign in to comment.