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