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 "private/qopcuagenericstructhandler_p.h"
5
6#include <QtOpcUa/qopcuaargument.h>
7#include <QtOpcUa/qopcuaaxisinformation.h>
8#include <QtOpcUa/qopcuabinarydataencoding.h>
9#include <QtOpcUa/qopcuacomplexnumber.h>
10#include <QtOpcUa/qopcuadatavalue.h>
11#include <QtOpcUa/qopcuadiagnosticinfo.h>
12#include <QtOpcUa/qopcuadoublecomplexnumber.h>
13#include <QtOpcUa/qopcuaenumfield.h>
14#include <QtOpcUa/qopcuaeuinformation.h>
15#include <QtOpcUa/qopcuagenericstructhandler.h>
16#include <QtOpcUa/qopcuagenericstructvalue.h>
17#include <QtOpcUa/qopcuarange.h>
18#include <QtOpcUa/qopcuastructurefield.h>
19#include <QtOpcUa/qopcuaxvalue.h>
20
21#include "qopcuainternaldatatypenode_p.h"
22
23#include <QtCore/quuid.h>
24
25QT_BEGIN_NAMESPACE
26
27Q_LOGGING_CATEGORY(lcGenericStructHandler, "qt.opcuagenericstructhandler")
28
29QOpcUaGenericStructHandlerPrivate::QOpcUaGenericStructHandlerPrivate(QOpcUaClient *client)
30 : m_client(client)
31{
32}
33
34bool QOpcUaGenericStructHandlerPrivate::initialize()
35{
36 if (!m_client)
37 return false;
38
39 m_initialized = false;
40
41 m_baseDataType.reset(other: new QOpcUaInternalDataTypeNode(m_client));
42
43 QObjectPrivate::connect(sender: m_baseDataType.get(), signal: &QOpcUaInternalDataTypeNode::initializeFinished,
44 receiverPrivate: this, slot: &QOpcUaGenericStructHandlerPrivate::handleInitializeFinished);
45
46 return m_baseDataType->initialize(nodeId: QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::BaseDataType));
47}
48
49QOpcUaGenericStructValue QOpcUaGenericStructHandlerPrivate::decode(const QOpcUaExtensionObject &extensionObject, bool &success) const
50{
51 const auto entry = m_structuresByEncodingId.constFind(key: extensionObject.encodingTypeId());
52 if (entry == m_structuresByEncodingId.constEnd()) {
53 qCWarning(lcGenericStructHandler) << "Failed to find description for" << extensionObject.encodingTypeId();
54 success = false;
55 return QOpcUaGenericStructValue();
56 }
57
58 qCDebug(lcGenericStructHandler) << "Decoding" << entry->name << entry.key();
59
60 auto data = extensionObject.encodedBody();
61 QOpcUaBinaryDataEncoding decoder(&data);
62
63 return decodeStructInternal(decoder, dataTypeId: entry->nodeId, success, currentDepth: 0);
64}
65
66bool QOpcUaGenericStructHandlerPrivate::encode(const QOpcUaGenericStructValue &value, QOpcUaExtensionObject &output)
67{
68 if (value.structureDefinition().fields().empty()) {
69 qCWarning(lcGenericStructHandler) << "The structure doesn't have any fields, unable to encode";
70 return false;
71 }
72
73 if (value.structureDefinition().defaultEncodingId().isEmpty()) {
74 qCWarning(lcGenericStructHandler) << "The struct doesn't have an encoding ID, unable to encode";
75 return false;
76 }
77
78 output.setEncodingTypeId(value.structureDefinition().defaultEncodingId());
79 output.setEncoding(QOpcUaExtensionObject::Encoding::ByteString);
80
81 QOpcUaBinaryDataEncoding encoder(output);
82 return encodeStructInternal(encoder, value);
83}
84
85QOpcUaGenericStructValue QOpcUaGenericStructHandlerPrivate::createGenericStructValueForTypeId(const QString &typeId)
86{
87 const auto entry = m_structuresByTypeId.constFind(key: typeId);
88
89 if (entry != m_structuresByTypeId.constEnd()) {
90 QOpcUaGenericStructValue value(entry.value().name, typeId, entry.value().structureDefinition);
91
92 if (entry.value().structureDefinition.structureType() != QOpcUaStructureDefinition::StructureType::Union) {
93 for (const auto &field : entry.value().structureDefinition.fields()) {
94 if (field.isOptional())
95 continue;
96
97 value.fieldsRef().insert(key: field.name(), value: QVariant());
98 }
99 }
100
101 return value;
102 }
103
104 qCWarning(lcGenericStructHandler) << "Unable to create a pre-filled generic struct value for" << typeId;
105 return {};
106}
107
108QOpcUaStructureDefinition QOpcUaGenericStructHandlerPrivate::structureDefinitionForBinaryEncodingId(const QString &id) const
109{
110 const auto entry = m_structuresByEncodingId.constFind(key: id);
111 return entry != m_structuresByEncodingId.constEnd() ? entry.value().structureDefinition : QOpcUaStructureDefinition();
112}
113
114QOpcUaStructureDefinition QOpcUaGenericStructHandlerPrivate::structureDefinitionForTypeId(const QString &id) const
115{
116 const auto entry = m_structuresByTypeId.constFind(key: id);
117 return entry != m_structuresByTypeId.constEnd() ? entry.value().structureDefinition : QOpcUaStructureDefinition();
118}
119
120QOpcUaEnumDefinition QOpcUaGenericStructHandlerPrivate::enumDefinitionForTypeId(const QString &id) const
121{
122 const auto entry = m_enumsByTypeId.constFind(key: id);
123 return entry != m_enumsByTypeId.constEnd() ? entry.value().enumDefinition : QOpcUaEnumDefinition();
124}
125
126QString QOpcUaGenericStructHandlerPrivate::typeNameForBinaryEncodingId(const QString &id) const
127{
128 const auto entry = m_typeNamesByEncodingId.constFind(key: id);
129 return entry != m_typeNamesByEncodingId.constEnd() ? entry.value() : QString();
130}
131
132QString QOpcUaGenericStructHandlerPrivate::typeNameForTypeId(const QString &id) const
133{
134 const auto entry = m_typeNamesByTypeId.constFind(key: id);
135 return entry != m_typeNamesByTypeId.constEnd() ? entry.value() : QString();
136}
137
138QOpcUaGenericStructHandler::DataTypeKind QOpcUaGenericStructHandlerPrivate::dataTypeKindForTypeId(const QString &id) const
139{
140 const auto isStruct = m_structuresByTypeId.constFind(key: id);
141 if (isStruct != m_structuresByTypeId.constEnd())
142 return QOpcUaGenericStructHandler::DataTypeKind::Struct;
143
144 const auto isEnum = m_enumsByTypeId.constFind(key: id);
145 if (isEnum != m_enumsByTypeId.constEnd())
146 return QOpcUaGenericStructHandler::DataTypeKind::Enum;
147
148 return typeNameForTypeId(id).isEmpty() ?
149 QOpcUaGenericStructHandler::DataTypeKind::Unknown : QOpcUaGenericStructHandler::DataTypeKind::Other;
150}
151
152QString QOpcUaGenericStructHandlerPrivate::typeIdForBinaryEncodingId(const QString &id) const
153{
154 const auto entry = m_structuresByEncodingId.constFind(key: id);
155 return entry != m_structuresByEncodingId.constEnd() ? entry->nodeId : QString();
156}
157
158bool QOpcUaGenericStructHandlerPrivate::isAbstractTypeId(const QString &id) const
159{
160 return m_abstractTypeIds.contains(value: id);
161}
162
163QOpcUaGenericStructValue QOpcUaGenericStructHandlerPrivate::decodeStructInternal(QOpcUaBinaryDataEncoding &decoder,
164 const QString &dataTypeId, bool &success,
165 int currentDepth) const
166{
167 if (currentDepth > m_maxNestingLevel) {
168 qCWarning(lcGenericStructHandler) << "Maximum nesting level of" << m_maxNestingLevel << "exceeded";
169 success = false;
170 return QOpcUaGenericStructValue();
171 }
172
173 const auto entry = m_structuresByTypeId.constFind(key: dataTypeId);
174 if (entry == m_structuresByTypeId.constEnd()) {
175 qCWarning(lcGenericStructHandler) << "Failed to find description for" << dataTypeId;
176 success = false;
177 return QOpcUaGenericStructValue();
178 }
179
180 if (entry->isAbstract) {
181 qCWarning(lcGenericStructHandler) << "Decoding of abstract struct" << entry->name << "requested";
182 success = false;
183 return QOpcUaGenericStructValue();
184 }
185
186 if (entry->structureDefinition.fields().isEmpty()) {
187 qCWarning(lcGenericStructHandler) << "Missing fields information for struct" << entry->name;
188 success = false;
189 return QOpcUaGenericStructValue();
190 }
191
192 QOpcUaGenericStructValue result(entry->name, entry->nodeId, entry->structureDefinition);
193 auto &fields = result.fieldsRef();
194
195 if (entry->structureDefinition.structureType() == QOpcUaStructureDefinition::StructureType::Structure) {
196 for (const auto &field : entry->structureDefinition.fields()) {
197 fields[field.name()] = decodeKnownTypesInternal(decoder, dataTypeId: field.dataType(), valueRank: field.valueRank(), success, currentDepth: currentDepth + 1);
198 if (!success) {
199 qCWarning(lcGenericStructHandler) << "Failed to decode struct field";
200 return QOpcUaGenericStructValue();
201 }
202 }
203 } else if (entry->structureDefinition.structureType() == QOpcUaStructureDefinition::StructureType::Union) {
204 auto switchField = decoder.decode<quint32>(success);
205 if (!success) {
206 qCWarning(lcGenericStructHandler) << "Failed to decode the union switch field";
207 return QOpcUaGenericStructValue();
208 }
209
210 if (!switchField)
211 return result; // Empty union, no need to continue processing
212
213 if (switchField > static_cast<quint32>(entry->structureDefinition.fields().size())) {
214 qCWarning(lcGenericStructHandler) << "Union switch field out of bounds";
215 success = false;
216 return QOpcUaGenericStructValue();
217 }
218
219 qCDebug(lcGenericStructHandler) << "Decode union field with switch value" << switchField;
220
221 auto field = entry->structureDefinition.fields().at(i: switchField - 1);
222
223 fields[field.name()] = decodeKnownTypesInternal(decoder, dataTypeId: field.dataType(), valueRank: field.valueRank() > 0, success, currentDepth: currentDepth + 1);
224 if (!success) {
225 qCWarning(lcGenericStructHandler) << "Failed to decode union content";
226 return QOpcUaGenericStructValue();
227 }
228 } else if (entry->structureDefinition.structureType() == QOpcUaStructureDefinition::StructureType::StructureWithOptionalFields) {
229 auto mask = decoder.decode<quint32>(success);
230 if (!success) {
231 qCWarning(lcGenericStructHandler) << "Failed to decode the optional fields mask";
232 return QOpcUaGenericStructValue();
233 }
234
235 int optionalFieldIndex = 0;
236 for (const auto &field : entry->structureDefinition.fields()) {
237 if (field.isOptional() && !(mask & (1 << optionalFieldIndex++)))
238 continue;
239
240 fields[field.name()] = decodeKnownTypesInternal(decoder, dataTypeId: field.dataType(), valueRank: field.valueRank() > 0, success, currentDepth: currentDepth + 1);
241 if (!success) {
242 qCWarning(lcGenericStructHandler) << "Failed to decode struct field";
243 return QOpcUaGenericStructValue();
244 }
245 }
246 }
247
248 return result;
249}
250
251QVariant QOpcUaGenericStructHandlerPrivate::decodeKnownTypesInternal(QOpcUaBinaryDataEncoding &decoder, const QString &dataTypeId,
252 qint32 valueRank, bool &success, int currentDepth) const
253{
254 if (currentDepth > m_maxNestingLevel) {
255 qCWarning(lcGenericStructHandler) << "Maximum nesting level of" << m_maxNestingLevel << "exceeded";
256 success = false;
257 return QOpcUaGenericStructValue();
258 }
259
260 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Boolean))
261 return decodeArrayOrScalar<bool>(decoder, valueRank, success);
262
263 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Byte))
264 return decodeArrayOrScalar<quint8>(decoder, valueRank, success);
265
266 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::SByte))
267 return decodeArrayOrScalar<qint8>(decoder, valueRank, success);
268
269 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::UInt16))
270 return decodeArrayOrScalar<quint16>(decoder, valueRank, success);
271
272 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Int16))
273 return decodeArrayOrScalar<qint16>(decoder, valueRank, success);
274
275 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::UInt32))
276 return decodeArrayOrScalar<quint32>(decoder, valueRank, success);
277
278 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Int32))
279 return decodeArrayOrScalar<qint32>(decoder, valueRank, success);
280
281 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::UInt64))
282 return decodeArrayOrScalar<quint64>(decoder, valueRank, success);
283
284 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Int64))
285 return decodeArrayOrScalar<qint64>(decoder, valueRank, success);
286
287 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Float))
288 return decodeArrayOrScalar<float>(decoder, valueRank, success);
289
290 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Double))
291 return decodeArrayOrScalar<double>(decoder, valueRank, success);
292
293 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::StatusCode))
294 return decodeArrayOrScalar<QOpcUa::UaStatusCode>(decoder, valueRank, success);
295
296 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::DateTime))
297 return decodeArrayOrScalar<QDateTime>(decoder, valueRank, success);
298
299 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::String))
300 return decodeArrayOrScalar<QString>(decoder, valueRank, success);
301
302 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::NodeId))
303 return decodeArrayOrScalar<QString, QOpcUa::Types::NodeId>(decoder, valueRank, success);
304
305 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::ByteString))
306 return decodeArrayOrScalar<QByteArray>(decoder, valueRank, success);
307
308 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::XmlElement))
309 return decodeArrayOrScalar<QByteArray>(decoder, valueRank, success);
310
311 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Guid))
312 return decodeArrayOrScalar<QUuid>(decoder, valueRank, success);
313
314 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::QualifiedName))
315 return decodeArrayOrScalar<QOpcUaQualifiedName>(decoder, valueRank, success);
316
317 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::LocalizedText))
318 return decodeArrayOrScalar<QOpcUaLocalizedText>(decoder, valueRank, success);
319
320 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Range))
321 return decodeArrayOrScalar<QOpcUaRange>(decoder, valueRank, success);
322
323 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::EUInformation))
324 return decodeArrayOrScalar<QOpcUaEUInformation>(decoder, valueRank, success);
325
326 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::ComplexNumberType))
327 return decodeArrayOrScalar<QOpcUaComplexNumber>(decoder, valueRank, success);
328
329 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::DoubleComplexNumberType))
330 return decodeArrayOrScalar<QOpcUaDoubleComplexNumber>(decoder, valueRank, success);
331
332 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::AxisInformation))
333 return decodeArrayOrScalar<QOpcUaAxisInformation>(decoder, valueRank, success);
334
335 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::XVType))
336 return decodeArrayOrScalar<QOpcUaXValue>(decoder, valueRank, success);
337
338 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::ExpandedNodeId))
339 return decodeArrayOrScalar<QOpcUaExpandedNodeId>(decoder, valueRank, success);
340
341 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Argument))
342 return decodeArrayOrScalar<QOpcUaArgument>(decoder, valueRank, success);
343
344 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::StructureDefinition))
345 return decodeArrayOrScalar<QOpcUaStructureDefinition>(decoder, valueRank, success);
346
347 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::StructureField))
348 return decodeArrayOrScalar<QOpcUaStructureField>(decoder, valueRank, success);
349
350 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::EnumDefinition))
351 return decodeArrayOrScalar<QOpcUaEnumDefinition>(decoder, valueRank, success);
352
353 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::EnumField))
354 return decodeArrayOrScalar<QOpcUaEnumField>(decoder, valueRank, success);
355
356 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::DiagnosticInfo)) {
357 return decodeArrayOrScalar<QOpcUaDiagnosticInfo>(decoder, valueRank, success);
358 }
359
360 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::DataValue))
361 return decodeArrayOrScalar<QOpcUaDataValue>(decoder, valueRank, success);
362
363 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::BaseDataType))
364 return decodeArrayOrScalar<QOpcUaVariant>(decoder, valueRank, success);
365
366 // Enumeration
367 const auto enumType = m_enumsByTypeId.constFind(key: dataTypeId);
368 if (enumType != m_enumsByTypeId.constEnd()) {
369 if (enumType->isAbstract) {
370 qCWarning(lcGenericStructHandler) << "Decoding abstract enum" << enumType->name << "requested";
371 success = false;
372 return QVariant();
373 }
374
375 const auto enumValue = decodeArrayOrScalar<qint32>(decoder, valueRank, success);
376 if (!success) {
377 qCWarning(lcGenericStructHandler) << "Failed to decode enum";
378 return QVariant();
379 }
380 return enumValue;
381 }
382
383 // Fallback for nested unknown structs
384 if (valueRank > 0) {
385 QList<quint32> arrayDimensions;
386 if (valueRank > 1) {
387 arrayDimensions = decoder.decodeArray<quint32>(success);
388
389 if (!success)
390 return QVariant();
391 }
392
393 const auto arrayLength = decoder.decode<qint32>(success);
394 if (!success)
395 return QVariant();
396
397 QList<QOpcUaGenericStructValue> result;
398 for (int i = 0; i < arrayLength; ++i) {
399 result.append(t: decodeStructInternal(decoder, dataTypeId, success, currentDepth: currentDepth + 1));
400 if (!success) {
401 qCWarning(lcGenericStructHandler) << "Failed to decode nested struct array";
402 return QVariant();
403 }
404 }
405
406 if (!arrayDimensions.isEmpty()) {
407 QVariantList data(result.constBegin(), result.constEnd());
408 return QOpcUaMultiDimensionalArray(data, arrayDimensions);
409 }
410
411 return QVariant::fromValue(value: result);
412 } else {
413 const auto result = decodeStructInternal(decoder, dataTypeId, success, currentDepth: currentDepth + 1);
414 if (!success) {
415 qCWarning(lcGenericStructHandler) << "Failed to decode nested struct";
416 return QVariant();
417 }
418 return result;
419 }
420
421 const auto superType = m_knownSubtypes.constFind(key: dataTypeId);
422 if (superType != m_knownSubtypes.constEnd())
423 return decodeKnownTypesInternal(decoder, dataTypeId: superType.value(), valueRank, success, currentDepth: currentDepth + 1);
424
425 success = false;
426 return QVariant();
427}
428
429bool QOpcUaGenericStructHandlerPrivate::encodeStructInternal(QOpcUaBinaryDataEncoding &encoder, const QOpcUaGenericStructValue &value)
430{
431 const auto entry = m_structuresByTypeId.constFind(key: value.typeId());
432
433 if (entry == m_structuresByTypeId.constEnd()) {
434 qCWarning(lcGenericStructHandler) << "Failed to find description for" << value.typeId();
435 return false;
436 }
437
438 if (entry->isAbstract) {
439 qCWarning(lcGenericStructHandler) << "Decoding of abstract struct" << entry->name << "requested";
440 return false;
441 }
442
443 if (entry->structureDefinition.fields().isEmpty()) {
444 qCWarning(lcGenericStructHandler) << "Missing fields information for struct" << entry->name;
445 return false;
446 }
447
448 if (value.structureDefinition().structureType() == QOpcUaStructureDefinition::StructureType::Structure) {
449 for (const auto &field : value.structureDefinition().fields()) {
450 if (!value.fields().contains(key: field.name())) {
451 qCWarning(lcGenericStructHandler) << "Field" << field.name() << "is missing, unable to encode struct";
452 return false;
453 }
454 const auto success = encodeKnownTypesInternal(encoder, value: value.fields().value(key: field.name()), valueRank: field.valueRank(), dataTypeId: field.dataType());
455 if (!success) {
456 qCWarning(lcGenericStructHandler) << "Failed to encode struct field" << field.name();
457 return false;
458 }
459 }
460
461 return true;
462 } else if (value.structureDefinition().structureType() == QOpcUaStructureDefinition::StructureType::StructureWithOptionalFields) {
463 quint32 mask = 0;
464 quint32 index = 0;
465 for (const auto &field : value.structureDefinition().fields()) {
466 if (!field.isOptional())
467 continue;
468
469 if (value.fields().contains(key: field.name()))
470 mask |= (1 << index);
471
472 ++index;
473 }
474
475 auto success = encoder.encode<quint32>(src: mask);
476
477 if (!success) {
478 qCWarning(lcGenericStructHandler) << "Failed to encode optional fields mask";
479 return false;
480 }
481
482 for (const auto &field : value.structureDefinition().fields()) {
483 if (!field.isOptional() && !value.fields().contains(key: field.name())) {
484 qCWarning(lcGenericStructHandler) << "Field" << field.name() << "is missing, unable to encode struct";
485 return false;
486 }
487
488 if (value.fields().contains(key: field.name())) {
489 const auto success = encodeKnownTypesInternal(encoder, value: value.fields().value(key: field.name()), valueRank: field.valueRank(), dataTypeId: field.dataType());
490 if (!success) {
491 qCWarning(lcGenericStructHandler) << "Failed to encode struct field" << field.name();
492 return false;
493 }
494 }
495 }
496
497 return true;
498 } else if (value.structureDefinition().structureType() == QOpcUaStructureDefinition::StructureType::Union) {
499 if (value.fields().size() > 1) {
500 qCWarning(lcGenericStructHandler) << "Multiple union fields were specified, unable to encode";
501 return false;
502 }
503
504 if (value.fields().size() > 0) {
505 for (int i = 0; i < value.structureDefinition().fields().size(); ++i) {
506 if (value.structureDefinition().fields().at(i).name() == value.fields().keys().first()) {
507 const auto success = encoder.encode<quint32>(src: 1 << i);
508
509 if (!success) {
510 qCWarning(lcGenericStructHandler) << "Failed to encode union mask";
511 return false;
512 }
513
514 return encodeKnownTypesInternal(encoder, value: value.fields().constKeyValueBegin()->second,
515 valueRank: value.structureDefinition().fields().at(i).valueRank(),
516 dataTypeId: value.structureDefinition().fields().at(i).dataType());
517 }
518 }
519
520 qCWarning(lcGenericStructHandler) << "Unknown union field" << value.fields().keys().first();
521 return false;
522 } else {
523 // An empty union consists only of the mask
524 return encoder.encode<quint32>(src: 0);
525 }
526 } else {
527 qCWarning(lcGenericStructHandler) << "Encoding failed, unknown struct type encountered";
528 return false;
529 }
530
531 return false;
532}
533
534bool QOpcUaGenericStructHandlerPrivate::encodeKnownTypesInternal(QOpcUaBinaryDataEncoding &encoder, const QVariant &value,
535 qint32 valueRank, const QString &dataTypeId)
536{
537 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Boolean))
538 return encodeArrayOrScalar<bool>(encoder, valueRank, value);
539
540 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Byte))
541 return encodeArrayOrScalar<quint8>(encoder, valueRank, value);
542
543 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::SByte))
544 return encodeArrayOrScalar<qint8>(encoder, valueRank, value);
545
546 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::UInt16))
547 return encodeArrayOrScalar<quint16>(encoder, valueRank, value);
548
549 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Int16))
550 return encodeArrayOrScalar<qint16>(encoder, valueRank, value);
551
552 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::UInt32))
553 return encodeArrayOrScalar<quint32>(encoder, valueRank, value);
554
555 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Int32))
556 return encodeArrayOrScalar<qint32>(encoder, valueRank, value);
557
558 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::UInt64))
559 return encodeArrayOrScalar<quint64>(encoder, valueRank, value);
560
561 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Int64))
562 return encodeArrayOrScalar<qint64>(encoder, valueRank, value);
563
564 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Float))
565 return encodeArrayOrScalar<float>(encoder, valueRank, value);
566
567 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Double))
568 return encodeArrayOrScalar<double>(encoder, valueRank, value);
569
570 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::StatusCode))
571 return encodeArrayOrScalar<QOpcUa::UaStatusCode>(encoder, valueRank, value);
572
573 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::DateTime))
574 return encodeArrayOrScalar<QDateTime>(encoder, valueRank, value);
575
576 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::String))
577 return encodeArrayOrScalar<QString>(encoder, valueRank, value);
578
579 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::NodeId))
580 return encodeArrayOrScalar<QString, QOpcUa::Types::NodeId>(encoder, valueRank, value);
581
582 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::ByteString))
583 return encodeArrayOrScalar<QByteArray>(encoder, valueRank, value);
584
585 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::XmlElement))
586 return encodeArrayOrScalar<QByteArray>(encoder, valueRank, value);
587
588 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Guid))
589 return encodeArrayOrScalar<QUuid>(encoder, valueRank, value);
590
591 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::QualifiedName))
592 return encodeArrayOrScalar<QOpcUaQualifiedName>(encoder, valueRank, value);
593
594 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::LocalizedText))
595 return encodeArrayOrScalar<QOpcUaLocalizedText>(encoder, valueRank, value);
596
597 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Range))
598 return encodeArrayOrScalar<QOpcUaRange>(encoder, valueRank, value);
599
600 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::EUInformation))
601 return encodeArrayOrScalar<QOpcUaEUInformation>(encoder, valueRank, value);
602
603 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::ComplexNumberType))
604 return encodeArrayOrScalar<QOpcUaComplexNumber>(encoder, valueRank, value);
605
606 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::DoubleComplexNumberType))
607 return encodeArrayOrScalar<QOpcUaDoubleComplexNumber>(encoder, valueRank, value);
608
609 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::AxisInformation))
610 return encodeArrayOrScalar<QOpcUaAxisInformation>(encoder, valueRank, value);
611
612 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::XVType))
613 return encodeArrayOrScalar<QOpcUaXValue>(encoder, valueRank, value);
614
615 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::ExpandedNodeId))
616 return encodeArrayOrScalar<QOpcUaExpandedNodeId>(encoder, valueRank, value);
617
618 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Argument))
619 return encodeArrayOrScalar<QOpcUaArgument>(encoder, valueRank, value);
620
621 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::StructureDefinition))
622 return encodeArrayOrScalar<QOpcUaStructureDefinition>(encoder, valueRank, value);
623
624 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::StructureField))
625 return encodeArrayOrScalar<QOpcUaStructureField>(encoder, valueRank, value);
626
627 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::EnumDefinition))
628 return encodeArrayOrScalar<QOpcUaEnumDefinition>(encoder, valueRank, value);
629
630 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::EnumField))
631 return encodeArrayOrScalar<QOpcUaEnumField>(encoder, valueRank, value);
632
633 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::DiagnosticInfo)) {
634 return encodeArrayOrScalar<QOpcUaDiagnosticInfo>(encoder, valueRank, value);
635 }
636
637 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::DataValue))
638 return encodeArrayOrScalar<QOpcUaDataValue>(encoder, valueRank, value);
639
640 if (dataTypeId == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::BaseDataType))
641 return encodeArrayOrScalar<QOpcUaVariant>(encoder, valueRank, value);
642
643 const auto enumType = m_enumsByTypeId.constFind(key: dataTypeId);
644 if (enumType != m_enumsByTypeId.constEnd()) {
645 if (enumType->isAbstract) {
646 qCWarning(lcGenericStructHandler) << "Encoding abstract enum" << enumType->name << "requested";
647 return false;
648 }
649
650 return encodeArrayOrScalar<qint32>(encoder, valueRank, value);
651 }
652
653 if (dataTypeKindForTypeId(id: dataTypeId) == QOpcUaGenericStructHandler::DataTypeKind::Struct) {
654 if (valueRank == -1) {
655 if (!value.canConvert<QOpcUaGenericStructValue>()) {
656 qCWarning(lcGenericStructHandler) << "Struct value expected for member, unable to encode";
657 return false;
658 }
659
660 const auto genericStruct = value.value<QOpcUaGenericStructValue>();
661
662 if (genericStruct.typeId() != dataTypeId) {
663 qCWarning(lcGenericStructHandler) << "Type mismatch for nested struct value, unable to encode";
664 return false;
665 }
666
667 return encodeStructInternal(encoder, value: genericStruct);
668 } else if (valueRank == 1) {
669 if (!value.canConvert<QList<QOpcUaGenericStructValue>>()) {
670 qCWarning(lcGenericStructHandler) << "Struct list value expected for member, unable to encode";
671 return false;
672 }
673
674 const auto data = value.value<QList<QOpcUaGenericStructValue>>();
675
676 auto success = encoder.encode<qint32>(src: data.size());
677
678 if (!success) {
679 qCWarning(lcGenericStructHandler) << "Failed to encode array length";
680 return false;
681 }
682
683 for (const auto &entry : data) {
684 success = encodeStructInternal(encoder, value: entry);
685
686 if (!success) {
687 qCWarning(lcGenericStructHandler) << "Failed to encode struct into the array";
688 return false;
689 }
690 }
691
692 return true;
693 } else if (valueRank > 1) {
694 if (!value.canConvert<QOpcUaMultiDimensionalArray>()) {
695 qCWarning(lcGenericStructHandler) << "QOpcUaMultiDimensionalArray value expected for member, unable to encode";
696 return false;
697 }
698
699 const auto array = value.value<QOpcUaMultiDimensionalArray>();
700
701 for (const auto &entry : array.valueArray()) {
702 if (!entry.canConvert<QOpcUaGenericStructValue>()) {
703 qCWarning(lcGenericStructHandler) << "QOpcUaMultiDimensionalArray value is expected to contain"
704 << "a generic struct, unable to encode";
705 return false;
706 }
707 }
708
709 auto success = encoder.encodeArray<quint32>(src: array.arrayDimensions());
710
711 if (!success) {
712 qCWarning(lcGenericStructHandler) << "Failed to encode array dimensions";
713 return false;
714 }
715
716 success = encoder.encode<qint32>(src: array.valueArray().size());
717
718 if (!success) {
719 qCWarning(lcGenericStructHandler) << "Failed to encode array length";
720 return false;
721 }
722
723 for (const auto &entry : array.valueArray()) {
724 success = encodeStructInternal(encoder, value: entry.value<QOpcUaGenericStructValue>());
725
726 if (!success) {
727 qCWarning(lcGenericStructHandler) << "Failed to encode struct into the array";
728 return false;
729 }
730 }
731
732 return true;
733 }
734
735 return false;
736 }
737
738 // Maybe this is a supertype of a built-in type
739 const auto superType = m_knownSubtypes.constFind(key: dataTypeId);
740 if (superType != m_knownSubtypes.constEnd())
741 return encodeKnownTypesInternal(encoder, value, valueRank, dataTypeId: superType.value());
742
743 return false;
744}
745
746void QOpcUaGenericStructHandlerPrivate::handleFinished(bool success)
747{
748 if (m_hasError)
749 return;
750
751 m_finishedCount++;
752 m_hasError = !success;
753
754 Q_Q(QOpcUaGenericStructHandler);
755
756 if (m_finishedCount == 1 || m_hasError) {
757 m_initialized = !m_hasError;
758 emit q->initializedChanged(initialized: m_initialized);
759 }
760}
761
762bool QOpcUaGenericStructHandlerPrivate::addCustomStructureDefinition(const QOpcUaStructureDefinition &definition,
763 const QString &typeId, const QString &name, QOpcUa::IsAbstract isAbstract)
764{
765 if (typeId.isEmpty()) {
766 qCWarning(lcGenericStructHandler) << "Failed to add custom structure definition, typeId must not be empty";
767 return false;
768 }
769
770 if (name.isEmpty()) {
771 qCWarning(lcGenericStructHandler) << "Failed to add custom structure definition, name must not be empty";
772 return false;
773 }
774
775 if (definition.defaultEncodingId().isEmpty()) {
776 qCWarning(lcGenericStructHandler) << "Failed to add custom structure definition, definition.defaultEncodingId() must not be empty";
777 return false;
778 }
779
780 StructMapEntry entry;
781 entry.isAbstract = isAbstract == QOpcUa::IsAbstract::Abstract;
782 entry.name = name;
783 entry.nodeId = typeId;
784 entry.structureDefinition = definition;
785
786 m_structuresByTypeId[typeId] = entry;
787 m_structuresByEncodingId[definition.defaultEncodingId()] = entry;
788 m_typeNamesByEncodingId[definition.defaultEncodingId()] = name;
789 m_typeNamesByTypeId[typeId] = name;
790
791 if (entry.isAbstract)
792 m_abstractTypeIds.insert(value: typeId);
793
794 return true;
795}
796
797bool QOpcUaGenericStructHandlerPrivate::addCustomEnumDefinition(const QOpcUaEnumDefinition &definition,
798 const QString &typeId, const QString &name,
799 QOpcUa::IsAbstract isAbstract)
800{
801 if (typeId.isEmpty()) {
802 qCWarning(lcGenericStructHandler) << "Failed to add custom enum definition, typeId must not be empty";
803 return false;
804 }
805
806 if (name.isEmpty()) {
807 qCWarning(lcGenericStructHandler) << "Failed to add custom enum definition, name must not be empty";
808 return false;
809 }
810
811 EnumMapEntry entry;
812 entry.isAbstract = isAbstract == QOpcUa::IsAbstract::Abstract;
813 entry.name = name;
814 entry.nodeId = typeId;
815 entry.enumDefinition = definition;
816
817 m_enumsByTypeId[typeId] = entry;
818 m_typeNamesByTypeId[typeId] = name;
819
820 return true;
821}
822
823bool QOpcUaGenericStructHandlerPrivate::initialized() const
824{
825 return m_initialized;
826}
827
828void QOpcUaGenericStructHandlerPrivate::handleInitializeFinished(bool success)
829{
830 if (!success) {
831 qCWarning(lcGenericStructHandler) << "Failed to read the data type tree";
832 handleFinished(success: false);
833 return;
834 } else {
835 processDataTypeRecursive(node: m_baseDataType.get());
836 handleFinished(success: true);
837 }
838}
839
840void QOpcUaGenericStructHandlerPrivate::processDataTypeRecursive(QOpcUaInternalDataTypeNode *node)
841{
842 qCDebug(lcGenericStructHandler) << "Found DataType:" << node->name();
843
844 m_typeNamesByTypeId[node->nodeId()] = node->name();
845 if (node->isAbstract())
846 m_abstractTypeIds.insert(value: node->nodeId());
847
848 for (const auto &child : node->children()) {
849 if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Structure))
850 processStructRecursive(node: child.get());
851 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Enumeration))
852 processEnumRecursive(node: child.get());
853 else {
854 if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Boolean))
855 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
856 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Int32))
857 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
858 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::UInt32))
859 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
860 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Double))
861 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
862 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Float))
863 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
864 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::String))
865 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
866 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::LocalizedText))
867 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
868 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::DateTime))
869 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
870 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::UInt16))
871 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
872 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Int16))
873 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
874 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::UInt64))
875 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
876 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Int64))
877 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
878 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Byte))
879 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
880 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::SByte))
881 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
882 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::ByteString))
883 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
884 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::XmlElement))
885 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
886 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::NodeId))
887 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
888 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::Guid))
889 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
890 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::QualifiedName))
891 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
892 else if (child->nodeId() == QOpcUa::namespace0Id(id: QOpcUa::NodeIds::Namespace0::StatusCode))
893 processSubtypeOfKnownTypeRecursive(node: child.get(), id: child->nodeId());
894 else
895 processDataTypeRecursive(node: child.get());
896 }
897 }
898}
899
900void QOpcUaGenericStructHandlerPrivate::processStructRecursive(QOpcUaInternalDataTypeNode *node)
901{
902 qCDebug(lcGenericStructHandler) << "Found struct:" << node->name();
903
904 m_typeNamesByTypeId.insert(key: node->nodeId(), value: node->name());
905
906 if (node->isAbstract())
907 m_abstractTypeIds.insert(value: node->nodeId());
908
909 const auto structureDefinition = node->definition().value<QOpcUaStructureDefinition>();
910 if (!structureDefinition.defaultEncodingId().isEmpty())
911 m_typeNamesByEncodingId.insert(key: structureDefinition.defaultEncodingId(), value: node->name());
912
913 const StructMapEntry entry{ .name: node->name(), .nodeId: node->nodeId(), .isAbstract: node->isAbstract(), .structureDefinition: structureDefinition };
914 m_structuresByEncodingId.insert(key: structureDefinition.defaultEncodingId(), value: entry);
915 m_structuresByTypeId.insert(key: node->nodeId(), value: entry);
916
917 for (const auto &child : node->children())
918 processStructRecursive(node: child.get());
919}
920
921void QOpcUaGenericStructHandlerPrivate::processEnumRecursive(QOpcUaInternalDataTypeNode *node)
922{
923 qCDebug(lcGenericStructHandler) << "Found enum:" << node->name();
924
925 m_typeNamesByTypeId[node->nodeId()] = node->name();
926
927 if (node->isAbstract())
928 m_abstractTypeIds.insert(value: node->nodeId());
929
930 EnumMapEntry entry;
931 entry.name = node->name();
932 entry.enumDefinition = node->definition().value<QOpcUaEnumDefinition>();
933 entry.nodeId = node->nodeId();
934 entry.isAbstract = node->isAbstract();
935 m_enumsByTypeId.insert(key: node->nodeId(), value: entry);
936
937 for (const auto &child : node->children())
938 processEnumRecursive(node: child.get());
939}
940
941void QOpcUaGenericStructHandlerPrivate::processSubtypeOfKnownTypeRecursive(QOpcUaInternalDataTypeNode *node, const QString &id)
942{
943 m_typeNamesByTypeId[node->nodeId()] = node->name();
944
945 if (node->isAbstract())
946 m_abstractTypeIds.insert(value: node->nodeId());
947
948 if (node->nodeId() != id)
949 m_knownSubtypes[node->nodeId()] = id;
950
951 for (const auto &child : node->children())
952 processSubtypeOfKnownTypeRecursive(node: child.get(), id);
953}
954
955QT_END_NAMESPACE
956

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtopcua/src/opcua/client/qopcuagenericstructhandlerprivate.cpp