Skip to content

Commit

Permalink
improve encode/decode for array/matrix of Iencodeable (#1398)
Browse files Browse the repository at this point in the history
Add tests for encode/decode of array/matrix of all IEncodeable
  • Loading branch information
AlinMoldovean committed May 12, 2021
1 parent a5e1f4c commit 923597e
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 17 deletions.
38 changes: 31 additions & 7 deletions Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1429,7 +1429,7 @@ public Array ReadEnumeratedArray(string fieldName, System.Type enumType)
/// <summary>
/// Reads an array with the specified valueRank and the specified BuiltInType
/// </summary>
public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType)
public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType, ExpandedNodeId encodeableTypeId = null)
{
if (valueRank == ValueRanks.OneDimension)
{
Expand Down Expand Up @@ -1481,6 +1481,14 @@ public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType
case BuiltInType.DataValue:
return ReadDataValueArray(fieldName).ToArray();
case BuiltInType.Variant:
if (encodeableTypeId != null)
{
Type systemType = Context.Factory.GetSystemType(encodeableTypeId);
if (systemType != null)
{
return ReadEncodeableArray(fieldName, systemType, encodeableTypeId);
}
}
return ReadVariantArray(fieldName).ToArray();
case BuiltInType.ExtensionObject:
return ReadExtensionObjectArray(fieldName).ToArray();
Expand Down Expand Up @@ -1516,14 +1524,33 @@ public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType
length *= dimensions[ii];
}
// read the elements
Array array = ReadArrayElements(length, builtInType);
if (array == null)
Array elements = null;
if (encodeableTypeId != null)
{
Type systemType = Context.Factory.GetSystemType(encodeableTypeId);
if (systemType != null)
{
elements = Array.CreateInstance(systemType, length);
for (int i = 0; i < length; i++)
{
IEncodeable element = ReadEncodeable(null, systemType, encodeableTypeId);

elements.SetValue(Convert.ChangeType(element, systemType), i);
}
}
}
if (elements == null)
{
elements = ReadArrayElements(length, builtInType);
}

if (elements == null)
{
throw new ServiceResultException(
StatusCodes.BadDecodingError,
Utils.Format("Unexpected null Array for multidimensional matrix with {0} elements.", length));
}
return new Matrix(array, builtInType, dimensions.ToArray());
return new Matrix(elements, builtInType, dimensions.ToArray());
}
throw new ServiceResultException(
StatusCodes.BadDecodingError,
Expand All @@ -1538,9 +1565,6 @@ public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType
/// <summary>
/// Reads and returns an array of elements of the specified length and builtInType
/// </summary>
/// <param name="length"></param>
/// <param name="builtInType"></param>
/// <returns></returns>
private Array ReadArrayElements(int length, BuiltInType builtInType)
{
Array array = null;
Expand Down
19 changes: 19 additions & 0 deletions Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1641,6 +1641,14 @@ public void WriteArray(string fieldName, object array, int valueRank, BuiltInTyp
WriteXmlElementArray(null, (System.Xml.XmlElement[])array);
break;
case BuiltInType.Variant:
// try to write IEncodeable Array
IEncodeable[] encodeableArray = array as IEncodeable[];
if (encodeableArray != null)
{
WriteEncodeableArray(fieldName, encodeableArray, array.GetType().GetElementType());
return;
}

WriteVariantArray(null, (Variant[])array);
break;
case BuiltInType.Enumeration:
Expand Down Expand Up @@ -1946,6 +1954,17 @@ public void WriteArray(string fieldName, object array, int valueRank, BuiltInTyp
break;
}

// try to write IEncodeable Array
IEncodeable[] encodeableArray = matrix.Elements as IEncodeable[];
if (encodeableArray != null)
{
for (int ii = 0; ii < encodeableArray.Length; ii++)
{
WriteEncodeable(null, encodeableArray[ii], null);
}
break;
}

object[] objects = matrix.Elements as object[];

if (objects != null)
Expand Down
2 changes: 1 addition & 1 deletion Stack/Opc.Ua.Core/Types/Encoders/IDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,6 @@ public interface IDecoder
/// <summary>
/// Reads an array with the specified valueRank and the specified BuiltInType
/// </summary>
object ReadArray(string fieldName, int valueRank, BuiltInType builtInType);
object ReadArray(string fieldName, int valueRank, BuiltInType builtInType, ExpandedNodeId encodeableTypeId = null);
}
}
33 changes: 28 additions & 5 deletions Stack/Opc.Ua.Core/Types/Encoders/JsonDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2390,7 +2390,7 @@ public Array ReadEnumeratedArray(string fieldName, System.Type enumType)
/// <summary>
/// Reads an array with the specified valueRank and the specified BuiltInType
/// </summary>
public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType)
public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType, ExpandedNodeId encodeableTypeId = null)
{
if (valueRank == ValueRanks.OneDimension)
{
Expand Down Expand Up @@ -2443,7 +2443,17 @@ public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType
case BuiltInType.Enumeration:
return ReadInt32Array(fieldName).ToArray();
case BuiltInType.Variant:
{
if (encodeableTypeId != null)
{
Type systemType = Context.Factory.GetSystemType(encodeableTypeId);
if (systemType != null)
{
return ReadEncodeableArray(fieldName, systemType, encodeableTypeId);
}
}
return ReadVariantArray(fieldName).ToArray();
}
case BuiltInType.ExtensionObject:
return ReadExtensionObjectArray(fieldName).ToArray();
case BuiltInType.DiagnosticInfo:
Expand All @@ -2465,7 +2475,7 @@ public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType
}
List<object> elements = new List<object>();
List<int> dimensions = new List<int>();
ReadMatrixPart(fieldName, array, builtInType, ref elements, ref dimensions, 0);
ReadMatrixPart(fieldName, array, builtInType, ref elements, ref dimensions, 0, encodeableTypeId);

switch (builtInType)
{
Expand Down Expand Up @@ -2516,6 +2526,19 @@ public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType
case BuiltInType.Enumeration:
return new Matrix(elements.Cast<Int32>().ToArray(), builtInType, dimensions.ToArray());
case BuiltInType.Variant:
if (encodeableTypeId != null)
{
Type systemType = Context.Factory.GetSystemType(encodeableTypeId);
if (systemType != null)
{
Array newElements = Array.CreateInstance(systemType, elements.Count);
for (int i = 0; i < elements.Count; i++)
{
newElements.SetValue(Convert.ChangeType(elements[i], systemType), i);
}
return new Matrix(newElements, builtInType, dimensions.ToArray());
}
}
return new Matrix(elements.Cast<Variant>().ToArray(), builtInType, dimensions.ToArray());
case BuiltInType.ExtensionObject:
return new Matrix(elements.Cast<ExtensionObject>().ToArray(), builtInType, dimensions.ToArray());
Expand Down Expand Up @@ -2788,7 +2811,7 @@ private List<object> ReadArray()
/// <summary>
/// Read the Matrix part (simple array or array of arrays)
/// </summary>
private void ReadMatrixPart(string fieldName, List<object> currentArray, BuiltInType builtInType, ref List<object> elements, ref List<int> dimensions, int level)
private void ReadMatrixPart(string fieldName, List<object> currentArray, BuiltInType builtInType, ref List<object> elements, ref List<int> dimensions, int level, ExpandedNodeId encodeableTypeId = null)
{
// check the nesting level for avoiding a stack overflow.
if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
Expand Down Expand Up @@ -2819,7 +2842,7 @@ private void ReadMatrixPart(string fieldName, List<object> currentArray, BuiltIn

PushArray(fieldName, ii);

ReadMatrixPart(null, currentArray[ii] as List<object>, builtInType, ref elements, ref dimensions, level + 1);
ReadMatrixPart(null, currentArray[ii] as List<object>, builtInType, ref elements, ref dimensions, level + 1, encodeableTypeId);

Pop();
}
Expand All @@ -2831,7 +2854,7 @@ private void ReadMatrixPart(string fieldName, List<object> currentArray, BuiltIn
if (!hasInnerArray)
{
// read array from one dimension
var part = ReadArray(null, ValueRanks.OneDimension, builtInType) as System.Collections.IList;
var part = ReadArray(null, ValueRanks.OneDimension, builtInType, encodeableTypeId) as System.Collections.IList;
if (part != null && part.Count > 0)
{
// add part elements to final list
Expand Down
8 changes: 8 additions & 0 deletions Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2372,6 +2372,14 @@ public void WriteArray(string fieldName, object array, int valueRank, BuiltInTyp
return;
}

// try to write IEncodeable Array
IEncodeable[] encodeableArray = array as IEncodeable[];
if (encodeableArray != null)
{
WriteEncodeableArray(fieldName, encodeableArray, array.GetType().GetElementType());
return;
}

object[] objects = array as object[];

if (objects != null)
Expand Down
18 changes: 14 additions & 4 deletions Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2622,15 +2622,15 @@ public Array ReadEnumeratedArray(string fieldName, System.Type enumType)
/// <summary>
/// Reads an array with the specified valueRank and the specified BuiltInType
/// </summary>
public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType)
public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType, ExpandedNodeId encodeableTypeId = null)
{
if (valueRank == ValueRanks.OneDimension)
{
/*One dimensional Array parameters are always encoded by wrapping the elements in a container element
* and inserting the container into the structure. The name of the container element should be the name of the parameter.
* The name of the element in the array shall be the type name.*/

return ReadArrayElements(fieldName, builtInType);
return ReadArrayElements(fieldName, builtInType, encodeableTypeId);
}

// write matrix.
Expand All @@ -2645,7 +2645,7 @@ public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType
// dimensions are written before elements when encoding multi dimensional array!! UA Specs
dimensions = ReadInt32Array("Dimensions");

elements = ReadArrayElements("Elements", builtInType);
elements = ReadArrayElements("Elements", builtInType, encodeableTypeId);

PopNamespace();

Expand Down Expand Up @@ -2729,8 +2729,9 @@ private Matrix ReadMatrix(string fieldName)
/// </summary>
/// <param name="fieldName">provides the fieldName for the array</param>
/// <param name="builtInType">provides the BuiltInType of the elements that are read</param>
/// <param name="encodeableTypeId">provides the type id of the encodeable element</param>
/// <returns></returns>
private Array ReadArrayElements(string fieldName, BuiltInType builtInType)
private Array ReadArrayElements(string fieldName, BuiltInType builtInType, ExpandedNodeId encodeableTypeId = null)
{
// check the nesting level for avoiding a stack overflow.
if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
Expand Down Expand Up @@ -2905,6 +2906,15 @@ private Array ReadArrayElements(string fieldName, BuiltInType builtInType)
}
case BuiltInType.Variant:
{
if (encodeableTypeId != null)
{
Type systemType = Context.Factory.GetSystemType(encodeableTypeId);
if (systemType != null)
{
return ReadEncodeableArray(fieldName, systemType, encodeableTypeId);
}
}

VariantCollection collection = ReadVariantArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
Expand Down
8 changes: 8 additions & 0 deletions Stack/Opc.Ua.Core/Types/Encoders/XmlEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2059,6 +2059,14 @@ public void WriteArray(string fieldName, object array, int valueRank, BuiltInTyp
return;
}

// try to write IEncodeable Array
IEncodeable[] encodeableArray = array as IEncodeable[];
if (encodeableArray != null)
{
WriteEncodeableArray(fieldName, encodeableArray, array.GetType().GetElementType());
return;
}

object[] objects = array as object[];

if (objects != null)
Expand Down

0 comments on commit 923597e

Please sign in to comment.