1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDBus module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdbusmetatype.h"
45 #include "qdbus_symbols_p.h"
47 #include <qbytearray.h>
49 #include <qreadwritelock.h>
52 #include "qdbusmetatype_p.h"
53 #include "qdbusargument_p.h"
54 #include "qdbusutil_p.h"
55 #include "qdbusunixfiledescriptor.h"
56 #ifndef QT_BOOTSTRAPPED
57 #include "qdbusmessage.h"
62 #ifndef DBUS_TYPE_UNIX_FD
63 # define DBUS_TYPE_UNIX_FD int('h')
64 # define DBUS_TYPE_UNIX_FD_AS_STRING "h"
69 class QDBusCustomTypeInfo
72 QDBusCustomTypeInfo() : signature(), marshall(0), demarshall(0)
76 // change 'signature' to char* and make QDBusCustomTypeInfo a Movable type
78 QDBusMetaType::MarshallFunction marshall;
79 QDBusMetaType::DemarshallFunction demarshall;
83 inline static void registerHelper(T * = 0)
85 void (*mf)(QDBusArgument &, const T *) = qDBusMarshallHelper<T>;
86 void (*df)(const QDBusArgument &, T *) = qDBusDemarshallHelper<T>;
87 QDBusMetaType::registerMarshallOperators(qMetaTypeId<T>(),
88 reinterpret_cast<QDBusMetaType::MarshallFunction>(mf),
89 reinterpret_cast<QDBusMetaType::DemarshallFunction>(df));
92 int QDBusMetaTypeId::message;
93 int QDBusMetaTypeId::argument;
94 int QDBusMetaTypeId::variant;
95 int QDBusMetaTypeId::objectpath;
96 int QDBusMetaTypeId::signature;
97 int QDBusMetaTypeId::error;
98 int QDBusMetaTypeId::unixfd;
100 void QDBusMetaTypeId::init()
102 static volatile bool initialized = false;
104 // reentrancy is not a problem since everything else is locked on their own
105 // set the guard variable at the end
107 #ifndef QT_BOOTSTRAPPED
108 // register our types with QtCore (calling qMetaTypeId<T>() does this implicitly)
109 message = qMetaTypeId<QDBusMessage>();
110 error = qMetaTypeId<QDBusError>();
112 argument = qMetaTypeId<QDBusArgument>();
113 variant = qMetaTypeId<QDBusVariant>();
114 objectpath = qMetaTypeId<QDBusObjectPath>();
115 signature = qMetaTypeId<QDBusSignature>();
116 unixfd = qMetaTypeId<QDBusUnixFileDescriptor>();
118 #ifndef QDBUS_NO_SPECIALTYPES
119 // and register QtCore's with us
120 registerHelper<QDate>();
121 registerHelper<QTime>();
122 registerHelper<QDateTime>();
123 registerHelper<QRect>();
124 registerHelper<QRectF>();
125 registerHelper<QSize>();
126 registerHelper<QSizeF>();
127 registerHelper<QPoint>();
128 registerHelper<QPointF>();
129 registerHelper<QLine>();
130 registerHelper<QLineF>();
131 registerHelper<QVariantList>();
132 registerHelper<QVariantMap>();
133 registerHelper<QVariantHash>();
135 qDBusRegisterMetaType<QList<bool> >();
136 qDBusRegisterMetaType<QList<short> >();
137 qDBusRegisterMetaType<QList<ushort> >();
138 qDBusRegisterMetaType<QList<int> >();
139 qDBusRegisterMetaType<QList<uint> >();
140 qDBusRegisterMetaType<QList<qlonglong> >();
141 qDBusRegisterMetaType<QList<qulonglong> >();
142 qDBusRegisterMetaType<QList<double> >();
143 qDBusRegisterMetaType<QList<QDBusObjectPath> >();
144 qDBusRegisterMetaType<QList<QDBusSignature> >();
145 qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
148 #ifdef QT_BOOTSTRAPPED
149 const int lastId = qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
150 message = lastId + 1;
157 Q_GLOBAL_STATIC(QVector<QDBusCustomTypeInfo>, customTypes)
158 Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
163 \brief Meta-type registration system for the QtDBus module.
166 The QDBusMetaType class allows you to register class types for
167 marshalling and demarshalling over D-Bus. D-Bus supports a very
168 limited set of primitive types, but allows one to extend the type
169 system by creating compound types, such as arrays (lists) and
170 structs. In order to use them with QtDBus, those types must be
173 See \l {qdbustypesystem.html}{QtDBus type system} for more
174 information on the type system and how to register additional
177 \sa {qdbustypesystem.html}{QtDBus type system},
178 qDBusRegisterMetaType(), QMetaType, QVariant, QDBusArgument
182 \fn int qDBusRegisterMetaType()
183 \relates QDBusArgument
187 Registers \c{T} with the
188 \l {qdbustypesystem.html}{QtDBus type system} and the Qt \l
189 {QMetaType}{meta-type system}, if it's not already registered.
191 To register a type, it must be declared as a meta-type with the
192 Q_DECLARE_METATYPE() macro, and then registered as in the
195 \snippet code/src_qdbus_qdbusmetatype.cpp 0
197 If \c{T} isn't a type derived from one of
198 Qt's \l{container classes}, the \c{operator<<} and
199 \c{operator>>} streaming operators between \c{T} and QDBusArgument
200 must be already declared. See the \l {qdbustypesystem.html}{QtDBus
201 type system} page for more information on how to declare such
204 This function returns the Qt meta type id for the type (the same
205 value that is returned from qRegisterMetaType()).
207 \sa {qdbustypesystem.html}{QtDBus type system}, qRegisterMetaType(), QMetaType
211 \typedef QDBusMetaType::MarshallFunction
216 \typedef QDBusMetaType::DemarshallFunction
222 Registers the marshalling and demarshalling functions for meta
225 void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf,
226 DemarshallFunction df)
229 QVector<QDBusCustomTypeInfo> *ct = customTypes();
230 if (id < 0 || !mf || !df || !ct)
233 QWriteLocker locker(customTypesLock());
234 if (id >= ct->size())
236 QDBusCustomTypeInfo &info = (*ct)[id];
238 info.demarshall = df;
243 Executes the marshalling of type \a id (whose data is contained in
244 \a data) to the D-Bus marshalling argument \a arg. Returns true if
245 the marshalling succeeded, or false if an error occurred.
247 bool QDBusMetaType::marshall(QDBusArgument &arg, int id, const void *data)
249 QDBusMetaTypeId::init();
253 QReadLocker locker(customTypesLock());
254 QVector<QDBusCustomTypeInfo> *ct = customTypes();
255 if (id >= ct->size())
256 return false; // non-existent
258 const QDBusCustomTypeInfo &info = (*ct).at(id);
259 if (!info.marshall) {
260 mf = 0; // make gcc happy
272 Executes the demarshalling of type \a id (whose data will be placed in
273 \a data) from the D-Bus marshalling argument \a arg. Returns true if
274 the demarshalling succeeded, or false if an error occurred.
276 bool QDBusMetaType::demarshall(const QDBusArgument &arg, int id, void *data)
278 QDBusMetaTypeId::init();
280 DemarshallFunction df;
282 QReadLocker locker(customTypesLock());
283 QVector<QDBusCustomTypeInfo> *ct = customTypes();
284 if (id >= ct->size())
285 return false; // non-existent
287 const QDBusCustomTypeInfo &info = (*ct).at(id);
288 if (!info.demarshall) {
289 df = 0; // make gcc happy
292 df = info.demarshall;
294 #ifndef QT_BOOTSTRAPPED
295 QDBusArgument copy = arg;
306 \fn QDBusMetaType::signatureToType(const char *signature)
309 Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
312 Note: this function only handles the basic D-Bus types.
314 \sa QDBusUtil::isValidSingleSignature(), typeToSignature(),
315 QVariant::type(), QVariant::userType()
317 int QDBusMetaType::signatureToType(const char *signature)
320 return QMetaType::UnknownType;
322 QDBusMetaTypeId::init();
323 switch (signature[0])
325 case DBUS_TYPE_BOOLEAN:
326 return QVariant::Bool;
329 return QMetaType::UChar;
331 case DBUS_TYPE_INT16:
332 return QMetaType::Short;
334 case DBUS_TYPE_UINT16:
335 return QMetaType::UShort;
337 case DBUS_TYPE_INT32:
338 return QVariant::Int;
340 case DBUS_TYPE_UINT32:
341 return QVariant::UInt;
343 case DBUS_TYPE_INT64:
344 return QVariant::LongLong;
346 case DBUS_TYPE_UINT64:
347 return QVariant::ULongLong;
349 case DBUS_TYPE_DOUBLE:
350 return QVariant::Double;
352 case DBUS_TYPE_STRING:
353 return QVariant::String;
355 case DBUS_TYPE_OBJECT_PATH:
356 return QDBusMetaTypeId::objectpath;
358 case DBUS_TYPE_SIGNATURE:
359 return QDBusMetaTypeId::signature;
361 case DBUS_TYPE_UNIX_FD:
362 return QDBusMetaTypeId::unixfd;
364 case DBUS_TYPE_VARIANT:
365 return QDBusMetaTypeId::variant;
367 case DBUS_TYPE_ARRAY: // special case
368 switch (signature[1]) {
370 return QVariant::ByteArray;
372 case DBUS_TYPE_STRING:
373 return QVariant::StringList;
375 case DBUS_TYPE_VARIANT:
376 return QVariant::List;
378 case DBUS_TYPE_OBJECT_PATH:
379 return qMetaTypeId<QList<QDBusObjectPath> >();
381 case DBUS_TYPE_SIGNATURE:
382 return qMetaTypeId<QList<QDBusSignature> >();
387 return QMetaType::UnknownType;
392 \fn QDBusMetaType::typeToSignature(int type)
395 Returns the D-Bus signature equivalent to the supplied meta type id \a type.
397 More types can be registered with the qDBusRegisterMetaType() function.
399 \sa QDBusUtil::isValidSingleSignature(), signatureToType(),
400 QVariant::type(), QVariant::userType()
402 const char *QDBusMetaType::typeToSignature(int type)
404 // check if it's a static type
407 case QMetaType::UChar:
408 return DBUS_TYPE_BYTE_AS_STRING;
411 return DBUS_TYPE_BOOLEAN_AS_STRING;
413 case QMetaType::Short:
414 return DBUS_TYPE_INT16_AS_STRING;
416 case QMetaType::UShort:
417 return DBUS_TYPE_UINT16_AS_STRING;
420 return DBUS_TYPE_INT32_AS_STRING;
423 return DBUS_TYPE_UINT32_AS_STRING;
425 case QVariant::LongLong:
426 return DBUS_TYPE_INT64_AS_STRING;
428 case QVariant::ULongLong:
429 return DBUS_TYPE_UINT64_AS_STRING;
431 case QVariant::Double:
432 return DBUS_TYPE_DOUBLE_AS_STRING;
434 case QVariant::String:
435 return DBUS_TYPE_STRING_AS_STRING;
437 case QVariant::StringList:
438 return DBUS_TYPE_ARRAY_AS_STRING
439 DBUS_TYPE_STRING_AS_STRING; // as
441 case QVariant::ByteArray:
442 return DBUS_TYPE_ARRAY_AS_STRING
443 DBUS_TYPE_BYTE_AS_STRING; // ay
446 QDBusMetaTypeId::init();
447 if (type == QDBusMetaTypeId::variant)
448 return DBUS_TYPE_VARIANT_AS_STRING;
449 else if (type == QDBusMetaTypeId::objectpath)
450 return DBUS_TYPE_OBJECT_PATH_AS_STRING;
451 else if (type == QDBusMetaTypeId::signature)
452 return DBUS_TYPE_SIGNATURE_AS_STRING;
453 else if (type == QDBusMetaTypeId::unixfd)
454 return DBUS_TYPE_UNIX_FD_AS_STRING;
457 QVector<QDBusCustomTypeInfo> *ct = customTypes();
459 QReadLocker locker(customTypesLock());
460 if (type >= ct->size())
461 return 0; // type not registered with us
463 const QDBusCustomTypeInfo &info = (*ct).at(type);
465 if (!info.signature.isNull())
466 return info.signature;
469 return 0; // type not registered with us
472 // call to user code to construct the signature type
473 QDBusCustomTypeInfo *info;
475 // createSignature will never return a null QByteArray
476 // if there was an error, it'll return ""
477 QByteArray signature = QDBusArgumentPrivate::createSignature(type);
480 QWriteLocker locker(customTypesLock());
482 info->signature = signature;
484 return info->signature;