3 * Copyright (C) 2006 Trolltech AS. All rights reserved.
4 * Author: Thiago Macieira <thiago.macieira@trolltech.com>
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "qdbusmetaobject_p.h"
26 #include <QtCore/qbytearray.h>
27 #include <QtCore/qhash.h>
28 #include <QtCore/qstring.h>
29 #include <QtCore/qvarlengtharray.h>
31 #include "qdbusutil.h"
32 #include "qdbuserror.h"
33 #include "qdbusintrospection_p.h"
34 #include "qdbusabstractinterface_p.h"
36 class QDBusMetaObjectGenerator
39 QDBusMetaObjectGenerator(const QString &interface,
40 const QDBusIntrospection::Interface *parsedData);
41 void write(QDBusMetaObject *obj);
42 void writeWithoutXml(QDBusMetaObject *obj);
46 QByteArray parameters;
49 QByteArray inputSignature;
50 QByteArray outputSignature;
51 QVarLengthArray<int, 4> inputTypes;
52 QVarLengthArray<int, 4> outputTypes;
65 Readable = 0x00000001,
66 Writable = 0x00000002,
67 Resettable = 0x00000004,
68 EnumOrFlag = 0x00000008,
69 StdCppSet = 0x00000100,
70 // Override = 0x00000200,
71 Designable = 0x00001000,
72 ResolveDesignable = 0x00002000,
73 Scriptable = 0x00004000,
74 ResolveScriptable = 0x00008000,
76 ResolveStored = 0x00020000,
77 Editable = 0x00040000,
78 ResolveEditable = 0x00080000,
80 ResolveUser = 0x00200000
85 AccessProtected = 0x01,
87 AccessMask = 0x03, //mask
92 MethodTypeMask = 0x0c,
94 MethodCompatibility = 0x10,
96 MethodScriptable = 0x40
99 QMap<QByteArray, Method> methods;
100 QMap<QByteArray, Property> properties;
102 const QDBusIntrospection::Interface *data;
107 void parseProperties();
110 static const int intsPerProperty = 2;
111 static const int intsPerMethod = 4;
113 // ### from kernel/qmetaobject.cpp (Qt 4.1.2):
114 struct QDBusMetaObjectPrivate
118 int classInfoCount, classInfoData;
119 int methodCount, methodData;
120 int propertyCount, propertyData;
121 int enumeratorCount, enumeratorData;
123 // this is specific for QDBusMetaObject:
124 int propertyDBusData;
128 QDBusMetaObjectGenerator::QDBusMetaObjectGenerator(const QString &interfaceName,
129 const QDBusIntrospection::Interface *parsedData)
130 : data(parsedData), interface(interfaceName)
134 parseSignals(); // call parseSignals first so that slots override signals
139 void QDBusMetaObjectGenerator::parseMethods()
141 foreach (const QDBusIntrospection::Method &m, data->methods) {
144 QByteArray prototype = m.name.toLatin1();
149 // build the input argument list
150 foreach (const QDBusIntrospection::Argument &arg, m.inputArgs) {
151 int typeId = QDBusUtil::signatureToType(arg.type);
152 if (typeId == QVariant::Invalid) {
157 mm.inputSignature += arg.type;
158 mm.inputTypes.append(typeId);
160 mm.parameters.append(arg.name.toLatin1());
161 mm.parameters.append(',');
163 prototype.append( QVariant::typeToName( QVariant::Type(typeId) ) );
164 prototype.append(',');
168 // build the output argument list:
169 for (int i = 0; i < m.outputArgs.count(); ++i) {
170 const QDBusIntrospection::Argument &arg = m.outputArgs.at(i);
172 int typeId = QDBusUtil::signatureToType(arg.type);
173 if (typeId == QVariant::Invalid) {
178 mm.outputSignature += arg.type;
179 mm.outputTypes.append(typeId);
183 mm.typeName = QVariant::typeToName( QVariant::Type(typeId) );
185 // non-const ref parameter
186 mm.parameters.append(arg.name.toLatin1());
187 mm.parameters.append(',');
189 prototype.append( QVariant::typeToName( QVariant::Type(typeId) ) );
190 prototype.append("&,");
195 // convert the last commas:
196 if (!mm.parameters.isEmpty()) {
197 mm.parameters.truncate(mm.parameters.length() - 1);
198 prototype[prototype.length() - 1] = ')';
200 prototype.append(')');
203 // check the async tag
204 if (m.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"))
208 mm.flags = AccessPublic | MethodSlot | MethodScriptable;
211 methods.insert(QMetaObject::normalizedSignature(prototype), mm);
215 void QDBusMetaObjectGenerator::parseSignals()
217 foreach (const QDBusIntrospection::Signal &s, data->signals_) {
220 QByteArray prototype = s.name.toLatin1();
225 // build the output argument list
226 foreach (const QDBusIntrospection::Argument &arg, s.outputArgs) {
227 int typeId = QDBusUtil::signatureToType(arg.type);
228 if (typeId == QVariant::Invalid) {
233 mm.inputSignature += arg.type;
234 mm.inputTypes.append(typeId);
236 mm.parameters.append(arg.name.toLatin1());
237 mm.parameters.append(',');
239 prototype.append( QVariant::typeToName( QVariant::Type(typeId) ) );
240 prototype.append(',');
244 // convert the last commas:
245 if (!mm.parameters.isEmpty()) {
246 mm.parameters.truncate(mm.parameters.length() - 1);
247 prototype[prototype.length() - 1] = ')';
249 prototype.append(')');
253 mm.flags = AccessProtected | MethodSignal | MethodScriptable;
256 methods.insert(QMetaObject::normalizedSignature(prototype), mm);
260 void QDBusMetaObjectGenerator::parseProperties()
262 foreach (const QDBusIntrospection::Property &p, data->properties) {
264 mp.type = QDBusUtil::signatureToType(p.type);
265 if (mp.type == QVariant::Invalid)
268 QByteArray name = p.name.toLatin1();
269 mp.signature = p.type.toLatin1();
270 mp.typeName = QVariant::typeToName( QVariant::Type(mp.type) );
273 mp.flags = StdCppSet | Scriptable | Stored;
274 if (p.access != QDBusIntrospection::Property::Write)
275 mp.flags |= Readable;
276 if (p.access != QDBusIntrospection::Property::Read)
277 mp.flags |= Writable;
279 if (mp.typeName == "QVariant")
280 mp.flags |= 0xff << 24;
281 else if (mp.type < 0xff)
282 // encode the type in the flags
283 mp.flags |= mp.type << 24;
286 properties.insert(name, mp);
290 void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
292 // this code here is mostly copied from qaxbase.cpp
293 // with a few modifications to make it cleaner
295 QString className = interface;
296 className.replace(QLatin1Char('.'), QLatin1String("::"));
297 if (className.isEmpty())
298 className = QLatin1String("QDBusInterface");
300 QVarLengthArray<int> data;
301 data.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int));
303 QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(data.data());
304 header->revision = 1;
305 header->className = 0;
306 header->classInfoCount = 0;
307 header->classInfoData = 0;
308 header->methodCount = methods.count();
309 header->methodData = data.size();
310 header->propertyCount = properties.count();
311 header->propertyData = header->methodData + header->methodCount * 5;
312 header->enumeratorCount = 0;
313 header->enumeratorData = 0;
314 header->propertyDBusData = header->propertyData + header->propertyCount * 3;
315 header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty;
317 int data_size = data.size() +
318 (header->methodCount * (5+intsPerMethod)) +
319 (header->propertyCount * (3+intsPerProperty));
320 foreach (const Method &mm, methods)
321 data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count();
322 data.resize(data_size + 1);
325 QByteArray stringdata = className.toLatin1();
327 stringdata.reserve(8192);
329 int offset = header->methodData;
330 int signatureOffset = header->methodDBusData;
331 int typeidOffset = header->methodDBusData + header->methodCount * intsPerMethod;
332 data[typeidOffset++] = 0; // eod
335 for (QMap<QByteArray, Method>::ConstIterator it = methods.constBegin();
336 it != methods.constEnd(); ++it) {
337 // form "prototype\0parameters\0typeName\0tag\0inputSignature\0outputSignature"
338 const Method &mm = it.value();
340 data[offset++] = stringdata.length();
341 stringdata += it.key(); // prototype
343 data[offset++] = stringdata.length();
344 stringdata += mm.parameters;
346 data[offset++] = stringdata.length();
347 stringdata += mm.typeName;
349 data[offset++] = stringdata.length();
350 stringdata += mm.tag;
352 data[offset++] = mm.flags;
354 data[signatureOffset++] = stringdata.length();
355 stringdata += mm.inputSignature;
357 data[signatureOffset++] = stringdata.length();
358 stringdata += mm.outputSignature;
361 data[signatureOffset++] = typeidOffset;
362 data[typeidOffset++] = mm.inputTypes.count();
363 memcpy(data.data() + typeidOffset, mm.inputTypes.data(), mm.inputTypes.count() * sizeof(int));
364 typeidOffset += mm.inputTypes.count();
366 data[signatureOffset++] = typeidOffset;
367 data[typeidOffset++] = mm.outputTypes.count();
368 memcpy(data.data() + typeidOffset, mm.outputTypes.data(), mm.outputTypes.count() * sizeof(int));
369 typeidOffset += mm.outputTypes.count();
372 Q_ASSERT(offset == header->propertyData);
373 Q_ASSERT(signatureOffset == header->methodDBusData + header->methodCount * intsPerMethod);
374 Q_ASSERT(typeidOffset == data.size());
377 signatureOffset = header->propertyDBusData;
378 for (QMap<QByteArray, Property>::ConstIterator it = properties.constBegin();
379 it != properties.constEnd(); ++it) {
380 const Property &mp = it.value();
382 // form is "name\0typeName\0signature\0"
383 data[offset++] = stringdata.length();
384 stringdata += it.key(); // name
386 data[offset++] = stringdata.length();
387 stringdata += mp.typeName;
389 data[offset++] = mp.flags;
391 data[signatureOffset++] = stringdata.length();
392 stringdata += mp.signature;
394 data[signatureOffset++] = mp.type;
397 Q_ASSERT(offset == header->propertyDBusData);
398 Q_ASSERT(signatureOffset == header->methodDBusData);
400 char *string_data = new char[stringdata.length()];
401 memcpy(string_data, stringdata, stringdata.length());
403 uint *uint_data = new uint[data.size()];
404 memcpy(uint_data, data.data(), data.size() * sizeof(int));
406 // put the metaobject together
407 obj->d.data = uint_data;
408 obj->d.extradata = 0;
409 obj->d.stringdata = string_data;
410 obj->d.superdata = &QDBusAbstractInterface::staticMetaObject;
414 void QDBusMetaObjectGenerator::writeWithoutXml(const QString &interface)
417 QString tmp(interface);
418 tmp.replace(QLatin1Char('.'), QLatin1String("::"));
419 QByteArray name(tmp.toLatin1());
421 QDBusMetaObjectPrivate *header = new QDBusMetaObjectPrivate;
422 memset(header, 0, sizeof *header);
423 header->revision = 1;
424 // leave the rest with 0
426 char *stringdata = new char[name.length() + 1];
427 stringdata[name.length()] = '\0';
429 d.data = reinterpret_cast<uint*>(header);
431 d.stringdata = stringdata;
432 d.superdata = &QDBusAbstractInterface::staticMetaObject;
438 // class QDBusMetaObject
440 QDBusMetaObject *QDBusMetaObject::createMetaObject(const QString &interface, const QString &xml,
441 QHash<QString, QDBusMetaObject *> &cache,
444 error = QDBusError();
445 QDBusIntrospection::Interfaces parsed = QDBusIntrospection::parseInterfaces(xml);
447 QDBusMetaObject *we = 0;
448 QDBusIntrospection::Interfaces::ConstIterator it = parsed.constBegin();
449 QDBusIntrospection::Interfaces::ConstIterator end = parsed.constEnd();
450 for ( ; it != end; ++it) {
451 // check if it's in the cache
452 QDBusMetaObject *obj = cache.value(it.key(), 0);
454 // not in cache; create
455 obj = new QDBusMetaObject;
456 QDBusMetaObjectGenerator generator(it.key(), it.value().constData());
457 generator.write(obj);
459 if ( (obj->cached = !it.key().startsWith( QLatin1String("local.") )) )
461 cache.insert(it.key(), obj);
465 if (it.key() == interface)
474 if (parsed.isEmpty()) {
475 // object didn't return introspection
476 we = new QDBusMetaObject;
477 QDBusMetaObjectGenerator generator(interface, 0);
481 } else if (interface.isEmpty()) {
482 // merge all interfaces
483 it = parsed.constBegin();
484 QDBusIntrospection::Interface merged = *it.value().constData();
486 for (++it; it != end; ++it) {
487 merged.annotations.unite(it.value()->annotations);
488 merged.methods.unite(it.value()->methods);
489 merged.signals_.unite(it.value()->signals_);
490 merged.properties.unite(it.value()->properties);
493 merged.name = QLatin1String("local.Merged");
494 merged.introspection.clear();
496 we = new QDBusMetaObject;
497 QDBusMetaObjectGenerator generator(merged.name, &merged);
504 error = QDBusError(QDBusError::UnknownInterface,
505 QString( QLatin1String("Interface '%1' was not found") )
510 QDBusMetaObject::QDBusMetaObject()
514 inline const QDBusMetaObjectPrivate *priv(const uint* data)
516 return reinterpret_cast<const QDBusMetaObjectPrivate *>(data);
519 const char *QDBusMetaObject::dbusNameForMethod(int id) const
521 //id -= methodOffset();
522 if (id >= 0 && id < priv(d.data)->methodCount) {
523 int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
524 return d.stringdata + d.data[handle];
529 const char *QDBusMetaObject::inputSignatureForMethod(int id) const
531 //id -= methodOffset();
532 if (id >= 0 && id < priv(d.data)->methodCount) {
533 int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
534 return d.stringdata + d.data[handle + 1];
539 const char *QDBusMetaObject::outputSignatureForMethod(int id) const
541 //id -= methodOffset();
542 if (id >= 0 && id < priv(d.data)->methodCount) {
543 int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
544 return d.stringdata + d.data[handle + 2];
549 const int *QDBusMetaObject::inputTypesForMethod(int id) const
551 //id -= methodOffset();
552 if (id >= 0 && id < priv(d.data)->methodCount) {
553 int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
554 return reinterpret_cast<const int*>(d.data + d.data[handle + 3]);
559 const int *QDBusMetaObject::outputTypesForMethod(int id) const
561 //id -= methodOffset();
562 if (id >= 0 && id < priv(d.data)->methodCount) {
563 int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
564 return reinterpret_cast<const int*>(d.data + d.data[handle + 4]);
569 int QDBusMetaObject::propertyMetaType(int id) const
571 //id -= propertyOffset();
572 if (id >= 0 && id < priv(d.data)->propertyCount) {
573 int handle = priv(d.data)->propertyDBusData + id*intsPerProperty;
574 return d.data[handle + 1];
580 static inline void assign_helper(void *ptr, const QVariant &value)
582 *reinterpret_cast<T *>(ptr) = qvariant_cast<T>(value);
585 void QDBusMetaObject::assign(void *ptr, const QVariant &value)
587 switch (value.userType())
590 assign_helper<bool>(ptr, value);
593 case QMetaType::UChar:
594 assign_helper<uchar>(ptr, value);
597 case QMetaType::Short:
598 assign_helper<short>(ptr, value);
601 case QMetaType::UShort:
602 assign_helper<ushort>(ptr, value);
606 assign_helper<int>(ptr, value);
610 assign_helper<uint>(ptr, value);
613 case QVariant::LongLong:
614 assign_helper<qlonglong>(ptr, value);
617 case QVariant::ULongLong:
618 assign_helper<qulonglong>(ptr, value);
621 case QVariant::Double:
622 assign_helper<double>(ptr, value);
625 case QVariant::String:
626 assign_helper<QString>(ptr, value);
629 case QVariant::ByteArray:
630 assign_helper<QByteArray>(ptr, value);
634 assign_helper<QVariantList>(ptr, value);
638 assign_helper<QVariantMap>(ptr, value);
646 bool QDBusMetaTypeId::initialized = false;
647 int QDBusMetaTypeId::variant = 0;
648 int QDBusMetaTypeId::boollist = 0;
649 int QDBusMetaTypeId::shortlist = 0;
650 int QDBusMetaTypeId::ushortlist = 0;
651 int QDBusMetaTypeId::intlist = 0;
652 int QDBusMetaTypeId::uintlist = 0;
653 int QDBusMetaTypeId::longlonglist = 0;
654 int QDBusMetaTypeId::ulonglonglist = 0;
655 int QDBusMetaTypeId::doublelist = 0;
657 bool QDBusMetaTypeId::innerInitialize()
659 variant = qRegisterMetaType<QVariant>("QVariant");
660 boollist = qRegisterMetaType<QList<bool> >("QList<bool>");
661 shortlist = qRegisterMetaType<QList<short> >("QList<short>");
662 ushortlist = qRegisterMetaType<QList<ushort> >("QList<ushort>");
663 intlist = qRegisterMetaType<QList<int> >("QList<int>");
664 uintlist = qRegisterMetaType<QList<uint> >("QList<uint>");
665 longlonglist = qRegisterMetaType<QList<qlonglong> >("QList<qlonglong>");
666 ulonglonglist = qRegisterMetaType<QList<qulonglong> >("QList<qulonglong>");
667 doublelist = qRegisterMetaType<QList<double> >("QList<double>");
672 int qDBusMetaTypeId(QVariant *)
673 { QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::variant; }
674 int qDBusMetaTypeId(QList<bool> *)
675 { QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::boollist; }
676 int qDBusMetaTypeId(QList<short> *)
677 { QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::shortlist; }
678 int qDBusMetaTypeId(QList<ushort> *)
679 { QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::ushortlist; }
680 int qDBusMetaTypeId(QList<int> *)
681 { QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::intlist; }
682 int qDBusMetaTypeId(QList<uint> *)
683 { QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::uintlist; }
684 int qDBusMetaTypeId(QList<qlonglong> *)
685 { QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::longlonglist; }
686 int qDBusMetaTypeId(QList<qulonglong> *)
687 { QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::ulonglonglist; }
688 int qDBusMetaTypeId(QList<double> *)
689 { QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::doublelist; }