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
109 message = qRegisterMetaType<QDBusMessage>("QDBusMessage");
110 error = qRegisterMetaType<QDBusError>("QDBusError");
112 argument = qRegisterMetaType<QDBusArgument>("QDBusArgument");
113 variant = qRegisterMetaType<QDBusVariant>("QDBusVariant");
114 objectpath = qRegisterMetaType<QDBusObjectPath>("QDBusObjectPath");
115 signature = qRegisterMetaType<QDBusSignature>("QDBusSignature");
116 unixfd = qRegisterMetaType<QDBusUnixFileDescriptor>("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> >();
149 const int lastId = qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
150 message = lastId + 1;
157 Q_GLOBAL_STATIC(QVector<QDBusCustomTypeInfo>, customTypes)
158 Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
162 \brief Meta-type registration system for the QtDBus module.
165 The QDBusMetaType class allows you to register class types for
166 marshalling and demarshalling over D-Bus. D-Bus supports a very
167 limited set of primitive types, but allows one to extend the type
168 system by creating compound types, such as arrays (lists) and
169 structs. In order to use them with QtDBus, those types must be
172 See \l {qdbustypesystem.html}{QtDBus type system} for more
173 information on the type system and how to register additional
176 \sa {qdbustypesystem.html}{QtDBus type system},
177 qDBusRegisterMetaType(), QMetaType, QVariant, QDBusArgument
181 \fn int qDBusRegisterMetaType()
182 \relates QDBusArgument
186 Registers \c{T} with the
187 \l {qdbustypesystem.html}{QtDBus type system} and the Qt \l
188 {QMetaType}{meta-type system}, if it's not already registered.
190 To register a type, it must be declared as a meta-type with the
191 Q_DECLARE_METATYPE() macro, and then registered as in the
194 \snippet code/src_qdbus_qdbusmetatype.cpp 0
196 If \c{T} isn't a type derived from one of
197 Qt's \l{container classes}, the \c{operator<<} and
198 \c{operator>>} streaming operators between \c{T} and QDBusArgument
199 must be already declared. See the \l {qdbustypesystem.html}{QtDBus
200 type system} page for more information on how to declare such
203 This function returns the Qt meta type id for the type (the same
204 value that is returned from qRegisterMetaType()).
206 \sa {qdbustypesystem.html}{QtDBus type system}, qRegisterMetaType(), QMetaType
210 \typedef QDBusMetaType::MarshallFunction
215 \typedef QDBusMetaType::DemarshallFunction
221 Registers the marshalling and demarshalling functions for meta
224 void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf,
225 DemarshallFunction df)
228 QVector<QDBusCustomTypeInfo> *ct = customTypes();
229 if (id < 0 || !mf || !df || !ct)
232 QWriteLocker locker(customTypesLock());
233 if (id >= ct->size())
235 QDBusCustomTypeInfo &info = (*ct)[id];
237 info.demarshall = df;
242 Executes the marshalling of type \a id (whose data is contained in
243 \a data) to the D-Bus marshalling argument \a arg. Returns true if
244 the marshalling succeeded, or false if an error occurred.
246 bool QDBusMetaType::marshall(QDBusArgument &arg, int id, const void *data)
248 QDBusMetaTypeId::init();
252 QReadLocker locker(customTypesLock());
253 QVector<QDBusCustomTypeInfo> *ct = customTypes();
254 if (id >= ct->size())
255 return false; // non-existent
257 const QDBusCustomTypeInfo &info = (*ct).at(id);
258 if (!info.marshall) {
259 mf = 0; // make gcc happy
271 Executes the demarshalling of type \a id (whose data will be placed in
272 \a data) from the D-Bus marshalling argument \a arg. Returns true if
273 the demarshalling succeeded, or false if an error occurred.
275 bool QDBusMetaType::demarshall(const QDBusArgument &arg, int id, void *data)
277 QDBusMetaTypeId::init();
279 DemarshallFunction df;
281 QReadLocker locker(customTypesLock());
282 QVector<QDBusCustomTypeInfo> *ct = customTypes();
283 if (id >= ct->size())
284 return false; // non-existent
286 const QDBusCustomTypeInfo &info = (*ct).at(id);
287 if (!info.demarshall) {
288 df = 0; // make gcc happy
291 df = info.demarshall;
293 #ifndef QT_BOOTSTRAPPED
294 QDBusArgument copy = arg;
305 \fn QDBusMetaType::signatureToType(const char *signature)
308 Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
311 Note: this function only handles the basic D-Bus types.
313 \sa QDBusUtil::isValidSingleSignature(), typeToSignature(),
314 QVariant::type(), QVariant::userType()
316 int QDBusMetaType::signatureToType(const char *signature)
319 return QMetaType::UnknownType;
321 QDBusMetaTypeId::init();
322 switch (signature[0])
324 case DBUS_TYPE_BOOLEAN:
325 return QVariant::Bool;
328 return QMetaType::UChar;
330 case DBUS_TYPE_INT16:
331 return QMetaType::Short;
333 case DBUS_TYPE_UINT16:
334 return QMetaType::UShort;
336 case DBUS_TYPE_INT32:
337 return QVariant::Int;
339 case DBUS_TYPE_UINT32:
340 return QVariant::UInt;
342 case DBUS_TYPE_INT64:
343 return QVariant::LongLong;
345 case DBUS_TYPE_UINT64:
346 return QVariant::ULongLong;
348 case DBUS_TYPE_DOUBLE:
349 return QVariant::Double;
351 case DBUS_TYPE_STRING:
352 return QVariant::String;
354 case DBUS_TYPE_OBJECT_PATH:
355 return QDBusMetaTypeId::objectpath;
357 case DBUS_TYPE_SIGNATURE:
358 return QDBusMetaTypeId::signature;
360 case DBUS_TYPE_UNIX_FD:
361 return QDBusMetaTypeId::unixfd;
363 case DBUS_TYPE_VARIANT:
364 return QDBusMetaTypeId::variant;
366 case DBUS_TYPE_ARRAY: // special case
367 switch (signature[1]) {
369 return QVariant::ByteArray;
371 case DBUS_TYPE_STRING:
372 return QVariant::StringList;
374 case DBUS_TYPE_VARIANT:
375 return QVariant::List;
377 case DBUS_TYPE_OBJECT_PATH:
378 return qMetaTypeId<QList<QDBusObjectPath> >();
380 case DBUS_TYPE_SIGNATURE:
381 return qMetaTypeId<QList<QDBusSignature> >();
386 return QMetaType::UnknownType;
391 \fn QDBusMetaType::typeToSignature(int type)
394 Returns the D-Bus signature equivalent to the supplied meta type id \a type.
396 More types can be registered with the qDBusRegisterMetaType() function.
398 \sa QDBusUtil::isValidSingleSignature(), signatureToType(),
399 QVariant::type(), QVariant::userType()
401 const char *QDBusMetaType::typeToSignature(int type)
403 // check if it's a static type
406 case QMetaType::UChar:
407 return DBUS_TYPE_BYTE_AS_STRING;
410 return DBUS_TYPE_BOOLEAN_AS_STRING;
412 case QMetaType::Short:
413 return DBUS_TYPE_INT16_AS_STRING;
415 case QMetaType::UShort:
416 return DBUS_TYPE_UINT16_AS_STRING;
419 return DBUS_TYPE_INT32_AS_STRING;
422 return DBUS_TYPE_UINT32_AS_STRING;
424 case QVariant::LongLong:
425 return DBUS_TYPE_INT64_AS_STRING;
427 case QVariant::ULongLong:
428 return DBUS_TYPE_UINT64_AS_STRING;
430 case QVariant::Double:
431 return DBUS_TYPE_DOUBLE_AS_STRING;
433 case QVariant::String:
434 return DBUS_TYPE_STRING_AS_STRING;
436 case QVariant::StringList:
437 return DBUS_TYPE_ARRAY_AS_STRING
438 DBUS_TYPE_STRING_AS_STRING; // as
440 case QVariant::ByteArray:
441 return DBUS_TYPE_ARRAY_AS_STRING
442 DBUS_TYPE_BYTE_AS_STRING; // ay
445 QDBusMetaTypeId::init();
446 if (type == QDBusMetaTypeId::variant)
447 return DBUS_TYPE_VARIANT_AS_STRING;
448 else if (type == QDBusMetaTypeId::objectpath)
449 return DBUS_TYPE_OBJECT_PATH_AS_STRING;
450 else if (type == QDBusMetaTypeId::signature)
451 return DBUS_TYPE_SIGNATURE_AS_STRING;
452 else if (type == QDBusMetaTypeId::unixfd)
453 return DBUS_TYPE_UNIX_FD_AS_STRING;
456 QVector<QDBusCustomTypeInfo> *ct = customTypes();
458 QReadLocker locker(customTypesLock());
459 if (type >= ct->size())
460 return 0; // type not registered with us
462 const QDBusCustomTypeInfo &info = (*ct).at(type);
464 if (!info.signature.isNull())
465 return info.signature;
468 return 0; // type not registered with us
471 // call to user code to construct the signature type
472 QDBusCustomTypeInfo *info;
474 // createSignature will never return a null QByteArray
475 // if there was an error, it'll return ""
476 QByteArray signature = QDBusArgumentPrivate::createSignature(type);
479 QWriteLocker locker(customTypesLock());
481 info->signature = signature;
483 return info->signature;