1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtDBus module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
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
65Q_DECLARE_METATYPE(QList<bool>)
66Q_DECLARE_METATYPE(QList<short>)
67Q_DECLARE_METATYPE(QList<ushort>)
68Q_DECLARE_METATYPE(QList<int>)
69Q_DECLARE_METATYPE(QList<uint>)
70Q_DECLARE_METATYPE(QList<qlonglong>)
71Q_DECLARE_METATYPE(QList<qulonglong>)
72Q_DECLARE_METATYPE(QList<double>)
73
74QT_BEGIN_NAMESPACE
75
76class QDBusCustomTypeInfo
77{
78public:
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
89template<typename T>
90inline 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
99int QDBusMetaTypeId::message;
100int QDBusMetaTypeId::argument;
101int QDBusMetaTypeId::variant;
102int QDBusMetaTypeId::objectpath;
103int QDBusMetaTypeId::signature;
104int QDBusMetaTypeId::error;
105int QDBusMetaTypeId::unixfd;
106
107void 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
157Q_GLOBAL_STATIC(QVector<QDBusCustomTypeInfo>, customTypes)
158Q_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*/
224void 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*/
246bool 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*/
275bool 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*/
311int 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*/
396const 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
481QT_END_NAMESPACE
482
483#endif // QT_NO_DBUS
484