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 PY_SIZE_T_CLEAN 1
28 #define DBG_IS_TOO_VERBOSE
29 #include "types-internal.h"
30 #include "message-internal.h"
32 char dbus_py_Message_get_args_list__doc__
[] = (
33 "get_args_list(**kwargs) -> list\n\n"
34 "Return the message's arguments. Keyword arguments control the translation\n"
35 "of D-Bus types to Python:\n"
38 " `byte_arrays` : bool\n"
39 " If true, convert arrays of byte (signature 'ay') into dbus.ByteArray,\n"
40 " a str subclass. In practice, this is usually what you want, but\n"
41 " it's off by default for consistency.\n"
43 " If false (default), convert them into a dbus.Array of Bytes.\n"
44 " `utf8_strings` : bool\n"
45 " If true, return D-Bus strings as Python 8-bit strings (of UTF-8).\n"
46 " If false (default), return D-Bus strings as Python unicode objects.\n"
48 "Most of the type mappings should be fairly obvious:\n"
50 "=============== ===================================================\n"
52 "=============== ===================================================\n"
53 "byte (y) dbus.Byte (int subclass)\n"
54 "bool (b) dbus.Boolean (int subclass)\n"
55 "Signature (g) dbus.Signature (str subclass)\n"
56 "intNN, uintNN dbus.IntNN, dbus.UIntNN (int or long subclasses)\n"
57 "double (d) dbus.Double\n"
58 "string (s) dbus.String (unicode subclass)\n"
59 " (or dbus.UTF8String, str subclass, if utf8_strings set)\n"
60 "Object path (o) dbus.ObjectPath (str subclass)\n"
61 "dict (a{...}) dbus.Dictionary\n"
62 "array (a...) dbus.Array (list subclass) containing appropriate types\n"
63 "byte array (ay) dbus.ByteArray (str subclass) if byte_arrays set; or\n"
65 "struct ((...)) dbus.Struct (tuple subclass) of appropriate types\n"
66 "variant (v) contained type, but with variant_level > 0\n"
67 "=============== ===================================================\n"
73 } Message_get_args_options
;
75 static PyObject
*_message_iter_get_pyobject(DBusMessageIter
*iter
,
76 Message_get_args_options
*opts
,
79 /* Append all the items iterated over to the given Python list object.
80 * Return 0 on success/-1 with exception on failure. */
82 _message_iter_append_all_to_list(DBusMessageIter
*iter
, PyObject
*list
,
83 Message_get_args_options
*opts
)
86 while ((type
= dbus_message_iter_get_arg_type(iter
))
87 != DBUS_TYPE_INVALID
) {
89 DBG("type == %d '%c'", type
, type
);
91 item
= _message_iter_get_pyobject(iter
, opts
, 0);
94 fprintf(stderr
, "DBG/%ld: appending to list: %p == ", (long)getpid(), item
);
95 PyObject_Print(item
, stderr
, 0);
96 fprintf(stderr
, " of type %p\n", item
->ob_type
);
98 ret
= PyList_Append(list
, item
);
101 if (ret
< 0) return -1;
103 fprintf(stderr
, "DBG/%ld: list now contains: ", (long)getpid());
104 PyObject_Print(list
, stderr
, 0);
105 fprintf(stderr
, "\n");
107 dbus_message_iter_next(iter
);
112 static inline PyObject
*
113 _message_iter_get_dict(DBusMessageIter
*iter
,
114 Message_get_args_options
*opts
,
117 DBusMessageIter entries
;
118 char *sig_str
= dbus_message_iter_get_signature(iter
);
123 sig
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
125 (Py_ssize_t
)strlen(sig_str
)-3);
126 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig
);
132 ret
= PyObject_Call((PyObject
*)&DBusPyDict_Type
, dbus_py_empty_tuple
, kwargs
);
137 dbus_message_iter_recurse(iter
, &entries
);
138 while (dbus_message_iter_get_arg_type(&entries
) == DBUS_TYPE_DICT_ENTRY
) {
139 PyObject
*key
= NULL
;
140 PyObject
*value
= NULL
;
143 DBG("%s", "dict entry...");
145 dbus_message_iter_recurse(&entries
, &kv
);
147 key
= _message_iter_get_pyobject(&kv
, opts
, 0);
152 dbus_message_iter_next(&kv
);
154 value
= _message_iter_get_pyobject(&kv
, opts
, 0);
161 status
= PyDict_SetItem(ret
, key
, value
);
169 dbus_message_iter_next(&entries
);
175 /* Returns a new reference. */
177 _message_iter_get_pyobject(DBusMessageIter
*iter
,
178 Message_get_args_options
*opts
,
191 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
196 int type
= dbus_message_iter_get_arg_type(iter
);
197 PyObject
*args
= NULL
;
198 PyObject
*kwargs
= NULL
;
199 PyObject
*ret
= NULL
;
201 /* If the variant-level is >0, prepare a dict for the kwargs.
202 * For variant wrappers optimize slightly by skipping this.
204 if (variant_level
> 0 && type
!= DBUS_TYPE_VARIANT
) {
205 PyObject
*variant_level_int
;
207 variant_level_int
= PyInt_FromLong(variant_level
);
208 if (!variant_level_int
) {
211 kwargs
= PyDict_New();
213 Py_DECREF(variant_level_int
);
216 if (PyDict_SetItem(kwargs
, dbus_py_variant_level_const
,
217 variant_level_int
) < 0) {
218 Py_DECREF(variant_level_int
);
222 Py_DECREF(variant_level_int
);
224 /* From here down you need to break from the switch to exit, so the
225 * dict is freed if necessary
229 case DBUS_TYPE_STRING
:
230 DBG("%s", "found a string");
231 dbus_message_iter_get_basic(iter
, &u
.s
);
232 if (opts
->utf8_strings
) {
233 args
= Py_BuildValue("(s)", u
.s
);
235 ret
= PyObject_Call((PyObject
*)&DBusPyUTF8String_Type
,
239 args
= Py_BuildValue("(O)", PyUnicode_DecodeUTF8(u
.s
,
245 ret
= PyObject_Call((PyObject
*)&DBusPyString_Type
,
250 case DBUS_TYPE_SIGNATURE
:
251 DBG("%s", "found a signature");
252 dbus_message_iter_get_basic(iter
, &u
.s
);
253 args
= Py_BuildValue("(s)", u
.s
);
255 ret
= PyObject_Call((PyObject
*)&DBusPySignature_Type
, args
, kwargs
);
258 case DBUS_TYPE_OBJECT_PATH
:
259 DBG("%s", "found an object path");
260 dbus_message_iter_get_basic(iter
, &u
.s
);
261 args
= Py_BuildValue("(s)", u
.s
);
263 ret
= PyObject_Call((PyObject
*)&DBusPyObjectPath_Type
, args
, kwargs
);
266 case DBUS_TYPE_DOUBLE
:
267 DBG("%s", "found a double");
268 dbus_message_iter_get_basic(iter
, &u
.d
);
269 args
= Py_BuildValue("(f)", u
.d
);
271 ret
= PyObject_Call((PyObject
*)&DBusPyDouble_Type
, args
, kwargs
);
274 #ifdef WITH_DBUS_FLOAT32
275 case DBUS_TYPE_FLOAT
:
276 DBG("%s", "found a float");
277 dbus_message_iter_get_basic(iter
, &u
.f
);
278 args
= Py_BuildValue("(f)", (double)u
.f
);
280 ret
= PyObject_Call((PyObject
*)&DBusPyFloat_Type
, args
, kwargs
);
284 case DBUS_TYPE_INT16
:
285 DBG("%s", "found an int16");
286 dbus_message_iter_get_basic(iter
, &u
.i16
);
287 args
= Py_BuildValue("(i)", (int)u
.i16
);
289 ret
= PyObject_Call((PyObject
*)&DBusPyInt16_Type
, args
, kwargs
);
292 case DBUS_TYPE_UINT16
:
293 DBG("%s", "found a uint16");
294 dbus_message_iter_get_basic(iter
, &u
.u16
);
295 args
= Py_BuildValue("(i)", (int)u
.u16
);
297 ret
= PyObject_Call((PyObject
*)&DBusPyUInt16_Type
, args
, kwargs
);
300 case DBUS_TYPE_INT32
:
301 DBG("%s", "found an int32");
302 dbus_message_iter_get_basic(iter
, &u
.i32
);
303 args
= Py_BuildValue("(l)", (long)u
.i32
);
305 ret
= PyObject_Call((PyObject
*)&DBusPyInt32_Type
, args
, kwargs
);
308 case DBUS_TYPE_UINT32
:
309 DBG("%s", "found a uint32");
310 dbus_message_iter_get_basic(iter
, &u
.u32
);
311 args
= Py_BuildValue("(k)", (unsigned long)u
.u32
);
313 ret
= PyObject_Call((PyObject
*)&DBusPyUInt32_Type
, args
, kwargs
);
316 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
317 case DBUS_TYPE_INT64
:
318 DBG("%s", "found an int64");
319 dbus_message_iter_get_basic(iter
, &u
.i64
);
320 args
= Py_BuildValue("(L)", (PY_LONG_LONG
)u
.i64
);
322 ret
= PyObject_Call((PyObject
*)&DBusPyInt64_Type
, args
, kwargs
);
325 case DBUS_TYPE_UINT64
:
326 DBG("%s", "found a uint64");
327 dbus_message_iter_get_basic(iter
, &u
.u64
);
328 args
= Py_BuildValue("(K)", (unsigned PY_LONG_LONG
)u
.u64
);
330 ret
= PyObject_Call((PyObject
*)&DBusPyUInt64_Type
, args
, kwargs
);
333 case DBUS_TYPE_INT64
:
334 case DBUS_TYPE_UINT64
:
335 PyErr_SetString(PyExc_NotImplementedError
,
336 "64-bit integer types are not supported on "
342 DBG("%s", "found a byte");
343 dbus_message_iter_get_basic(iter
, &u
.y
);
344 args
= Py_BuildValue("(l)", (long)u
.y
);
347 ret
= PyObject_Call((PyObject
*)&DBusPyByte_Type
, args
, kwargs
);
350 case DBUS_TYPE_BOOLEAN
:
351 DBG("%s", "found a bool");
352 dbus_message_iter_get_basic(iter
, &u
.b
);
353 args
= Py_BuildValue("(l)", (long)u
.b
);
356 ret
= PyObject_Call((PyObject
*)&DBusPyBoolean_Type
, args
, kwargs
);
359 case DBUS_TYPE_ARRAY
:
360 DBG("%s", "found an array...");
361 /* Dicts are arrays of DBUS_TYPE_DICT_ENTRY on the wire.
362 Also, we special-case arrays of DBUS_TYPE_BYTE sometimes. */
363 type
= dbus_message_iter_get_element_type(iter
);
364 if (type
== DBUS_TYPE_DICT_ENTRY
) {
365 DBG("%s", "no, actually it's a dict...");
367 kwargs
= PyDict_New();
370 ret
= _message_iter_get_dict(iter
, opts
, kwargs
);
372 else if (opts
->byte_arrays
&& type
== DBUS_TYPE_BYTE
) {
376 DBG("%s", "actually, a byte array...");
377 dbus_message_iter_recurse(iter
, &sub
);
378 dbus_message_iter_get_fixed_array(&sub
,
379 (const unsigned char **)&u
.s
,
381 args
= Py_BuildValue("(s#)", u
.s
, (Py_ssize_t
)n
);
383 ret
= PyObject_Call((PyObject
*)&DBusPyByteArray_Type
,
392 DBG("%s", "a normal array...");
394 kwargs
= PyDict_New();
397 dbus_message_iter_recurse(iter
, &sub
);
398 sig
= dbus_message_iter_get_signature(&sub
);
400 sig_obj
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
404 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig_obj
);
406 if (status
< 0) break;
407 ret
= PyObject_Call((PyObject
*)&DBusPyArray_Type
,
408 dbus_py_empty_tuple
, kwargs
);
410 if (_message_iter_append_all_to_list(&sub
, ret
, opts
) < 0) {
417 case DBUS_TYPE_STRUCT
:
420 PyObject
*list
= PyList_New(0);
423 DBG("%s", "found a struct...");
425 dbus_message_iter_recurse(iter
, &sub
);
426 if (_message_iter_append_all_to_list(&sub
, list
, opts
) < 0) {
430 tuple
= Py_BuildValue("(O)", list
);
432 ret
= PyObject_Call((PyObject
*)&DBusPyStruct_Type
, tuple
, kwargs
);
437 /* whether successful or not, we take the same action: */
443 case DBUS_TYPE_VARIANT
:
447 DBG("%s", "found a variant...");
448 dbus_message_iter_recurse(iter
, &sub
);
449 ret
= _message_iter_get_pyobject(&sub
, opts
, variant_level
+1);
454 PyErr_Format(PyExc_TypeError
, "Unknown type '\\%x' in D-Bus "
468 dbus_py_Message_get_args_list(Message
*self
, PyObject
*args
, PyObject
*kwargs
)
470 Message_get_args_options opts
= { 0, 0 };
471 static char *argnames
[] = { "byte_arrays", "utf8_strings", NULL
};
473 DBusMessageIter iter
;
476 fprintf(stderr
, "DBG/%ld: called Message_get_args_list(self, *",
478 PyObject_Print(args
, stderr
, 0);
480 fprintf(stderr
, ", **");
481 PyObject_Print(kwargs
, stderr
, 0);
483 fprintf(stderr
, ")\n");
486 if (PyTuple_Size(args
) != 0) {
487 PyErr_SetString(PyExc_TypeError
, "get_args_list takes no positional "
491 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|ii:get_args_list",
494 &(opts
.utf8_strings
))) return NULL
;
495 if (!self
->msg
) return DBusPy_RaiseUnusableMessage();
497 list
= PyList_New(0);
498 if (!list
) return NULL
;
500 /* Iterate over args, if any, appending to list */
501 if (dbus_message_iter_init(self
->msg
, &iter
)) {
502 if (_message_iter_append_all_to_list(&iter
, list
, &opts
) < 0) {
504 DBG_EXC("%s", "Message_get_args: appending all to list failed:");
510 fprintf(stderr
, "DBG/%ld: message has args list ", (long)getpid());
511 PyObject_Print(list
, stderr
, 0);
512 fprintf(stderr
, "\n");
518 /* vim:set ft=c cino< sw=4 sts=4 et: */