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 | |
24 | QT_BEGIN_NAMESPACE |
25 | |
26 | using namespace Qt::StringLiterals; |
27 | |
28 | class QDBusMetaObjectGenerator |
29 | { |
30 | public: |
31 | QDBusMetaObjectGenerator(const QString &interface, |
32 | const QDBusIntrospection::Interface *parsedData); |
33 | void write(QDBusMetaObject *obj); |
34 | void writeWithoutXml(QDBusMetaObject *obj); |
35 | |
36 | private: |
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 | |
77 | static const qsizetype intsPerProperty = 2; |
78 | static const qsizetype intsPerMethod = 2; |
79 | |
80 | struct QDBusMetaObjectPrivate : public QMetaObjectPrivate |
81 | { |
82 | int propertyDBusData; |
83 | int methodDBusData; |
84 | }; |
85 | |
86 | QDBusMetaObjectGenerator::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 | |
97 | static 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 | |
130 | Q_DBUS_EXPORT bool qt_dbus_metaobject_skip_annotations = false; |
131 | |
132 | QDBusMetaObjectGenerator::Type |
133 | QDBusMetaObjectGenerator::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 | |
207 | void 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 | |
285 | void 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 | |
329 | void 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. |
357 | qsizetype 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 | |
365 | void 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 |
544 | void 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 | |
572 | QDBusMetaObject *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 | |
645 | QDBusMetaObject::QDBusMetaObject() |
646 | { |
647 | } |
648 | |
649 | static inline const QDBusMetaObjectPrivate *priv(const uint* data) |
650 | { |
651 | return reinterpret_cast<const QDBusMetaObjectPrivate *>(data); |
652 | } |
653 | |
654 | const 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 | |
664 | const 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 | |
674 | int 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 | |
684 | QT_END_NAMESPACE |
685 | |
686 | #endif // QT_NO_DBUS |
687 |
Definitions
- QDBusMetaObjectGenerator
- Method
- Property
- Type
- intsPerProperty
- intsPerMethod
- QDBusMetaObjectPrivate
- QDBusMetaObjectGenerator
- registerComplexDBusType
- qt_dbus_metaobject_skip_annotations
- findType
- parseMethods
- parseSignals
- parseProperties
- aggregateParameterCount
- write
- createMetaObject
- QDBusMetaObject
- priv
- inputTypesForMethod
- outputTypesForMethod
Learn to use CMake with our Intro Training
Find out more