Coverage Report

Created: 2026-11-12 07:19

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