Merge remote-tracking branch 'origin/api_changes'
[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 Q_DECLARE_METATYPE(QList<bool>)
68 Q_DECLARE_METATYPE(QList<short>)
69 Q_DECLARE_METATYPE(QList<ushort>)
70 Q_DECLARE_METATYPE(QList<int>)
71 Q_DECLARE_METATYPE(QList<uint>)
72 Q_DECLARE_METATYPE(QList<qlonglong>)
73 Q_DECLARE_METATYPE(QList<qulonglong>)
74 Q_DECLARE_METATYPE(QList<double>)
75
76 QT_BEGIN_NAMESPACE
77
78 class QDBusCustomTypeInfo
79 {
80 public:
81     QDBusCustomTypeInfo() : signature(), marshall(0), demarshall(0)
82     { }
83
84     // Suggestion:
85     // change 'signature' to char* and make QDBusCustomTypeInfo a Movable type
86     QByteArray signature;
87     QDBusMetaType::MarshallFunction marshall;
88     QDBusMetaType::DemarshallFunction demarshall;
89 };
90
91 template<typename T>
92 inline static void registerHelper(T * = 0)
93 {
94     void (*mf)(QDBusArgument &, const T *) = qDBusMarshallHelper<T>;
95     void (*df)(const QDBusArgument &, T *) = qDBusDemarshallHelper<T>;
96     QDBusMetaType::registerMarshallOperators(qMetaTypeId<T>(),
97         reinterpret_cast<QDBusMetaType::MarshallFunction>(mf),
98         reinterpret_cast<QDBusMetaType::DemarshallFunction>(df));
99 }
100
101 int QDBusMetaTypeId::message;
102 int QDBusMetaTypeId::argument;
103 int QDBusMetaTypeId::variant;
104 int QDBusMetaTypeId::objectpath;
105 int QDBusMetaTypeId::signature;
106 int QDBusMetaTypeId::error;
107 int QDBusMetaTypeId::unixfd;
108
109 void QDBusMetaTypeId::init()
110 {
111     static volatile bool initialized = false;
112
113     // reentrancy is not a problem since everything else is locked on their own
114     // set the guard variable at the end
115     if (!initialized) {
116 #ifndef QT_BOOTSTRAPPED
117         // register our types with QtCore
118         message = qRegisterMetaType<QDBusMessage>("QDBusMessage");
119         error = qRegisterMetaType<QDBusError>("QDBusError");
120 #endif
121         argument = qRegisterMetaType<QDBusArgument>("QDBusArgument");
122         variant = qRegisterMetaType<QDBusVariant>("QDBusVariant");
123         objectpath = qRegisterMetaType<QDBusObjectPath>("QDBusObjectPath");
124         signature = qRegisterMetaType<QDBusSignature>("QDBusSignature");
125         unixfd = qRegisterMetaType<QDBusUnixFileDescriptor>("QDBusUnixFileDescriptor");
126
127 #ifndef QDBUS_NO_SPECIALTYPES
128         // and register QtCore's with us
129         registerHelper<QDate>();
130         registerHelper<QTime>();
131         registerHelper<QDateTime>();
132         registerHelper<QRect>();
133         registerHelper<QRectF>();
134         registerHelper<QSize>();
135         registerHelper<QSizeF>();
136         registerHelper<QPoint>();
137         registerHelper<QPointF>();
138         registerHelper<QLine>();
139         registerHelper<QLineF>();
140         registerHelper<QVariantList>();
141         registerHelper<QVariantMap>();
142         registerHelper<QVariantHash>();
143
144         qDBusRegisterMetaType<QList<bool> >();
145         qDBusRegisterMetaType<QList<short> >();
146         qDBusRegisterMetaType<QList<ushort> >();
147         qDBusRegisterMetaType<QList<int> >();
148         qDBusRegisterMetaType<QList<uint> >();
149         qDBusRegisterMetaType<QList<qlonglong> >();
150         qDBusRegisterMetaType<QList<qulonglong> >();
151         qDBusRegisterMetaType<QList<double> >();
152         qDBusRegisterMetaType<QList<QDBusObjectPath> >();
153         qDBusRegisterMetaType<QList<QDBusSignature> >();
154         qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
155 #endif
156
157 #if QT_BOOTSTRAPPED
158         const int lastId = qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
159         message = lastId + 1;
160         error = lastId + 2;
161 #endif
162         initialized = true;
163     }
164 }
165
166 Q_GLOBAL_STATIC(QVector<QDBusCustomTypeInfo>, customTypes)
167 Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
168
169 /*!
170     \class QDBusMetaType
171     \brief Meta-type registration system for the QtDBus module.
172     \internal
173
174     The QDBusMetaType class allows you to register class types for
175     marshalling and demarshalling over D-Bus. D-Bus supports a very
176     limited set of primitive types, but allows one to extend the type
177     system by creating compound types, such as arrays (lists) and
178     structs. In order to use them with QtDBus, those types must be
179     registered.
180
181     See \l {qdbustypesystem.html}{QtDBus type system} for more
182     information on the type system and how to register additional
183     types.
184
185     \sa {qdbustypesystem.html}{QtDBus type system},
186     qDBusRegisterMetaType(), QMetaType, QVariant, QDBusArgument
187 */
188
189 /*!
190     \fn int qDBusRegisterMetaType()
191     \relates QDBusArgument
192     \threadsafe
193     \since 4.2
194
195     Registers \c{T} with the
196     \l {qdbustypesystem.html}{QtDBus type system} and the Qt \l
197     {QMetaType}{meta-type system}, if it's not already registered.
198
199     To register a type, it must be declared as a meta-type with the
200     Q_DECLARE_METATYPE() macro, and then registered as in the
201     following example:
202
203     \snippet doc/src/snippets/code/src_qdbus_qdbusmetatype.cpp 0
204
205     If \c{T} isn't a type derived from one of
206     Qt's \l{container classes}, the \c{operator<<} and
207     \c{operator>>} streaming operators between \c{T} and QDBusArgument
208     must be already declared. See the \l {qdbustypesystem.html}{QtDBus
209     type system} page for more information on how to declare such
210     types.
211
212     This function returns the Qt meta type id for the type (the same
213     value that is returned from qRegisterMetaType()).
214
215     \sa {qdbustypesystem.html}{QtDBus type system}, qRegisterMetaType(), QMetaType
216 */
217
218 /*!
219     \typedef QDBusMetaType::MarshallFunction
220     \internal
221 */
222
223 /*!
224     \typedef QDBusMetaType::DemarshallFunction
225     \internal
226 */
227
228 /*!
229     \internal
230     Registers the marshalling and demarshalling functions for meta
231     type \a id.
232 */
233 void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf,
234                                               DemarshallFunction df)
235 {
236     QByteArray var;
237     QVector<QDBusCustomTypeInfo> *ct = customTypes();
238     if (id < 0 || !mf || !df || !ct)
239         return;                 // error!
240
241     QWriteLocker locker(customTypesLock());
242     if (id >= ct->size())
243         ct->resize(id + 1);
244     QDBusCustomTypeInfo &info = (*ct)[id];
245     info.marshall = mf;
246     info.demarshall = df;
247 }
248
249 /*!
250     \internal
251     Executes the marshalling of type \a id (whose data is contained in
252     \a data) to the D-Bus marshalling argument \a arg. Returns true if
253     the marshalling succeeded, or false if an error occurred.
254 */
255 bool QDBusMetaType::marshall(QDBusArgument &arg, int id, const void *data)
256 {
257     QDBusMetaTypeId::init();
258
259     MarshallFunction mf;
260     {
261         QReadLocker locker(customTypesLock());
262         QVector<QDBusCustomTypeInfo> *ct = customTypes();
263         if (id >= ct->size())
264             return false;       // non-existent
265
266         const QDBusCustomTypeInfo &info = (*ct).at(id);
267         if (!info.marshall) {
268             mf = 0;             // make gcc happy
269             return false;
270         } else
271             mf = info.marshall;
272     }
273
274     mf(arg, data);
275     return true;
276 }
277
278 /*!
279     \internal
280     Executes the demarshalling of type \a id (whose data will be placed in
281     \a data) from the D-Bus marshalling argument \a arg. Returns true if
282     the demarshalling succeeded, or false if an error occurred.
283 */
284 bool QDBusMetaType::demarshall(const QDBusArgument &arg, int id, void *data)
285 {
286     QDBusMetaTypeId::init();
287
288     DemarshallFunction df;
289     {
290         QReadLocker locker(customTypesLock());
291         QVector<QDBusCustomTypeInfo> *ct = customTypes();
292         if (id >= ct->size())
293             return false;       // non-existent
294
295         const QDBusCustomTypeInfo &info = (*ct).at(id);
296         if (!info.demarshall) {
297             df = 0;             // make gcc happy
298             return false;
299         } else
300             df = info.demarshall;
301     }
302 #ifndef QT_BOOTSTRAPPED
303     QDBusArgument copy = arg;
304     df(copy, data);
305 #else
306     Q_UNUSED(arg);
307     Q_UNUSED(data);
308     Q_UNUSED(df);
309 #endif
310     return true;
311 }
312
313 /*!
314     \fn QDBusMetaType::signatureToType(const char *signature)
315     \internal
316
317     Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
318     by \a signature.
319
320     Note: this function only handles the basic D-Bus types.
321
322     \sa QDBusUtil::isValidSingleSignature(), typeToSignature(),
323         QVariant::type(), QVariant::userType()
324 */
325 int QDBusMetaType::signatureToType(const char *signature)
326 {
327     if (!signature)
328         return QMetaType::UnknownType;
329
330     QDBusMetaTypeId::init();
331     switch (signature[0])
332     {
333     case DBUS_TYPE_BOOLEAN:
334         return QVariant::Bool;
335
336     case DBUS_TYPE_BYTE:
337         return QMetaType::UChar;
338
339     case DBUS_TYPE_INT16:
340         return QMetaType::Short;
341
342     case DBUS_TYPE_UINT16:
343         return QMetaType::UShort;
344         
345     case DBUS_TYPE_INT32:
346         return QVariant::Int;
347         
348     case DBUS_TYPE_UINT32:
349         return QVariant::UInt;
350
351     case DBUS_TYPE_INT64:
352         return QVariant::LongLong;
353
354     case DBUS_TYPE_UINT64:
355         return QVariant::ULongLong;
356
357     case DBUS_TYPE_DOUBLE:
358         return QVariant::Double;
359
360     case DBUS_TYPE_STRING:
361         return QVariant::String;
362
363     case DBUS_TYPE_OBJECT_PATH:
364         return QDBusMetaTypeId::objectpath;
365
366     case DBUS_TYPE_SIGNATURE:
367         return QDBusMetaTypeId::signature;
368
369     case DBUS_TYPE_UNIX_FD:
370         return QDBusMetaTypeId::unixfd;
371
372     case DBUS_TYPE_VARIANT:
373         return QDBusMetaTypeId::variant;
374
375     case DBUS_TYPE_ARRAY:       // special case
376         switch (signature[1]) {
377         case DBUS_TYPE_BYTE:
378             return QVariant::ByteArray;
379
380         case DBUS_TYPE_STRING:
381             return QVariant::StringList;
382
383         case DBUS_TYPE_VARIANT:
384             return QVariant::List;
385
386         case DBUS_TYPE_OBJECT_PATH:
387             return qMetaTypeId<QList<QDBusObjectPath> >();
388
389         case DBUS_TYPE_SIGNATURE:
390             return qMetaTypeId<QList<QDBusSignature> >();
391
392         }
393         // fall through
394     default:
395         return QMetaType::UnknownType;
396     }
397 }
398
399 /*!
400     \fn QDBusMetaType::typeToSignature(int type)
401     \internal 
402
403     Returns the D-Bus signature equivalent to the supplied meta type id \a type.
404
405     More types can be registered with the qDBusRegisterMetaType() function.
406
407     \sa QDBusUtil::isValidSingleSignature(), signatureToType(),
408         QVariant::type(), QVariant::userType()
409 */
410 const char *QDBusMetaType::typeToSignature(int type)
411 {
412     // check if it's a static type
413     switch (type)
414     {
415     case QMetaType::UChar:
416         return DBUS_TYPE_BYTE_AS_STRING;
417
418     case QVariant::Bool:
419         return DBUS_TYPE_BOOLEAN_AS_STRING;
420
421     case QMetaType::Short:
422         return DBUS_TYPE_INT16_AS_STRING;
423
424     case QMetaType::UShort:
425         return DBUS_TYPE_UINT16_AS_STRING;
426
427     case QVariant::Int:
428         return DBUS_TYPE_INT32_AS_STRING;
429
430     case QVariant::UInt:
431         return DBUS_TYPE_UINT32_AS_STRING;
432
433     case QVariant::LongLong:
434         return DBUS_TYPE_INT64_AS_STRING;
435
436     case QVariant::ULongLong:
437         return DBUS_TYPE_UINT64_AS_STRING;
438
439     case QVariant::Double:
440         return DBUS_TYPE_DOUBLE_AS_STRING;
441
442     case QVariant::String:
443         return DBUS_TYPE_STRING_AS_STRING;
444
445     case QVariant::StringList:
446         return DBUS_TYPE_ARRAY_AS_STRING
447             DBUS_TYPE_STRING_AS_STRING; // as
448
449     case QVariant::ByteArray:
450         return DBUS_TYPE_ARRAY_AS_STRING
451             DBUS_TYPE_BYTE_AS_STRING; // ay
452     }
453
454     QDBusMetaTypeId::init();
455     if (type == QDBusMetaTypeId::variant)
456         return DBUS_TYPE_VARIANT_AS_STRING;
457     else if (type == QDBusMetaTypeId::objectpath)
458         return DBUS_TYPE_OBJECT_PATH_AS_STRING;
459     else if (type == QDBusMetaTypeId::signature)
460         return DBUS_TYPE_SIGNATURE_AS_STRING;
461     else if (type == QDBusMetaTypeId::unixfd)
462         return DBUS_TYPE_UNIX_FD_AS_STRING;
463
464     // try the database
465     QVector<QDBusCustomTypeInfo> *ct = customTypes();
466     {
467         QReadLocker locker(customTypesLock());
468         if (type >= ct->size())
469             return 0;           // type not registered with us
470
471         const QDBusCustomTypeInfo &info = (*ct).at(type);
472
473         if (!info.signature.isNull())
474             return info.signature;
475
476         if (!info.marshall)
477             return 0;           // type not registered with us
478     }
479
480     // call to user code to construct the signature type
481     QDBusCustomTypeInfo *info;
482     {
483         // createSignature will never return a null QByteArray
484         // if there was an error, it'll return ""
485         QByteArray signature = QDBusArgumentPrivate::createSignature(type);
486
487         // re-acquire lock
488         QWriteLocker locker(customTypesLock());
489         info = &(*ct)[type];
490         info->signature = signature;
491     }
492     return info->signature;
493 }
494
495 QT_END_NAMESPACE
496
497 #endif // QT_NO_DBUS