Files
Mapo-IOB-WIN/IOB-OPC-UA/Stack/Opc.Ua.Core/Schema/UANodeSetHelpers.cs
T
2021-03-25 18:25:25 +01:00

1395 lines
48 KiB
C#

/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
The source code in this file is covered under a dual-license scenario:
- RCL: for OPC Foundation members in good-standing
- GPL V2: everybody else
RCL license terms accompanied with this source code. See http://opcfoundation.org/License/RCL/1.00/
GNU General Public License as published by the Free Software Foundation;
version 2 of the License are accompanied with this source code. See http://opcfoundation.org/License/GPLv2
This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace Opc.Ua.Export
{
/// <summary>
/// A set of nodes in an address space.
/// </summary>
public partial class UANodeSet
{
#region Constructors
/// <summary>
/// Creates an empty nodeset.
/// </summary>
public UANodeSet()
{
}
/// <summary>
/// Loads a nodeset from a stream.
/// </summary>
/// <param name="istrm">The input stream.</param>
/// <returns>The set of nodes</returns>
public static UANodeSet Read(Stream istrm)
{
StreamReader reader = new StreamReader(istrm);
try
{
XmlSerializer serializer = new XmlSerializer(typeof(UANodeSet));
return serializer.Deserialize(reader) as UANodeSet;
}
finally
{
reader.Dispose();
}
}
/// <summary>
/// Write a nodeset to a stream.
/// </summary>
/// <param name="istrm">The input stream.</param>
public void Write(Stream istrm)
{
StreamWriter writer = new StreamWriter(istrm, Encoding.UTF8);
try
{
XmlSerializer serializer = new XmlSerializer(typeof(UANodeSet));
serializer.Serialize(writer, this);
}
finally
{
writer.Flush();
writer.Dispose();
}
}
#endregion
#region Public Methods
/// <summary>
/// Adds an alias to the node set.
/// </summary>
public void AddAlias(ISystemContext context, string alias, Opc.Ua.NodeId nodeId)
{
int count = 1;
if (this.Aliases != null)
{
for (int ii = 0; ii < this.Aliases.Length; ii++)
{
if (this.Aliases[ii].Alias == alias)
{
this.Aliases[ii].Value = Export(nodeId, context.NamespaceUris);
return;
}
}
count += this.Aliases.Length;
}
NodeIdAlias[] aliases = new NodeIdAlias[count];
if (this.Aliases != null)
{
Array.Copy(this.Aliases, aliases, this.Aliases.Length);
}
aliases[count-1] = new NodeIdAlias() { Alias = alias, Value = Export(nodeId, context.NamespaceUris) };
this.Aliases = aliases;
}
/// <summary>
/// Imports a node from the set.
/// </summary>
public void Import(ISystemContext context, NodeStateCollection nodes)
{
for (int ii = 0; ii < this.Items.Length; ii++)
{
UANode node = this.Items[ii];
NodeState importedNode = Import(context, node);
nodes.Add(importedNode);
}
}
/// <summary>
/// Adds a node to the set.
/// </summary>
public void Export(ISystemContext context, NodeState node, bool outputRedundantNames =true)
{
if (node == null) throw new ArgumentNullException(nameof(node));
if (Opc.Ua.NodeId.IsNull(node.NodeId))
{
throw new ArgumentException("A non-null NodeId must be specified.");
}
UANode exportedNode = null;
switch (node.NodeClass)
{
case NodeClass.Object:
{
BaseObjectState o = (BaseObjectState)node;
UAObject value = new UAObject();
value.EventNotifier = o.EventNotifier;
if (o.Parent != null)
{
value.ParentNodeId = ExportAlias(o.Parent.NodeId, context.NamespaceUris);
}
exportedNode = value;
break;
}
case NodeClass.Variable:
{
BaseVariableState o = (BaseVariableState)node;
UAVariable value = new UAVariable();
value.DataType = ExportAlias(o.DataType, context.NamespaceUris);
value.ValueRank = o.ValueRank;
value.ArrayDimensions = Export(o.ArrayDimensions);
value.AccessLevel = o.AccessLevelEx;
value.MinimumSamplingInterval = o.MinimumSamplingInterval;
value.Historizing = o.Historizing;
if (o.Parent != null)
{
value.ParentNodeId = ExportAlias(o.Parent.NodeId, context.NamespaceUris);
}
if (o.Value != null)
{
XmlEncoder encoder = CreateEncoder(context);
Variant variant = new Variant(o.Value);
encoder.WriteVariantContents(variant.Value, variant.TypeInfo);
XmlDocument document = new XmlDocument();
document.InnerXml = encoder.Close();
value.Value = document.DocumentElement;
}
exportedNode = value;
break;
}
case NodeClass.Method:
{
MethodState o = (MethodState)node;
UAMethod value = new UAMethod();
value.Executable = o.Executable;
if (o.TypeDefinitionId != null && !o.TypeDefinitionId.IsNullNodeId && o.TypeDefinitionId != o.NodeId)
{
value.MethodDeclarationId = Export(o.TypeDefinitionId, context.NamespaceUris);
}
if (o.Parent != null)
{
value.ParentNodeId = ExportAlias(o.Parent.NodeId, context.NamespaceUris);
}
exportedNode = value;
break;
}
case NodeClass.View:
{
ViewState o = (ViewState)node;
UAView value = new UAView();
value.ContainsNoLoops = o.ContainsNoLoops;
exportedNode = value;
break;
}
case NodeClass.ObjectType:
{
BaseObjectTypeState o = (BaseObjectTypeState)node;
UAObjectType value = new UAObjectType();
value.IsAbstract = o.IsAbstract;
exportedNode = value;
break;
}
case NodeClass.VariableType:
{
BaseVariableTypeState o = (BaseVariableTypeState)node;
UAVariableType value = new UAVariableType();
value.IsAbstract = o.IsAbstract;
value.DataType = ExportAlias(o.DataType, context.NamespaceUris);
value.ValueRank = o.ValueRank;
value.ArrayDimensions = Export(o.ArrayDimensions);
if (o.Value != null)
{
XmlEncoder encoder = CreateEncoder(context);
Variant variant = new Variant(o.Value);
encoder.WriteVariantContents(variant.Value, variant.TypeInfo);
XmlDocument document = new XmlDocument();
document.InnerXml = encoder.Close();
value.Value = document.DocumentElement;
}
exportedNode = value;
break;
}
case NodeClass.DataType:
{
DataTypeState o = (DataTypeState)node;
UADataType value = new UADataType();
value.IsAbstract = o.IsAbstract;
value.Definition = Export(o, o.DataTypeDefinition, context.NamespaceUris, outputRedundantNames);
value.Purpose = o.Purpose;
exportedNode = value;
break;
}
case NodeClass.ReferenceType:
{
ReferenceTypeState o = (ReferenceTypeState)node;
UAReferenceType value = new UAReferenceType();
value.IsAbstract = o.IsAbstract;
if (!Opc.Ua.LocalizedText.IsNullOrEmpty(o.InverseName))
{
value.InverseName = Export(new Opc.Ua.LocalizedText[] { o.InverseName });
}
value.Symmetric = o.Symmetric;
exportedNode = value;
break;
}
}
exportedNode.NodeId = Export(node.NodeId, context.NamespaceUris);
exportedNode.BrowseName = Export(node.BrowseName, context.NamespaceUris);
if (outputRedundantNames || node.DisplayName.Text != node.BrowseName.Name)
{
exportedNode.DisplayName = Export(new Opc.Ua.LocalizedText[] { node.DisplayName });
}
else
{
exportedNode.DisplayName = null;
}
if (node.Description != null && !String.IsNullOrEmpty(node.Description.Text))
{
exportedNode.Description = Export(new Opc.Ua.LocalizedText[] { node.Description });
}
else
{
exportedNode.Description = new LocalizedText[0];
}
exportedNode.Documentation = node.NodeSetDocumentation;
exportedNode.Category = (node.Categories != null && node.Categories.Count > 0) ? new List<string>(node.Categories).ToArray() : null;
exportedNode.ReleaseStatus = node.ReleaseStatus;
exportedNode.WriteMask = (uint)node.WriteMask;
exportedNode.UserWriteMask = (uint)node.UserWriteMask;
exportedNode.Extensions = node.Extensions;
if (!String.IsNullOrEmpty(node.SymbolicName) && node.SymbolicName != node.BrowseName.Name)
{
exportedNode.SymbolicName = node.SymbolicName;
}
// export references.
INodeBrowser browser = node.CreateBrowser(context, null, null, true, BrowseDirection.Both, null, null, true);
List<Reference> exportedReferences = new List<Reference>();
IReference reference = browser.Next();
while (reference != null)
{
if (node.NodeClass == NodeClass.Method)
{
if (!reference.IsInverse && reference.ReferenceTypeId == ReferenceTypeIds.HasTypeDefinition)
{
reference = browser.Next();
continue;
}
}
Reference exportedReference = new Reference();
exportedReference.ReferenceType = ExportAlias(reference.ReferenceTypeId, context.NamespaceUris);
exportedReference.IsForward = !reference.IsInverse;
exportedReference.Value = Export(reference.TargetId, context.NamespaceUris, context.ServerUris);
exportedReferences.Add(exportedReference);
reference = browser.Next();
}
exportedNode.References = exportedReferences.ToArray();
// add node to list.
UANode[] nodes = null;
int count = 1;
if (this.Items == null)
{
nodes = new UANode[count];
}
else
{
count += this.Items.Length;
nodes = new UANode[count];
Array.Copy(this.Items, nodes, this.Items.Length);
}
nodes[count-1] = exportedNode;
this.Items = nodes;
// recusively process children.
List<BaseInstanceState> children = new List<BaseInstanceState>();
node.GetChildren(context, children);
for (int ii = 0; ii < children.Count; ii++)
{
Export(context, children[ii], outputRedundantNames);
}
}
#endregion
#region Private Members
/// <summary>
/// Creates an encoder to save Variant values.
/// </summary>
private XmlEncoder CreateEncoder(ISystemContext context)
{
ServiceMessageContext messageContext = new ServiceMessageContext();
messageContext.NamespaceUris = context.NamespaceUris;
messageContext.ServerUris = context.ServerUris;
messageContext.Factory = context.EncodeableFactory;
XmlEncoder encoder = new XmlEncoder(messageContext);
NamespaceTable namespaceUris = new NamespaceTable();
if (NamespaceUris != null)
{
for (int ii = 0; ii < NamespaceUris.Length; ii++)
{
namespaceUris.Append(NamespaceUris[ii]);
}
}
StringTable serverUris = new StringTable();
if (ServerUris != null)
{
serverUris.Append(context.ServerUris.GetString(0));
for (int ii = 0; ii < ServerUris.Length; ii++)
{
serverUris.Append(ServerUris[ii]);
}
}
encoder.SetMappingTables(namespaceUris, serverUris);
return encoder;
}
/// <summary>
/// Creates an decoder to restore Variant values.
/// </summary>
private XmlDecoder CreateDecoder(ISystemContext context, XmlElement source)
{
ServiceMessageContext messageContext = new ServiceMessageContext();
messageContext.NamespaceUris = context.NamespaceUris;
messageContext.ServerUris = context.ServerUris;
messageContext.Factory = context.EncodeableFactory;
XmlDecoder decoder = new XmlDecoder(source, messageContext);
NamespaceTable namespaceUris = new NamespaceTable();
if (NamespaceUris != null)
{
for (int ii = 0; ii < NamespaceUris.Length; ii++)
{
namespaceUris.Append(NamespaceUris[ii]);
}
}
StringTable serverUris = new StringTable();
if (ServerUris != null)
{
serverUris.Append(context.ServerUris.GetString(0));
for (int ii = 0; ii < ServerUris.Length; ii++)
{
serverUris.Append(ServerUris[ii]);
}
}
decoder.SetMappingTables(namespaceUris, serverUris);
return decoder;
}
/// <summary>
/// Imports a node from the set.
/// </summary>
private NodeState Import(ISystemContext context, UANode node)
{
NodeState importedNode = null;
NodeClass nodeClass = NodeClass.Unspecified;
if (node is UAObject) nodeClass = NodeClass.Object;
else if (node is UAVariable) nodeClass = NodeClass.Variable;
else if (node is UAMethod) nodeClass = NodeClass.Method;
else if (node is UAObjectType) nodeClass = NodeClass.ObjectType;
else if (node is UAVariableType) nodeClass = NodeClass.VariableType;
else if (node is UADataType) nodeClass = NodeClass.DataType;
else if (node is UAReferenceType) nodeClass = NodeClass.ReferenceType;
else if (node is UAView) nodeClass = NodeClass.View;
switch (nodeClass)
{
case NodeClass.Object:
{
UAObject o = (UAObject)node;
BaseObjectState value = new BaseObjectState(null);
value.EventNotifier = o.EventNotifier;
importedNode = value;
break;
}
case NodeClass.Variable:
{
UAVariable o = (UAVariable)node;
NodeId typeDefinitionId = null;
if (node.References != null)
{
for (int ii = 0; ii < node.References.Length; ii++)
{
Opc.Ua.NodeId referenceTypeId = ImportNodeId(node.References[ii].ReferenceType, context.NamespaceUris, true);
bool isInverse = !node.References[ii].IsForward;
Opc.Ua.ExpandedNodeId targetId = ImportExpandedNodeId(node.References[ii].Value, context.NamespaceUris, context.ServerUris);
if (referenceTypeId == ReferenceTypeIds.HasTypeDefinition && !isInverse)
{
typeDefinitionId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris);
break;
}
}
}
BaseVariableState value = null;
if (typeDefinitionId == Opc.Ua.VariableTypeIds.PropertyType)
{
value = new PropertyState(null);
}
else
{
value = new BaseDataVariableState(null);
}
value.DataType = ImportNodeId(o.DataType, context.NamespaceUris, true);
value.ValueRank = o.ValueRank;
value.ArrayDimensions = ImportArrayDimensions(o.ArrayDimensions);
value.AccessLevelEx = o.AccessLevel;
value.UserAccessLevel = (byte)(o.AccessLevel & 0xFF);
value.MinimumSamplingInterval = o.MinimumSamplingInterval;
value.Historizing = o.Historizing;
if (o.Value != null)
{
XmlDecoder decoder = CreateDecoder(context, o.Value);
TypeInfo typeInfo = null;
value.Value = decoder.ReadVariantContents(out typeInfo);
decoder.Close();
}
importedNode = value;
break;
}
case NodeClass.Method:
{
UAMethod o = (UAMethod)node;
MethodState value = new MethodState(null);
value.Executable = o.Executable;
value.UserExecutable = o.Executable;
value.TypeDefinitionId = ImportNodeId(o.MethodDeclarationId, context.NamespaceUris, true);
importedNode = value;
break;
}
case NodeClass.View:
{
UAView o = (UAView)node;
ViewState value = new ViewState();
value.ContainsNoLoops = o.ContainsNoLoops;
importedNode = value;
break;
}
case NodeClass.ObjectType:
{
UAObjectType o = (UAObjectType)node;
BaseObjectTypeState value = new BaseObjectTypeState();
value.IsAbstract = o.IsAbstract;
importedNode = value;
break;
}
case NodeClass.VariableType:
{
UAVariableType o = (UAVariableType)node;
BaseVariableTypeState value = new BaseDataVariableTypeState();
value.IsAbstract = o.IsAbstract;
value.DataType = ImportNodeId(o.DataType, context.NamespaceUris, true);
value.ValueRank = o.ValueRank;
value.ArrayDimensions = ImportArrayDimensions(o.ArrayDimensions);
if (o.Value != null)
{
XmlDecoder decoder = CreateDecoder(context, o.Value);
TypeInfo typeInfo = null;
value.Value = decoder.ReadVariantContents(out typeInfo);
decoder.Close();
}
importedNode = value;
break;
}
case NodeClass.DataType:
{
UADataType o = (UADataType)node;
DataTypeState value = new DataTypeState();
value.IsAbstract = o.IsAbstract;
Opc.Ua.DataTypeDefinition dataTypeDefinition = Import(o, o.Definition, context.NamespaceUris);
value.DataTypeDefinition = new ExtensionObject(dataTypeDefinition);
value.Purpose = o.Purpose;
value.DataTypeModifier = DataTypeModifier.None;
if (o.Definition != null)
{
if (o.Definition.IsOptionSet)
{
value.DataTypeModifier = DataTypeModifier.OptionSet;
}
else if (o.Definition.IsUnion)
{
value.DataTypeModifier = DataTypeModifier.Union;
}
}
importedNode = value;
break;
}
case NodeClass.ReferenceType:
{
UAReferenceType o = (UAReferenceType)node;
ReferenceTypeState value = new ReferenceTypeState();
value.IsAbstract = o.IsAbstract;
value.InverseName = Import(o.InverseName);
value.Symmetric = o.Symmetric;
importedNode = value;
break;
}
}
importedNode.NodeId = ImportNodeId(node.NodeId, context.NamespaceUris, false);
importedNode.BrowseName = ImportQualifiedName(node.BrowseName, context.NamespaceUris);
importedNode.DisplayName = Import(node.DisplayName);
if (importedNode.DisplayName == null)
{
importedNode.DisplayName = new Ua.LocalizedText(importedNode.BrowseName.Name);
}
importedNode.Description = Import(node.Description);
importedNode.NodeSetDocumentation = node.Documentation;
importedNode.Categories = (node.Category != null && node.Category.Length > 0) ? node.Category : null;
importedNode.ReleaseStatus = node.ReleaseStatus;
importedNode.WriteMask = (AttributeWriteMask)node.WriteMask;
importedNode.UserWriteMask = (AttributeWriteMask)node.UserWriteMask;
importedNode.Extensions = node.Extensions;
if (!String.IsNullOrEmpty(node.SymbolicName))
{
importedNode.SymbolicName = node.SymbolicName;
}
if (node.References != null)
{
BaseInstanceState instance = importedNode as BaseInstanceState;
BaseTypeState type = importedNode as BaseTypeState;
for (int ii = 0; ii < node.References.Length; ii++)
{
Opc.Ua.NodeId referenceTypeId = ImportNodeId(node.References[ii].ReferenceType, context.NamespaceUris, true);
bool isInverse = !node.References[ii].IsForward;
Opc.Ua.ExpandedNodeId targetId = ImportExpandedNodeId(node.References[ii].Value, context.NamespaceUris, context.ServerUris);
if (instance != null)
{
if (referenceTypeId == ReferenceTypeIds.HasModellingRule && !isInverse)
{
instance.ModellingRuleId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris);
continue;
}
if (referenceTypeId == ReferenceTypeIds.HasTypeDefinition && !isInverse)
{
instance.TypeDefinitionId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris);
continue;
}
}
if (type != null)
{
if (referenceTypeId == ReferenceTypeIds.HasSubtype && isInverse)
{
type.SuperTypeId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris);
continue;
}
}
importedNode.AddReference(referenceTypeId, isInverse, targetId);
}
}
string parentNodeId = (node as UAInstance)?.ParentNodeId;
if (!String.IsNullOrEmpty(parentNodeId))
{
// set parent NodeId in Handle property.
importedNode.Handle = ImportNodeId(parentNodeId, context.NamespaceUris, true);
}
return importedNode;
}
/// <summary>
/// Exports a NodeId as an alias.
/// </summary>
private string ExportAlias(Opc.Ua.NodeId source, NamespaceTable namespaceUris)
{
string nodeId = Export(source, namespaceUris);
if (!String.IsNullOrEmpty(nodeId))
{
if (this.Aliases != null)
{
for (int ii = 0; ii < this.Aliases.Length; ii++)
{
if (this.Aliases[ii].Value == nodeId)
{
return this.Aliases[ii].Alias;
}
}
}
}
return nodeId;
}
/// <summary>
/// Exports a NodeId
/// </summary>
private string Export(Opc.Ua.NodeId source, NamespaceTable namespaceUris)
{
if (Opc.Ua.NodeId.IsNull(source))
{
return String.Empty;
}
if (source.NamespaceIndex > 0)
{
ushort namespaceIndex = ExportNamespaceIndex(source.NamespaceIndex, namespaceUris);
source = new Opc.Ua.NodeId(source.Identifier, namespaceIndex);
}
return source.ToString();
}
/// <summary>
/// Imports a NodeId
/// </summary>
private Opc.Ua.NodeId ImportNodeId(string source, NamespaceTable namespaceUris, bool lookupAlias)
{
if (String.IsNullOrEmpty(source))
{
return Opc.Ua.NodeId.Null;
}
// lookup alias.
if (lookupAlias && this.Aliases != null)
{
for (int ii = 0; ii < this.Aliases.Length; ii++)
{
if (this.Aliases[ii].Alias == source)
{
source = this.Aliases[ii].Value;
break;
}
}
}
// parse the string.
Opc.Ua.NodeId nodeId = Opc.Ua.NodeId.Parse(source);
if (nodeId.NamespaceIndex > 0)
{
ushort namespaceIndex = ImportNamespaceIndex(nodeId.NamespaceIndex, namespaceUris);
nodeId = new Opc.Ua.NodeId(nodeId.Identifier, namespaceIndex);
}
return nodeId;
}
/// <summary>
/// Exports a ExpandedNodeId
/// </summary>
private string Export(Opc.Ua.ExpandedNodeId source, NamespaceTable namespaceUris, StringTable serverUris)
{
if (Opc.Ua.NodeId.IsNull(source))
{
return String.Empty;
}
if (source.ServerIndex <= 0 && source.NamespaceIndex <= 0 && String.IsNullOrEmpty(source.NamespaceUri))
{
return source.ToString();
}
ushort namespaceIndex = 0;
if (String.IsNullOrEmpty(source.NamespaceUri))
{
namespaceIndex = ExportNamespaceIndex(source.NamespaceIndex, namespaceUris);
}
else
{
namespaceIndex = ExportNamespaceUri(source.NamespaceUri, namespaceUris);
}
uint serverIndex = ExportServerIndex(source.ServerIndex, serverUris);
source = new Opc.Ua.ExpandedNodeId(source.Identifier, namespaceIndex, null, serverIndex);
return source.ToString();
}
/// <summary>
/// Imports a ExpandedNodeId
/// </summary>
private Opc.Ua.ExpandedNodeId ImportExpandedNodeId(string source, NamespaceTable namespaceUris, StringTable serverUris)
{
if (String.IsNullOrEmpty(source))
{
return Opc.Ua.ExpandedNodeId.Null;
}
// lookup aliases
if (this.Aliases != null)
{
for (int ii = 0; ii < this.Aliases.Length; ii++)
{
if (this.Aliases[ii].Alias == source)
{
source = this.Aliases[ii].Value;
break;
}
}
}
// parse the node.
Opc.Ua.ExpandedNodeId nodeId = Opc.Ua.ExpandedNodeId.Parse(source);
if (nodeId.ServerIndex <= 0 && nodeId.NamespaceIndex <= 0 && String.IsNullOrEmpty(nodeId.NamespaceUri))
{
return nodeId;
}
uint serverIndex = ImportServerIndex(nodeId.ServerIndex, serverUris);
ushort namespaceIndex = ImportNamespaceIndex(nodeId.NamespaceIndex, namespaceUris);
if (serverIndex > 0)
{
string namespaceUri = nodeId.NamespaceUri;
if (String.IsNullOrEmpty(nodeId.NamespaceUri))
{
namespaceUri = namespaceUris.GetString(namespaceIndex);
}
nodeId = new Opc.Ua.ExpandedNodeId(nodeId.Identifier, 0, namespaceUri, serverIndex);
return nodeId;
}
nodeId = new Opc.Ua.ExpandedNodeId(nodeId.Identifier, namespaceIndex, null, 0);
return nodeId;
}
/// <summary>
/// Exports a QualifiedName
/// </summary>
private string Export(Opc.Ua.QualifiedName source, NamespaceTable namespaceUris)
{
if (Opc.Ua.QualifiedName.IsNull(source))
{
return String.Empty;
}
if (source.NamespaceIndex > 0)
{
ushort namespaceIndex = ExportNamespaceIndex(source.NamespaceIndex, namespaceUris);
source = new Opc.Ua.QualifiedName(source.Name, namespaceIndex);
}
return source.ToString();
}
/// <summary>
/// Exports a DataTypeDefinition
/// </summary>
private Opc.Ua.Export.DataTypeDefinition Export(
DataTypeState dataType,
ExtensionObject source,
NamespaceTable namespaceUris,
bool outputRedundantNames)
{
if (source == null || source.Body == null)
{
return null;
}
DataTypeDefinition definition = new DataTypeDefinition();
if (outputRedundantNames || dataType.BrowseName != null)
{
definition.Name = Export(dataType.BrowseName, namespaceUris);
}
if (dataType.BrowseName.Name != dataType.SymbolicName)
{
definition.SymbolicName = dataType.SymbolicName;
}
switch (dataType.DataTypeModifier)
{
case DataTypeModifier.Union: { definition.IsUnion = true; break; }
case DataTypeModifier.OptionSet: { definition.IsOptionSet = true; break; }
}
StructureDefinition structureDefinition = source.Body as StructureDefinition;
if (structureDefinition != null)
{
if (structureDefinition.StructureType == StructureType.Union)
{
definition.IsUnion = true;
}
if (structureDefinition.Fields != null)
{
List<Opc.Ua.Export.DataTypeField> fields = new List<DataTypeField>();
for (int ii = structureDefinition.FirstExplicitFieldIndex; ii < structureDefinition.Fields.Count; ii++)
{
StructureField field = structureDefinition.Fields[ii];
Opc.Ua.Export.DataTypeField output = new Opc.Ua.Export.DataTypeField();
output.Name = field.Name;
output.Description = Export(new Opc.Ua.LocalizedText[] { field.Description });
output.IsOptional = field.IsOptional;
if (NodeId.IsNull(field.DataType))
{
output.DataType = Export(DataTypeIds.BaseDataType, namespaceUris);
}
else
{
output.DataType = Export(field.DataType, namespaceUris);
}
output.ValueRank = field.ValueRank;
fields.Add(output);
}
definition.Field = fields.ToArray();
}
}
EnumDefinition enumDefinition = source.Body as EnumDefinition;
if (enumDefinition != null)
{
if (enumDefinition.Fields != null)
{
List<Opc.Ua.Export.DataTypeField> fields = new List<DataTypeField>();
foreach (EnumField field in enumDefinition.Fields)
{
Opc.Ua.Export.DataTypeField output = new Opc.Ua.Export.DataTypeField();
output.Name = field.Name;
if (field.DisplayName != null && output.Name != field.DisplayName.Text)
{
output.DisplayName = Export(new Opc.Ua.LocalizedText[] { field.DisplayName });
}
else
{
output.DisplayName = new LocalizedText[0];
}
output.Description = Export(new Opc.Ua.LocalizedText[] { field.Description });
output.ValueRank = ValueRanks.Scalar;
output.Value = (int)field.Value;
fields.Add(output);
}
definition.Field = fields.ToArray();
}
}
return definition;
}
/// <summary>
/// Imports a DataTypeDefinition
/// </summary>
private Opc.Ua.DataTypeDefinition Import(UADataType dataType, Opc.Ua.Export.DataTypeDefinition source, NamespaceTable namespaceUris)
{
if (source == null)
{
return null;
}
Opc.Ua.DataTypeDefinition definition = null;
if (source.Field != null)
{
// check if definition is for enumeration or structure.
bool isStructure = Array.Exists<DataTypeField>(source.Field, delegate (DataTypeField fieldLookup)
{
return fieldLookup.Value == -1;
});
if (isStructure)
{
StructureDefinition structureDefinition = new StructureDefinition();
structureDefinition.BaseDataType = ImportNodeId(source.BaseType, namespaceUris, true);
if (source.IsUnion)
{
structureDefinition.StructureType = StructureType.Union;
}
if (source.Field != null)
{
List<StructureField> fields = new List<StructureField>();
foreach (DataTypeField field in source.Field)
{
if (field.IsOptional)
{
structureDefinition.StructureType = StructureType.StructureWithOptionalFields;
}
StructureField output = new StructureField();
output.Name = field.Name;
output.Description = Import(field.Description);
output.DataType = ImportNodeId(field.DataType, namespaceUris, true);
output.ValueRank = field.ValueRank;
output.IsOptional = field.IsOptional;
fields.Add(output);
}
structureDefinition.Fields = fields.ToArray();
}
definition = structureDefinition;
}
else
{
EnumDefinition enumDefinition = new EnumDefinition();
if (source.Field != null)
{
List<EnumField> fields = new List<EnumField>();
foreach (DataTypeField field in source.Field)
{
EnumField output = new EnumField();
output.Name = field.Name;
output.DisplayName = Import(field.DisplayName);
output.Description = Import(field.Description);
output.Value = field.Value;
fields.Add(output);
}
enumDefinition.Fields = fields.ToArray();
}
definition = enumDefinition;
}
}
return definition;
}
/// <summary>
/// Imports a QualifiedName
/// </summary>
private Opc.Ua.QualifiedName ImportQualifiedName(string source, NamespaceTable namespaceUris)
{
if (String.IsNullOrEmpty(source))
{
return Opc.Ua.QualifiedName.Null;
}
Opc.Ua.QualifiedName qname = Opc.Ua.QualifiedName.Parse(source);
if (qname.NamespaceIndex > 0)
{
ushort namespaceIndex = ImportNamespaceIndex(qname.NamespaceIndex, namespaceUris);
qname = new Opc.Ua.QualifiedName(qname.Name, namespaceIndex);
}
return qname;
}
/// <summary>
/// Exports the array dimensions.
/// </summary>
private string Export(IList<uint> arrayDimensions)
{
if (arrayDimensions == null)
{
return String.Empty;
}
StringBuilder buffer = new StringBuilder();
for (int ii = 0; ii < arrayDimensions.Count; ii++)
{
if (buffer.Length > 0)
{
buffer.Append(',');
}
buffer.Append(arrayDimensions[ii]);
}
return buffer.ToString();
}
/// <summary>
/// Imports the array dimensions.
/// </summary>
private uint[] ImportArrayDimensions(string arrayDimensions)
{
if (String.IsNullOrEmpty(arrayDimensions))
{
return null;
}
string[] fields = arrayDimensions.Split(',');
uint[] dimensions = new uint[fields.Length];
for (int ii = 0; ii < fields.Length; ii++)
{
try
{
dimensions[ii] = Convert.ToUInt32(fields[ii]);
}
catch
{
dimensions[ii] = 0;
}
}
return dimensions;
}
/// <summary>
/// Exports localized text.
/// </summary>
private Opc.Ua.Export.LocalizedText[] Export(Opc.Ua.LocalizedText[] input)
{
if (input == null)
{
return null;
}
List<Opc.Ua.Export.LocalizedText> output = new List<LocalizedText>();
for (int ii = 0; ii < input.Length; ii++)
{
if (input[ii] != null)
{
Opc.Ua.Export.LocalizedText text = new LocalizedText();
text.Locale = input[ii].Locale;
text.Value = input[ii].Text;
output.Add(text);
}
}
return output.ToArray();
}
/// <summary>
/// Exports localized text.
/// </summary>
private Opc.Ua.Export.LocalizedText Export(Opc.Ua.LocalizedText input)
{
if (input == null)
{
return null;
}
Opc.Ua.Export.LocalizedText text = new LocalizedText();
text.Locale = input.Locale;
text.Value = input.Text;
return text;
}
/// <summary>
/// Imports localized text.
/// </summary>
private Opc.Ua.LocalizedText Import(params Opc.Ua.Export.LocalizedText[] input)
{
if (input == null)
{
return null;
}
for (int ii = 0; ii < input.Length; ii++)
{
if (input[ii] != null)
{
return new Opc.Ua.LocalizedText(input[ii].Locale, input[ii].Value);
}
}
return null;
}
/// <summary>
/// Exports a namespace index.
/// </summary>
private ushort ExportNamespaceIndex(ushort namespaceIndex, NamespaceTable namespaceUris)
{
// nothing special required for indexes 0.
if (namespaceIndex < 1)
{
return namespaceIndex;
}
// return a bad value if parameters are bad.
if (namespaceUris == null || namespaceUris.Count <= namespaceIndex)
{
return UInt16.MaxValue;
}
// find an existing index.
int count = 1;
string targetUri = namespaceUris.GetString(namespaceIndex);
if (this.NamespaceUris != null)
{
for (int ii = 0; ii < this.NamespaceUris.Length; ii++)
{
if (this.NamespaceUris[ii] == targetUri)
{
return (ushort)(ii+1); // add 1 to adjust for the well-known URIs which are not stored.
}
}
count += this.NamespaceUris.Length;
}
// add a new entry.
string[] uris = new string[count];
if (this.NamespaceUris != null)
{
Array.Copy(this.NamespaceUris, uris, count - 1);
}
uris[count-1] = targetUri;
this.NamespaceUris = uris;
// return the new index.
return (ushort)count;
}
/// <summary>
/// Exports a namespace index.
/// </summary>
private ushort ImportNamespaceIndex(ushort namespaceIndex, NamespaceTable namespaceUris)
{
// nothing special required for indexes 0 and 1.
if (namespaceIndex < 1)
{
return namespaceIndex;
}
// return a bad value if parameters are bad.
if (namespaceUris == null || this.NamespaceUris == null || this.NamespaceUris.Length <= namespaceIndex-1)
{
return UInt16.MaxValue;
}
// find or append uri.
return namespaceUris.GetIndexOrAppend(this.NamespaceUris[namespaceIndex-1]);
}
/// <summary>
/// Exports a namespace uri.
/// </summary>
private ushort ExportNamespaceUri(string namespaceUri, NamespaceTable namespaceUris)
{
// return a bad value if parameters are bad.
if (namespaceUris == null)
{
return UInt16.MaxValue;
}
int namespaceIndex = namespaceUris.GetIndex(namespaceUri);
// nothing special required for the first two URIs.
if (namespaceIndex == 0)
{
return (ushort)namespaceIndex;
}
// find an existing index.
int count = 1;;
if (this.NamespaceUris != null)
{
for (int ii = 0; ii < this.NamespaceUris.Length; ii++)
{
if (this.NamespaceUris[ii] == namespaceUri)
{
return (ushort)(ii + 1); // add 1 to adjust for the well-known URIs which are not stored.
}
}
count += this.NamespaceUris.Length;
}
// add a new entry.
string[] uris = new string[count];
if (this.NamespaceUris != null)
{
Array.Copy(this.NamespaceUris, uris, count - 1);
}
uris[count - 1] = namespaceUri;
this.NamespaceUris = uris;
// return the new index.
return (ushort)(count + 1);
}
/// <summary>
/// Exports a server index.
/// </summary>
private uint ExportServerIndex(uint serverIndex, StringTable serverUris)
{
// nothing special required for indexes 0.
if (serverIndex <= 0)
{
return serverIndex;
}
// return a bad value if parameters are bad.
if (serverUris == null || serverUris.Count < serverIndex)
{
return UInt16.MaxValue;
}
// find an existing index.
int count = 1;
string targetUri = serverUris.GetString(serverIndex);
if (this.ServerUris != null)
{
for (int ii = 0; ii < this.ServerUris.Length; ii++)
{
if (this.ServerUris[ii] == targetUri)
{
return (ushort)(ii + 1); // add 1 to adjust for the well-known URIs which are not stored.
}
}
count += this.ServerUris.Length;
}
// add a new entry.
string[] uris = new string[count];
if (this.ServerUris != null)
{
Array.Copy(this.ServerUris, uris, count - 1);
}
uris[count-1] = targetUri;
this.ServerUris = uris;
// return the new index.
return (ushort)count;
}
/// <summary>
/// Exports a server index.
/// </summary>
private uint ImportServerIndex(uint serverIndex, StringTable serverUris)
{
// nothing special required for indexes 0.
if (serverIndex <= 0)
{
return serverIndex;
}
// return a bad value if parameters are bad.
if (serverUris == null || this.ServerUris == null || this.ServerUris.Length <= serverIndex-1)
{
return UInt16.MaxValue;
}
// find or append uri.
return serverUris.GetIndexOrAppend(this.ServerUris[serverIndex - 1]);
}
#endregion
#region Private Fields
#endregion
}
}