1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the QtDBus module of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at [email protected].
|
---|
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 "qdbusutil_p.h"
|
---|
54 | #include "qdbusmetatype_p.h"
|
---|
55 | #include "qdbusargument_p.h"
|
---|
56 |
|
---|
57 | #ifndef QT_NO_DBUS
|
---|
58 |
|
---|
59 | Q_DECLARE_METATYPE(QList<bool>)
|
---|
60 | Q_DECLARE_METATYPE(QList<short>)
|
---|
61 | Q_DECLARE_METATYPE(QList<ushort>)
|
---|
62 | Q_DECLARE_METATYPE(QList<int>)
|
---|
63 | Q_DECLARE_METATYPE(QList<uint>)
|
---|
64 | Q_DECLARE_METATYPE(QList<qlonglong>)
|
---|
65 | Q_DECLARE_METATYPE(QList<qulonglong>)
|
---|
66 | Q_DECLARE_METATYPE(QList<double>)
|
---|
67 |
|
---|
68 | QT_BEGIN_NAMESPACE
|
---|
69 |
|
---|
70 | class QDBusCustomTypeInfo
|
---|
71 | {
|
---|
72 | public:
|
---|
73 | QDBusCustomTypeInfo() : signature(0, '\0'), marshall(0), demarshall(0)
|
---|
74 | { }
|
---|
75 |
|
---|
76 | // Suggestion:
|
---|
77 | // change 'signature' to char* and make QDBusCustomTypeInfo a Movable type
|
---|
78 | QByteArray signature;
|
---|
79 | QDBusMetaType::MarshallFunction marshall;
|
---|
80 | QDBusMetaType::DemarshallFunction demarshall;
|
---|
81 | };
|
---|
82 |
|
---|
83 | template<typename T>
|
---|
84 | inline static void registerHelper(T * = 0)
|
---|
85 | {
|
---|
86 | void (*mf)(QDBusArgument &, const T *) = qDBusMarshallHelper<T>;
|
---|
87 | void (*df)(const QDBusArgument &, T *) = qDBusDemarshallHelper<T>;
|
---|
88 | QDBusMetaType::registerMarshallOperators(qMetaTypeId<T>(),
|
---|
89 | reinterpret_cast<QDBusMetaType::MarshallFunction>(mf),
|
---|
90 | reinterpret_cast<QDBusMetaType::DemarshallFunction>(df));
|
---|
91 | }
|
---|
92 |
|
---|
93 | int QDBusMetaTypeId::message;
|
---|
94 | int QDBusMetaTypeId::argument;
|
---|
95 | int QDBusMetaTypeId::variant;
|
---|
96 | int QDBusMetaTypeId::objectpath;
|
---|
97 | int QDBusMetaTypeId::signature;
|
---|
98 | int QDBusMetaTypeId::error;
|
---|
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 | // register our types with QtCore
|
---|
108 | message = qRegisterMetaType<QDBusMessage>("QDBusMessage");
|
---|
109 | argument = qRegisterMetaType<QDBusArgument>("QDBusArgument");
|
---|
110 | variant = qRegisterMetaType<QDBusVariant>("QDBusVariant");
|
---|
111 | objectpath = qRegisterMetaType<QDBusObjectPath>("QDBusObjectPath");
|
---|
112 | signature = qRegisterMetaType<QDBusSignature>("QDBusSignature");
|
---|
113 | error = qRegisterMetaType<QDBusError>("QDBusError");
|
---|
114 |
|
---|
115 | #ifndef QDBUS_NO_SPECIALTYPES
|
---|
116 | // and register QtCore's with us
|
---|
117 | registerHelper<QDate>();
|
---|
118 | registerHelper<QTime>();
|
---|
119 | registerHelper<QDateTime>();
|
---|
120 | registerHelper<QRect>();
|
---|
121 | registerHelper<QRectF>();
|
---|
122 | registerHelper<QSize>();
|
---|
123 | registerHelper<QSizeF>();
|
---|
124 | registerHelper<QPoint>();
|
---|
125 | registerHelper<QPointF>();
|
---|
126 | registerHelper<QLine>();
|
---|
127 | registerHelper<QLineF>();
|
---|
128 | registerHelper<QVariantList>();
|
---|
129 | registerHelper<QVariantMap>();
|
---|
130 |
|
---|
131 | qDBusRegisterMetaType<QList<bool> >();
|
---|
132 | qDBusRegisterMetaType<QList<short> >();
|
---|
133 | qDBusRegisterMetaType<QList<ushort> >();
|
---|
134 | qDBusRegisterMetaType<QList<int> >();
|
---|
135 | qDBusRegisterMetaType<QList<uint> >();
|
---|
136 | qDBusRegisterMetaType<QList<qlonglong> >();
|
---|
137 | qDBusRegisterMetaType<QList<qulonglong> >();
|
---|
138 | qDBusRegisterMetaType<QList<double> >();
|
---|
139 | qDBusRegisterMetaType<QList<QDBusObjectPath> >();
|
---|
140 | qDBusRegisterMetaType<QList<QDBusSignature> >();
|
---|
141 | #endif
|
---|
142 |
|
---|
143 | initialized = true;
|
---|
144 | }
|
---|
145 | }
|
---|
146 |
|
---|
147 | Q_GLOBAL_STATIC(QVector<QDBusCustomTypeInfo>, customTypes)
|
---|
148 | Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
|
---|
149 |
|
---|
150 | /*!
|
---|
151 | \class QDBusMetaType
|
---|
152 | \brief Meta-type registration system for the QtDBus module.
|
---|
153 | \internal
|
---|
154 |
|
---|
155 | The QDBusMetaType class allows you to register class types for
|
---|
156 | marshalling and demarshalling over D-Bus. D-Bus supports a very
|
---|
157 | limited set of primitive types, but allows one to extend the type
|
---|
158 | system by creating compound types, such as arrays (lists) and
|
---|
159 | structs. In order to use them with QtDBus, those types must be
|
---|
160 | registered.
|
---|
161 |
|
---|
162 | See \l {qdbustypesystem.html}{QtDBus type system} for more
|
---|
163 | information on the type system and how to register additional
|
---|
164 | types.
|
---|
165 |
|
---|
166 | \sa {qdbustypesystem.html}{QtDBus type system},
|
---|
167 | qDBusRegisterMetaType(), QMetaType, QVariant, QDBusArgument
|
---|
168 | */
|
---|
169 |
|
---|
170 | /*!
|
---|
171 | \fn int qDBusRegisterMetaType()
|
---|
172 | \relates QDBusArgument
|
---|
173 | \threadsafe
|
---|
174 | \since 4.2
|
---|
175 |
|
---|
176 | Registers \c{T} with the
|
---|
177 | \l {qdbustypesystem.html}{QtDBus type system} and the Qt \l
|
---|
178 | {QMetaType}{meta-type system}, if it's not already registered.
|
---|
179 |
|
---|
180 | To register a type, it must be declared as a meta-type with the
|
---|
181 | Q_DECLARE_METATYPE() macro, and then registered as in the
|
---|
182 | following example:
|
---|
183 |
|
---|
184 | \snippet doc/src/snippets/code/src_qdbus_qdbusmetatype.cpp 0
|
---|
185 |
|
---|
186 | If \c{T} isn't a type derived from one of
|
---|
187 | Qt's \l{container classes}, the \c{operator<<} and
|
---|
188 | \c{operator>>} streaming operators between \c{T} and QDBusArgument
|
---|
189 | must be already declared. See the \l {qdbustypesystem.html}{QtDBus
|
---|
190 | type system} page for more information on how to declare such
|
---|
191 | types.
|
---|
192 |
|
---|
193 | This function returns the Qt meta type id for the type (the same
|
---|
194 | value that is returned from qRegisterMetaType()).
|
---|
195 |
|
---|
196 | \sa {qdbustypesystem.html}{QtDBus type system}, qRegisterMetaType(), QMetaType
|
---|
197 | */
|
---|
198 |
|
---|
199 | /*!
|
---|
200 | \typedef QDBusMetaType::MarshallFunction
|
---|
201 | \internal
|
---|
202 | */
|
---|
203 |
|
---|
204 | /*!
|
---|
205 | \typedef QDBusMetaType::DemarshallFunction
|
---|
206 | \internal
|
---|
207 | */
|
---|
208 |
|
---|
209 | /*!
|
---|
210 | \internal
|
---|
211 | Registers the marshalling and demarshalling functions for meta
|
---|
212 | type \a id.
|
---|
213 | */
|
---|
214 | void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf,
|
---|
215 | DemarshallFunction df)
|
---|
216 | {
|
---|
217 | QByteArray var;
|
---|
218 | QVector<QDBusCustomTypeInfo> *ct = customTypes();
|
---|
219 | if (id < 0 || !mf || !df || !ct)
|
---|
220 | return; // error!
|
---|
221 |
|
---|
222 | QWriteLocker locker(customTypesLock());
|
---|
223 | if (id >= ct->size())
|
---|
224 | ct->resize(id + 1);
|
---|
225 | QDBusCustomTypeInfo &info = (*ct)[id];
|
---|
226 | info.marshall = mf;
|
---|
227 | info.demarshall = df;
|
---|
228 | }
|
---|
229 |
|
---|
230 | /*!
|
---|
231 | \internal
|
---|
232 | Executes the marshalling of type \a id (whose data is contained in
|
---|
233 | \a data) to the D-Bus marshalling argument \a arg. Returns true if
|
---|
234 | the marshalling succeeded, or false if an error occurred.
|
---|
235 | */
|
---|
236 | bool QDBusMetaType::marshall(QDBusArgument &arg, int id, const void *data)
|
---|
237 | {
|
---|
238 | QDBusMetaTypeId::init();
|
---|
239 |
|
---|
240 | MarshallFunction mf;
|
---|
241 | {
|
---|
242 | QReadLocker locker(customTypesLock());
|
---|
243 | QVector<QDBusCustomTypeInfo> *ct = customTypes();
|
---|
244 | if (id >= ct->size())
|
---|
245 | return false; // non-existent
|
---|
246 |
|
---|
247 | const QDBusCustomTypeInfo &info = (*ct).at(id);
|
---|
248 | if (!info.marshall) {
|
---|
249 | mf = 0; // make gcc happy
|
---|
250 | return false;
|
---|
251 | } else
|
---|
252 | mf = info.marshall;
|
---|
253 | }
|
---|
254 |
|
---|
255 | mf(arg, data);
|
---|
256 | return true;
|
---|
257 | }
|
---|
258 |
|
---|
259 | /*!
|
---|
260 | \internal
|
---|
261 | Executes the demarshalling of type \a id (whose data will be placed in
|
---|
262 | \a data) from the D-Bus marshalling argument \a arg. Returns true if
|
---|
263 | the demarshalling succeeded, or false if an error occurred.
|
---|
264 | */
|
---|
265 | bool QDBusMetaType::demarshall(const QDBusArgument &arg, int id, void *data)
|
---|
266 | {
|
---|
267 | QDBusMetaTypeId::init();
|
---|
268 |
|
---|
269 | DemarshallFunction df;
|
---|
270 | {
|
---|
271 | QReadLocker locker(customTypesLock());
|
---|
272 | QVector<QDBusCustomTypeInfo> *ct = customTypes();
|
---|
273 | if (id >= ct->size())
|
---|
274 | return false; // non-existent
|
---|
275 |
|
---|
276 | const QDBusCustomTypeInfo &info = (*ct).at(id);
|
---|
277 | if (!info.demarshall) {
|
---|
278 | df = 0; // make gcc happy
|
---|
279 | return false;
|
---|
280 | } else
|
---|
281 | df = info.demarshall;
|
---|
282 | }
|
---|
283 |
|
---|
284 | QDBusArgument copy = arg;
|
---|
285 | df(copy, data);
|
---|
286 | return true;
|
---|
287 | }
|
---|
288 |
|
---|
289 | /*!
|
---|
290 | \fn QDBusMetaType::signatureToType(const char *signature)
|
---|
291 | \internal
|
---|
292 |
|
---|
293 | Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
|
---|
294 | by \a signature.
|
---|
295 |
|
---|
296 | Note: this function only handles the basic D-Bus types.
|
---|
297 |
|
---|
298 | \sa QDBusUtil::isValidSingleSignature(), typeToSignature(),
|
---|
299 | QVariant::type(), QVariant::userType()
|
---|
300 | */
|
---|
301 | int QDBusMetaType::signatureToType(const char *signature)
|
---|
302 | {
|
---|
303 | if (!signature)
|
---|
304 | return QVariant::Invalid;
|
---|
305 |
|
---|
306 | QDBusMetaTypeId::init();
|
---|
307 | switch (signature[0])
|
---|
308 | {
|
---|
309 | case DBUS_TYPE_BOOLEAN:
|
---|
310 | return QVariant::Bool;
|
---|
311 |
|
---|
312 | case DBUS_TYPE_BYTE:
|
---|
313 | return QMetaType::UChar;
|
---|
314 |
|
---|
315 | case DBUS_TYPE_INT16:
|
---|
316 | return QMetaType::Short;
|
---|
317 |
|
---|
318 | case DBUS_TYPE_UINT16:
|
---|
319 | return QMetaType::UShort;
|
---|
320 |
|
---|
321 | case DBUS_TYPE_INT32:
|
---|
322 | return QVariant::Int;
|
---|
323 |
|
---|
324 | case DBUS_TYPE_UINT32:
|
---|
325 | return QVariant::UInt;
|
---|
326 |
|
---|
327 | case DBUS_TYPE_INT64:
|
---|
328 | return QVariant::LongLong;
|
---|
329 |
|
---|
330 | case DBUS_TYPE_UINT64:
|
---|
331 | return QVariant::ULongLong;
|
---|
332 |
|
---|
333 | case DBUS_TYPE_DOUBLE:
|
---|
334 | return QVariant::Double;
|
---|
335 |
|
---|
336 | case DBUS_TYPE_STRING:
|
---|
337 | return QVariant::String;
|
---|
338 |
|
---|
339 | case DBUS_TYPE_OBJECT_PATH:
|
---|
340 | return QDBusMetaTypeId::objectpath;
|
---|
341 |
|
---|
342 | case DBUS_TYPE_SIGNATURE:
|
---|
343 | return QDBusMetaTypeId::signature;
|
---|
344 |
|
---|
345 | case DBUS_TYPE_VARIANT:
|
---|
346 | return QDBusMetaTypeId::variant;
|
---|
347 |
|
---|
348 | case DBUS_TYPE_ARRAY: // special case
|
---|
349 | switch (signature[1]) {
|
---|
350 | case DBUS_TYPE_BYTE:
|
---|
351 | return QVariant::ByteArray;
|
---|
352 |
|
---|
353 | case DBUS_TYPE_STRING:
|
---|
354 | return QVariant::StringList;
|
---|
355 |
|
---|
356 | case DBUS_TYPE_VARIANT:
|
---|
357 | return QVariant::List;
|
---|
358 |
|
---|
359 | case DBUS_TYPE_OBJECT_PATH:
|
---|
360 | return qMetaTypeId<QList<QDBusObjectPath> >();
|
---|
361 |
|
---|
362 | case DBUS_TYPE_SIGNATURE:
|
---|
363 | return qMetaTypeId<QList<QDBusSignature> >();
|
---|
364 |
|
---|
365 | }
|
---|
366 | // fall through
|
---|
367 | default:
|
---|
368 | return QVariant::Invalid;
|
---|
369 | }
|
---|
370 | }
|
---|
371 |
|
---|
372 | /*!
|
---|
373 | \fn QDBusMetaType::typeToSignature(int type)
|
---|
374 | \internal
|
---|
375 |
|
---|
376 | Returns the D-Bus signature equivalent to the supplied meta type id \a type.
|
---|
377 |
|
---|
378 | More types can be registered with the qDBusRegisterMetaType() function.
|
---|
379 |
|
---|
380 | \sa QDBusUtil::isValidSingleSignature(), signatureToType(),
|
---|
381 | QVariant::type(), QVariant::userType()
|
---|
382 | */
|
---|
383 | const char *QDBusMetaType::typeToSignature(int type)
|
---|
384 | {
|
---|
385 | // check if it's a static type
|
---|
386 | switch (type)
|
---|
387 | {
|
---|
388 | case QMetaType::UChar:
|
---|
389 | return DBUS_TYPE_BYTE_AS_STRING;
|
---|
390 |
|
---|
391 | case QVariant::Bool:
|
---|
392 | return DBUS_TYPE_BOOLEAN_AS_STRING;
|
---|
393 |
|
---|
394 | case QMetaType::Short:
|
---|
395 | return DBUS_TYPE_INT16_AS_STRING;
|
---|
396 |
|
---|
397 | case QMetaType::UShort:
|
---|
398 | return DBUS_TYPE_UINT16_AS_STRING;
|
---|
399 |
|
---|
400 | case QVariant::Int:
|
---|
401 | return DBUS_TYPE_INT32_AS_STRING;
|
---|
402 |
|
---|
403 | case QVariant::UInt:
|
---|
404 | return DBUS_TYPE_UINT32_AS_STRING;
|
---|
405 |
|
---|
406 | case QVariant::LongLong:
|
---|
407 | return DBUS_TYPE_INT64_AS_STRING;
|
---|
408 |
|
---|
409 | case QVariant::ULongLong:
|
---|
410 | return DBUS_TYPE_UINT64_AS_STRING;
|
---|
411 |
|
---|
412 | case QVariant::Double:
|
---|
413 | return DBUS_TYPE_DOUBLE_AS_STRING;
|
---|
414 |
|
---|
415 | case QVariant::String:
|
---|
416 | return DBUS_TYPE_STRING_AS_STRING;
|
---|
417 |
|
---|
418 | case QVariant::StringList:
|
---|
419 | return DBUS_TYPE_ARRAY_AS_STRING
|
---|
420 | DBUS_TYPE_STRING_AS_STRING; // as
|
---|
421 |
|
---|
422 | case QVariant::ByteArray:
|
---|
423 | return DBUS_TYPE_ARRAY_AS_STRING
|
---|
424 | DBUS_TYPE_BYTE_AS_STRING; // ay
|
---|
425 | }
|
---|
426 |
|
---|
427 | QDBusMetaTypeId::init();
|
---|
428 | if (type == QDBusMetaTypeId::variant)
|
---|
429 | return DBUS_TYPE_VARIANT_AS_STRING;
|
---|
430 | else if (type == QDBusMetaTypeId::objectpath)
|
---|
431 | return DBUS_TYPE_OBJECT_PATH_AS_STRING;
|
---|
432 | else if (type == QDBusMetaTypeId::signature)
|
---|
433 | return DBUS_TYPE_SIGNATURE_AS_STRING;
|
---|
434 |
|
---|
435 | // try the database
|
---|
436 | QVector<QDBusCustomTypeInfo> *ct = customTypes();
|
---|
437 | {
|
---|
438 | QReadLocker locker(customTypesLock());
|
---|
439 | if (type >= ct->size())
|
---|
440 | return 0; // type not registered with us
|
---|
441 |
|
---|
442 | const QDBusCustomTypeInfo &info = (*ct).at(type);
|
---|
443 |
|
---|
444 | if (!info.signature.isNull())
|
---|
445 | return info.signature;
|
---|
446 |
|
---|
447 | if (!info.marshall)
|
---|
448 | return 0; // type not registered with us
|
---|
449 | }
|
---|
450 |
|
---|
451 | // call to user code to construct the signature type
|
---|
452 | QDBusCustomTypeInfo *info;
|
---|
453 | {
|
---|
454 | // createSignature will never return a null QByteArray
|
---|
455 | // if there was an error, it'll return ""
|
---|
456 | QByteArray signature = QDBusArgumentPrivate::createSignature(type);
|
---|
457 |
|
---|
458 | // re-acquire lock
|
---|
459 | QWriteLocker locker(customTypesLock());
|
---|
460 | info = &(*ct)[type];
|
---|
461 | info->signature = signature;
|
---|
462 | }
|
---|
463 | return info->signature;
|
---|
464 | }
|
---|
465 |
|
---|
466 | QT_END_NAMESPACE
|
---|
467 |
|
---|
468 | #endif // QT_NO_DBUS
|
---|