QDBusPendingCallPrivate: save 8 bytes on 64-bit archs
[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 #ifdef 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     \inmodule QtDBus
163     \brief Meta-type registration system for the QtDBus module.
164     \internal
165
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
171     registered.
172
173     See \l {qdbustypesystem.html}{QtDBus type system} for more
174     information on the type system and how to register additional
175     types.
176
177     \sa {qdbustypesystem.html}{QtDBus type system},
178     qDBusRegisterMetaType(), QMetaType, QVariant, QDBusArgument
179 */
180
181 /*!
182     \fn int qDBusRegisterMetaType()
183     \relates QDBusArgument
184     \threadsafe
185     \since 4.2
186
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.
190
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
193     following example:
194
195     \snippet code/src_qdbus_qdbusmetatype.cpp 0
196
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
202     types.
203
204     This function returns the Qt meta type id for the type (the same
205     value that is returned from qRegisterMetaType()).
206
207     \sa {qdbustypesystem.html}{QtDBus type system}, qRegisterMetaType(), QMetaType
208 */
209
210 /*!
211     \typedef QDBusMetaType::MarshallFunction
212     \internal
213 */
214
215 /*!
216     \typedef QDBusMetaType::DemarshallFunction
217     \internal
218 */
219
220 /*!
221     \internal
222     Registers the marshalling and demarshalling functions for meta
223     type \a id.
224 */
225 void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf,
226                                               DemarshallFunction df)
227 {
228     QByteArray var;
229     QVector<QDBusCustomTypeInfo> *ct = customTypes();
230     if (id < 0 || !mf || !df || !ct)
231         return;                 // error!
232
233     QWriteLocker locker(customTypesLock());
234     if (id >= ct->size())
235         ct->resize(id + 1);
236     QDBusCustomTypeInfo &info = (*ct)[id];
237     info.marshall = mf;
238     info.demarshall = df;
239 }
240
241 /*!
242     \internal
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.
246 */
247 bool QDBusMetaType::marshall(QDBusArgument &arg, int id, const void *data)
248 {
249     QDBusMetaTypeId::init();
250
251     MarshallFunction mf;
252     {
253         QReadLocker locker(customTypesLock());
254         QVector<QDBusCustomTypeInfo> *ct = customTypes();
255         if (id >= ct->size())
256             return false;       // non-existent
257
258         const QDBusCustomTypeInfo &info = (*ct).at(id);
259         if (!info.marshall) {
260             mf = 0;             // make gcc happy
261             return false;
262         } else
263             mf = info.marshall;
264     }
265
266     mf(arg, data);
267     return true;
268 }
269
270 /*!
271     \internal
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.
275 */
276 bool QDBusMetaType::demarshall(const QDBusArgument &arg, int id, void *data)
277 {
278     QDBusMetaTypeId::init();
279
280     DemarshallFunction df;
281     {
282         QReadLocker locker(customTypesLock());
283         QVector<QDBusCustomTypeInfo> *ct = customTypes();
284         if (id >= ct->size())
285             return false;       // non-existent
286
287         const QDBusCustomTypeInfo &info = (*ct).at(id);
288         if (!info.demarshall) {
289             df = 0;             // make gcc happy
290             return false;
291         } else
292             df = info.demarshall;
293     }
294 #ifndef QT_BOOTSTRAPPED
295     QDBusArgument copy = arg;
296     df(copy, data);
297 #else
298     Q_UNUSED(arg);
299     Q_UNUSED(data);
300     Q_UNUSED(df);
301 #endif
302     return true;
303 }
304
305 /*!
306     \fn QDBusMetaType::signatureToType(const char *signature)
307     \internal
308
309     Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
310     by \a signature.
311
312     Note: this function only handles the basic D-Bus types.
313
314     \sa QDBusUtil::isValidSingleSignature(), typeToSignature(),
315         QVariant::type(), QVariant::userType()
316 */
317 int QDBusMetaType::signatureToType(const char *signature)
318 {
319     if (!signature)
320         return QMetaType::UnknownType;
321
322     QDBusMetaTypeId::init();
323     switch (signature[0])
324     {
325     case DBUS_TYPE_BOOLEAN:
326         return QVariant::Bool;
327
328     case DBUS_TYPE_BYTE:
329         return QMetaType::UChar;
330
331     case DBUS_TYPE_INT16:
332         return QMetaType::Short;
333
334     case DBUS_TYPE_UINT16:
335         return QMetaType::UShort;
336         
337     case DBUS_TYPE_INT32:
338         return QVariant::Int;
339         
340     case DBUS_TYPE_UINT32:
341         return QVariant::UInt;
342
343     case DBUS_TYPE_INT64:
344         return QVariant::LongLong;
345
346     case DBUS_TYPE_UINT64:
347         return QVariant::ULongLong;
348
349     case DBUS_TYPE_DOUBLE:
350         return QVariant::Double;
351
352     case DBUS_TYPE_STRING:
353         return QVariant::String;
354
355     case DBUS_TYPE_OBJECT_PATH:
356         return QDBusMetaTypeId::objectpath;
357
358     case DBUS_TYPE_SIGNATURE:
359         return QDBusMetaTypeId::signature;
360
361     case DBUS_TYPE_UNIX_FD:
362         return QDBusMetaTypeId::unixfd;
363
364     case DBUS_TYPE_VARIANT:
365         return QDBusMetaTypeId::variant;
366
367     case DBUS_TYPE_ARRAY:       // special case
368         switch (signature[1]) {
369         case DBUS_TYPE_BYTE:
370             return QVariant::ByteArray;
371
372         case DBUS_TYPE_STRING:
373             return QVariant::StringList;
374
375         case DBUS_TYPE_VARIANT:
376             return QVariant::List;
377
378         case DBUS_TYPE_OBJECT_PATH:
379             return qMetaTypeId<QList<QDBusObjectPath> >();
380
381         case DBUS_TYPE_SIGNATURE:
382             return qMetaTypeId<QList<QDBusSignature> >();
383
384         }
385         // fall through
386     default:
387         return QMetaType::UnknownType;
388     }
389 }
390
391 /*!
392     \fn QDBusMetaType::typeToSignature(int type)
393     \internal 
394
395     Returns the D-Bus signature equivalent to the supplied meta type id \a type.
396
397     More types can be registered with the qDBusRegisterMetaType() function.
398
399     \sa QDBusUtil::isValidSingleSignature(), signatureToType(),
400         QVariant::type(), QVariant::userType()
401 */
402 const char *QDBusMetaType::typeToSignature(int type)
403 {
404     // check if it's a static type
405     switch (type)
406     {
407     case QMetaType::UChar:
408         return DBUS_TYPE_BYTE_AS_STRING;
409
410     case QVariant::Bool:
411         return DBUS_TYPE_BOOLEAN_AS_STRING;
412
413     case QMetaType::Short:
414         return DBUS_TYPE_INT16_AS_STRING;
415
416     case QMetaType::UShort:
417         return DBUS_TYPE_UINT16_AS_STRING;
418
419     case QVariant::Int:
420         return DBUS_TYPE_INT32_AS_STRING;
421
422     case QVariant::UInt:
423         return DBUS_TYPE_UINT32_AS_STRING;
424
425     case QVariant::LongLong:
426         return DBUS_TYPE_INT64_AS_STRING;
427
428     case QVariant::ULongLong:
429         return DBUS_TYPE_UINT64_AS_STRING;
430
431     case QVariant::Double:
432         return DBUS_TYPE_DOUBLE_AS_STRING;
433
434     case QVariant::String:
435         return DBUS_TYPE_STRING_AS_STRING;
436
437     case QVariant::StringList:
438         return DBUS_TYPE_ARRAY_AS_STRING
439             DBUS_TYPE_STRING_AS_STRING; // as
440
441     case QVariant::ByteArray:
442         return DBUS_TYPE_ARRAY_AS_STRING
443             DBUS_TYPE_BYTE_AS_STRING; // ay
444     }
445
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;
455
456     // try the database
457     QVector<QDBusCustomTypeInfo> *ct = customTypes();
458     {
459         QReadLocker locker(customTypesLock());
460         if (type >= ct->size())
461             return 0;           // type not registered with us
462
463         const QDBusCustomTypeInfo &info = (*ct).at(type);
464
465         if (!info.signature.isNull())
466             return info.signature;
467
468         if (!info.marshall)
469             return 0;           // type not registered with us
470     }
471
472     // call to user code to construct the signature type
473     QDBusCustomTypeInfo *info;
474     {
475         // createSignature will never return a null QByteArray
476         // if there was an error, it'll return ""
477         QByteArray signature = QDBusArgumentPrivate::createSignature(type);
478
479         // re-acquire lock
480         QWriteLocker locker(customTypesLock());
481         info = &(*ct)[type];
482         info->signature = signature;
483     }
484     return info->signature;
485 }
486
487 QT_END_NAMESPACE
488
489 #endif // QT_NO_DBUS