/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 |