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 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #define PY_SIZE_T_CLEAN 1
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 dbus.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) dbus.Byte (int subclass)\n"
52 "bool (b) dbus.Boolean (int subclass)\n"
53 "Signature (g) dbus.Signature (str subclass)\n"
54 "intNN, uintNN dbus.IntNN, dbus.UIntNN (int or long subclasses)\n"
55 "double (d) dbus.Double\n"
56 "string (s) dbus.String (unicode subclass)\n"
57 " (or dbus.UTF8String, str subclass, if utf8_strings set)\n"
58 "Object path (o) dbus.ObjectPath (str subclass)\n"
59 "dict (a{...}) dbus.Dictionary\n"
60 "array (a...) dbus.Array (list subclass) containing appropriate types\n"
61 "byte array (ay) dbus.ByteArray (str subclass) if byte_arrays set; or\n"
63 "struct ((...)) dbus.Struct (tuple subclass) of appropriate types\n"
64 "variant (v) contained type, but with variant_level > 0\n"
65 "=============== ===================================================\n"
71 } Message_get_args_options
;
73 static PyObject
*_message_iter_get_pyobject(DBusMessageIter
*iter
,
74 Message_get_args_options
*opts
,
77 /* Append all the items iterated over to the given Python list object.
78 * Return 0 on success/-1 with exception on failure. */
80 _message_iter_append_all_to_list(DBusMessageIter
*iter
, PyObject
*list
,
81 Message_get_args_options
*opts
)
84 while ((type
= dbus_message_iter_get_arg_type(iter
))
85 != DBUS_TYPE_INVALID
) {
87 DBG("type == %d '%c'", type
, type
);
89 item
= _message_iter_get_pyobject(iter
, opts
, 0);
92 fprintf(stderr
, "DBG/%ld: appending to list: %p == ", (long)getpid(), item
);
93 PyObject_Print(item
, stderr
, 0);
94 fprintf(stderr
, " of type %p\n", item
->ob_type
);
96 ret
= PyList_Append(list
, item
);
99 if (ret
< 0) return -1;
101 fprintf(stderr
, "DBG/%ld: list now contains: ", (long)getpid());
102 PyObject_Print(list
, stderr
, 0);
103 fprintf(stderr
, "\n");
105 dbus_message_iter_next(iter
);
110 static inline PyObject
*
111 _message_iter_get_dict(DBusMessageIter
*iter
,
112 Message_get_args_options
*opts
,
115 DBusMessageIter entries
;
116 char *sig_str
= dbus_message_iter_get_signature(iter
);
121 sig
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
123 (Py_ssize_t
)strlen(sig_str
)-3);
124 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig
);
130 ret
= PyObject_Call((PyObject
*)&DBusPyDict_Type
, dbus_py_empty_tuple
, kwargs
);
135 dbus_message_iter_recurse(iter
, &entries
);
136 while (dbus_message_iter_get_arg_type(&entries
) == DBUS_TYPE_DICT_ENTRY
) {
137 PyObject
*key
= NULL
;
138 PyObject
*value
= NULL
;
141 DBG("%s", "dict entry...");
143 dbus_message_iter_recurse(&entries
, &kv
);
145 key
= _message_iter_get_pyobject(&kv
, opts
, 0);
150 dbus_message_iter_next(&kv
);
152 value
= _message_iter_get_pyobject(&kv
, opts
, 0);
159 status
= PyDict_SetItem(ret
, key
, value
);
167 dbus_message_iter_next(&entries
);
173 /* Returns a new reference. */
175 _message_iter_get_pyobject(DBusMessageIter
*iter
,
176 Message_get_args_options
*opts
,
189 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
194 int type
= dbus_message_iter_get_arg_type(iter
);
195 PyObject
*args
= NULL
;
196 PyObject
*kwargs
= NULL
;
197 PyObject
*ret
= NULL
;
199 /* If the variant-level is >0, prepare a dict for the kwargs.
200 * For variant wrappers optimize slightly by skipping this.
202 if (variant_level
> 0 && type
!= DBUS_TYPE_VARIANT
) {
203 PyObject
*variant_level_int
;
205 variant_level_int
= PyInt_FromLong(variant_level
);
206 if (!variant_level_int
) {
209 kwargs
= PyDict_New();
211 Py_DECREF(variant_level_int
);
214 if (PyDict_SetItem(kwargs
, dbus_py_variant_level_const
,
215 variant_level_int
) < 0) {
216 Py_DECREF(variant_level_int
);
220 Py_DECREF(variant_level_int
);
222 /* From here down you need to break from the switch to exit, so the
223 * dict is freed if necessary
227 case DBUS_TYPE_STRING
:
228 DBG("%s", "found a string");
229 dbus_message_iter_get_basic(iter
, &u
.s
);
230 if (opts
->utf8_strings
) {
231 args
= Py_BuildValue("(s)", u
.s
);
233 ret
= PyObject_Call((PyObject
*)&DBusPyUTF8String_Type
,
237 args
= Py_BuildValue("(O)", PyUnicode_DecodeUTF8(u
.s
,
243 ret
= PyObject_Call((PyObject
*)&DBusPyString_Type
,
248 case DBUS_TYPE_SIGNATURE
:
249 DBG("%s", "found a signature");
250 dbus_message_iter_get_basic(iter
, &u
.s
);
251 args
= Py_BuildValue("(s)", u
.s
);
253 ret
= PyObject_Call((PyObject
*)&DBusPySignature_Type
, args
, kwargs
);
256 case DBUS_TYPE_OBJECT_PATH
:
257 DBG("%s", "found an object path");
258 dbus_message_iter_get_basic(iter
, &u
.s
);
259 args
= Py_BuildValue("(s)", u
.s
);
261 ret
= PyObject_Call((PyObject
*)&DBusPyObjectPath_Type
, args
, kwargs
);
264 case DBUS_TYPE_DOUBLE
:
265 DBG("%s", "found a double");
266 dbus_message_iter_get_basic(iter
, &u
.d
);
267 args
= Py_BuildValue("(f)", u
.d
);
269 ret
= PyObject_Call((PyObject
*)&DBusPyDouble_Type
, args
, kwargs
);
272 #ifdef WITH_DBUS_FLOAT32
273 case DBUS_TYPE_FLOAT
:
274 DBG("%s", "found a float");
275 dbus_message_iter_get_basic(iter
, &u
.f
);
276 args
= Py_BuildValue("(f)", (double)u
.f
);
278 ret
= PyObject_Call((PyObject
*)&DBusPyFloat_Type
, args
, kwargs
);
282 case DBUS_TYPE_INT16
:
283 DBG("%s", "found an int16");
284 dbus_message_iter_get_basic(iter
, &u
.i16
);
285 args
= Py_BuildValue("(i)", (int)u
.i16
);
287 ret
= PyObject_Call((PyObject
*)&DBusPyInt16_Type
, args
, kwargs
);
290 case DBUS_TYPE_UINT16
:
291 DBG("%s", "found a uint16");
292 dbus_message_iter_get_basic(iter
, &u
.u16
);
293 args
= Py_BuildValue("(i)", (int)u
.u16
);
295 ret
= PyObject_Call((PyObject
*)&DBusPyUInt16_Type
, args
, kwargs
);
298 case DBUS_TYPE_INT32
:
299 DBG("%s", "found an int32");
300 dbus_message_iter_get_basic(iter
, &u
.i32
);
301 args
= Py_BuildValue("(l)", (long)u
.i32
);
303 ret
= PyObject_Call((PyObject
*)&DBusPyInt32_Type
, args
, kwargs
);
306 case DBUS_TYPE_UINT32
:
307 DBG("%s", "found a uint32");
308 dbus_message_iter_get_basic(iter
, &u
.u32
);
309 args
= Py_BuildValue("(k)", (unsigned long)u
.u32
);
311 ret
= PyObject_Call((PyObject
*)&DBusPyUInt32_Type
, args
, kwargs
);
314 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
315 case DBUS_TYPE_INT64
:
316 DBG("%s", "found an int64");
317 dbus_message_iter_get_basic(iter
, &u
.i64
);
318 args
= Py_BuildValue("(L)", (PY_LONG_LONG
)u
.i64
);
320 ret
= PyObject_Call((PyObject
*)&DBusPyInt64_Type
, args
, kwargs
);
323 case DBUS_TYPE_UINT64
:
324 DBG("%s", "found a uint64");
325 dbus_message_iter_get_basic(iter
, &u
.u64
);
326 args
= Py_BuildValue("(K)", (unsigned PY_LONG_LONG
)u
.u64
);
328 ret
= PyObject_Call((PyObject
*)&DBusPyUInt64_Type
, args
, kwargs
);
331 case DBUS_TYPE_INT64
:
332 case DBUS_TYPE_UINT64
:
333 PyErr_SetString(PyExc_NotImplementedError
,
334 "64-bit integer types are not supported on "
340 DBG("%s", "found a byte");
341 dbus_message_iter_get_basic(iter
, &u
.y
);
342 args
= Py_BuildValue("(l)", (long)u
.y
);
345 ret
= PyObject_Call((PyObject
*)&DBusPyByte_Type
, args
, kwargs
);
348 case DBUS_TYPE_BOOLEAN
:
349 DBG("%s", "found a bool");
350 dbus_message_iter_get_basic(iter
, &u
.b
);
351 args
= Py_BuildValue("(l)", (long)u
.b
);
354 ret
= PyObject_Call((PyObject
*)&DBusPyBoolean_Type
, args
, kwargs
);
357 case DBUS_TYPE_ARRAY
:
358 DBG("%s", "found an array...");
359 /* Dicts are arrays of DBUS_TYPE_DICT_ENTRY on the wire.
360 Also, we special-case arrays of DBUS_TYPE_BYTE sometimes. */
361 type
= dbus_message_iter_get_element_type(iter
);
362 if (type
== DBUS_TYPE_DICT_ENTRY
) {
363 DBG("%s", "no, actually it's a dict...");
365 kwargs
= PyDict_New();
368 ret
= _message_iter_get_dict(iter
, opts
, kwargs
);
370 else if (opts
->byte_arrays
&& type
== DBUS_TYPE_BYTE
) {
374 DBG("%s", "actually, a byte array...");
375 dbus_message_iter_recurse(iter
, &sub
);
376 dbus_message_iter_get_fixed_array(&sub
,
377 (const unsigned char **)&u
.s
,
379 args
= Py_BuildValue("(s#)", u
.s
, (Py_ssize_t
)n
);
381 ret
= PyObject_Call((PyObject
*)&DBusPyByteArray_Type
,
390 DBG("%s", "a normal array...");
392 kwargs
= PyDict_New();
395 dbus_message_iter_recurse(iter
, &sub
);
396 sig
= dbus_message_iter_get_signature(&sub
);
398 sig_obj
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
402 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig_obj
);
404 if (status
< 0) break;
405 ret
= PyObject_Call((PyObject
*)&DBusPyArray_Type
,
406 dbus_py_empty_tuple
, kwargs
);
408 if (_message_iter_append_all_to_list(&sub
, ret
, opts
) < 0) {
415 case DBUS_TYPE_STRUCT
:
418 PyObject
*list
= PyList_New(0);
421 DBG("%s", "found a struct...");
423 dbus_message_iter_recurse(iter
, &sub
);
424 if (_message_iter_append_all_to_list(&sub
, list
, opts
) < 0) {
428 tuple
= Py_BuildValue("(O)", list
);
430 ret
= PyObject_Call((PyObject
*)&DBusPyStruct_Type
, tuple
, kwargs
);
435 /* whether successful or not, we take the same action: */
441 case DBUS_TYPE_VARIANT
:
445 DBG("%s", "found a variant...");
446 dbus_message_iter_recurse(iter
, &sub
);
447 ret
= _message_iter_get_pyobject(&sub
, opts
, variant_level
+1);
452 PyErr_Format(PyExc_TypeError
, "Unknown type '\\%x' in D-Bus "
466 dbus_py_Message_get_args_list(Message
*self
, PyObject
*args
, PyObject
*kwargs
)
468 Message_get_args_options opts
= { 0, 0 };
469 static char *argnames
[] = { "byte_arrays", "utf8_strings", NULL
};
471 DBusMessageIter iter
;
474 fprintf(stderr
, "DBG/%ld: called Message_get_args_list(self, *",
476 PyObject_Print(args
, stderr
, 0);
478 fprintf(stderr
, ", **");
479 PyObject_Print(kwargs
, stderr
, 0);
481 fprintf(stderr
, ")\n");
484 if (PyTuple_Size(args
) != 0) {
485 PyErr_SetString(PyExc_TypeError
, "get_args_list takes no positional "
489 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|ii:get_args_list",
492 &(opts
.utf8_strings
))) return NULL
;
493 if (!self
->msg
) return DBusPy_RaiseUnusableMessage();
495 list
= PyList_New(0);
496 if (!list
) return NULL
;
498 /* Iterate over args, if any, appending to list */
499 if (dbus_message_iter_init(self
->msg
, &iter
)) {
500 if (_message_iter_append_all_to_list(&iter
, list
, &opts
) < 0) {
502 DBG_EXC("%s", "Message_get_args: appending all to list failed:");
508 fprintf(stderr
, "DBG/%ld: message has args list ", (long)getpid());
509 PyObject_Print(list
, stderr
, 0);
510 fprintf(stderr
, "\n");
516 /* vim:set ft=c cino< sw=4 sts=4 et: */