3 * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
5 * Licensed under the Academic Free License version 2.1
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "qdbusmarshall.h"
24 #include "qdbusvariant.h"
26 #include <QtCore/qdebug.h>
27 #include <QtCore/qvariant.h>
28 #include <QtCore/qlist.h>
29 #include <QtCore/qmap.h>
30 #include <QtCore/qstringlist.h>
31 #include <QtCore/qvarlengtharray.h>
32 #include <QtCore/qvector.h>
34 #include <dbus/dbus.h>
37 inline T qIterGet(DBusMessageIter *it)
40 dbus_message_iter_get_basic(it, &t);
44 static QStringList qFetchStringList(DBusMessageIter *arrayIt)
49 dbus_message_iter_recurse(arrayIt, &it);
52 list.append(QString::fromUtf8(qIterGet<char *>(&it)));
53 } while (dbus_message_iter_next(&it));
58 static QVariant qFetchParameter(DBusMessageIter *it)
60 switch (dbus_message_iter_get_arg_type(it)) {
62 return qIterGet<unsigned char>(it);
64 return qIterGet<dbus_int32_t>(it);
65 case DBUS_TYPE_UINT32:
66 return qIterGet<dbus_uint32_t>(it);
67 case DBUS_TYPE_DOUBLE:
68 return qIterGet<double>(it);
69 case DBUS_TYPE_BOOLEAN:
70 return qIterGet<dbus_bool_t>(it);
72 return static_cast<qlonglong>(qIterGet<dbus_int64_t>(it));
73 case DBUS_TYPE_UINT64:
74 return static_cast<qulonglong>(qIterGet<dbus_uint64_t>(it));
75 case DBUS_TYPE_STRING:
76 case DBUS_TYPE_OBJECT_PATH:
77 case DBUS_TYPE_SIGNATURE:
78 return QString::fromUtf8(qIterGet<char *>(it));
79 case DBUS_TYPE_ARRAY: {
80 int arrayType = dbus_message_iter_get_element_type(it);
81 if (arrayType == DBUS_TYPE_STRING || arrayType == DBUS_TYPE_OBJECT_PATH) {
82 return qFetchStringList(it);
83 } else if (arrayType == DBUS_TYPE_DICT_ENTRY) {
84 // ### support other types of maps?
85 QMap<QString, QVariant> map;
87 dbus_message_iter_recurse(it, &sub);
88 if (!dbus_message_iter_has_next(&sub))
91 DBusMessageIter itemIter;
92 dbus_message_iter_recurse(&sub, &itemIter);
93 Q_ASSERT(dbus_message_iter_has_next(&itemIter));
94 QString key = qFetchParameter(&itemIter).toString();
95 dbus_message_iter_next(&itemIter);
96 map.insertMulti(key, qFetchParameter(&itemIter));
97 } while (dbus_message_iter_next(&sub));
100 QList<QVariant> list;
102 dbus_message_iter_recurse(it, &sub);
103 if (!dbus_message_iter_has_next(&sub))
106 list.append(qFetchParameter(&sub));
107 } while (dbus_message_iter_next(&sub));
111 case DBUS_TYPE_VARIANT: {
112 QDBusVariant dvariant;
114 dbus_message_iter_recurse(it, &sub);
115 dvariant.signature = QString::fromUtf8(dbus_message_iter_get_signature(&sub));
116 dvariant.value = qFetchParameter(&sub);
117 return qVariantFromValue(dvariant);
120 case DBUS_TYPE_DICT: {
121 QMap<QString, QVariant> map;
124 if (dbus_message_iter_init_dict_iterator(it, &dictIt)) {
126 map[QString::fromUtf8(dbus_message_iter_get_dict_key(&dictIt))] =
127 qFetchParameter(&dictIt);
128 } while (dbus_message_iter_next(&dictIt));
132 case DBUS_TYPE_CUSTOM:
133 return qGetCustomValue(it);
137 qWarning("Don't know how to handle type %d '%c'", dbus_message_iter_get_arg_type(it), dbus_message_iter_get_arg_type(it));
143 void QDBusMarshall::messageToList(QList<QVariant> &list, DBusMessage *message)
148 if (!dbus_message_iter_init(message, &it))
152 list.append(qFetchParameter(&it));
153 } while (dbus_message_iter_next(&it));
156 #define DBUS_APPEND(type,dtype,var) \
157 type dtype##v=(var); \
158 dbus_message_append_args(msg, dtype, &dtype##v, DBUS_TYPE_INVALID)
159 #define DBUS_APPEND_LIST(type,dtype,var,size) \
160 type dtype##v=(var); \
161 dbus_message_append_args(msg, DBUS_TYPE_ARRAY, dtype, &dtype##v, size, DBUS_TYPE_INVALID)
164 static void qAppendToMessage(DBusMessageIter *it, const QString &str)
166 QByteArray ba = str.toUtf8();
167 const char *cdata = ba.constData();
168 dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &cdata);
171 static QVariant::Type qVariantListType(const QList<QVariant> &list)
173 // TODO - catch lists that have a list as first parameter
174 QVariant::Type tp = list.value(0).type();
175 if (tp < QVariant::Int || tp > QVariant::Double)
176 return QVariant::Invalid;
178 for (int i = 1; i < list.count(); ++i) {
179 const QVariant &var = list.at(i);
181 && (var.type() != QVariant::List || qVariantListType(var.toList()) != tp))
182 return QVariant::Invalid;
187 static const char *qDBusListType(const QList<QVariant> &list)
189 static const char *DBusArgs[] = { 0, 0, DBUS_TYPE_INT32_AS_STRING, DBUS_TYPE_UINT32_AS_STRING,
190 DBUS_TYPE_INT64_AS_STRING, DBUS_TYPE_UINT64_AS_STRING, DBUS_TYPE_DOUBLE_AS_STRING };
192 return DBusArgs[qVariantListType(list)];
195 static void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list);
197 static void qVariantToIterator(DBusMessageIter *it, const QVariant &var)
199 static const int Variant2DBus[] = { DBUS_TYPE_INVALID,
200 DBUS_TYPE_BOOLEAN, DBUS_TYPE_INT32, DBUS_TYPE_UINT32,
201 DBUS_TYPE_INT64, DBUS_TYPE_UINT64, DBUS_TYPE_DOUBLE };
203 // these really are static asserts
204 Q_ASSERT(QVariant::Invalid == 0);
205 Q_ASSERT(QVariant::Int == 2);
206 Q_ASSERT(QVariant::Double == 6);
208 switch (var.type()) {
211 case QVariant::LongLong:
212 case QVariant::ULongLong:
213 case QVariant::Double:
214 dbus_message_iter_append_basic(it, Variant2DBus[var.type()],
217 case QVariant::String:
218 qAppendToMessage(it, var.toString());
220 case QVariant::StringList: {
221 const QStringList list = var.toStringList();
223 dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
224 DBUS_TYPE_STRING_AS_STRING, &sub);
225 for (int s = 0; s < list.count(); ++s)
226 qAppendToMessage(&sub, list.at(s));
227 dbus_message_iter_close_container(it, &sub);
230 case QVariant::List: {
231 const QList<QVariant> &list = var.toList();
232 const char *listType = qDBusListType(list);
234 qWarning("Don't know how to marshall list.");
238 dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, listType, &sub);
239 qListToIterator(&sub, list);
240 dbus_message_iter_close_container(it, &sub);
243 case QVariant::Map: {
244 // ### TODO - marshall more than qstring/qstring maps
245 const QMap<QString, QVariant> &map = var.toMap();
247 QVarLengthArray<char, 16> sig;
248 sig.append(DBUS_DICT_ENTRY_BEGIN_CHAR);
249 sig.append(DBUS_TYPE_STRING);
250 sig.append(DBUS_TYPE_STRING);
251 sig.append(DBUS_DICT_ENTRY_END_CHAR);
253 qDebug() << QString::fromAscii(sig.constData());
254 dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.constData(), &sub);
255 for (QMap<QString, QVariant>::const_iterator mit = map.constBegin();
256 mit != map.constEnd(); ++mit) {
257 DBusMessageIter itemIterator;
258 dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, 0, &itemIterator);
259 qAppendToMessage(&itemIterator, mit.key());
260 qAppendToMessage(&itemIterator, mit.value().toString());
261 dbus_message_iter_close_container(&sub, &itemIterator);
263 dbus_message_iter_close_container(it, &sub);
266 case QVariant::UserType: {
267 if (var.userType() == QMetaTypeId<QDBusVariant>::qt_metatype_id()) {
269 QDBusVariant dvariant = qvariant_cast<QDBusVariant>(var);
270 dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT,
271 dvariant.signature.toUtf8().constData(), &sub);
272 qVariantToIterator(&sub, dvariant.value);
273 dbus_message_iter_close_container(it, &sub);
279 qWarning("Don't know how to handle type %s", var.typeName());
284 void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list)
289 for (int i = 0; i < list.count(); ++i)
290 qVariantToIterator(it, list.at(i));
293 void QDBusMarshall::listToMessage(const QList<QVariant> &list, DBusMessage *msg)
297 dbus_message_iter_init_append(msg, &it);
298 qListToIterator(&it, list);