Merge remote branch 'staging/master' into refactor
[profile/ivi/qtbase.git] / src / dbus / qdbusmetatype.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDBus module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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 "qdbusmessage.h"
53 #include "qdbusunixfiledescriptor.h"
54 #include "qdbusutil_p.h"
55 #include "qdbusmetatype_p.h"
56 #include "qdbusargument_p.h"
57
58 #ifndef QT_NO_DBUS
59
60 #ifndef DBUS_TYPE_UNIX_FD
61 # define DBUS_TYPE_UNIX_FD int('h')
62 # define DBUS_TYPE_UNIX_FD_AS_STRING "h"
63 #endif
64
65 Q_DECLARE_METATYPE(QList<bool>)
66 Q_DECLARE_METATYPE(QList<short>)
67 Q_DECLARE_METATYPE(QList<ushort>)
68 Q_DECLARE_METATYPE(QList<int>)
69 Q_DECLARE_METATYPE(QList<uint>)
70 Q_DECLARE_METATYPE(QList<qlonglong>)
71 Q_DECLARE_METATYPE(QList<qulonglong>)
72 Q_DECLARE_METATYPE(QList<double>)
73
74 QT_BEGIN_NAMESPACE
75
76 class QDBusCustomTypeInfo
77 {
78 public:
79     QDBusCustomTypeInfo() : signature(0, '\0'), marshall(0), demarshall(0)
80     { }
81
82     // Suggestion:
83     // change 'signature' to char* and make QDBusCustomTypeInfo a Movable type
84     QByteArray signature;
85     QDBusMetaType::MarshallFunction marshall;
86     QDBusMetaType::DemarshallFunction demarshall;
87 };
88
89 template<typename T>
90 inline static void registerHelper(T * = 0)
91 {
92     void (*mf)(QDBusArgument &, const T *) = qDBusMarshallHelper<T>;
93     void (*df)(const QDBusArgument &, T *) = qDBusDemarshallHelper<T>;
94     QDBusMetaType::registerMarshallOperators(qMetaTypeId<T>(),
95         reinterpret_cast<QDBusMetaType::MarshallFunction>(mf),
96         reinterpret_cast<QDBusMetaType::DemarshallFunction>(df));
97 }
98
99 int QDBusMetaTypeId::message;
100 int QDBusMetaTypeId::argument;
101 int QDBusMetaTypeId::variant;
102 int QDBusMetaTypeId::objectpath;
103 int QDBusMetaTypeId::signature;
104 int QDBusMetaTypeId::error;
105 int QDBusMetaTypeId::unixfd;
106
107 void QDBusMetaTypeId::init()
108 {
109     static volatile bool initialized = false;
110
111     // reentrancy is not a problem since everything else is locked on their own
112     // set the guard variable at the end
113     if (!initialized) {
114         // register our types with QtCore
115         message = qRegisterMetaType<QDBusMessage>("QDBusMessage");
116         argument = qRegisterMetaType<QDBusArgument>("QDBusArgument");
117         variant = qRegisterMetaType<QDBusVariant>("QDBusVariant");
118         objectpath = qRegisterMetaType<QDBusObjectPath>("QDBusObjectPath");
119         signature = qRegisterMetaType<QDBusSignature>("QDBusSignature");
120         error = qRegisterMetaType<QDBusError>("QDBusError");
121         unixfd = qRegisterMetaType<QDBusUnixFileDescriptor>("QDBusUnixFileDescriptor");
122
123 #ifndef QDBUS_NO_SPECIALTYPES
124         // and register QtCore's with us
125         registerHelper<QDate>();
126         registerHelper<QTime>();
127         registerHelper<QDateTime>();
128         registerHelper<QRect>();
129         registerHelper<QRectF>();
130         registerHelper<QSize>();
131         registerHelper<QSizeF>();
132         registerHelper<QPoint>();
133         registerHelper<QPointF>();
134         registerHelper<QLine>();
135         registerHelper<QLineF>();
136         registerHelper<QVariantList>();
137         registerHelper<QVariantMap>();
138         registerHelper<QVariantHash>();
139
140         qDBusRegisterMetaType<QList<bool> >();
141         qDBusRegisterMetaType<QList<short> >();
142         qDBusRegisterMetaType<QList<ushort> >();
143         qDBusRegisterMetaType<QList<int> >();
144         qDBusRegisterMetaType<QList<uint> >();
145         qDBusRegisterMetaType<QList<qlonglong> >();
146         qDBusRegisterMetaType<QList<qulonglong> >();
147         qDBusRegisterMetaType<QList<double> >();
148         qDBusRegisterMetaType<QList<QDBusObjectPath> >();
149         qDBusRegisterMetaType<QList<QDBusSignature> >();
150         qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
151 #endif
152
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 doc/src/snippets/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
294     QDBusArgument copy = arg;
295     df(copy, data);
296     return true;
297 }
298
299 /*!
300     \fn QDBusMetaType::signatureToType(const char *signature)
301     \internal
302
303     Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
304     by \a signature.
305
306     Note: this function only handles the basic D-Bus types.
307
308     \sa QDBusUtil::isValidSingleSignature(), typeToSignature(),
309         QVariant::type(), QVariant::userType()
310 */
311 int QDBusMetaType::signatureToType(const char *signature)
312 {
313     if (!signature)
314         return QVariant::Invalid;
315
316     QDBusMetaTypeId::init();
317     switch (signature[0])
318     {
319     case DBUS_TYPE_BOOLEAN:
320         return QVariant::Bool;
321
322     case DBUS_TYPE_BYTE:
323         return QMetaType::UChar;
324
325     case DBUS_TYPE_INT16:
326         return QMetaType::Short;
327
328     case DBUS_TYPE_UINT16:
329         return QMetaType::UShort;
330         
331     case DBUS_TYPE_INT32:
332         return QVariant::Int;
333         
334     case DBUS_TYPE_UINT32:
335         return QVariant::UInt;
336
337     case DBUS_TYPE_INT64:
338         return QVariant::LongLong;
339
340     case DBUS_TYPE_UINT64:
341         return QVariant::ULongLong;
342
343     case DBUS_TYPE_DOUBLE:
344         return QVariant::Double;
345
346     case DBUS_TYPE_STRING:
347         return QVariant::String;
348
349     case DBUS_TYPE_OBJECT_PATH:
350         return QDBusMetaTypeId::objectpath;
351
352     case DBUS_TYPE_SIGNATURE:
353         return QDBusMetaTypeId::signature;
354
355     case DBUS_TYPE_UNIX_FD:
356         return QDBusMetaTypeId::unixfd;
357
358     case DBUS_TYPE_VARIANT:
359         return QDBusMetaTypeId::variant;
360
361     case DBUS_TYPE_ARRAY:       // special case
362         switch (signature[1]) {
363         case DBUS_TYPE_BYTE:
364             return QVariant::ByteArray;
365
366         case DBUS_TYPE_STRING:
367             return QVariant::StringList;
368
369         case DBUS_TYPE_VARIANT:
370             return QVariant::List;
371
372         case DBUS_TYPE_OBJECT_PATH:
373             return qMetaTypeId<QList<QDBusObjectPath> >();
374
375         case DBUS_TYPE_SIGNATURE:
376             return qMetaTypeId<QList<QDBusSignature> >();
377
378         }
379         // fall through
380     default:
381         return QVariant::Invalid;
382     }
383 }
384
385 /*!
386     \fn QDBusMetaType::typeToSignature(int type)
387     \internal 
388
389     Returns the D-Bus signature equivalent to the supplied meta type id \a type.
390
391     More types can be registered with the qDBusRegisterMetaType() function.
392
393     \sa QDBusUtil::isValidSingleSignature(), signatureToType(),
394         QVariant::type(), QVariant::userType()
395 */
396 const char *QDBusMetaType::typeToSignature(int type)
397 {
398     // check if it's a static type
399     switch (type)
400     {
401     case QMetaType::UChar:
402         return DBUS_TYPE_BYTE_AS_STRING;
403
404     case QVariant::Bool:
405         return DBUS_TYPE_BOOLEAN_AS_STRING;
406
407     case QMetaType::Short:
408         return DBUS_TYPE_INT16_AS_STRING;
409
410     case QMetaType::UShort:
411         return DBUS_TYPE_UINT16_AS_STRING;
412
413     case QVariant::Int:
414         return DBUS_TYPE_INT32_AS_STRING;
415
416     case QVariant::UInt:
417         return DBUS_TYPE_UINT32_AS_STRING;
418
419     case QVariant::LongLong:
420         return DBUS_TYPE_INT64_AS_STRING;
421
422     case QVariant::ULongLong:
423         return DBUS_TYPE_UINT64_AS_STRING;
424
425     case QVariant::Double:
426         return DBUS_TYPE_DOUBLE_AS_STRING;
427
428     case QVariant::String:
429         return DBUS_TYPE_STRING_AS_STRING;
430
431     case QVariant::StringList:
432         return DBUS_TYPE_ARRAY_AS_STRING
433             DBUS_TYPE_STRING_AS_STRING; // as
434
435     case QVariant::ByteArray:
436         return DBUS_TYPE_ARRAY_AS_STRING
437             DBUS_TYPE_BYTE_AS_STRING; // ay
438     }
439
440     QDBusMetaTypeId::init();
441     if (type == QDBusMetaTypeId::variant)
442         return DBUS_TYPE_VARIANT_AS_STRING;
443     else if (type == QDBusMetaTypeId::objectpath)
444         return DBUS_TYPE_OBJECT_PATH_AS_STRING;
445     else if (type == QDBusMetaTypeId::signature)
446         return DBUS_TYPE_SIGNATURE_AS_STRING;
447     else if (type == QDBusMetaTypeId::unixfd)
448         return DBUS_TYPE_UNIX_FD_AS_STRING;
449
450     // try the database
451     QVector<QDBusCustomTypeInfo> *ct = customTypes();
452     {
453         QReadLocker locker(customTypesLock());
454         if (type >= ct->size())
455             return 0;           // type not registered with us
456
457         const QDBusCustomTypeInfo &info = (*ct).at(type);
458
459         if (!info.signature.isNull())
460             return info.signature;
461
462         if (!info.marshall)
463             return 0;           // type not registered with us
464     }
465
466     // call to user code to construct the signature type
467     QDBusCustomTypeInfo *info;
468     {
469         // createSignature will never return a null QByteArray
470         // if there was an error, it'll return ""
471         QByteArray signature = QDBusArgumentPrivate::createSignature(type);
472
473         // re-acquire lock
474         QWriteLocker locker(customTypesLock());
475         info = &(*ct)[type];
476         info->signature = signature;
477     }
478     return info->signature;
479 }
480
481 QT_END_NAMESPACE
482
483 #endif // QT_NO_DBUS