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 const auto valueArray = array.valueArray();
119 for (const auto &entry : valueArray) {
120 if (!entry.canConvert<T>()) {
121 qCWarning(lcGenericStructHandler) << "Invalid type in multi dimensional array";
122 }
123 data.push_back(entry.value<T>());
124 }
125
126 const auto success = encoder.encodeArray<quint32>(src: array.arrayDimensions());
127
128 if (!success)
129 return false;
130
131 return encoder.encodeArray<T, OVERLAY>(data);
132 }
133
134 return valueRank == 1 ? encoder.encodeArray<T, OVERLAY>(value.value<QList<T>>()) : encoder.encode<T, OVERLAY>(value.value<T>());
135 }
136
137protected:
138 void handleInitializeFinished(bool success);
139 void processDataTypeRecursive(QOpcUaInternalDataTypeNode *node);
140 void processStructRecursive(QOpcUaInternalDataTypeNode *node);
141 void processEnumRecursive(QOpcUaInternalDataTypeNode *node);
142 void processSubtypeOfKnownTypeRecursive(QOpcUaInternalDataTypeNode *node, const QString &id);
143
144private:
145 QPointer<QOpcUaClient> m_client;
146 QScopedPointer<QOpcUaInternalDataTypeNode> m_baseDataType;
147
148 int m_finishedCount = 0;
149 bool m_hasError = false;
150
151 class StructMapEntry {
152 public:
153 QString name;
154 QString nodeId;
155 bool isAbstract = false;
156 QOpcUaStructureDefinition structureDefinition;
157 };
158
159 class EnumMapEntry {
160 public:
161 QString name;
162 QString nodeId;
163 bool isAbstract = false;
164 QOpcUaEnumDefinition enumDefinition;
165 };
166
167 QHash<QString, StructMapEntry> m_structuresByEncodingId;
168 QHash<QString, StructMapEntry> m_structuresByTypeId;
169 QHash<QString, EnumMapEntry> m_enumsByTypeId;
170 QHash<QString, QString> m_typeNamesByTypeId;
171 QHash<QString, QString> m_typeNamesByEncodingId;
172 QSet<QString> m_abstractTypeIds;
173
174 QHash<QString, QString> m_knownSubtypes;
175
176 const int m_maxNestingLevel = 500;
177
178 bool m_initialized = false;
179};
180
181QT_END_NAMESPACE
182
183#endif // QOPCUAGENERICSTRUCTHANDLERPRIVATE_H
184

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