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 | |
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 |
484 | |