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 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | Q_LOGGING_CATEGORY(lcGenericStructHandler, "qt.opcuagenericstructhandler" ) |
28 | |
29 | QOpcUaGenericStructHandlerPrivate::QOpcUaGenericStructHandlerPrivate(QOpcUaClient *client) |
30 | : m_client(client) |
31 | { |
32 | } |
33 | |
34 | bool 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 | |
49 | QOpcUaGenericStructValue 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 | |
66 | bool 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 | |
85 | QOpcUaGenericStructValue 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 | |
108 | QOpcUaStructureDefinition 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 | |
114 | QOpcUaStructureDefinition 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 | |
120 | QOpcUaEnumDefinition 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 | |
126 | QString 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 | |
132 | QString 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 | |
138 | QOpcUaGenericStructHandler::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 | |
152 | QString 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 | |
158 | bool QOpcUaGenericStructHandlerPrivate::isAbstractTypeId(const QString &id) const |
159 | { |
160 | return m_abstractTypeIds.contains(value: id); |
161 | } |
162 | |
163 | QOpcUaGenericStructValue 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 | |
251 | QVariant 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 | |
429 | bool 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 | |
534 | bool 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 | |
746 | void 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 | |
762 | bool 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 | |
797 | bool 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 | |
823 | bool QOpcUaGenericStructHandlerPrivate::initialized() const |
824 | { |
825 | return m_initialized; |
826 | } |
827 | |
828 | void 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 | |
840 | void 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 | |
900 | void 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 | |
921 | void 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 | |
941 | void 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 | |
955 | QT_END_NAMESPACE |
956 | |