3 * Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
4 * Copyright (C) 2006 Trolltech AS. All rights reserved.
5 * Author: Thiago Macieira <thiago.macieira@trolltech.com>
7 * Licensed under the Academic Free License version 2.1
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "qdbustype_p.h"
26 #include "qdbustypehelper_p.h"
27 #include <dbus/dbus.h>
29 #include <QtCore/qstringlist.h>
31 class QDBusTypePrivate: public QSharedData
35 mutable int qvariantType;
36 mutable QByteArray signature;
37 QDBusTypeList subTypes;
39 inline QDBusTypePrivate()
40 : code(0), qvariantType(QVariant::Invalid)
46 \brief Represents one single D-Bus type.
49 D-Bus provides a set of primitive types that map to normal, C++ types and to QString, as well as
50 the possibility to extend the set with the so-called "container" types. The available types are
53 - Primitive (or basic): integers of 16, 32 and 64 bits, both signed and unsigned; byte (8 bits);
54 double-precision floating point and Unicode strings
55 - Arrays: a homogeneous, ordered list of zero or more entries
56 - Maps: an unordered list of (key, value) pairs, where key must be a primitive type and value
58 - Structs: an ordered list of a fixed number of entries of any type
59 - Variants: a "wildcard" container that can assume the value of any other type, including
62 Any type can be placed inside an array (including other arrays), but only entries of the same
63 type can be placed inside the same array. The analogous type for D-Bus arrays are the Qt
64 #QList template classes.
66 Structs have a fixed number of entries and each entry has a fixed type. They are analogous to C
67 and C++ structs (hence the name).
69 Maps or dictionaries are analogous to the Qt #QMap template class, with the additional
70 restriction that the key type must be a primitive one. D-Bus implements maps by using arrays of
71 a special type (a "dictionary entry"), so inspecting a QDBusType of a Map will reveal that it is
72 an array (see isArray()).
74 Variants contain exactly one entry, but the type can vary freely. It is analogous to the Qt
75 class #QVariant, but the QtDBus implementation uses #QDBusVariant to represent D-Bus Variants.
79 Constructs an empty (invalid) type.
81 QDBusType::QDBusType()
87 Constructs the type based on the D-Bus type given by \a type.
89 QDBusType::QDBusType(int type)
91 char c[2] = { type, 0 };
96 Constructs the type based on the QVariant type given by \a type.
100 QDBusType::QDBusType(QVariant::Type type)
102 const char *sig = dbusSignature(type);
104 // it never returns NULL
105 // but it may return an empty string:
109 if (qstrlen(sig) > 2) {
110 *this = QDBusType(sig);
112 d = new QDBusTypePrivate;
113 d->qvariantType = type;
116 // single-letter type
123 t.d = new QDBusTypePrivate;
131 Parses the D-Bus signature given by \a signature and constructs the type it represents.
133 QDBusType::QDBusType(const char* signature)
135 if ( !dbus_signature_validate_single(signature, 0) )
138 DBusSignatureIter iter;
139 dbus_signature_iter_init(&iter, signature);
140 *this = QDBusType(&iter);
142 d->signature = signature;
147 Parses the D-Bus signature given by \a str and constructs the type it represents.
149 QDBusType::QDBusType(const QString& str)
151 *this = QDBusType( str.toUtf8().constData() );
156 Parses the D-Bus signature given by \a str and constructs the type it represents.
158 QDBusType::QDBusType(const QByteArray& str)
160 *this = QDBusType( str.constData() );
165 Creates a QDBusType object based on the current element pointed to by \a iter.
167 QDBusType::QDBusType(DBusSignatureIter* iter)
168 : d(new QDBusTypePrivate)
170 if ( dbus_type_is_container( d->code = dbus_signature_iter_get_current_type(iter) ) ) {
171 // we have to recurse
172 if ( d->code == DBUS_TYPE_VARIANT )
173 return; // no we don't. dbus_type_is_container lies to us
175 // we have to recurse
176 DBusSignatureIter subiter;
177 dbus_signature_iter_recurse(iter, &subiter);
179 d->subTypes = QDBusTypeList(&subiter);
182 if ( d->code == DBUS_TYPE_ARRAY )
183 Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType",
184 "more than one element in array");
185 else if (d->code == DBUS_TYPE_DICT_ENTRY )
186 Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType",
187 "maps must have exactly two elements");
192 Copies the type from the object \a other.
194 QDBusType::QDBusType(const QDBusType& other)
200 Release the resources associated with this type.
202 QDBusType::~QDBusType()
207 Copies the type from the object given by \a other.
209 QDBusType& QDBusType::operator=(const QDBusType& other)
216 Returns the DBus type for this type.
218 int QDBusType::dbusType() const
220 return d ? d->code : DBUS_TYPE_INVALID;
224 Returns the DBus signature for this type and subtypes.
226 QByteArray QDBusType::dbusSignature() const
231 if (!d->signature.isEmpty())
234 if (d->subTypes.isEmpty())
235 return d->signature = QByteArray(1, d->code);
239 // can only be array, map or struct
241 case DBUS_TYPE_ARRAY:
242 Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType::dbusSignature",
243 "more than one element in array");
245 retval += DBUS_TYPE_ARRAY;
246 retval += d->subTypes.at(0).dbusSignature();
249 case DBUS_TYPE_DICT_ENTRY: {
250 Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType::dbusSignature",
251 "maps must have exactly two elements");
253 QByteArray value = d->subTypes.at(1).dbusSignature();
254 char key = d->subTypes.at(0).dbusType();
256 Q_ASSERT(key != DBUS_TYPE_INVALID);
257 Q_ASSERT(!value.isEmpty());
259 retval.reserve(value.length() + 3);
260 retval = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
263 retval += DBUS_DICT_ENTRY_END_CHAR;
267 case DBUS_TYPE_STRUCT:
268 retval = d->subTypes.dbusSignature();
269 retval.prepend(DBUS_STRUCT_BEGIN_CHAR);
270 retval.append(DBUS_STRUCT_END_CHAR);
274 Q_ASSERT_X(false, "QDBusType::dbusSignature", "invalid container type");
277 d->signature = retval;
282 Returns the QVariant::Type for this entry.
284 int QDBusType::qvariantType() const
286 if (d && d->qvariantType != QVariant::Invalid)
287 return d->qvariantType;
290 return QVariant::Invalid;
292 return d->qvariantType = qvariantType(dbusSignature().constData());
296 Returns true if this type is a valid one.
298 bool QDBusType::isValid() const
300 return d && d->code != DBUS_TYPE_INVALID;
304 Returns true if this type is a basic one.
306 bool QDBusType::isBasic() const
308 return d && dbus_type_is_basic(d->code);
312 Returns true if this type is a container.
314 bool QDBusType::isContainer() const
316 return d && dbus_type_is_container(d->code);
320 Returns the subtypes of this type, if this is a container.
324 QDBusTypeList QDBusType::subTypes() const
328 return QDBusTypeList();
332 Returns true if this type is an array.
334 \sa isContainer(), arrayElement()
336 bool QDBusType::isArray() const
338 return dbusType() == DBUS_TYPE_ARRAY;
342 This is a convenience function that returns the element type of an array.
343 If this object is not an array, it returns an invalid QDBusType.
347 QDBusType QDBusType::arrayElement() const
349 if (isArray() && d->subTypes.count() == 1)
350 return d->subTypes.first();
355 Returns true if this type is a map (i.e., an array of dictionary entries).
357 \sa isContainer(), isArray(), arrayElement()
359 bool QDBusType::isMap() const
361 return arrayElement().dbusType() == DBUS_TYPE_DICT_ENTRY;
365 If this object is a map, returns the (basic) type that corresponds to the key type.
366 If this object is not a map, returns an invalid QDBusType.
370 QDBusType QDBusType::mapKey() const
373 return arrayElement().d->subTypes.first();
378 If this object is a map, returns the type that corresponds to the value type.
379 If this object is not a map, returns an invalid QDBusType.
383 QDBusType QDBusType::mapValue() const
386 return arrayElement().d->subTypes.at(1);
391 Returns true if this type is the same one as \a other.
393 bool QDBusType::operator==(const QDBusType& other) const
399 return d->code == other.d->code && d->subTypes == other.d->subTypes;
403 \fn QDBusType::operator!=(const QDBusType &other) const
404 Returns true if the this type and the one given by \a other are different.
408 Converts the DBus type code \a type to QVariant::Type.
410 int QDBusType::qvariantType(int type)
412 char c[2] = { type, 0 };
413 return qvariantType(c);
417 Converts the DBus type signature \a signature to QVariant::Type.
419 int QDBusType::qvariantType(const char* signature)
422 return QVariant::Invalid;
424 // three special cases that don't validate as single:
425 if (qstrlen(signature) == 1) {
426 if (signature[0] == DBUS_TYPE_STRUCT)
427 return QVariant::List;
428 else if (signature[0] == DBUS_TYPE_DICT_ENTRY)
429 return QVariant::Map;
430 else if (signature[0] == DBUS_TYPE_ARRAY)
431 return QVariant::List;
434 // now we can validate
435 if ( !dbus_signature_validate_single(signature, 0) )
436 return QVariant::Invalid;
438 switch (signature[0])
440 case DBUS_TYPE_BOOLEAN:
441 return QVariant::Bool;
444 return QMetaType::UChar;
446 case DBUS_TYPE_INT16:
447 return QMetaType::Short;
449 case DBUS_TYPE_UINT16:
450 return QMetaType::UShort;
452 case DBUS_TYPE_INT32:
453 return QVariant::Int;
455 case DBUS_TYPE_UINT32:
456 return QVariant::UInt;
458 case DBUS_TYPE_INT64:
459 return QVariant::LongLong;
461 case DBUS_TYPE_UINT64:
462 return QVariant::ULongLong;
464 case DBUS_TYPE_DOUBLE:
465 return QVariant::Double;
467 case DBUS_TYPE_STRING:
468 case DBUS_TYPE_OBJECT_PATH:
469 case DBUS_TYPE_SIGNATURE:
470 return QVariant::String;
472 case DBUS_STRUCT_BEGIN_CHAR:
473 return QVariant::List; // change to QDBusStruct in the future
475 case DBUS_TYPE_VARIANT:
476 return QDBusTypeHelper<QVariant>::id();
478 case DBUS_TYPE_ARRAY: // special case
479 switch (signature[1]) {
480 case DBUS_TYPE_BOOLEAN:
481 return QDBusTypeHelper<bool>::listId();
484 return QVariant::ByteArray;
486 case DBUS_TYPE_INT16:
487 return QDBusTypeHelper<short>::listId();
489 case DBUS_TYPE_UINT16:
490 return QDBusTypeHelper<ushort>::listId();
492 case DBUS_TYPE_INT32:
493 return QDBusTypeHelper<int>::listId();
495 case DBUS_TYPE_UINT32:
496 return QDBusTypeHelper<uint>::listId();
498 case DBUS_TYPE_INT64:
499 return QDBusTypeHelper<qlonglong>::listId();
501 case DBUS_TYPE_UINT64:
502 return QDBusTypeHelper<qulonglong>::listId();
504 case DBUS_TYPE_DOUBLE:
505 return QDBusTypeHelper<double>::listId();
507 case DBUS_TYPE_STRING:
508 case DBUS_TYPE_OBJECT_PATH:
509 case DBUS_TYPE_SIGNATURE:
510 return QVariant::StringList;
512 case DBUS_TYPE_VARIANT:
513 return QVariant::List;
515 case DBUS_DICT_ENTRY_BEGIN_CHAR:
516 return QVariant::Map;
519 return QVariant::List;
522 return QVariant::Invalid;
528 Converts the QVariant::Type \a t to a DBus type code.
530 int QDBusType::dbusType(QVariant::Type t)
535 return DBUS_TYPE_BOOLEAN;
538 return DBUS_TYPE_INT32;
541 return DBUS_TYPE_UINT32;
543 case QVariant::LongLong:
544 return DBUS_TYPE_INT64;
546 case QVariant::ULongLong:
547 return DBUS_TYPE_UINT64;
549 case QVariant::Double:
550 return DBUS_TYPE_DOUBLE;
553 case QMetaType::Short:
554 return DBUS_TYPE_INT16;
556 case QMetaType::UShort:
557 return DBUS_TYPE_UINT16;
559 case QMetaType::UChar:
560 return DBUS_TYPE_BYTE;
562 case QVariant::String:
563 return DBUS_TYPE_STRING;
566 // internal type information has been lost
567 return DBUS_TYPE_DICT_ENTRY;
570 case QVariant::StringList:
571 case QVariant::ByteArray:
572 // could also be a struct...
573 return DBUS_TYPE_ARRAY;
575 case QVariant::UserType:
576 return DBUS_TYPE_INVALID; // invalid
579 break; // avoid compiler warnings
582 if (int(t) == QDBusTypeHelper<QVariant>::id())
583 return DBUS_TYPE_VARIANT;
585 return DBUS_TYPE_INVALID;
589 Converts the QVariant::Type \a t to a DBus type signature.
591 const char* QDBusType::dbusSignature(QVariant::Type t)
596 return DBUS_TYPE_BOOLEAN_AS_STRING;
599 return DBUS_TYPE_INT32_AS_STRING;
602 return DBUS_TYPE_UINT32_AS_STRING;
604 case QMetaType::Short:
605 return DBUS_TYPE_INT16_AS_STRING;
607 case QMetaType::UShort:
608 return DBUS_TYPE_UINT16_AS_STRING;
610 case QMetaType::UChar:
611 return DBUS_TYPE_BYTE_AS_STRING;
613 case QVariant::LongLong:
614 return DBUS_TYPE_INT64_AS_STRING;
616 case QVariant::ULongLong:
617 return DBUS_TYPE_UINT64_AS_STRING;
619 case QVariant::Double:
620 return DBUS_TYPE_DOUBLE_AS_STRING;
622 case QVariant::String:
623 return DBUS_TYPE_STRING_AS_STRING;
626 // internal type information has been lost
627 return DBUS_TYPE_ARRAY_AS_STRING
628 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
629 DBUS_TYPE_STRING_AS_STRING
630 DBUS_TYPE_VARIANT_AS_STRING
631 DBUS_DICT_ENTRY_END_CHAR_AS_STRING; // a{sv}
633 case QVariant::StringList:
634 return DBUS_TYPE_ARRAY_AS_STRING
635 DBUS_TYPE_STRING_AS_STRING; // as
637 case QVariant::ByteArray:
638 return DBUS_TYPE_ARRAY_AS_STRING
639 DBUS_TYPE_BYTE_AS_STRING; // ay
643 // internal list data has been lost
644 // could also be a struct...
645 return DBUS_TYPE_ARRAY_AS_STRING
646 DBUS_TYPE_VARIANT_AS_STRING; // av
649 if (int(t) == QDBusTypeHelper<QVariant>::id())
650 return DBUS_TYPE_VARIANT_AS_STRING;
651 if (int(t) == QDBusTypeHelper<bool>::listId())
652 return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING;
653 if (int(t) == QDBusTypeHelper<short>::listId())
654 return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT16_AS_STRING;
655 if (int(t) == QDBusTypeHelper<ushort>::listId())
656 return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT16_AS_STRING;
657 if (int(t) == QDBusTypeHelper<int>::listId())
658 return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING;
659 if (int(t) == QDBusTypeHelper<uint>::listId())
660 return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING;
661 if (int(t) == QDBusTypeHelper<qlonglong>::listId())
662 return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT64_AS_STRING;
663 if (int(t) == QDBusTypeHelper<qulonglong>::listId())
664 return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT64_AS_STRING;
665 if (int(t) == QDBusTypeHelper<double>::listId())
666 return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_DOUBLE_AS_STRING;
668 return DBUS_TYPE_INVALID_AS_STRING;
673 \enum QDBusType::VariantListMode
674 Defines how the guessFromVariant() function will behave when the QVariant is of type
679 Guesses the DBus type from the given \a variant.
681 QDBusType QDBusType::guessFromVariant(const QVariant& variant, VariantListMode mode)
683 if (variant.type() == QVariant::List) {
684 // investigate deeper
686 t.d = new QDBusTypePrivate;
687 const QVariantList list = variant.toList();
689 t.d->code = DBUS_TYPE_ARRAY;
690 if (!list.isEmpty()) {
691 // check if all elements have the same type
692 QVariant::Type type = list.first().type();
693 foreach (const QVariant& v, list)
694 if (type != v.type()) {
695 // at least one is different
696 type = QVariant::Invalid;
700 if (type != QVariant::Invalid) {
701 // all are of the same type
702 t.d->subTypes << guessFromVariant(list.first());
706 // an array of "something"
707 t.d->subTypes << QDBusType('v');
711 // treat it as a struct
712 t.d->code = DBUS_TYPE_STRUCT;
713 foreach (const QVariant& v, list)
714 t.d->subTypes << guessFromVariant(v, mode);
718 else if (variant.type() == QVariant::Map) {
719 // investigate deeper
721 t2.d = new QDBusTypePrivate;
722 t2.d->code = DBUS_TYPE_DICT_ENTRY;
725 t3.d = new QDBusTypePrivate;
726 t3.d->code = DBUS_TYPE_STRING;
727 t2.d->subTypes << t3;
729 const QVariantMap map = variant.toMap();
730 if (!map.isEmpty()) {
731 // check if all elements have the same type
732 QVariantMap::const_iterator it = map.constBegin(),
733 end = map.constEnd();
734 QVariant::Type type = it.value().type();
735 for ( ; it != end; ++it)
736 if (type != it.value().type()) {
737 // at least one is different
738 type = QVariant::Invalid;
742 if (type != QVariant::Invalid)
743 t2.d->subTypes << guessFromVariant(map.constBegin().value());
746 t3.d->code = DBUS_TYPE_VARIANT;
747 t2.d->subTypes << t3;
752 t3.d->code = DBUS_TYPE_VARIANT;
753 t2.d->subTypes << t3;
756 t.d = new QDBusTypePrivate;
757 t.d->code = DBUS_TYPE_ARRAY;
762 return QDBusType( QVariant::Type( variant.userType() ) );
767 \brief A list of DBus types.
770 Represents zero or more DBus types in sequence, such as those used in argument lists
771 or in subtypes of structs and maps.
775 \fn QDBusTypeList::QDBusTypeList()
781 \fn QDBusTypeList::QDBusTypeList(const QDBusTypeList& other)
783 Copy constructor: copies the type list from \a other.
787 \fn QDBusTypeList::QDBusTypeList(const QList<QDBusType>& other)
789 Copy constructor: copies the type list from \a other.
793 Constructs a type list by parsing the given \a signature.
795 QDBusTypeList::QDBusTypeList(const char* signature)
797 if (!signature || !*signature)
801 if ( !dbus_signature_validate(signature, 0) )
804 // split it into components
805 DBusSignatureIter iter;
806 dbus_signature_iter_init(&iter, signature);
809 *this << QDBusType(&iter);
810 } while (dbus_signature_iter_next(&iter));
815 Constructs a type list by parsing the elements on this iterator level.
817 QDBusTypeList::QDBusTypeList(DBusSignatureIter* iter)
820 QDBusType item(iter);
821 if (!item.isValid()) {
827 } while (dbus_signature_iter_next(iter));
831 Returns true if this type list can represent the inner components of a map.
833 bool QDBusTypeList::canBeMap() const
835 return size() == 2 && at(0).isBasic();
839 Reconstructs the type signature that this type list represents.
841 QByteArray QDBusTypeList::dbusSignature() const
844 foreach (QDBusType t, *this)
845 retval += t.dbusSignature();