mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-01-01 16:20:12 +01:00
This is a major change: library is source- and binary-incompatible to what it used to be. All testcases are green, functionality is preserved. It is not feature-complete. Development will continue in the branch in the Subversion server for a while.
1151 lines
29 KiB
C++
1151 lines
29 KiB
C++
/* -*- 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;
|
|
}
|