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