Skip to content

Commit

Permalink
Implement encoders support for Arrays and multi-dimensional Arrays. (#…
Browse files Browse the repository at this point in the history
…1350)

* Implement encoders support Arrays and multi-dimensional Arrays.
* JsonEncoder/Decoder fix for non reversible encoding of NodeId, ExpandedNodeId and QualifiedName
  • Loading branch information
AlinMoldovean committed Apr 7, 2021
1 parent 1d5e87c commit cb1abb1
Show file tree
Hide file tree
Showing 9 changed files with 2,306 additions and 843 deletions.
978 changes: 554 additions & 424 deletions Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs

Large diffs are not rendered by default.

417 changes: 417 additions & 0 deletions Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Stack/Opc.Ua.Core/Types/Encoders/IDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,5 +324,10 @@ public interface IDecoder
/// Reads an enumerated value array from the stream.
/// </summary>
Array ReadEnumeratedArray(string fieldName, System.Type enumType);

/// <summary>
/// Reads an array with the specified valueRank and the specified BuiltInType
/// </summary>
object ReadArray(string fieldName, int valueRank, BuiltInType builtInType);
}
}
5 changes: 5 additions & 0 deletions Stack/Opc.Ua.Core/Types/Encoders/IEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,11 @@ public interface IEncoder
/// Writes an enumerated value array to the stream.
/// </summary>
void WriteEnumeratedArray(string fieldName, Array values, System.Type systemType);

/// <summary>
/// Encode an array according to its valueRank and BuiltInType
/// </summary>
void WriteArray(string fieldName, object array, int valueRank, BuiltInType builtInType);
}

/// <summary>
Expand Down
884 changes: 630 additions & 254 deletions Stack/Opc.Ua.Core/Types/Encoders/JsonDecoder.cs

Large diffs are not rendered by default.

324 changes: 188 additions & 136 deletions Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs

Large diffs are not rendered by default.

247 changes: 247 additions & 0 deletions Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2617,6 +2617,56 @@ public Array ReadEnumeratedArray(string fieldName, System.Type enumType)

return Array.CreateInstance(enumType, 0);
}

/// <summary>
/// Reads an array with the specified valueRank and the specified BuiltInType
/// </summary>
public object ReadArray(string fieldName, int valueRank, BuiltInType builtInType)
{
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);
}

// write matrix.
else if (valueRank > ValueRanks.OneDimension)
{
Array elements = null;
Int32Collection dimensions = null;

if (BeginField(fieldName, true))
{
PushNamespace(Namespaces.OpcUaXsd);
// dimensions are written before elements when encoding multi dimensional array!! UA Specs
dimensions = ReadInt32Array("Dimensions");

elements = ReadArrayElements("Elements", builtInType);

PopNamespace();

EndField(fieldName);
}

if (elements == null)
{
throw new ServiceResultException(StatusCodes.BadDecodingError, "The Matrix contains invalid elements");
}

if (dimensions != null && dimensions.Count > 0)
{
return new Matrix(elements, builtInType, dimensions.ToArray());
}

return new Matrix(elements, builtInType);
}

throw new ServiceResultException(StatusCodes.BadDecodingError,
string.Format("Invalid ValueRank {0} for Array", valueRank));
}
#endregion

#region Private Methods
Expand Down Expand Up @@ -2673,6 +2723,203 @@ private Matrix ReadMatrix(string fieldName)
return new Matrix(elements, typeInfo.BuiltInType);
}

/// <summary>
/// Read array items from current ListOf element
/// </summary>
/// <param name="fieldName">provides the fieldName for the array</param>
/// <param name="builtInType">provides the BuiltInType of the elements that are read</param>
/// <returns></returns>
private Array ReadArrayElements(string fieldName, BuiltInType builtInType)
{
// check the nesting level for avoiding a stack overflow.
if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
{
throw ServiceResultException.Create(
StatusCodes.BadEncodingLimitsExceeded,
"Maximum nesting level of {0} was exceeded",
m_context.MaxEncodingNestingLevels);
}

m_nestingLevel++;


// skip whitespace.
while (m_reader.NodeType != XmlNodeType.Element)
{
m_reader.Read();
}

try
{
m_namespaces.Push(Namespaces.OpcUaXsd);

// process array types.

switch (builtInType)
{
case BuiltInType.Boolean:
{
BooleanCollection collection = ReadBooleanArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.SByte:
{
SByteCollection collection = ReadSByteArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.Byte:
{
ByteCollection collection = ReadByteArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.Int16:
{
Int16Collection collection = ReadInt16Array(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.UInt16:
{
UInt16Collection collection = ReadUInt16Array(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.Enumeration:
case BuiltInType.Int32:
{
Int32Collection collection = ReadInt32Array(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.UInt32:
{
UInt32Collection collection = ReadUInt32Array(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.Int64:
{
Int64Collection collection = ReadInt64Array(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.UInt64:
{
UInt64Collection collection = ReadUInt64Array(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.Float:
{
FloatCollection collection = ReadFloatArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.Double:
{
DoubleCollection collection = ReadDoubleArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.String:
{
StringCollection collection = ReadStringArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.DateTime:
{
DateTimeCollection collection = ReadDateTimeArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.Guid:
{
UuidCollection collection = ReadGuidArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.ByteString:
{
ByteStringCollection collection = ReadByteStringArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.XmlElement:
{
XmlElementCollection collection = ReadXmlElementArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.NodeId:
{
NodeIdCollection collection = ReadNodeIdArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.ExpandedNodeId:
{
ExpandedNodeIdCollection collection = ReadExpandedNodeIdArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.StatusCode:
{
StatusCodeCollection collection = ReadStatusCodeArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.DiagnosticInfo:
{
DiagnosticInfoCollection collection = ReadDiagnosticInfoArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.QualifiedName:
{
QualifiedNameCollection collection = ReadQualifiedNameArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.LocalizedText:
{
LocalizedTextCollection collection = ReadLocalizedTextArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.ExtensionObject:
{
ExtensionObjectCollection collection = ReadExtensionObjectArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.DataValue:
{
DataValueCollection collection = ReadDataValueArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
case BuiltInType.Variant:
{
VariantCollection collection = ReadVariantArray(fieldName);
if (collection != null) return collection.ToArray();
return null;
}
}

}
finally
{
m_namespaces.Pop();
m_nestingLevel--;
}

return null;
}

/// <summary>
/// Reads a string from the stream.
/// </summary>
Expand Down

0 comments on commit cb1abb1

Please sign in to comment.