1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qdbusmetaobject_p.h"
6
7#include <QtCore/qbytearray.h>
8#include <QtCore/qhash.h>
9#include <QtCore/qstring.h>
10#include <QtCore/qvarlengtharray.h>
11
12#include "qdbusutil_p.h"
13#include "qdbuserror.h"
14#include "qdbusmetatype.h"
15#include "qdbusargument.h"
16#include "qdbusintrospection_p.h"
17#include "qdbusabstractinterface_p.h"
18
19#include <private/qmetaobject_p.h>
20#include <private/qmetaobjectbuilder_p.h>
21
22#ifndef QT_NO_DBUS
23
24QT_BEGIN_NAMESPACE
25
26using namespace Qt::StringLiterals;
27
28class QDBusMetaObjectGenerator
29{
30public:
31 QDBusMetaObjectGenerator(const QString &interface,
32 const QDBusIntrospection::Interface *parsedData);
33 void write(QDBusMetaObject *obj);
34 void writeWithoutXml(QDBusMetaObject *obj);
35
36private:
37 struct Method {
38 QList<QByteArray> parameterNames;
39 QByteArray tag;
40 QByteArray name;
41 QVarLengthArray<int, 4> inputTypes;
42 QVarLengthArray<int, 4> outputTypes;
43 QByteArray rawReturnType;
44 quint32 flags;
45 };
46
47 struct Property {
48 QByteArray typeName;
49 QByteArray signature;
50 int type;
51 quint32 flags;
52 };
53 struct Type {
54 int id;
55 QByteArray name;
56 };
57
58 using MethodMap = QMap<QByteArray, Method>;
59 MethodMap signals_;
60 MethodMap methods;
61 QMap<QByteArray, Property> properties;
62
63 const QDBusIntrospection::Interface *data;
64 QString interface;
65
66 Type findType(const QByteArray &signature,
67 const QDBusIntrospection::Annotations &annotations,
68 const char *direction = "Out", int id = -1);
69
70 void parseMethods();
71 void parseSignals();
72 void parseProperties();
73
74 static qsizetype aggregateParameterCount(const MethodMap &map);
75};
76
77static const qsizetype intsPerProperty = 2;
78static const qsizetype intsPerMethod = 2;
79
80struct QDBusMetaObjectPrivate : public QMetaObjectPrivate
81{
82 int propertyDBusData;
83 int methodDBusData;
84};
85
86QDBusMetaObjectGenerator::QDBusMetaObjectGenerator(const QString &interfaceName,
87 const QDBusIntrospection::Interface *parsedData)
88 : data(parsedData), interface(interfaceName)
89{
90 if (data) {
91 parseProperties();
92 parseSignals(); // call parseSignals first so that slots override signals
93 parseMethods();
94 }
95}
96
97static int registerComplexDBusType(const QByteArray &typeName)
98{
99 struct QDBusRawTypeHandler : QtPrivate::QMetaTypeInterface
100 {
101 const QByteArray name;
102 QDBusRawTypeHandler(const QByteArray &name)
103 : QtPrivate::QMetaTypeInterface {
104 .revision: 0, .alignment: sizeof(void *), .size: sizeof(void *), .flags: QMetaType::RelocatableType, .typeId: 0, .metaObjectFn: nullptr,
105 .name: name.constData(),
106 .defaultCtr: nullptr, .copyCtr: nullptr, .moveCtr: nullptr, .dtor: nullptr,
107 .equals: nullptr, .lessThan: nullptr, .debugStream: nullptr,
108 .dataStreamOut: nullptr, .dataStreamIn: nullptr, .legacyRegisterOp: nullptr
109 },
110 name(name)
111 {}
112 };
113
114 Q_CONSTINIT static QBasicMutex mutex;
115 Q_CONSTINIT static struct Hash : QHash<QByteArray, QMetaType>
116 {
117 ~Hash()
118 {
119 for (QMetaType entry : std::as_const(t&: *this))
120 QMetaType::unregisterMetaType(type: entry);
121 }
122 } hash;
123 QMutexLocker lock(&mutex);
124 QMetaType &metatype = hash[typeName];
125 if (!metatype.isValid())
126 metatype = QMetaType(new QDBusRawTypeHandler(typeName));
127 return metatype.id();
128}
129
130Q_DBUS_EXPORT bool qt_dbus_metaobject_skip_annotations = false;
131
132QDBusMetaObjectGenerator::Type
133QDBusMetaObjectGenerator::findType(const QByteArray &signature,
134 const QDBusIntrospection::Annotations &annotations,
135 const char *direction, int id)
136{
137 Type result;
138 result.id = QMetaType::UnknownType;
139
140 int type = QDBusMetaType::signatureToMetaType(signature).id();
141 if (type == QMetaType::UnknownType && !qt_dbus_metaobject_skip_annotations) {
142 // it's not a type normally handled by our meta type system
143 // it must contain an annotation
144 QString annotationName = QString::fromLatin1(ba: "org.qtproject.QtDBus.QtTypeName");
145 if (id >= 0)
146 annotationName += QString::fromLatin1(ba: ".%1%2")
147 .arg(a: QLatin1StringView(direction))
148 .arg(a: id);
149
150 // extract from annotations:
151 auto annotation = annotations.value(key: annotationName);
152 QByteArray typeName = annotation.value.toLatin1();
153
154 // verify that it's a valid one
155 if (typeName.isEmpty()) {
156 // try the old annotation from Qt 4
157 annotationName = QString::fromLatin1(ba: "com.trolltech.QtDBus.QtTypeName");
158 if (id >= 0)
159 annotationName += QString::fromLatin1(ba: ".%1%2")
160 .arg(a: QLatin1StringView(direction))
161 .arg(a: id);
162 annotation = annotations.value(key: annotationName);
163 typeName = annotation.value.toLatin1();
164 }
165
166 if (!typeName.isEmpty()) {
167 // type name found
168 type = QMetaType::fromName(name: typeName).id();
169 }
170
171 if (type == QMetaType::UnknownType || signature != QDBusMetaType::typeToSignature(type: QMetaType(type))) {
172 // type is still unknown or doesn't match back to the signature that it
173 // was expected to, so synthesize a fake type
174 typeName = "QDBusRawType<0x" + signature.toHex() + ">*";
175 type = registerComplexDBusType(typeName);
176 }
177
178 result.name = typeName;
179 } else if (type == QMetaType::UnknownType) {
180 // this case is used only by the qdbus command-line tool
181 // invalid, let's create an impossible type that contains the signature
182
183 if (signature == "av") {
184 result.name = "QVariantList";
185 type = QMetaType::QVariantList;
186 } else if (signature == "a{sv}") {
187 result.name = "QVariantMap";
188 type = QMetaType::QVariantMap;
189 } else if (signature == "a{ss}") {
190 result.name = "QMap<QString,QString>";
191 type = qMetaTypeId<QMap<QString, QString> >();
192 } else if (signature == "aay") {
193 result.name = "QByteArrayList";
194 type = qMetaTypeId<QByteArrayList>();
195 } else {
196 result.name = "{D-Bus type \"" + signature + "\"}";
197 type = registerComplexDBusType(typeName: result.name);
198 }
199 } else {
200 result.name = QMetaType(type).name();
201 }
202
203 result.id = type;
204 return result; // success
205}
206
207void QDBusMetaObjectGenerator::parseMethods()
208{
209 //
210 // TODO:
211 // Add cloned methods when the remote object has return types
212 //
213
214 for (const QDBusIntrospection::Method &m : std::as_const(t: data->methods)) {
215 Method mm;
216
217 mm.name = m.name.toLatin1();
218 QByteArray prototype = mm.name;
219 prototype += '(';
220
221 bool ok = true;
222
223 // build the input argument list
224 for (qsizetype i = 0; i < m.inputArgs.size(); ++i) {
225 const QDBusIntrospection::Argument &arg = m.inputArgs.at(i);
226
227 Type type = findType(signature: arg.type.toLatin1(), annotations: m.annotations, direction: "In", id: i);
228 if (type.id == QMetaType::UnknownType) {
229 ok = false;
230 break;
231 }
232
233 mm.inputTypes.append(t: type.id);
234
235 mm.parameterNames.append(t: arg.name.toLatin1());
236
237 prototype.append(a: type.name);
238 prototype.append(c: ',');
239 }
240 if (!ok) continue;
241
242 // build the output argument list:
243 for (qsizetype i = 0; i < m.outputArgs.size(); ++i) {
244 const QDBusIntrospection::Argument &arg = m.outputArgs.at(i);
245
246 Type type = findType(signature: arg.type.toLatin1(), annotations: m.annotations, direction: "Out", id: i);
247 if (type.id == QMetaType::UnknownType) {
248 ok = false;
249 break;
250 }
251
252 mm.outputTypes.append(t: type.id);
253
254 if (i == 0 && type.id == -1) {
255 mm.rawReturnType = type.name;
256 }
257 if (i != 0) {
258 // non-const ref parameter
259 mm.parameterNames.append(t: arg.name.toLatin1());
260
261 prototype.append(a: type.name);
262 prototype.append(s: "&,");
263 }
264 }
265 if (!ok) continue;
266
267 // convert the last commas:
268 if (!mm.parameterNames.isEmpty())
269 prototype[prototype.size() - 1] = ')';
270 else
271 prototype.append(c: ')');
272
273 // check the async tag
274 if (m.annotations.value(ANNOTATION_NO_WAIT ""_L1).value == "true"_L1)
275 mm.tag = "Q_NOREPLY";
276
277 // meta method flags
278 mm.flags = AccessPublic | MethodSlot | MethodScriptable;
279
280 // add
281 methods.insert(key: QMetaObject::normalizedSignature(method: prototype), value: mm);
282 }
283}
284
285void QDBusMetaObjectGenerator::parseSignals()
286{
287 for (const QDBusIntrospection::Signal &s : std::as_const(t: data->signals_)) {
288 Method mm;
289
290 mm.name = s.name.toLatin1();
291 QByteArray prototype = mm.name;
292 prototype += '(';
293
294 bool ok = true;
295
296 // build the output argument list
297 for (qsizetype i = 0; i < s.outputArgs.size(); ++i) {
298 const QDBusIntrospection::Argument &arg = s.outputArgs.at(i);
299
300 Type type = findType(signature: arg.type.toLatin1(), annotations: s.annotations, direction: "Out", id: i);
301 if (type.id == QMetaType::UnknownType) {
302 ok = false;
303 break;
304 }
305
306 mm.inputTypes.append(t: type.id);
307
308 mm.parameterNames.append(t: arg.name.toLatin1());
309
310 prototype.append(a: type.name);
311 prototype.append(c: ',');
312 }
313 if (!ok) continue;
314
315 // convert the last commas:
316 if (!mm.parameterNames.isEmpty())
317 prototype[prototype.size() - 1] = ')';
318 else
319 prototype.append(c: ')');
320
321 // meta method flags
322 mm.flags = AccessPublic | MethodSignal | MethodScriptable;
323
324 // add
325 signals_.insert(key: QMetaObject::normalizedSignature(method: prototype), value: mm);
326 }
327}
328
329void QDBusMetaObjectGenerator::parseProperties()
330{
331 for (const QDBusIntrospection::Property &p : std::as_const(t: data->properties)) {
332 Property mp;
333 Type type = findType(signature: p.type.toLatin1(), annotations: p.annotations);
334 if (type.id == QMetaType::UnknownType)
335 continue;
336
337 QByteArray name = p.name.toLatin1();
338 mp.signature = p.type.toLatin1();
339 mp.type = type.id;
340 mp.typeName = type.name;
341
342 // build the flags:
343 mp.flags = StdCppSet | Scriptable | Stored | Designable;
344 if (p.access != QDBusIntrospection::Property::Write)
345 mp.flags |= Readable;
346 if (p.access != QDBusIntrospection::Property::Read)
347 mp.flags |= Writable;
348
349 // add the property:
350 properties.insert(key: name, value: mp);
351 }
352}
353
354// Returns the sum of all parameters (including return type) for the given
355// \a map of methods. This is needed for calculating the size of the methods'
356// parameter type/name meta-data.
357qsizetype QDBusMetaObjectGenerator::aggregateParameterCount(const MethodMap &map)
358{
359 qsizetype sum = 0;
360 for (const Method &m : map)
361 sum += m.inputTypes.size() + qMax(a: qsizetype(1), b: m.outputTypes.size());
362 return sum;
363}
364
365void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
366{
367 // this code here is mostly copied from qaxbase.cpp
368 // with a few modifications to make it cleaner
369
370 QString className = interface;
371 className.replace(c: u'.', after: "::"_L1);
372 if (className.isEmpty())
373 className = "QDBusInterface"_L1;
374
375 QVarLengthArray<uint> idata;
376 idata.resize(sz: sizeof(QDBusMetaObjectPrivate) / sizeof(uint));
377
378 qsizetype methodParametersDataSize =
379 ((aggregateParameterCount(map: signals_)
380 + aggregateParameterCount(map: methods)) * 2) // types and parameter names
381 - signals_.size() // return "parameters" don't have names
382 - methods.size(); // ditto
383
384 QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data());
385 static_assert(QMetaObjectPrivate::OutputRevision == 12, "QtDBus meta-object generator should generate the same version as moc");
386 header->revision = QMetaObjectPrivate::OutputRevision;
387 header->className = 0;
388 header->classInfoCount = 0;
389 header->classInfoData = 0;
390 header->methodCount = int(signals_.size() + methods.size());
391 header->methodData = int(idata.size());
392 header->propertyCount = int(properties.size());
393 header->propertyData = int(header->methodData + header->methodCount *
394 QMetaObjectPrivate::IntsPerMethod + methodParametersDataSize);
395 header->enumeratorCount = 0;
396 header->enumeratorData = 0;
397 header->constructorCount = 0;
398 header->constructorData = 0;
399 header->flags = RequiresVariantMetaObject;
400 header->signalCount = signals_.size();
401 // These are specific to QDBusMetaObject:
402 header->propertyDBusData = int(header->propertyData + header->propertyCount
403 * QMetaObjectPrivate::IntsPerProperty);
404 header->methodDBusData = int(header->propertyDBusData + header->propertyCount * intsPerProperty);
405
406 qsizetype data_size = idata.size() +
407 (header->methodCount * (QMetaObjectPrivate::IntsPerMethod+intsPerMethod)) + methodParametersDataSize +
408 (header->propertyCount * (QMetaObjectPrivate::IntsPerProperty+intsPerProperty));
409
410 // Signals must be added before other methods, to match moc.
411 std::array<std::reference_wrapper<const MethodMap>, 2> methodMaps = { signals_, methods };
412
413 for (const auto &methodMap : methodMaps) {
414 for (const Method &mm : methodMap.get())
415 data_size += 2 + mm.inputTypes.size() + mm.outputTypes.size();
416 }
417 idata.resize(sz: data_size + 1);
418
419 QMetaStringTable strings(className.toLatin1());
420
421 qsizetype offset = header->methodData;
422 qsizetype parametersOffset = offset + header->methodCount * QMetaObjectPrivate::IntsPerMethod;
423 qsizetype signatureOffset = header->methodDBusData;
424 qsizetype typeidOffset = header->methodDBusData + header->methodCount * intsPerMethod;
425 idata[typeidOffset++] = 0; // eod
426
427 qsizetype totalMetaTypeCount = properties.size();
428 ++totalMetaTypeCount; // + 1 for metatype of dynamic metaobject
429 for (const auto &methodMap : methodMaps) {
430 for (const Method &mm : methodMap.get()) {
431 qsizetype argc = mm.inputTypes.size() + qMax(a: qsizetype(0), b: mm.outputTypes.size() - 1);
432 totalMetaTypeCount += argc + 1;
433 }
434 }
435 QMetaType *metaTypes = new QMetaType[totalMetaTypeCount];
436 int propertyId = 0;
437
438 // add each method:
439 qsizetype currentMethodMetaTypeOffset = properties.size() + 1;
440
441 for (const auto &methodMap : methodMaps) {
442 for (const Method &mm : methodMap.get()) {
443 qsizetype argc = mm.inputTypes.size() + qMax(a: qsizetype(0), b: mm.outputTypes.size() - 1);
444
445 idata[offset++] = strings.enter(value: mm.name);
446 idata[offset++] = argc;
447 idata[offset++] = parametersOffset;
448 idata[offset++] = strings.enter(value: mm.tag);
449 idata[offset++] = mm.flags;
450 idata[offset++] = currentMethodMetaTypeOffset;
451
452 // Parameter types
453 for (qsizetype i = -1; i < argc; ++i) {
454 int type;
455 QByteArray typeName;
456 if (i < 0) { // Return type
457 if (!mm.outputTypes.isEmpty()) {
458 type = mm.outputTypes.first();
459 if (type == -1) {
460 type = IsUnresolvedType | strings.enter(value: mm.rawReturnType);
461 }
462 } else {
463 type = QMetaType::Void;
464 }
465 } else if (i < mm.inputTypes.size()) {
466 type = mm.inputTypes.at(idx: i);
467 } else {
468 Q_ASSERT(mm.outputTypes.size() > 1);
469 type = mm.outputTypes.at(idx: i - mm.inputTypes.size() + 1);
470 // Output parameters are references; type id not available
471 typeName = QMetaType(type).name();
472 typeName.append(c: '&');
473 type = QMetaType::UnknownType;
474 }
475 int typeInfo;
476 if (!typeName.isEmpty())
477 typeInfo = IsUnresolvedType | strings.enter(value: typeName);
478 else
479 typeInfo = type;
480 metaTypes[currentMethodMetaTypeOffset++] = QMetaType(type);
481 idata[parametersOffset++] = typeInfo;
482 }
483 // Parameter names
484 for (qsizetype i = 0; i < argc; ++i)
485 idata[parametersOffset++] = strings.enter(value: mm.parameterNames.at(i));
486
487 idata[signatureOffset++] = typeidOffset;
488 idata[typeidOffset++] = mm.inputTypes.size();
489 memcpy(dest: idata.data() + typeidOffset, src: mm.inputTypes.data(), n: mm.inputTypes.size() * sizeof(uint));
490 typeidOffset += mm.inputTypes.size();
491
492 idata[signatureOffset++] = typeidOffset;
493 idata[typeidOffset++] = mm.outputTypes.size();
494 memcpy(dest: idata.data() + typeidOffset, src: mm.outputTypes.data(), n: mm.outputTypes.size() * sizeof(uint));
495 typeidOffset += mm.outputTypes.size();
496 }
497 }
498
499 Q_ASSERT(offset == header->methodData + header->methodCount * QMetaObjectPrivate::IntsPerMethod);
500 Q_ASSERT(parametersOffset == header->propertyData);
501 Q_ASSERT(signatureOffset == header->methodDBusData + header->methodCount * intsPerMethod);
502 Q_ASSERT(typeidOffset == idata.size());
503 offset += methodParametersDataSize;
504 Q_ASSERT(offset == header->propertyData);
505
506 // add each property
507 signatureOffset = header->propertyDBusData;
508 for (const auto &[name, mp] : std::as_const(t&: properties).asKeyValueRange()) {
509 // form is name, typeinfo, flags
510 idata[offset++] = strings.enter(value: name);
511 Q_ASSERT(mp.type != QMetaType::UnknownType);
512 idata[offset++] = mp.type;
513 idata[offset++] = mp.flags;
514 idata[offset++] = -1; // notify index
515 idata[offset++] = 0; // revision
516
517 idata[signatureOffset++] = strings.enter(value: mp.signature);
518 idata[signatureOffset++] = mp.type;
519
520 metaTypes[propertyId++] = QMetaType(mp.type);
521 }
522 metaTypes[propertyId] = QMetaType(); // we can't know our own metatype
523
524 Q_ASSERT(offset == header->propertyDBusData);
525 Q_ASSERT(signatureOffset == header->methodDBusData);
526
527 char *string_data = new char[strings.blobSize()];
528 strings.writeBlob(out: string_data);
529
530 uint *uint_data = new uint[idata.size()];
531 memcpy(dest: uint_data, src: idata.data(), n: idata.size() * sizeof(uint));
532
533 // put the metaobject together
534 obj->d.data = uint_data;
535 obj->d.relatedMetaObjects = nullptr;
536 obj->d.static_metacall = nullptr;
537 obj->d.extradata = nullptr;
538 obj->d.stringdata = reinterpret_cast<const uint *>(string_data);
539 obj->d.superdata = &QDBusAbstractInterface::staticMetaObject;
540 obj->d.metaTypes = reinterpret_cast<QtPrivate::QMetaTypeInterface *const *>(metaTypes);
541}
542
543#if 0
544void QDBusMetaObjectGenerator::writeWithoutXml(const QString &interface)
545{
546 // no XML definition
547 QString tmp(interface);
548 tmp.replace(u'.', "::"_L1);
549 QByteArray name(tmp.toLatin1());
550
551 QDBusMetaObjectPrivate *header = new QDBusMetaObjectPrivate;
552 memset(header, 0, sizeof *header);
553 header->revision = 1;
554 // leave the rest with 0
555
556 char *stringdata = new char[name.length() + 1];
557 stringdata[name.length()] = '\0';
558
559 d.data = reinterpret_cast<uint*>(header);
560 d.relatedMetaObjects = 0;
561 d.static_metacall = 0;
562 d.extradata = 0;
563 d.stringdata = stringdata;
564 d.superdata = &QDBusAbstractInterface::staticMetaObject;
565 cached = false;
566}
567#endif
568
569/////////
570// class QDBusMetaObject
571
572QDBusMetaObject *QDBusMetaObject::createMetaObject(const QString &interface, const QString &xml,
573 QHash<QString, QDBusMetaObject *> &cache,
574 QDBusError &error)
575{
576 error = QDBusError();
577 QDBusIntrospection::Interfaces parsed = QDBusIntrospection::parseInterfaces(xml);
578
579 QDBusMetaObject *we = nullptr;
580 QDBusIntrospection::Interfaces::ConstIterator it = parsed.constBegin();
581 QDBusIntrospection::Interfaces::ConstIterator end = parsed.constEnd();
582 for ( ; it != end; ++it) {
583 // check if it's in the cache
584 bool us = it.key() == interface;
585
586 QDBusMetaObject *obj = cache.value(key: it.key(), defaultValue: 0);
587 if (!obj && (us || !interface.startsWith(s: "local."_L1 ))) {
588 // not in cache; create
589 obj = new QDBusMetaObject;
590 QDBusMetaObjectGenerator generator(it.key(), it.value().constData());
591 generator.write(obj);
592
593 if ((obj->cached = !it.key().startsWith(s: "local."_L1)))
594 // cache it
595 cache.insert(key: it.key(), value: obj);
596 else if (!us)
597 delete obj;
598
599 }
600
601 if (us)
602 // it's us
603 we = obj;
604 }
605
606 if (we)
607 return we;
608 // still nothing?
609
610 if (parsed.isEmpty()) {
611 // object didn't return introspection
612 we = new QDBusMetaObject;
613 QDBusMetaObjectGenerator generator(interface, nullptr);
614 generator.write(obj: we);
615 we->cached = false;
616 return we;
617 } else if (interface.isEmpty()) {
618 // merge all interfaces
619 it = parsed.constBegin();
620 QDBusIntrospection::Interface merged = *it.value().constData();
621
622 for (++it; it != end; ++it) {
623 merged.annotations.insert(map: it.value()->annotations);
624 merged.methods.unite(other: it.value()->methods);
625 merged.signals_.unite(other: it.value()->signals_);
626 merged.properties.insert(map: it.value()->properties);
627 }
628
629 merged.name = "local.Merged"_L1;
630 merged.introspection.clear();
631
632 we = new QDBusMetaObject;
633 QDBusMetaObjectGenerator generator(merged.name, &merged);
634 generator.write(obj: we);
635 we->cached = false;
636 return we;
637 }
638
639 // mark as an error
640 error = QDBusError(QDBusError::UnknownInterface,
641 "Interface '%1' was not found"_L1.arg(args: interface));
642 return nullptr;
643}
644
645QDBusMetaObject::QDBusMetaObject()
646{
647}
648
649static inline const QDBusMetaObjectPrivate *priv(const uint* data)
650{
651 return reinterpret_cast<const QDBusMetaObjectPrivate *>(data);
652}
653
654const int *QDBusMetaObject::inputTypesForMethod(int id) const
655{
656 //id -= methodOffset();
657 if (id >= 0 && id < priv(data: d.data)->methodCount) {
658 int handle = priv(data: d.data)->methodDBusData + id*intsPerMethod;
659 return reinterpret_cast<const int*>(d.data + d.data[handle]);
660 }
661 return nullptr;
662}
663
664const int *QDBusMetaObject::outputTypesForMethod(int id) const
665{
666 //id -= methodOffset();
667 if (id >= 0 && id < priv(data: d.data)->methodCount) {
668 int handle = priv(data: d.data)->methodDBusData + id*intsPerMethod;
669 return reinterpret_cast<const int*>(d.data + d.data[handle + 1]);
670 }
671 return nullptr;
672}
673
674int QDBusMetaObject::propertyMetaType(int id) const
675{
676 //id -= propertyOffset();
677 if (id >= 0 && id < priv(data: d.data)->propertyCount) {
678 int handle = priv(data: d.data)->propertyDBusData + id*intsPerProperty;
679 return d.data[handle + 1];
680 }
681 return 0;
682}
683
684QT_END_NAMESPACE
685
686#endif // QT_NO_DBUS
687

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/dbus/qdbusmetaobject.cpp