summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJannis Voelker <jannis.voelker@basyskom.com>2018-08-09 16:53:56 +0200
committerJannis Völker <jannis.voelker@basyskom.com>2018-08-14 05:08:01 +0000
commitb5f002f872052f126e7a6798862f3db5f5ea5ad2 (patch)
treea33c516727a3cedac207fb59909c05b857f3d13b /src
parentfda85c90d9b90a42f48867aadc70d622a4b0cc75 (diff)
Allow omitting ns=0 in node ids
OPC UA part 6, 5.3.1.10 states that the ns= clause in the XML encoded node id shall be omitted if the namespace index is 0. The string node ids in Qt OPC UA use the XML notation defined in part 6, so skipping the ns=0 part should be allowed. Change-Id: I7e688ebe191d43aac3ca43b209c9797fbd5c3086 Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com>
Diffstat (limited to 'src')
-rw-r--r--src/opcua/client/qopcuatype.cpp53
-rw-r--r--src/opcua/client/qopcuatype.h1
-rw-r--r--src/plugins/opcua/uacpp/quacpputils.cpp50
3 files changed, 44 insertions, 60 deletions
diff --git a/src/opcua/client/qopcuatype.cpp b/src/opcua/client/qopcuatype.cpp
index dc838a4..30d1841 100644
--- a/src/opcua/client/qopcuatype.cpp
+++ b/src/opcua/client/qopcuatype.cpp
@@ -37,6 +37,7 @@
#include "qopcuatype.h"
#include <QMetaEnum>
+#include <QRegularExpression>
#include <QUuid>
QT_BEGIN_NAMESPACE
@@ -812,42 +813,56 @@ QString QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId referenceType)
Returns \c true if the node id could be split successfully.
For example, "ns=1;s=MyString" is split into 1, 's' and "MyString".
+ If no namespace index is given, ns=0 is assumed.
*/
bool QOpcUa::nodeIdStringSplit(const QString &nodeIdString, quint16 *nsIndex, QString *identifier, char *identifierType)
{
- QStringList components = nodeIdString.split(QLatin1String(";"));
- QStringList result;
+ quint16 namespaceIndex = 0;
- if (components.size() != 2)
- return false;
+ QStringList components = nodeIdString.split(QLatin1String(";"));
- if (components.at(0).contains(QRegExp(QLatin1String("/^ns=[0-9]+$/"))))
+ if (components.size() > 2)
return false;
- bool success = false;
- uint ns = components.at(0).midRef(3).toString().toUInt(&success);
- if (!success || ns > std::numeric_limits<quint16>::max())
- return false;
+ if (components.size() == 2 && components.at(0).contains(QRegularExpression(QLatin1String("^ns=[0-9]+")))) {
+ bool success = false;
+ uint ns = components.at(0).midRef(3).toString().toUInt(&success);
+ if (!success || ns > std::numeric_limits<quint16>::max())
+ return false;
+ namespaceIndex = ns;
+ }
- if (components.at(1).size() < 3)
+ if (components.last().size() < 3)
return false;
- if (!components.at(1).contains(QRegExp(QLatin1String("^[isgb]="))))
+ if (!components.last().contains(QRegularExpression(QLatin1String("^[isgb]="))))
return false;
if (nsIndex)
- *nsIndex = ns;
+ *nsIndex = namespaceIndex;
if (identifier)
- *identifier = components.at(1).midRef(2).toString();
+ *identifier = components.last().midRef(2).toString();
if (identifierType)
- *identifierType = components.at(1).at(0).toLatin1();
-
- result.append(components.at(1).midRef(2).toString());
+ *identifierType = components.last().at(0).toLatin1();
return true;
}
/*!
+ Returns \c true if the two node ids have the same namespace index and identifier.
+ A node id string without a namespace index is assumed to be in namespace 0.
+*/
+bool QOpcUa::nodeIdEquals(const QString &first, const QString &second)
+{
+ if (first.startsWith(QLatin1String("ns=0;")) && !second.startsWith(QLatin1String("ns=")))
+ return first.midRef(5) == second;
+ else if (second.startsWith(QLatin1String("ns=0;")) && !first.startsWith(QLatin1String("ns=")))
+ return second.midRef(5) == first;
+ else
+ return first == second;
+}
+
+/*!
Returns a node id string for the namespace 0 identifier \a id.
*/
QString QOpcUa::ns0ID(QOpcUa::NodeIds::NS0 id)
@@ -1716,7 +1731,7 @@ QOpcUa::QExpandedNodeId &QOpcUa::QExpandedNodeId::operator=(const QOpcUa::QExpan
bool QOpcUa::QExpandedNodeId::operator==(const QOpcUa::QExpandedNodeId &rhs) const
{
return data->namespaceUri == rhs.namespaceUri() &&
- data->nodeId == rhs.nodeId() &&
+ nodeIdEquals(data->nodeId, rhs.nodeId()) &&
data->serverIndex == rhs.serverIndex();
}
@@ -3495,7 +3510,7 @@ QOpcUa::QArgument &QOpcUa::QArgument::operator=(const QOpcUa::QArgument &rhs)
bool QOpcUa::QArgument::operator==(const QOpcUa::QArgument &other) const
{
return data->arrayDimensions == other.arrayDimensions() &&
- data->dataTypeId == other.dataTypeId() &&
+ nodeIdEquals(data->dataTypeId, other.dataTypeId()) &&
data->description == other.description() &&
data->name == other.name() &&
data->valueRank == other.valueRank();
@@ -3688,7 +3703,7 @@ QOpcUa::QExtensionObject &QOpcUa::QExtensionObject::operator=(const QOpcUa::QExt
bool QOpcUa::QExtensionObject::operator==(const QOpcUa::QExtensionObject &rhs) const
{
return data->encoding == rhs.encoding() &&
- data->encodingTypeId == rhs.encodingTypeId() &&
+ nodeIdEquals(data->encodingTypeId, rhs.encodingTypeId()) &&
data->encodedBody == rhs.encodedBody();
}
diff --git a/src/opcua/client/qopcuatype.h b/src/opcua/client/qopcuatype.h
index 3b372c2..bee0954 100644
--- a/src/opcua/client/qopcuatype.h
+++ b/src/opcua/client/qopcuatype.h
@@ -427,6 +427,7 @@ Q_OPCUA_EXPORT QString nodeIdFromInteger(quint16 ns, quint32 identifier);
Q_OPCUA_EXPORT QString nodeIdFromReferenceType(QOpcUa::ReferenceTypeId referenceType);
Q_OPCUA_EXPORT bool nodeIdStringSplit(const QString &nodeIdString, quint16 *nsIndex,
QString *identifier, char *identifierType);
+Q_OPCUA_EXPORT bool nodeIdEquals(const QString &first, const QString &second);
Q_OPCUA_EXPORT QString ns0ID(QOpcUa::NodeIds::NS0 id);
Q_OPCUA_EXPORT QOpcUa::NodeIds::NS0 ns0IDFromNodeId(const QString &nodeId);
Q_OPCUA_EXPORT QString ns0IDName(QOpcUa::NodeIds::NS0 id);
diff --git a/src/plugins/opcua/uacpp/quacpputils.cpp b/src/plugins/opcua/uacpp/quacpputils.cpp
index 940016d..4d5853e 100644
--- a/src/plugins/opcua/uacpp/quacpputils.cpp
+++ b/src/plugins/opcua/uacpp/quacpputils.cpp
@@ -21,6 +21,8 @@
#include "quacpputils.h"
+#include <QtOpcUa/qopcuatype.h>
+
#include <QtCore/QLoggingCategory>
#include <QtCore/QString>
#include <QtCore/QUuid>
@@ -36,50 +38,16 @@ namespace UACppUtils {
UaNodeId nodeIdFromQString(const QString &name)
{
- const int semicolonIndex = name.indexOf(';');
+ quint16 index = 0;
+ char identifierType = 0;
+ QString identifierString;
- if (semicolonIndex <= 0) {
+ bool success = QOpcUa::nodeIdStringSplit(name, &index, &identifierString, &identifierType);
+ if (!success) {
qCWarning(QT_OPCUA_PLUGINS_UACPP, "Unable to split node id string: %s", qUtf8Printable(name));
return UaNodeId();
}
- QStringRef namespaceString = name.leftRef(semicolonIndex);
- if (namespaceString.length() <= 3 || !namespaceString.startsWith(QLatin1String("ns="))) {
- qCWarning(QT_OPCUA_PLUGINS_UACPP, "Not a valid index string in node id string: %s", qUtf8Printable(name));
- return UaNodeId();
- }
- namespaceString = namespaceString.mid(3); // Remove "ns="
-
- QStringRef identifierString = name.midRef(semicolonIndex + 1);
-
- if (identifierString.length() <= 2) {
- qCWarning(QT_OPCUA_PLUGINS_UACPP, "There is no identifier in node id string: %s", qUtf8Printable(name));
- return UaNodeId();
- }
-
- char identifierType;
- if (identifierString.startsWith(QLatin1String("s=")))
- identifierType = 's';
- else if (identifierString.startsWith(QLatin1String("i=")))
- identifierType = 'i';
- else if (identifierString.startsWith(QLatin1String("g=")))
- identifierType = 'g';
- else if (identifierString.startsWith(QLatin1String("b=")))
- identifierType = 'b';
- else {
- qCWarning(QT_OPCUA_PLUGINS_UACPP, "There is no valid identifier type in node id string: %s", qUtf8Printable(name));
- return UaNodeId();
- }
- identifierString = identifierString.mid(2); // Remove identifier type
-
- bool ok = false;
- OpcUa_UInt16 index = static_cast<OpcUa_UInt16>(namespaceString.toUInt(&ok));
-
- if (!ok) {
- qCWarning(QT_OPCUA_PLUGINS_UACPP, "Not a valid namespace index in node id string: %s", qUtf8Printable(name));
- return UaNodeId();
- }
-
switch (identifierType) {
case 'i': {
bool isNumber;
@@ -98,7 +66,7 @@ UaNodeId nodeIdFromQString(const QString &name)
break;
}
case 'g': {
- QUuid uuid(identifierString.toString());
+ QUuid uuid(identifierString);
if (uuid.isNull()) {
qCWarning(QT_OPCUA_PLUGINS_UACPP, "%s does not contain a valid guid identifier", qUtf8Printable(name));
@@ -112,7 +80,7 @@ UaNodeId nodeIdFromQString(const QString &name)
return UaNodeId(guid, index);
}
case 'b': {
- QByteArray temp = QByteArray::fromBase64(identifierString.toLocal8Bit());
+ QByteArray temp = QByteArray::fromBase64(identifierString.toLatin1());
UaByteString bstr((OpcUa_Int32)temp.size(), reinterpret_cast<OpcUa_Byte *>(temp.data()));
if (temp.size() > 0) {
return UaNodeId(bstr, index);