1 /* D-Bus Message unserialization. This contains all the logic to map from
2 * D-Bus types to Python objects.
4 * Copyright (C) 2006 Collabora Ltd.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #define DBG_IS_TOO_VERBOSE
27 #include "types-internal.h"
28 #include "message-internal.h"
30 char dbus_py_Message_get_args_list__doc__
[] = (
31 "get_args_list(**kwargs) -> list\n\n"
32 "Return the message's arguments. Keyword arguments control the translation\n"
33 "of D-Bus types to Python:\n"
36 " `byte_arrays` : bool\n"
37 " If true, convert arrays of byte (signature 'ay') into ByteArray,\n"
38 " a str subclass. In practice, this is usually what you want, but\n"
39 " it's off by default for consistency.\n"
41 " If false (default), convert them into a dbus.Array of Bytes.\n"
42 " `utf8_strings` : bool\n"
43 " If true, return D-Bus strings as Python 8-bit strings (of UTF-8).\n"
44 " If false (default), return D-Bus strings as Python unicode objects.\n"
46 "Most of the type mappings should be fairly obvious:\n"
48 "=============== ===================================================\n"
50 "=============== ===================================================\n"
51 "byte (y) Byte (int if integer_bytes set)\n"
52 "bool (b) Boolean (int subclass)\n"
53 "Signature (g) Signature (str subclass)\n"
54 "intNN, uintNN IntNN, UIntNN (int/long subclass)\n"
56 "string (s) unicode (str if utf8_strings set)\n"
57 "Object path (o) ObjectPath (str subclass)\n"
58 "dict (a{...}) dict\n"
59 "array (a...) list of appropriate types\n"
60 "byte array (ay) ByteArray (str subclass) if byte_arrays set; or\n"
62 "struct ((...)) tuple of appropriate types\n"
63 "variant (v) contained type, but with variant_level > 0\n"
64 "=============== ===================================================\n"
70 } Message_get_args_options
;
72 static PyObject
*_message_iter_get_pyobject(DBusMessageIter
*iter
,
73 Message_get_args_options
*opts
,
76 /* Append all the items iterated over to the given Python list object.
77 * Return 0 on success/-1 with exception on failure. */
79 _message_iter_append_all_to_list(DBusMessageIter
*iter
, PyObject
*list
,
80 Message_get_args_options
*opts
)
83 while ((type
= dbus_message_iter_get_arg_type(iter
))
84 != DBUS_TYPE_INVALID
) {
86 DBG("type == %d '%c'", type
, type
);
88 item
= _message_iter_get_pyobject(iter
, opts
, 0);
91 fprintf(stderr
, "DBG/%ld: appending to list: %p == ", (long)getpid(), item
);
92 PyObject_Print(item
, stderr
, 0);
93 fprintf(stderr
, " of type %p\n", item
->ob_type
);
95 ret
= PyList_Append(list
, item
);
98 if (ret
< 0) return -1;
100 fprintf(stderr
, "DBG/%ld: list now contains: ", (long)getpid());
101 PyObject_Print(list
, stderr
, 0);
102 fprintf(stderr
, "\n");
104 dbus_message_iter_next(iter
);
109 static inline PyObject
*
110 _message_iter_get_dict(DBusMessageIter
*iter
,
111 Message_get_args_options
*opts
,
114 DBusMessageIter entries
;
115 char *sig_str
= dbus_message_iter_get_signature(iter
);
120 sig
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
121 "(s#)", sig_str
+2, strlen(sig_str
)-3);
122 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig
);
128 ret
= PyObject_Call((PyObject
*)&DBusPyDict_Type
, dbus_py_empty_tuple
, kwargs
);
133 dbus_message_iter_recurse(iter
, &entries
);
134 while (dbus_message_iter_get_arg_type(&entries
) == DBUS_TYPE_DICT_ENTRY
) {
135 PyObject
*key
= NULL
;
136 PyObject
*value
= NULL
;
139 DBG("%s", "dict entry...");
141 dbus_message_iter_recurse(&entries
, &kv
);
143 key
= _message_iter_get_pyobject(&kv
, opts
, 0);
148 dbus_message_iter_next(&kv
);
150 value
= _message_iter_get_pyobject(&kv
, opts
, 0);
157 status
= PyDict_SetItem(ret
, key
, value
);
165 dbus_message_iter_next(&entries
);
171 /* Returns a new reference. */
173 _message_iter_get_pyobject(DBusMessageIter
*iter
,
174 Message_get_args_options
*opts
,
187 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
192 int type
= dbus_message_iter_get_arg_type(iter
);
193 PyObject
*args
= NULL
;
194 PyObject
*kwargs
= NULL
;
195 PyObject
*ret
= NULL
;
197 /* If the variant-level is >0, prepare a dict for the kwargs.
198 * For variant wrappers optimize slightly by skipping this.
200 if (variant_level
> 0 && type
!= DBUS_TYPE_VARIANT
) {
201 PyObject
*variant_level_int
;
203 variant_level_int
= PyInt_FromLong(variant_level
);
204 if (!variant_level_int
) {
207 kwargs
= PyDict_New();
209 Py_DECREF(variant_level_int
);
212 if (PyDict_SetItem(kwargs
, dbus_py_variant_level_const
,
213 variant_level_int
) < 0) {
214 Py_DECREF(variant_level_int
);
218 Py_DECREF(variant_level_int
);
220 /* From here down you need to break from the switch to exit, so the
221 * dict is freed if necessary
225 case DBUS_TYPE_STRING
:
226 DBG("%s", "found a string");
227 dbus_message_iter_get_basic(iter
, &u
.s
);
228 if (opts
->utf8_strings
) {
229 args
= Py_BuildValue("(s)", u
.s
);
231 ret
= PyObject_Call((PyObject
*)&DBusPyUTF8String_Type
,
235 args
= Py_BuildValue("(O)", PyUnicode_DecodeUTF8(u
.s
,
241 ret
= PyObject_Call((PyObject
*)&DBusPyString_Type
,
246 case DBUS_TYPE_SIGNATURE
:
247 DBG("%s", "found a signature");
248 dbus_message_iter_get_basic(iter
, &u
.s
);
249 args
= Py_BuildValue("(s)", u
.s
);
251 ret
= PyObject_Call((PyObject
*)&DBusPySignature_Type
, args
, kwargs
);
254 case DBUS_TYPE_OBJECT_PATH
:
255 DBG("%s", "found an object path");
256 dbus_message_iter_get_basic(iter
, &u
.s
);
257 args
= Py_BuildValue("(s)", u
.s
);
259 ret
= PyObject_Call((PyObject
*)&DBusPyObjectPath_Type
, args
, kwargs
);
262 case DBUS_TYPE_DOUBLE
:
263 DBG("%s", "found a double");
264 dbus_message_iter_get_basic(iter
, &u
.d
);
265 args
= Py_BuildValue("(f)", u
.d
);
267 ret
= PyObject_Call((PyObject
*)&DBusPyDouble_Type
, args
, kwargs
);
270 #ifdef WITH_DBUS_FLOAT32
271 case DBUS_TYPE_FLOAT
:
272 DBG("%s", "found a float");
273 dbus_message_iter_get_basic(iter
, &u
.f
);
274 args
= Py_BuildValue("(f)", (double)u
.f
);
276 ret
= PyObject_Call((PyObject
*)&DBusPyFloat_Type
, args
, kwargs
);
280 case DBUS_TYPE_INT16
:
281 DBG("%s", "found an int16");
282 dbus_message_iter_get_basic(iter
, &u
.i16
);
283 args
= Py_BuildValue("(i)", (int)u
.i16
);
285 ret
= PyObject_Call((PyObject
*)&DBusPyInt16_Type
, args
, kwargs
);
288 case DBUS_TYPE_UINT16
:
289 DBG("%s", "found a uint16");
290 dbus_message_iter_get_basic(iter
, &u
.u16
);
291 args
= Py_BuildValue("(i)", (int)u
.u16
);
293 ret
= PyObject_Call((PyObject
*)&DBusPyUInt16_Type
, args
, kwargs
);
296 case DBUS_TYPE_INT32
:
297 DBG("%s", "found an int32");
298 dbus_message_iter_get_basic(iter
, &u
.i32
);
299 args
= Py_BuildValue("(l)", (long)u
.i32
);
301 ret
= PyObject_Call((PyObject
*)&DBusPyInt32_Type
, args
, kwargs
);
304 case DBUS_TYPE_UINT32
:
305 DBG("%s", "found a uint32");
306 dbus_message_iter_get_basic(iter
, &u
.u32
);
307 args
= Py_BuildValue("(k)", (unsigned long)u
.u32
);
309 ret
= PyObject_Call((PyObject
*)&DBusPyUInt32_Type
, args
, kwargs
);
312 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
313 case DBUS_TYPE_INT64
:
314 DBG("%s", "found an int64");
315 dbus_message_iter_get_basic(iter
, &u
.i64
);
316 args
= Py_BuildValue("(L)", (PY_LONG_LONG
)u
.i64
);
318 ret
= PyObject_Call((PyObject
*)&DBusPyInt64_Type
, args
, kwargs
);
321 case DBUS_TYPE_UINT64
:
322 DBG("%s", "found a uint64");
323 dbus_message_iter_get_basic(iter
, &u
.u64
);
324 args
= Py_BuildValue("(K)", (unsigned PY_LONG_LONG
)u
.u64
);
326 ret
= PyObject_Call((PyObject
*)&DBusPyUInt64_Type
, args
, kwargs
);
329 case DBUS_TYPE_INT64
:
330 case DBUS_TYPE_UINT64
:
331 PyErr_SetString(PyExc_NotImplementedError
,
332 "64-bit integer types are not supported on "
338 DBG("%s", "found a byte");
339 dbus_message_iter_get_basic(iter
, &u
.y
);
340 args
= Py_BuildValue("(l)", (long)u
.y
);
343 ret
= PyObject_Call((PyObject
*)&DBusPyByte_Type
, args
, kwargs
);
346 case DBUS_TYPE_BOOLEAN
:
347 DBG("%s", "found a bool");
348 dbus_message_iter_get_basic(iter
, &u
.b
);
349 args
= Py_BuildValue("(l)", (long)u
.b
);
352 ret
= PyObject_Call((PyObject
*)&DBusPyBoolean_Type
, args
, kwargs
);
355 case DBUS_TYPE_ARRAY
:
356 DBG("%s", "found an array...");
357 /* Dicts are arrays of DBUS_TYPE_DICT_ENTRY on the wire.
358 Also, we special-case arrays of DBUS_TYPE_BYTE sometimes. */
359 type
= dbus_message_iter_get_element_type(iter
);
360 if (type
== DBUS_TYPE_DICT_ENTRY
) {
361 DBG("%s", "no, actually it's a dict...");
363 kwargs
= PyDict_New();
366 ret
= _message_iter_get_dict(iter
, opts
, kwargs
);
368 else if (opts
->byte_arrays
&& type
== DBUS_TYPE_BYTE
) {
372 DBG("%s", "actually, a byte array...");
373 dbus_message_iter_recurse(iter
, &sub
);
374 dbus_message_iter_get_fixed_array(&sub
,
375 (const unsigned char **)&u
.s
,
377 args
= Py_BuildValue("(s#)", u
.s
, n
);
379 ret
= PyObject_Call((PyObject
*)&DBusPyByteArray_Type
,
388 DBG("%s", "a normal array...");
390 kwargs
= PyDict_New();
393 dbus_message_iter_recurse(iter
, &sub
);
394 sig
= dbus_message_iter_get_signature(&sub
);
396 sig_obj
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
400 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig_obj
);
402 if (status
< 0) break;
403 ret
= PyObject_Call((PyObject
*)&DBusPyArray_Type
,
404 dbus_py_empty_tuple
, kwargs
);
406 if (_message_iter_append_all_to_list(&sub
, ret
, opts
) < 0) {
413 case DBUS_TYPE_STRUCT
:
416 PyObject
*list
= PyList_New(0);
419 DBG("%s", "found a struct...");
421 dbus_message_iter_recurse(iter
, &sub
);
422 if (_message_iter_append_all_to_list(&sub
, list
, opts
) < 0) {
426 tuple
= Py_BuildValue("(O)", list
);
428 ret
= PyObject_Call((PyObject
*)&DBusPyStruct_Type
, tuple
, kwargs
);
433 /* whether successful or not, we take the same action: */
439 case DBUS_TYPE_VARIANT
:
443 DBG("%s", "found a variant...");
444 dbus_message_iter_recurse(iter
, &sub
);
445 ret
= _message_iter_get_pyobject(&sub
, opts
, variant_level
+1);
450 PyErr_Format(PyExc_TypeError
, "Unknown type '\\%x' in D-Bus "
464 dbus_py_Message_get_args_list(Message
*self
, PyObject
*args
, PyObject
*kwargs
)
466 Message_get_args_options opts
= { 0, 0 };
467 static char *argnames
[] = { "byte_arrays", "utf8_strings", NULL
};
469 DBusMessageIter iter
;
472 fprintf(stderr
, "DBG/%ld: called Message_get_args_list(self, *",
474 PyObject_Print(args
, stderr
, 0);
476 fprintf(stderr
, ", **");
477 PyObject_Print(kwargs
, stderr
, 0);
479 fprintf(stderr
, ")\n");
482 if (PyTuple_Size(args
) != 0) {
483 PyErr_SetString(PyExc_TypeError
, "get_args_list takes no positional "
487 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|ii:get_args_list",
490 &(opts
.utf8_strings
))) return NULL
;
491 if (!self
->msg
) return DBusPy_RaiseUnusableMessage();
493 list
= PyList_New(0);
494 if (!list
) return NULL
;
496 /* Iterate over args, if any, appending to list */
497 if (dbus_message_iter_init(self
->msg
, &iter
)) {
498 if (_message_iter_append_all_to_list(&iter
, list
, &opts
) < 0) {
500 DBG_EXC("%s", "Message_get_args: appending all to list failed:");
506 fprintf(stderr
, "DBG/%ld: message has args list ", (long)getpid());
507 PyObject_Print(list
, stderr
, 0);
508 fprintf(stderr
, "\n");
514 /* vim:set ft=c cino< sw=4 sts=4 et: */