1 /* D-Bus Message unserialization. This contains all the logic to map from
2 * D-Bus types to Python objects.
4 * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use, copy,
10 * modify, merge, publish, distribute, sublicense, and/or sell copies
11 * of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
27 #define PY_SIZE_T_CLEAN 1
29 #define DBG_IS_TOO_VERBOSE
30 #include "types-internal.h"
31 #include "message-internal.h"
33 char dbus_py_Message_get_args_list__doc__
[] = (
34 "get_args_list(**kwargs) -> list\n\n"
35 "Return the message's arguments. Keyword arguments control the translation\n"
36 "of D-Bus types to Python:\n"
39 " `byte_arrays` : bool\n"
40 " If true, convert arrays of byte (signature 'ay') into dbus.ByteArray,\n"
41 " a str subclass. In practice, this is usually what you want, but\n"
42 " it's off by default for consistency.\n"
44 " If false (default), convert them into a dbus.Array of Bytes.\n"
45 " `utf8_strings` : bool\n"
46 " If true, return D-Bus strings as Python 8-bit strings (of UTF-8).\n"
47 " If false (default), return D-Bus strings as Python unicode objects.\n"
49 "Most of the type mappings should be fairly obvious:\n"
51 "=============== ===================================================\n"
53 "=============== ===================================================\n"
54 "byte (y) dbus.Byte (int subclass)\n"
55 "bool (b) dbus.Boolean (int subclass)\n"
56 "Signature (g) dbus.Signature (str subclass)\n"
57 "intNN, uintNN dbus.IntNN, dbus.UIntNN (int or long subclasses)\n"
58 "double (d) dbus.Double\n"
59 "string (s) dbus.String (unicode subclass)\n"
60 " (or dbus.UTF8String, str subclass, if utf8_strings set)\n"
61 "Object path (o) dbus.ObjectPath (str subclass)\n"
62 "dict (a{...}) dbus.Dictionary\n"
63 "array (a...) dbus.Array (list subclass) containing appropriate types\n"
64 "byte array (ay) dbus.ByteArray (str subclass) if byte_arrays set; or\n"
66 "struct ((...)) dbus.Struct (tuple subclass) of appropriate types\n"
67 "variant (v) contained type, but with variant_level > 0\n"
68 "=============== ===================================================\n"
74 } Message_get_args_options
;
76 static PyObject
*_message_iter_get_pyobject(DBusMessageIter
*iter
,
77 Message_get_args_options
*opts
,
80 /* Append all the items iterated over to the given Python list object.
81 * Return 0 on success/-1 with exception on failure. */
83 _message_iter_append_all_to_list(DBusMessageIter
*iter
, PyObject
*list
,
84 Message_get_args_options
*opts
)
87 while ((type
= dbus_message_iter_get_arg_type(iter
))
88 != DBUS_TYPE_INVALID
) {
90 DBG("type == %d '%c'", type
, type
);
92 item
= _message_iter_get_pyobject(iter
, opts
, 0);
95 fprintf(stderr
, "DBG/%ld: appending to list: %p == ", (long)getpid(), item
);
96 PyObject_Print(item
, stderr
, 0);
97 fprintf(stderr
, " of type %p\n", item
->ob_type
);
99 ret
= PyList_Append(list
, item
);
102 if (ret
< 0) return -1;
104 fprintf(stderr
, "DBG/%ld: list now contains: ", (long)getpid());
105 PyObject_Print(list
, stderr
, 0);
106 fprintf(stderr
, "\n");
108 dbus_message_iter_next(iter
);
113 static inline PyObject
*
114 _message_iter_get_dict(DBusMessageIter
*iter
,
115 Message_get_args_options
*opts
,
118 DBusMessageIter entries
;
119 char *sig_str
= dbus_message_iter_get_signature(iter
);
128 sig
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
130 (Py_ssize_t
)strlen(sig_str
)-3);
135 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig
);
141 ret
= PyObject_Call((PyObject
*)&DBusPyDict_Type
, dbus_py_empty_tuple
, kwargs
);
146 dbus_message_iter_recurse(iter
, &entries
);
147 while (dbus_message_iter_get_arg_type(&entries
) == DBUS_TYPE_DICT_ENTRY
) {
148 PyObject
*key
= NULL
;
149 PyObject
*value
= NULL
;
152 DBG("%s", "dict entry...");
154 dbus_message_iter_recurse(&entries
, &kv
);
156 key
= _message_iter_get_pyobject(&kv
, opts
, 0);
161 dbus_message_iter_next(&kv
);
163 value
= _message_iter_get_pyobject(&kv
, opts
, 0);
170 status
= PyDict_SetItem(ret
, key
, value
);
178 dbus_message_iter_next(&entries
);
184 /* Returns a new reference. */
186 _message_iter_get_pyobject(DBusMessageIter
*iter
,
187 Message_get_args_options
*opts
,
200 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
205 int type
= dbus_message_iter_get_arg_type(iter
);
206 PyObject
*args
= NULL
;
207 PyObject
*kwargs
= NULL
;
208 PyObject
*ret
= NULL
;
210 /* If the variant-level is >0, prepare a dict for the kwargs.
211 * For variant wrappers optimize slightly by skipping this.
213 if (variant_level
> 0 && type
!= DBUS_TYPE_VARIANT
) {
214 PyObject
*variant_level_int
;
216 variant_level_int
= PyInt_FromLong(variant_level
);
217 if (!variant_level_int
) {
220 kwargs
= PyDict_New();
222 Py_DECREF(variant_level_int
);
225 if (PyDict_SetItem(kwargs
, dbus_py_variant_level_const
,
226 variant_level_int
) < 0) {
227 Py_DECREF(variant_level_int
);
231 Py_DECREF(variant_level_int
);
233 /* From here down you need to break from the switch to exit, so the
234 * dict is freed if necessary
238 case DBUS_TYPE_STRING
:
239 DBG("%s", "found a string");
240 dbus_message_iter_get_basic(iter
, &u
.s
);
241 if (opts
->utf8_strings
) {
242 args
= Py_BuildValue("(s)", u
.s
);
244 ret
= PyObject_Call((PyObject
*)&DBusPyUTF8String_Type
,
248 args
= Py_BuildValue("(N)", PyUnicode_DecodeUTF8(u
.s
,
254 ret
= PyObject_Call((PyObject
*)&DBusPyString_Type
,
259 case DBUS_TYPE_SIGNATURE
:
260 DBG("%s", "found a signature");
261 dbus_message_iter_get_basic(iter
, &u
.s
);
262 args
= Py_BuildValue("(s)", u
.s
);
264 ret
= PyObject_Call((PyObject
*)&DBusPySignature_Type
, args
, kwargs
);
267 case DBUS_TYPE_OBJECT_PATH
:
268 DBG("%s", "found an object path");
269 dbus_message_iter_get_basic(iter
, &u
.s
);
270 args
= Py_BuildValue("(s)", u
.s
);
272 ret
= PyObject_Call((PyObject
*)&DBusPyObjectPath_Type
, args
, kwargs
);
275 case DBUS_TYPE_DOUBLE
:
276 DBG("%s", "found a double");
277 dbus_message_iter_get_basic(iter
, &u
.d
);
278 args
= Py_BuildValue("(f)", u
.d
);
280 ret
= PyObject_Call((PyObject
*)&DBusPyDouble_Type
, args
, kwargs
);
283 #ifdef WITH_DBUS_FLOAT32
284 case DBUS_TYPE_FLOAT
:
285 DBG("%s", "found a float");
286 dbus_message_iter_get_basic(iter
, &u
.f
);
287 args
= Py_BuildValue("(f)", (double)u
.f
);
289 ret
= PyObject_Call((PyObject
*)&DBusPyFloat_Type
, args
, kwargs
);
293 case DBUS_TYPE_INT16
:
294 DBG("%s", "found an int16");
295 dbus_message_iter_get_basic(iter
, &u
.i16
);
296 args
= Py_BuildValue("(i)", (int)u
.i16
);
298 ret
= PyObject_Call((PyObject
*)&DBusPyInt16_Type
, args
, kwargs
);
301 case DBUS_TYPE_UINT16
:
302 DBG("%s", "found a uint16");
303 dbus_message_iter_get_basic(iter
, &u
.u16
);
304 args
= Py_BuildValue("(i)", (int)u
.u16
);
306 ret
= PyObject_Call((PyObject
*)&DBusPyUInt16_Type
, args
, kwargs
);
309 case DBUS_TYPE_INT32
:
310 DBG("%s", "found an int32");
311 dbus_message_iter_get_basic(iter
, &u
.i32
);
312 args
= Py_BuildValue("(l)", (long)u
.i32
);
314 ret
= PyObject_Call((PyObject
*)&DBusPyInt32_Type
, args
, kwargs
);
317 case DBUS_TYPE_UINT32
:
318 DBG("%s", "found a uint32");
319 dbus_message_iter_get_basic(iter
, &u
.u32
);
320 args
= Py_BuildValue("(k)", (unsigned long)u
.u32
);
322 ret
= PyObject_Call((PyObject
*)&DBusPyUInt32_Type
, args
, kwargs
);
325 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
326 case DBUS_TYPE_INT64
:
327 DBG("%s", "found an int64");
328 dbus_message_iter_get_basic(iter
, &u
.i64
);
329 args
= Py_BuildValue("(L)", (PY_LONG_LONG
)u
.i64
);
331 ret
= PyObject_Call((PyObject
*)&DBusPyInt64_Type
, args
, kwargs
);
334 case DBUS_TYPE_UINT64
:
335 DBG("%s", "found a uint64");
336 dbus_message_iter_get_basic(iter
, &u
.u64
);
337 args
= Py_BuildValue("(K)", (unsigned PY_LONG_LONG
)u
.u64
);
339 ret
= PyObject_Call((PyObject
*)&DBusPyUInt64_Type
, args
, kwargs
);
342 case DBUS_TYPE_INT64
:
343 case DBUS_TYPE_UINT64
:
344 PyErr_SetString(PyExc_NotImplementedError
,
345 "64-bit integer types are not supported on "
351 DBG("%s", "found a byte");
352 dbus_message_iter_get_basic(iter
, &u
.y
);
353 args
= Py_BuildValue("(l)", (long)u
.y
);
356 ret
= PyObject_Call((PyObject
*)&DBusPyByte_Type
, args
, kwargs
);
359 case DBUS_TYPE_BOOLEAN
:
360 DBG("%s", "found a bool");
361 dbus_message_iter_get_basic(iter
, &u
.b
);
362 args
= Py_BuildValue("(l)", (long)u
.b
);
365 ret
= PyObject_Call((PyObject
*)&DBusPyBoolean_Type
, args
, kwargs
);
368 case DBUS_TYPE_ARRAY
:
369 DBG("%s", "found an array...");
370 /* Dicts are arrays of DBUS_TYPE_DICT_ENTRY on the wire.
371 Also, we special-case arrays of DBUS_TYPE_BYTE sometimes. */
372 type
= dbus_message_iter_get_element_type(iter
);
373 if (type
== DBUS_TYPE_DICT_ENTRY
) {
374 DBG("%s", "no, actually it's a dict...");
376 kwargs
= PyDict_New();
379 ret
= _message_iter_get_dict(iter
, opts
, kwargs
);
381 else if (opts
->byte_arrays
&& type
== DBUS_TYPE_BYTE
) {
385 DBG("%s", "actually, a byte array...");
386 dbus_message_iter_recurse(iter
, &sub
);
387 dbus_message_iter_get_fixed_array(&sub
,
388 (const unsigned char **)&u
.s
,
390 args
= Py_BuildValue("(s#)", u
.s
, (Py_ssize_t
)n
);
392 ret
= PyObject_Call((PyObject
*)&DBusPyByteArray_Type
,
401 DBG("%s", "a normal array...");
403 kwargs
= PyDict_New();
406 dbus_message_iter_recurse(iter
, &sub
);
407 sig
= dbus_message_iter_get_signature(&sub
);
409 sig_obj
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
413 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig_obj
);
415 if (status
< 0) break;
416 ret
= PyObject_Call((PyObject
*)&DBusPyArray_Type
,
417 dbus_py_empty_tuple
, kwargs
);
419 if (_message_iter_append_all_to_list(&sub
, ret
, opts
) < 0) {
426 case DBUS_TYPE_STRUCT
:
429 PyObject
*list
= PyList_New(0);
432 DBG("%s", "found a struct...");
434 dbus_message_iter_recurse(iter
, &sub
);
435 if (_message_iter_append_all_to_list(&sub
, list
, opts
) < 0) {
439 tuple
= Py_BuildValue("(O)", list
);
441 ret
= PyObject_Call((PyObject
*)&DBusPyStruct_Type
, tuple
, kwargs
);
446 /* whether successful or not, we take the same action: */
452 case DBUS_TYPE_VARIANT
:
456 DBG("%s", "found a variant...");
457 dbus_message_iter_recurse(iter
, &sub
);
458 ret
= _message_iter_get_pyobject(&sub
, opts
, variant_level
+1);
463 PyErr_Format(PyExc_TypeError
, "Unknown type '\\%x' in D-Bus "
473 dbus_py_Message_get_args_list(Message
*self
, PyObject
*args
, PyObject
*kwargs
)
475 Message_get_args_options opts
= { 0, 0 };
476 static char *argnames
[] = { "byte_arrays", "utf8_strings", NULL
};
478 DBusMessageIter iter
;
481 fprintf(stderr
, "DBG/%ld: called Message_get_args_list(self, *",
483 PyObject_Print(args
, stderr
, 0);
485 fprintf(stderr
, ", **");
486 PyObject_Print(kwargs
, stderr
, 0);
488 fprintf(stderr
, ")\n");
491 if (PyTuple_Size(args
) != 0) {
492 PyErr_SetString(PyExc_TypeError
, "get_args_list takes no positional "
496 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|ii:get_args_list",
499 &(opts
.utf8_strings
))) return NULL
;
500 if (!self
->msg
) return DBusPy_RaiseUnusableMessage();
502 list
= PyList_New(0);
503 if (!list
) return NULL
;
505 /* Iterate over args, if any, appending to list */
506 if (dbus_message_iter_init(self
->msg
, &iter
)) {
507 if (_message_iter_append_all_to_list(&iter
, list
, &opts
) < 0) {
509 DBG_EXC("%s", "Message_get_args: appending all to list failed:");
515 fprintf(stderr
, "DBG/%ld: message has args list ", (long)getpid());
516 PyObject_Print(list
, stderr
, 0);
517 fprintf(stderr
, "\n");
523 /* vim:set ft=c cino< sw=4 sts=4 et: */