summaryrefslogtreecommitdiff
path: root/qt/qdbustype.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qt/qdbustype.cpp')
-rw-r--r--qt/qdbustype.cpp1151
1 files changed, 1151 insertions, 0 deletions
diff --git a/qt/qdbustype.cpp b/qt/qdbustype.cpp
new file mode 100644
index 0000000..036bbe1
--- /dev/null
+++ b/qt/qdbustype.cpp
@@ -0,0 +1,1151 @@
+/* -*- C++ -*-
+ *
+ * Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira@trolltech.com>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "qdbustype.h"
+#include "qdbusvariant.h"
+#include <dbus/dbus.h>
+
+#include <QtCore/qstringlist.h>
+
+/// \internal
+class QDBusPrettyTypeBase
+{
+public:
+ struct Entry
+ {
+ const char* prettyName;
+ char signature;
+ };
+
+ enum Direction
+ {
+ In,
+ Out
+ };
+
+ enum Access
+ {
+ Read,
+ Write,
+ ReadWrite
+ };
+
+ // so that the compiler doesn't complain
+ virtual ~QDBusPrettyTypeBase() { }
+
+ virtual QString addElementsToArray(const QString& subType) = 0;
+ virtual QString addElementsToMap(const QString& key, const QString& value) = 0;
+ virtual QString addElementsToStruct(const QStringList& subTypes) = 0;
+ virtual const Entry* entryMap() = 0;
+
+ QString toString(const QDBusType& type);
+ QString toString(const QDBusTypeList& list);
+};
+
+/// \internal
+class QDBusConventionalNames: public QDBusPrettyTypeBase
+{
+public:
+ virtual QString addElementsToArray(const QString& subType);
+ virtual QString addElementsToMap(const QString& key, const QString& value);
+ virtual QString addElementsToStruct(const QStringList& subTypes) ;
+ virtual const Entry* entryMap();
+};
+
+/// \internal
+class QDBusQtNames: public QDBusPrettyTypeBase
+{
+public:
+ virtual QString addElementsToArray(const QString& subType);
+ virtual QString addElementsToMap(const QString& key, const QString& value);
+ virtual QString addElementsToStruct(const QStringList& subTypes) ;
+ virtual const Entry* entryMap();
+};
+
+//! \internal
+class QDBusQVariantNames: public QDBusQtNames
+{
+public:
+ virtual QString addElementsToArray(const QString& subType);
+ virtual QString addElementsToMap(const QString& key, const QString& value);
+ virtual QString addElementsToStruct(const QStringList& subTypes) ;
+};
+
+#if 0
+/*
+ * Parse the signature and return the max length that is valid
+ */
+static int parse(const char* signature)
+{
+ if (!signature || !*signature)
+ return 0; // not valid
+
+ switch (signature[0]) {
+ case DBUS_TYPE_BOOLEAN:
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ case DBUS_TYPE_DOUBLE:
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ case DBUS_TYPE_VARIANT:
+ return 1;
+
+ case DBUS_TYPE_ARRAY: {
+ // check if it's a dict-entry array
+ if (signature[1] == DBUS_DICT_ENTRY_BEGIN_CHAR) {
+ // the first type must be ok and primitive (length 1)
+ char c[2] = { signature[2], 0 };
+ if (parse(c) != 1)
+ return 0; // not valid
+
+ // the rest must be a valid type too
+ int len = parse(signature + 3);
+ if (len == 0)
+ return 0; // not valid
+
+ // check the closing brace
+ if (signature[len + 3] != DBUS_DICT_ENTRY_END_CHAR)
+ return 0; // not valid
+
+ // it's valid
+ return len + 4;
+ }
+
+ // it's not a dict-entry, so it's ok as long as the internal type is ok too
+ int len = parse(signature + 1);
+ return len ? len + 1 : 0;
+ }
+
+ case DBUS_STRUCT_BEGIN_CHAR: {
+ // check that each entry is valid
+ int i = 1;
+ while (i) {
+ if (i > 1 && signature[i] == DBUS_STRUCT_END_CHAR)
+ break; // this is valid
+
+ int len = parse(signature + i);
+ if (len)
+ i += len;
+ else
+ i = 0;
+ }
+ return i;
+ }
+
+ default:
+ return 0; // not valid
+ }
+}
+#endif
+
+static QString findInMap(char type, const QDBusPrettyTypeBase::Entry* map)
+{
+ for ( ; map->signature; ++map)
+ if (type == map->signature)
+ return QLatin1String(map->prettyName);
+ return QString();
+}
+
+//
+// Input MUST be valid
+//
+inline QString QDBusPrettyTypeBase::toString(const QDBusType& type)
+{
+ const Entry* map = entryMap();
+
+ const QDBusTypeList subTypes = type.subTypes();
+ switch (type.dbusType()) {
+ case DBUS_TYPE_STRUCT: {
+ // handle a struct
+ // find its sub-types
+
+ QStringList subStrings;
+ QDBusTypeList subTypes = type.subTypes();
+ foreach (QDBusType t, subTypes)
+ subStrings << toString( t );
+
+ return addElementsToStruct(subStrings);
+ }
+
+ case DBUS_TYPE_DICT_ENTRY: {
+ Q_ASSERT_X(subTypes.size() == 2, "QDBusType::toString",
+ "maps must have exactly two elements");
+
+ QString key = findInMap( subTypes.at(0).dbusType(), map );
+ QString value = toString( subTypes.at(1) );
+
+ Q_ASSERT(!key.isNull());
+
+ return addElementsToMap( key, value );
+ }
+ case DBUS_TYPE_ARRAY: {
+ Q_ASSERT_X(subTypes.size() == 1, "QDBusType::toString",
+ "more than one element in array");
+
+ if (type.qvariantType() == QVariant::Map)
+ return toString( subTypes.first() );
+ return addElementsToArray( toString( subTypes.at(0) ) );
+ }
+
+ default: {
+ // normal, non-compound type
+ QString name = findInMap(type.dbusType(), map);
+ Q_ASSERT(!name.isNull());
+ return name;
+ }
+ }
+}
+
+const QDBusPrettyTypeBase::Entry* QDBusConventionalNames::entryMap()
+{
+ static QDBusPrettyTypeBase::Entry translation[] = {
+ { "BYTE", DBUS_TYPE_BYTE },
+ { "BOOLEAN", DBUS_TYPE_BOOLEAN },
+ { "INT16", DBUS_TYPE_INT16 },
+ { "UINT16", DBUS_TYPE_UINT16 },
+ { "INT32", DBUS_TYPE_INT32 },
+ { "UINT32", DBUS_TYPE_UINT32 },
+ { "INT64", DBUS_TYPE_INT64 },
+ { "UINT64", DBUS_TYPE_UINT64 },
+ { "DOUBLE", DBUS_TYPE_DOUBLE },
+ { "STRING", DBUS_TYPE_STRING },
+ { "OBJECT_PATH", DBUS_TYPE_OBJECT_PATH },
+ { "SIGNATURE", DBUS_TYPE_SIGNATURE },
+ { "VARIANT", DBUS_TYPE_VARIANT }
+ };
+ return translation;
+}
+
+QString QDBusConventionalNames::addElementsToStruct(const QStringList& subTypes)
+{
+ return QString( QLatin1String("STRUCT of (%1)") )
+ .arg( subTypes.join( QLatin1String(",") ) );
+}
+
+QString QDBusConventionalNames::addElementsToMap(const QString& key, const QString& value)
+{
+ return QString( QLatin1String("ARRAY of DICT_ENTRY of (%1,%2)") )
+ .arg(key).arg(value);
+}
+
+QString QDBusConventionalNames::addElementsToArray(const QString& subType)
+{
+ return QString( QLatin1String("ARRAY of %1") )
+ .arg(subType);
+}
+
+const QDBusPrettyTypeBase::Entry* QDBusQtNames::entryMap()
+{
+ static QDBusPrettyTypeBase::Entry translation[] = {
+ { "quint8", DBUS_TYPE_BYTE },
+ { "bool", DBUS_TYPE_BOOLEAN },
+ { "qint16", DBUS_TYPE_INT16 },
+ { "quint16", DBUS_TYPE_UINT16 },
+ { "qint32", DBUS_TYPE_INT32 },
+ { "quint32", DBUS_TYPE_UINT32 },
+ { "qint64", DBUS_TYPE_INT64 },
+ { "quint64", DBUS_TYPE_UINT64 },
+ { "double", DBUS_TYPE_DOUBLE },
+ { "QString", DBUS_TYPE_STRING },
+ { "QString", DBUS_TYPE_OBJECT_PATH },
+ { "QString", DBUS_TYPE_SIGNATURE },
+ { "QDBusVariant", DBUS_TYPE_VARIANT }
+ };
+ return translation;
+}
+
+static inline QString templateArg(const QString& input)
+{
+ if (input.endsWith('>'))
+ return input + ' ';
+ return input;
+}
+
+QString QDBusQtNames::addElementsToStruct(const QStringList& subTypes)
+{
+ Q_UNUSED(subTypes);
+
+ return QLatin1String("QList"); // CHANGEME in the future
+}
+
+QString QDBusQtNames::addElementsToMap(const QString& key, const QString& value)
+{
+ return QString( QLatin1String("QMap<%1, %2>") )
+ .arg(key)
+ .arg( templateArg(value) );
+}
+
+QString QDBusQtNames::addElementsToArray(const QString& subType)
+{
+ if (subType == QLatin1String("quint8"))
+ // special case
+ return QLatin1String("QByteArray");
+
+ return QString( QLatin1String("QList<%1>") )
+ .arg( templateArg(subType) );
+}
+
+QString QDBusQVariantNames::addElementsToStruct(const QStringList& subTypes)
+{
+ Q_UNUSED(subTypes);
+
+ return QLatin1String("QVariantList");
+}
+
+QString QDBusQVariantNames::addElementsToMap(const QString& key, const QString& value)
+{
+ Q_UNUSED(key);
+ Q_UNUSED(value);
+
+ return QLatin1String("QVariantMap");
+}
+
+QString QDBusQVariantNames::addElementsToArray(const QString& subType)
+{
+ if (subType == QLatin1String("quint8"))
+ // special case
+ return QLatin1String("QByteArray");
+
+ return QLatin1String("QVariantList");
+}
+
+/*!
+ \internal
+*/
+class QDBusTypePrivate: public QSharedData
+{
+public:
+ int code;
+ mutable QVariant::Type qvariantType;
+ mutable QByteArray signature;
+ QDBusTypeList subTypes;
+
+ inline QDBusTypePrivate()
+ : code(0), qvariantType(QVariant::Invalid)
+ { }
+};
+
+/*!
+ \class QDBusType
+
+ Represents one single DBus type.
+*/
+
+/*!
+ \enum QDBusType::StringFormat
+
+ This enum is used in QDBusType::toString to determine which type of formatting
+ to apply to the DBus types:
+
+ \value ConventionalNames Use the DBus conventional names, such as STRING, BOOLEAN or
+ ARRAY of BYTE.
+ \value QtNames Use the Qt type names, such as QString, bool and QList<quint32>
+ \value QVariantNames Same as QtNames, but for containers, use QVariantList and QVariantMap
+*/
+
+/*!
+ Constructs an empty (invalid) type.
+*/
+QDBusType::QDBusType()
+ : d(0)
+{
+}
+
+/*!
+ Constructs the type based on the given DBus type.
+
+ \param type the type
+*/
+QDBusType::QDBusType(int type)
+{
+ char c[2] = { type, 0 };
+ *this = QDBusType(c);
+}
+
+/*!
+ Constructs the type based on the given QVariant type.
+
+ \param type the type
+ \sa QVariant::Type
+*/
+QDBusType::QDBusType(QVariant::Type type)
+{
+ const char *sig = dbusSignature(type);
+
+ // it never returns NULL
+ if (sig[0] == '\0')
+ return;
+
+ d = new QDBusTypePrivate;
+ d->qvariantType = type;
+ d->code = sig[0];
+ if (sig[1] == '\0')
+ // single-letter type
+ return;
+ else if (sig[2] == '\0') {
+ // two-letter type
+ // must be an array
+ d->code = sig[0];
+ QDBusType t;
+ t.d = new QDBusTypePrivate;
+ t.d->code = sig[1];
+ d->subTypes << t;
+ }
+ else {
+ // the only longer type is "a{sv}"
+ Q_ASSERT(sig[1] == '{' && sig[5] == '\0');
+
+ static QDBusType map("a{sv}");
+ d->subTypes = map.d->subTypes;
+ }
+}
+
+/*!
+ Parses the given DBus signature and constructs the type it represents.
+
+ \param signature the signature to parse. It must represent one single type, but can
+ a container type.
+*/
+QDBusType::QDBusType(const char* signature)
+{
+ if ( !dbus_signature_validate_single(signature, 0) )
+ return;
+
+ DBusSignatureIter iter;
+ dbus_signature_iter_init(&iter, signature);
+ *this = QDBusType(&iter);
+ if (d)
+ d->signature = signature;
+}
+
+/*!
+ Parses the given DBus signature and constructs the type it represents.
+
+ \param signature the signature to parse. It must represent one single type, but can
+ a container type.
+*/
+QDBusType::QDBusType(const QString& str)
+{
+ *this = QDBusType( str.toUtf8().constData() );
+}
+
+/*!
+ Parses the given DBus signature and constructs the type it represents.
+
+ \param signature the signature to parse. It must represent one single type, but can
+ a container type.
+*/
+QDBusType::QDBusType(const QByteArray& str)
+{
+ *this = QDBusType( str.constData() );
+}
+
+/*!
+ Creates a QDBusType object based on the current element pointed to by \a iter.
+
+ \param iter the iterator. Can be pointing to container types.
+*/
+QDBusType::QDBusType(DBusSignatureIter* iter)
+ : d(new QDBusTypePrivate)
+{
+ if ( dbus_type_is_container( d->code = dbus_signature_iter_get_current_type(iter) ) ) {
+ // we have to recurse
+ if ( d->code == DBUS_TYPE_VARIANT )
+ return; // no we don't. dbus_type_is_container lies to us
+
+ // we have to recurse
+ DBusSignatureIter subiter;
+ dbus_signature_iter_recurse(iter, &subiter);
+
+ d->subTypes = QDBusTypeList(&subiter);
+
+ // sanity checking:
+ if ( d->code == DBUS_TYPE_ARRAY )
+ Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType",
+ "more than one element in array");
+ else if (d->code == DBUS_TYPE_DICT_ENTRY )
+ Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType",
+ "maps must have exactly two elements");
+ }
+}
+
+/*!
+ Copies the type from the other object.
+*/
+QDBusType::QDBusType(const QDBusType& other)
+ : d(other.d)
+{
+}
+
+/*!
+ Release the resources associated with this type.
+*/
+QDBusType::~QDBusType()
+{
+}
+
+/*!
+ Copies the type from the other object.
+*/
+QDBusType& QDBusType::operator=(const QDBusType& other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns the DBus type for this type.
+*/
+int QDBusType::dbusType() const
+{
+ return d ? d->code : DBUS_TYPE_INVALID;
+}
+
+/*!
+ Returns the DBus signature for this type and subtypes.
+*/
+QByteArray QDBusType::dbusSignature() const
+{
+ if (!d)
+ return QByteArray();
+
+ if (!d->signature.isEmpty())
+ return d->signature;
+
+ if (d->subTypes.isEmpty())
+ return d->signature = QByteArray(1, d->code);
+
+ QByteArray retval;
+ switch (d->code) {
+ // can only be array, map or struct
+
+ case DBUS_TYPE_ARRAY:
+ Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType::dbusSignature",
+ "more than one element in array");
+
+ retval += DBUS_TYPE_ARRAY;
+ retval += d->subTypes.at(0).dbusSignature();
+ break;
+
+ case DBUS_TYPE_DICT_ENTRY: {
+ Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType::dbusSignature",
+ "maps must have exactly two elements");
+
+ QByteArray value = d->subTypes.at(1).dbusSignature();
+ char key = d->subTypes.at(0).dbusType();
+
+ Q_ASSERT(key != DBUS_TYPE_INVALID);
+ Q_ASSERT(!value.isEmpty());
+
+ retval.reserve(value.length() + 3);
+ retval = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
+ retval += key;
+ retval += value;
+ retval += DBUS_DICT_ENTRY_END_CHAR;
+ break;
+ }
+
+ case DBUS_TYPE_STRUCT:
+ retval = d->subTypes.dbusSignature();
+ retval.prepend(DBUS_STRUCT_BEGIN_CHAR);
+ retval.append(DBUS_STRUCT_END_CHAR);
+ break;
+
+ default:
+ Q_ASSERT_X(false, "QDBusType::dbusSignature", "invalid container type");
+ }
+
+ d->signature = retval;
+ return retval;
+}
+
+/*!
+ Returns the QVariant::Type for this entry.
+*/
+QVariant::Type QDBusType::qvariantType() const
+{
+ if (d && d->qvariantType != QVariant::Invalid)
+ return d->qvariantType;
+
+ // check the special array cases:
+ if (isArray()) {
+ QDBusType t = arrayElement();
+
+ if (t.dbusType() == DBUS_TYPE_BYTE)
+ return QVariant::ByteArray;
+ else if (t.dbusType() == DBUS_TYPE_DICT_ENTRY)
+ return QVariant::Map;
+ else if (t.isBasic() && t.qvariantType() == QVariant::String)
+ return QVariant::StringList;
+ }
+
+ return qvariantType(dbusType());
+}
+
+/*!
+ Returns true if this type is a valid one.
+*/
+bool QDBusType::isValid() const
+{
+ return d && d->code != DBUS_TYPE_INVALID;
+}
+
+/*!
+ Returns true if this type is a basic one.
+
+ \sa dbus_type_is_basic
+*/
+bool QDBusType::isBasic() const
+{
+ return d && dbus_type_is_basic(d->code);
+}
+
+/*!
+ Returns true if this type is a container.
+
+ \sa dbus_type_is_container
+*/
+bool QDBusType::isContainer() const
+{
+ return d && dbus_type_is_container(d->code);
+}
+
+/*!
+ Returns the subtypes of this type, if this is a container.
+
+ \sa isContainer
+*/
+QDBusTypeList QDBusType::subTypes() const
+{
+ if (d)
+ return d->subTypes;
+ return QDBusTypeList();
+}
+
+/*!
+ Returns true if this type is an array.
+
+ \sa isContainer, arrayElement
+*/
+bool QDBusType::isArray() const
+{
+ return dbusType() == DBUS_TYPE_ARRAY;
+}
+
+/*!
+ This is a convenience function that returns the element type of an array.
+ If this object is not an array, it returns an invalid QDBusType.
+
+ \sa isArray
+*/
+QDBusType QDBusType::arrayElement() const
+{
+ if (isArray() && d->subTypes.count() == 1)
+ return d->subTypes.first();
+ return QDBusType();
+}
+
+/*!
+ Returns true if this type is a map (i.e., an array of dictionary entries).
+
+ \sa isContainer, isArray, arrayElement
+*/
+bool QDBusType::isMap() const
+{
+ return arrayElement().dbusType() == DBUS_TYPE_DICT_ENTRY;
+}
+
+/*!
+ If this object is a map, returns the (basic) type that corresponds to the key type.
+ If this object is not a map, returns an invalid QDBusType.
+
+ \sa isMap
+*/
+QDBusType QDBusType::mapKey() const
+{
+ if (isMap())
+ return arrayElement().d->subTypes.first();
+ return QDBusType();
+}
+
+/*!
+ If this object is a map, returns the type that corresponds to the value type.
+ If this object is not a map, returns an invalid QDBusType.
+
+ \sa isMap
+*/
+QDBusType QDBusType::mapValue() const
+{
+ if (isMap())
+ return arrayElement().d->subTypes.at(1);
+ return QDBusType();
+}
+
+/*!
+ Returns true if the two types match.
+*/
+bool QDBusType::operator==(const QDBusType& other) const
+{
+ if (!d && !other.d)
+ return true;
+ if (!d || !other.d)
+ return false;
+ return d->code == other.d->code && d->subTypes == other.d->subTypes;
+}
+
+/*!
+ Returns a string representation of this type.
+*/
+QString QDBusType::toString(StringFormat sf) const
+{
+ switch (sf) {
+ case ConventionalNames:
+ return QDBusConventionalNames().toString(*this);
+
+ case QtNames:
+ return QDBusQtNames().toString(*this);
+
+ case QVariantNames:
+ return QDBusQVariantNames().toString(*this);
+ }
+
+ return QString(); // invalid
+}
+
+/*!
+ Converts the DBus type to QVariant::Type
+*/
+QVariant::Type QDBusType::qvariantType(int type)
+{
+ char c[2] = { type, 0 };
+ return qvariantType(c);
+}
+
+/*!
+ Converts the DBus type signature to QVariant::Type.
+*/
+QVariant::Type QDBusType::qvariantType(const char* signature)
+{
+ if (!signature)
+ return QVariant::Invalid;
+
+ // three special cases that don't validate as single:
+ if (qstrlen(signature) == 1) {
+ if (signature[0] == DBUS_TYPE_STRUCT)
+ return QVariant::List;
+ else if (signature[0] == DBUS_TYPE_DICT_ENTRY)
+ return QVariant::Map;
+ else if (signature[0] == DBUS_TYPE_ARRAY)
+ return QVariant::List;
+ }
+
+ // now we can validate
+ if ( !dbus_signature_validate_single(signature, 0) )
+ return QVariant::Invalid;
+
+ switch (signature[0])
+ {
+ case DBUS_TYPE_BOOLEAN:
+ return QVariant::Bool;
+
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_INT32:
+ return QVariant::Int;
+
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_UINT32:
+ return QVariant::UInt;
+
+ case DBUS_TYPE_INT64:
+ return QVariant::LongLong;
+
+ case DBUS_TYPE_UINT64:
+ return QVariant::ULongLong;
+
+ case DBUS_TYPE_DOUBLE:
+ return QVariant::Double;
+
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ return QVariant::String;
+
+ case DBUS_STRUCT_BEGIN_CHAR:
+ return QVariant::List; // change to QDBusStruct in the future
+
+ case DBUS_TYPE_VARIANT:
+ return QVariant::UserType; // must set user-type too
+
+ case DBUS_TYPE_ARRAY: // special case
+ // check if it's a string list
+ if (qvariantType(signature + 1) == QVariant::String)
+ return QVariant::StringList;
+
+ // maybe it's a byte array
+ if (DBUS_TYPE_BYTE == signature[1])
+ return QVariant::ByteArray;
+
+ // check if it's a dict
+ if (DBUS_DICT_ENTRY_BEGIN_CHAR == signature[1])
+ return QVariant::Map;
+
+ return QVariant::List;
+
+ default:
+ return QVariant::Invalid;
+
+ }
+}
+
+/*!
+ Converts the QVariant::Type to a DBus type code.
+
+ \param t the type to convert
+*/
+int QDBusType::dbusType(QVariant::Type t)
+{
+ switch (t)
+ {
+ case QVariant::Bool:
+ return DBUS_TYPE_BOOLEAN;
+
+ case QVariant::Int:
+ return DBUS_TYPE_INT32;
+
+ case QVariant::UInt:
+ case QVariant::Char:
+ return DBUS_TYPE_UINT32;
+
+ case QVariant::LongLong:
+ return DBUS_TYPE_INT64;
+
+ case QVariant::ULongLong:
+ return DBUS_TYPE_UINT64;
+
+ case QVariant::Double:
+ return DBUS_TYPE_DOUBLE;
+
+ // from QMetaType:
+ case QMetaType::Short:
+ return DBUS_TYPE_INT16;
+
+ case QMetaType::UShort:
+ return DBUS_TYPE_UINT16;
+
+ case QMetaType::UChar:
+ return DBUS_TYPE_BYTE;
+
+ case QVariant::String:
+ case QVariant::Date:
+ case QVariant::Time:
+ case QVariant::DateTime:
+ return DBUS_TYPE_STRING;
+
+ case QVariant::Map:
+ // internal type information has been lost
+ return DBUS_TYPE_DICT_ENTRY;
+
+ case QVariant::List:
+ case QVariant::StringList:
+ case QVariant::ByteArray:
+ // could also be a struct...
+ return DBUS_TYPE_ARRAY;
+
+ case QVariant::UserType:
+ return DBUS_TYPE_VARIANT;
+
+ default:
+ break; // avoid compiler warnings
+ }
+
+ if (int(t) == QMetaTypeId<QDBusVariant>::qt_metatype_id())
+ return DBUS_TYPE_VARIANT;
+
+ return DBUS_TYPE_INVALID;
+}
+
+/*!
+ Converts the QVariant::Type to a DBus type signature.
+
+ \param t the type to convert
+*/
+const char* QDBusType::dbusSignature(QVariant::Type t)
+{
+ switch (t)
+ {
+ case QVariant::Bool:
+ return DBUS_TYPE_BOOLEAN_AS_STRING;
+
+ case QVariant::Int:
+ return DBUS_TYPE_INT32_AS_STRING;
+
+ case QVariant::UInt:
+ case QVariant::Char:
+ return DBUS_TYPE_UINT32_AS_STRING;
+
+ case QMetaType::Short:
+ return DBUS_TYPE_INT16_AS_STRING;
+
+ case QMetaType::UShort:
+ return DBUS_TYPE_UINT16_AS_STRING;
+
+ case QMetaType::UChar:
+ return DBUS_TYPE_BYTE_AS_STRING;
+
+ case QVariant::LongLong:
+ return DBUS_TYPE_INT64_AS_STRING;
+
+ case QVariant::ULongLong:
+ return DBUS_TYPE_UINT64_AS_STRING;
+
+ case QVariant::Double:
+ return DBUS_TYPE_DOUBLE_AS_STRING;
+
+ case QVariant::String:
+ case QVariant::Date:
+ case QVariant::Time:
+ case QVariant::DateTime:
+ return DBUS_TYPE_STRING_AS_STRING;
+
+ case QVariant::Map:
+ // internal type information has been lost
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING; // a{sv}
+
+ case QVariant::StringList:
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING; // as
+
+ case QVariant::ByteArray:
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING; // ay
+
+ case QVariant::List:
+ // not a string list
+ // internal list data has been lost
+ // could also be a struct...
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING; // av
+
+ default:
+ if (int(t) == qMetaTypeId<QDBusVariant>())
+ return DBUS_TYPE_VARIANT_AS_STRING;
+
+ return DBUS_TYPE_INVALID_AS_STRING;
+ }
+}
+
+/*!
+ Guesses the DBus type from the given variant.
+*/
+QDBusType QDBusType::guessFromVariant(const QVariant& variant, VariantListMode mode)
+{
+ if (variant.type() == QVariant::List) {
+ // investigate deeper
+ QDBusType t;
+ t.d = new QDBusTypePrivate;
+
+ if (mode == ListIsArray) {
+ t.d->code = DBUS_TYPE_ARRAY;
+
+ const QVariantList list = variant.toList();
+ if (!list.isEmpty()) {
+ // check if all elements have the same type
+ QVariant::Type type = list.first().type();
+ foreach (const QVariant& v, list)
+ if (type != v.type()) {
+ // at least one is different
+ type = QVariant::Invalid;
+ break;
+ }
+
+ if (type != QVariant::Invalid) {
+ // all are of the same type
+ t.d->subTypes << guessFromVariant(list.first());
+ return t;
+ }
+ }
+
+ // internal information has been lost or there are many types
+ QDBusType nested;
+ nested.d = new QDBusTypePrivate;
+ nested.d->code = DBUS_TYPE_VARIANT;
+ t.d->subTypes << nested;
+ return t;
+ }
+ else {
+ // treat it as a struct
+ t.d->code = DBUS_TYPE_STRUCT;
+
+ // add the elements:
+ const QVariantList list = variant.toList();
+ foreach (const QVariant& v, list)
+ t.d->subTypes << guessFromVariant(v, mode);
+
+ return t;
+ }
+ }
+ else if (variant.type() == QVariant::Map) {
+ // investigate deeper
+ QDBusType t, t2, t3;
+ t2.d = new QDBusTypePrivate;
+ t2.d->code = DBUS_TYPE_DICT_ENTRY;
+
+ // the key
+ t3.d = new QDBusTypePrivate;
+ t3.d->code = DBUS_TYPE_STRING;
+ t2.d->subTypes << t3;
+
+ const QVariantMap map = variant.toMap();
+ if (!map.isEmpty()) {
+ // check if all elements have the same type
+ QVariantMap::const_iterator it = map.constBegin(),
+ end = map.constEnd();
+ QVariant::Type type = it.value().type();
+ for ( ; it != end; ++it)
+ if (type != it.value().type()) {
+ // at least one is different
+ type = QVariant::Invalid;
+ break;
+ }
+
+ if (type != QVariant::Invalid)
+ t2.d->subTypes << guessFromVariant(map.constBegin().value());
+ else {
+ // multiple types
+ t3.d->code = DBUS_TYPE_VARIANT;
+ t2.d->subTypes << t3;
+ }
+ }
+ else {
+ // information lost
+ t3.d->code = DBUS_TYPE_VARIANT;
+ t2.d->subTypes << t3;
+ }
+
+ t.d = new QDBusTypePrivate;
+ t.d->code = DBUS_TYPE_ARRAY;
+ t.d->subTypes << t2;
+ return t;
+ }
+ else
+ return QDBusType(variant.type());
+}
+
+/*!
+ \class QDBusTypeList
+ \brief A list of DBus types.
+
+ Represents zero or more DBus types in sequence, such as those used in argument lists
+ or in subtypes of structs and maps.
+*/
+
+/*!
+ \fn QDBusTypeList::QDBusTypeList()
+
+ Default constructor.
+ */
+
+/*!
+ \fn QDBusTypeList::QDBusTypeList(const QDBusTypeList& other)
+
+ Copy constructor.
+ \param other the list to copy
+ */
+
+/*!
+ \fn QDBusTypeList::QDBusTypeList(const QList<QDBusType>& other)
+
+ Copy constructor.
+ \param other the list to copy
+ */
+
+/*!
+ Constructs a type list by parsing the signature given.
+ \param signature the signature to be parsed
+ */
+QDBusTypeList::QDBusTypeList(const char* signature)
+{
+ if (!signature || !*signature)
+ return; // empty
+
+ // validate it first
+ if ( !dbus_signature_validate(signature, 0) )
+ return;
+
+ // split it into components
+ DBusSignatureIter iter;
+ dbus_signature_iter_init(&iter, signature);
+
+ do {
+ *this << QDBusType(&iter);
+ } while (dbus_signature_iter_next(&iter));
+}
+
+/*!
+ Constructs a type list by parsing the elements on this iterator level.
+
+ \param iter the iterator containing the elements on this level
+*/
+QDBusTypeList::QDBusTypeList(DBusSignatureIter* iter)
+{
+ do {
+ QDBusType item(iter);
+ if (!item.isValid()) {
+ clear();
+ return;
+ }
+
+ *this << item;
+ } while (dbus_signature_iter_next(iter));
+}
+
+/*!
+ Returns true if this type list can represent the inner components of a map.
+*/
+bool QDBusTypeList::canBeMap() const
+{
+ return size() == 2 && at(0).isBasic();
+}
+
+/*!
+ Reconstructs the type signature that this type list represents.
+*/
+QByteArray QDBusTypeList::dbusSignature() const
+{
+ QByteArray retval;
+ foreach (QDBusType t, *this)
+ retval += t.dbusSignature();
+ return retval;
+}