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

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