1// Copyright (C) 2023 basysKom GmbH, opensource@basyskom.com
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtOpcUa/qopcuaenumdefinition.h>
5#include <QtOpcUa/qopcuagenericstructhandler.h>
6#include <QtOpcUa/qopcuaclient.h>
7#include <QtOpcUa/qopcuaextensionobject.h>
8#include <QtOpcUa/qopcuastructuredefinition.h>
9#include <QtOpcUa/qopcuabinarydataencoding.h>
10#include <QtOpcUa/qopcuamultidimensionalarray.h>
11
12#include <private/qobject_p.h>
13#include <QLoggingCategory>
14#include <QPointer>
15#include <QSet>
16
17//
18// W A R N I N G
19// -------------
20//
21// This file is not part of the Qt API. It exists purely as an
22// implementation detail. This header file may change from version to
23// version without notice, or even be removed.
24//
25// We mean it.
26//
27
28#ifndef QOPCUAGENERICSTRUCTHANDLERPRIVATE_H
29#define QOPCUAGENERICSTRUCTHANDLERPRIVATE_H
30
31QT_BEGIN_NAMESPACE
32
33Q_DECLARE_LOGGING_CATEGORY(lcGenericStructHandler);
34
35class QOpcUaInternalDataTypeNode;
36
37class QOpcUaGenericStructHandlerPrivate : public QObjectPrivate {
38 Q_DECLARE_PUBLIC(QOpcUaGenericStructHandler)
39
40 Q_DISABLE_COPY(QOpcUaGenericStructHandlerPrivate)
41public:
42 QOpcUaGenericStructHandlerPrivate(QOpcUaClient *client);
43
44 bool initialize();
45
46 QOpcUaGenericStructValue decode(const QOpcUaExtensionObject &extensionObject, bool &success) const;
47 bool encode(const QOpcUaGenericStructValue &value, QOpcUaExtensionObject &output);
48
49 QOpcUaGenericStructValue createGenericStructValueForTypeId(const QString &typeId);
50
51 QOpcUaStructureDefinition structureDefinitionForBinaryEncodingId(const QString &id) const;
52 QOpcUaStructureDefinition structureDefinitionForTypeId(const QString &id) const;
53 QOpcUaEnumDefinition enumDefinitionForTypeId(const QString &id) const;
54 QString typeNameForBinaryEncodingId(const QString &id) const;
55 QString typeNameForTypeId(const QString &id) const;
56 QOpcUaGenericStructHandler::DataTypeKind dataTypeKindForTypeId(const QString &id) const;
57 QString typeIdForBinaryEncodingId(const QString &id) const;
58 bool isAbstractTypeId(const QString &id) const;
59
60Q_SIGNALS:
61 void initializeFinished(bool success);
62
63protected:
64 QOpcUaGenericStructValue decodeStructInternal(QOpcUaBinaryDataEncoding &decoder, const QString &dataTypeId,
65 bool &success, int currentDepth) const;
66 QVariant decodeKnownTypesInternal(QOpcUaBinaryDataEncoding &decoder, const QString &dataTypeId, qint32 valueRank,
67 bool &success, int currentDepth) const;
68 bool encodeStructInternal(QOpcUaBinaryDataEncoding &encoder, const QOpcUaGenericStructValue &value);
69 bool encodeKnownTypesInternal(QOpcUaBinaryDataEncoding &encoder, const QVariant &value, qint32 valueRank, const QString &dataTypeId);
70 void handleFinished(bool success);
71
72 bool addCustomStructureDefinition(const QOpcUaStructureDefinition &definition, const QString &typeId, const QString &name,
73 QOpcUa::IsAbstract isAbstract);
74 bool addCustomEnumDefinition(const QOpcUaEnumDefinition &definition, const QString &typeId, const QString &name,
75 QOpcUa::IsAbstract isAbstract);
76
77 bool initialized() const;
78
79 template <typename T, QOpcUa::Types OVERLAY = QOpcUa::Types::Undefined>
80 QVariant decodeArrayOrScalar(QOpcUaBinaryDataEncoding &decoder, qint32 valueRank, bool &success) const
81 {
82 if (valueRank > 1) {
83 const auto arrayDimensions = decoder.decodeArray<quint32>(success);
84
85 if (!success)
86 return QVariant();
87
88 const auto data = decoder.decodeArray<T, OVERLAY>(success);
89
90 if (!success)
91 return QVariant();
92
93 QOpcUaMultiDimensionalArray matrix;
94 matrix.setArrayDimensions(arrayDimensions);
95 matrix.setValueArray({data.constBegin(), data.constEnd()});
96 return matrix;
97 }
98
99 return valueRank == 1 ? QVariant::fromValue(decoder.decodeArray<T, OVERLAY>(success)) : decoder.decode<T, OVERLAY>(success);
100 }
101
102 template <typename T, QOpcUa::Types OVERLAY = QOpcUa::Types::Undefined>
103 bool encodeArrayOrScalar(QOpcUaBinaryDataEncoding &encoder, qint32 valueRank, const QVariant &value)
104 {
105 if ((valueRank == 1 && !value.canConvert<QList<T>>()) || (valueRank <= 0 && !value.canConvert<T>())) {
106 qCWarning(lcGenericStructHandler) << "Type mismatch for enum field, unable to encode";
107 return false;
108 }
109
110 if (valueRank > 1) {
111 if (!value.canConvert<QOpcUaMultiDimensionalArray>()) {
112 qCWarning(lcGenericStructHandler) << "Type mismatch for enum field, value rank > 1 requires QOpcUaMultiDimensionalArray";
113 return false;
114 }
115
116 auto array = value.value<QOpcUaMultiDimensionalArray>();
117 QList<T> data;
118 for (const auto &entry : array.valueArray()) {
119 if (!entry.canConvert<T>()) {
120 qCWarning(lcGenericStructHandler) << "Invalid type in multi dimensional array";
121 }
122 data.push_back(entry.value<T>());
123 }
124
125 const auto success = encoder.encodeArray<quint32>(src: array.arrayDimensions());
126
127 if (!success)
128 return false;
129
130 return encoder.encodeArray<T, OVERLAY>(data);
131 }
132
133 return valueRank == 1 ? encoder.encodeArray<T, OVERLAY>(value.value<QList<T>>()) : encoder.encode<T, OVERLAY>(value.value<T>());
134 }
135
136protected:
137 void handleInitializeFinished(bool success);
138 void processDataTypeRecursive(QOpcUaInternalDataTypeNode *node);
139 void processStructRecursive(QOpcUaInternalDataTypeNode *node);
140 void processEnumRecursive(QOpcUaInternalDataTypeNode *node);
141 void processSubtypeOfKnownTypeRecursive(QOpcUaInternalDataTypeNode *node, const QString &id);
142
143private:
144 QPointer<QOpcUaClient> m_client;
145 QScopedPointer<QOpcUaInternalDataTypeNode> m_baseDataType;
146
147 int m_finishedCount = 0;
148 bool m_hasError = false;
149
150 class StructMapEntry {
151 public:
152 QString name;
153 QString nodeId;
154 bool isAbstract = false;
155 QOpcUaStructureDefinition structureDefinition;
156 };
157
158 class EnumMapEntry {
159 public:
160 QString name;
161 QString nodeId;
162 bool isAbstract = false;
163 QOpcUaEnumDefinition enumDefinition;
164 };
165
166 QHash<QString, StructMapEntry> m_structuresByEncodingId;
167 QHash<QString, StructMapEntry> m_structuresByTypeId;
168 QHash<QString, EnumMapEntry> m_enumsByTypeId;
169 QHash<QString, QString> m_typeNamesByTypeId;
170 QHash<QString, QString> m_typeNamesByEncodingId;
171 QSet<QString> m_abstractTypeIds;
172
173 QHash<QString, QString> m_knownSubtypes;
174
175 const int m_maxNestingLevel = 500;
176
177 bool m_initialized = false;
178};
179
180QT_END_NAMESPACE
181
182#endif // QOPCUAGENERICSTRUCTHANDLERPRIVATE_H
183

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtopcua/src/opcua/client/qopcuagenericstructhandler_p.h