QtDBus: use qMetaTypeId<T>() instead of qRegisterMetaType<T>("T")
[profile/ivi/qtbase.git] / src / dbus / qdbusmetatype.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdbusmetatype.h"
43
44 #include <string.h>
45 #include "qdbus_symbols_p.h"
46
47 #include <qbytearray.h>
48 #include <qglobal.h>
49 #include <qreadwritelock.h>
50 #include <qvector.h>
51
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"
58 #endif
59
60 #ifndef QT_NO_DBUS
61
62 #ifndef DBUS_TYPE_UNIX_FD
63 # define DBUS_TYPE_UNIX_FD int('h')
64 # define DBUS_TYPE_UNIX_FD_AS_STRING "h"
65 #endif
66
67 QT_BEGIN_NAMESPACE
68
69 class QDBusCustomTypeInfo
70 {
71 public:
72     QDBusCustomTypeInfo() : signature(), marshall(0), demarshall(0)
73     { }
74
75     // Suggestion:
76     // change 'signature' to char* and make QDBusCustomTypeInfo a Movable type
77     QByteArray signature;
78     QDBusMetaType::MarshallFunction marshall;
79     QDBusMetaType::DemarshallFunction demarshall;
80 };
81
82 template<typename T>
83 inline static void registerHelper(T * = 0)
84 {
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));
90 }
91
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;
99
100 void QDBusMetaTypeId::init()
101 {
102     static volatile bool initialized = false;
103
104     // reentrancy is not a problem since everything else is locked on their own
105     // set the guard variable at the end
106     if (!initialized) {
107 #ifndef QT_BOOTSTRAPPED
108         // register our types with QtCore (calling qMetaTypeId<T>() does this implicitly)
109         message = qMetaTypeId<QDBusMessage>();
110         error = qMetaTypeId<QDBusError>();
111 #endif
112         argument = qMetaTypeId<QDBusArgument>();
113         variant = qMetaTypeId<QDBusVariant>();
114         objectpath = qMetaTypeId<QDBusObjectPath>();
115         signature = qMetaTypeId<QDBusSignature>();
116         unixfd = qMetaTypeId<QDBusUnixFileDescriptor>();
117
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>();
134
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> >();
146 #endif
147
148 #if QT_BOOTSTRAPPED
149         const int lastId = qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
150         message = lastId + 1;
151         error = lastId + 2;
152 #endif
153         initialized = true;
154     }
155 }
156
157 Q_GLOBAL_STATIC(QVector<QDBusCustomTypeInfo>, customTypes)
158 Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
159
160 /*!
161     \class QDBusMetaType
162     \brief Meta-type registration system for the QtDBus module.
163     \internal
164
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
170     registered.
171
172     See \l {qdbustypesystem.html}{QtDBus type system} for more
173     information on the type system and how to register additional
174     types.
175
176     \sa {qdbustypesystem.html}{QtDBus type system},
177     qDBusRegisterMetaType(), QMetaType, QVariant, QDBusArgument
178 */
179
180 /*!
181     \fn int qDBusRegisterMetaType()
182     \relates QDBusArgument
183     \threadsafe
184     \since 4.2
185
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.
189
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
192     following example:
193
194     \snippet code/src_qdbus_qdbusmetatype.cpp 0
195
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
201     types.
202
203     This function returns the Qt meta type id for the type (the same
204     value that is returned from qRegisterMetaType()).
205
206     \sa {qdbustypesystem.html}{QtDBus type system}, qRegisterMetaType(), QMetaType
207 */
208
209 /*!
210     \typedef QDBusMetaType::MarshallFunction
211     \internal
212 */
213
214 /*!
215     \typedef QDBusMetaType::DemarshallFunction
216     \internal
217 */
218
219 /*!
220     \internal
221     Registers the marshalling and demarshalling functions for meta
222     type \a id.
223 */
224 void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf,
225                                               DemarshallFunction df)
226 {
227     QByteArray var;
228     QVector<QDBusCustomTypeInfo> *ct = customTypes();
229     if (id < 0 || !mf || !df || !ct)
230         return;                 // error!
231
232     QWriteLocker locker(customTypesLock());
233     if (id >= ct->size())
234         ct->resize(id + 1);
235     QDBusCustomTypeInfo &info = (*ct)[id];
236     info.marshall = mf;
237     info.demarshall = df;
238 }
239
240 /*!
241     \internal
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.
245 */
246 bool QDBusMetaType::marshall(QDBusArgument &arg, int id, const void *data)
247 {
248     QDBusMetaTypeId::init();
249
250     MarshallFunction mf;
251     {
252         QReadLocker locker(customTypesLock());
253         QVector<QDBusCustomTypeInfo> *ct = customTypes();
254         if (id >= ct->size())
255             return false;       // non-existent
256
257         const QDBusCustomTypeInfo &info = (*ct).at(id);
258         if (!info.marshall) {
259             mf = 0;             // make gcc happy
260             return false;
261         } else
262             mf = info.marshall;
263     }
264
265     mf(arg, data);
266     return true;
267 }
268
269 /*!
270     \internal
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.
274 */
275 bool QDBusMetaType::demarshall(const QDBusArgument &arg, int id, void *data)
276 {
277     QDBusMetaTypeId::init();
278
279     DemarshallFunction df;
280     {
281         QReadLocker locker(customTypesLock());
282         QVector<QDBusCustomTypeInfo> *ct = customTypes();
283         if (id >= ct->size())
284             return false;       // non-existent
285
286         const QDBusCustomTypeInfo &info = (*ct).at(id);
287         if (!info.demarshall) {
288             df = 0;             // make gcc happy
289             return false;
290         } else
291             df = info.demarshall;
292     }
293 #ifndef QT_BOOTSTRAPPED
294     QDBusArgument copy = arg;
295     df(copy, data);
296 #else
297     Q_UNUSED(arg);
298     Q_UNUSED(data);
299     Q_UNUSED(df);
300 #endif
301     return true;
302 }
303
304 /*!
305     \fn QDBusMetaType::signatureToType(const char *signature)
306     \internal
307
308     Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
309     by \a signature.
310
311     Note: this function only handles the basic D-Bus types.
312
313     \sa QDBusUtil::isValidSingleSignature(), typeToSignature(),
314         QVariant::type(), QVariant::userType()
315 */
316 int QDBusMetaType::signatureToType(const char *signature)
317 {
318     if (!signature)
319         return QMetaType::UnknownType;
320
321     QDBusMetaTypeId::init();
322     switch (signature[0])
323     {
324     case DBUS_TYPE_BOOLEAN:
325         return QVariant::Bool;
326
327     case DBUS_TYPE_BYTE:
328         return QMetaType::UChar;
329
330     case DBUS_TYPE_INT16:
331         return QMetaType::Short;
332
333     case DBUS_TYPE_UINT16:
334         return QMetaType::UShort;
335         
336     case DBUS_TYPE_INT32:
337         return QVariant::Int;
338         
339     case DBUS_TYPE_UINT32:
340         return QVariant::UInt;
341
342     case DBUS_TYPE_INT64:
343         return QVariant::LongLong;
344
345     case DBUS_TYPE_UINT64:
346         return QVariant::ULongLong;
347
348     case DBUS_TYPE_DOUBLE:
349         return QVariant::Double;
350
351     case DBUS_TYPE_STRING:
352         return QVariant::String;
353
354     case DBUS_TYPE_OBJECT_PATH:
355         return QDBusMetaTypeId::objectpath;
356
357     case DBUS_TYPE_SIGNATURE:
358         return QDBusMetaTypeId::signature;
359
360     case DBUS_TYPE_UNIX_FD:
361         return QDBusMetaTypeId::unixfd;
362
363     case DBUS_TYPE_VARIANT:
364         return QDBusMetaTypeId::variant;
365
366     case DBUS_TYPE_ARRAY:       // special case
367         switch (signature[1]) {
368         case DBUS_TYPE_BYTE:
369             return QVariant::ByteArray;
370
371         case DBUS_TYPE_STRING:
372             return QVariant::StringList;
373
374         case DBUS_TYPE_VARIANT:
375             return QVariant::List;
376
377         case DBUS_TYPE_OBJECT_PATH:
378             return qMetaTypeId<QList<QDBusObjectPath> >();
379
380         case DBUS_TYPE_SIGNATURE:
381             return qMetaTypeId<QList<QDBusSignature> >();
382
383         }
384         // fall through
385     default:
386         return QMetaType::UnknownType;
387     }
388 }
389
390 /*!
391     \fn QDBusMetaType::typeToSignature(int type)
392     \internal 
393
394     Returns the D-Bus signature equivalent to the supplied meta type id \a type.
395
396     More types can be registered with the qDBusRegisterMetaType() function.
397
398     \sa QDBusUtil::isValidSingleSignature(), signatureToType(),
399         QVariant::type(), QVariant::userType()
400 */
401 const char *QDBusMetaType::typeToSignature(int type)
402 {
403     // check if it's a static type
404     switch (type)
405     {
406     case QMetaType::UChar:
407         return DBUS_TYPE_BYTE_AS_STRING;
408
409     case QVariant::Bool:
410         return DBUS_TYPE_BOOLEAN_AS_STRING;
411
412     case QMetaType::Short:
413         return DBUS_TYPE_INT16_AS_STRING;
414
415     case QMetaType::UShort:
416         return DBUS_TYPE_UINT16_AS_STRING;
417
418     case QVariant::Int:
419         return DBUS_TYPE_INT32_AS_STRING;
420
421     case QVariant::UInt:
422         return DBUS_TYPE_UINT32_AS_STRING;
423
424     case QVariant::LongLong:
425         return DBUS_TYPE_INT64_AS_STRING;
426
427     case QVariant::ULongLong:
428         return DBUS_TYPE_UINT64_AS_STRING;
429
430     case QVariant::Double:
431         return DBUS_TYPE_DOUBLE_AS_STRING;
432
433     case QVariant::String:
434         return DBUS_TYPE_STRING_AS_STRING;
435
436     case QVariant::StringList:
437         return DBUS_TYPE_ARRAY_AS_STRING
438             DBUS_TYPE_STRING_AS_STRING; // as
439
440     case QVariant::ByteArray:
441         return DBUS_TYPE_ARRAY_AS_STRING
442             DBUS_TYPE_BYTE_AS_STRING; // ay
443     }
444
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;
454
455     // try the database
456     QVector<QDBusCustomTypeInfo> *ct = customTypes();
457     {
458         QReadLocker locker(customTypesLock());
459         if (type >= ct->size())
460             return 0;           // type not registered with us
461
462         const QDBusCustomTypeInfo &info = (*ct).at(type);
463
464         if (!info.signature.isNull())
465             return info.signature;
466
467         if (!info.marshall)
468             return 0;           // type not registered with us
469     }
470
471     // call to user code to construct the signature type
472     QDBusCustomTypeInfo *info;
473     {
474         // createSignature will never return a null QByteArray
475         // if there was an error, it'll return ""
476         QByteArray signature = QDBusArgumentPrivate::createSignature(type);
477
478         // re-acquire lock
479         QWriteLocker locker(customTypesLock());
480         info = &(*ct)[type];
481         info->signature = signature;
482     }
483     return info->signature;
484 }
485
486 QT_END_NAMESPACE
487
488 #endif // QT_NO_DBUS