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.
6 * Licensed under the Academic Free License version 2.1
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This library 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 Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; 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
);
125 sig
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
127 (Py_ssize_t
)strlen(sig_str
)-3);
132 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig
);
138 ret
= PyObject_Call((PyObject
*)&DBusPyDict_Type
, dbus_py_empty_tuple
, kwargs
);
143 dbus_message_iter_recurse(iter
, &entries
);
144 while (dbus_message_iter_get_arg_type(&entries
) == DBUS_TYPE_DICT_ENTRY
) {
145 PyObject
*key
= NULL
;
146 PyObject
*value
= NULL
;
149 DBG("%s", "dict entry...");
151 dbus_message_iter_recurse(&entries
, &kv
);
153 key
= _message_iter_get_pyobject(&kv
, opts
, 0);
158 dbus_message_iter_next(&kv
);
160 value
= _message_iter_get_pyobject(&kv
, opts
, 0);
167 status
= PyDict_SetItem(ret
, key
, value
);
175 dbus_message_iter_next(&entries
);
181 /* Returns a new reference. */
183 _message_iter_get_pyobject(DBusMessageIter
*iter
,
184 Message_get_args_options
*opts
,
197 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
202 int type
= dbus_message_iter_get_arg_type(iter
);
203 PyObject
*args
= NULL
;
204 PyObject
*kwargs
= NULL
;
205 PyObject
*ret
= NULL
;
207 /* If the variant-level is >0, prepare a dict for the kwargs.
208 * For variant wrappers optimize slightly by skipping this.
210 if (variant_level
> 0 && type
!= DBUS_TYPE_VARIANT
) {
211 PyObject
*variant_level_int
;
213 variant_level_int
= PyInt_FromLong(variant_level
);
214 if (!variant_level_int
) {
217 kwargs
= PyDict_New();
219 Py_DECREF(variant_level_int
);
222 if (PyDict_SetItem(kwargs
, dbus_py_variant_level_const
,
223 variant_level_int
) < 0) {
224 Py_DECREF(variant_level_int
);
228 Py_DECREF(variant_level_int
);
230 /* From here down you need to break from the switch to exit, so the
231 * dict is freed if necessary
235 case DBUS_TYPE_STRING
:
236 DBG("%s", "found a string");
237 dbus_message_iter_get_basic(iter
, &u
.s
);
238 if (opts
->utf8_strings
) {
239 args
= Py_BuildValue("(s)", u
.s
);
241 ret
= PyObject_Call((PyObject
*)&DBusPyUTF8String_Type
,
245 args
= Py_BuildValue("(N)", PyUnicode_DecodeUTF8(u
.s
,
251 ret
= PyObject_Call((PyObject
*)&DBusPyString_Type
,
256 case DBUS_TYPE_SIGNATURE
:
257 DBG("%s", "found a signature");
258 dbus_message_iter_get_basic(iter
, &u
.s
);
259 args
= Py_BuildValue("(s)", u
.s
);
261 ret
= PyObject_Call((PyObject
*)&DBusPySignature_Type
, args
, kwargs
);
264 case DBUS_TYPE_OBJECT_PATH
:
265 DBG("%s", "found an object path");
266 dbus_message_iter_get_basic(iter
, &u
.s
);
267 args
= Py_BuildValue("(s)", u
.s
);
269 ret
= PyObject_Call((PyObject
*)&DBusPyObjectPath_Type
, args
, kwargs
);
272 case DBUS_TYPE_DOUBLE
:
273 DBG("%s", "found a double");
274 dbus_message_iter_get_basic(iter
, &u
.d
);
275 args
= Py_BuildValue("(f)", u
.d
);
277 ret
= PyObject_Call((PyObject
*)&DBusPyDouble_Type
, args
, kwargs
);
280 #ifdef WITH_DBUS_FLOAT32
281 case DBUS_TYPE_FLOAT
:
282 DBG("%s", "found a float");
283 dbus_message_iter_get_basic(iter
, &u
.f
);
284 args
= Py_BuildValue("(f)", (double)u
.f
);
286 ret
= PyObject_Call((PyObject
*)&DBusPyFloat_Type
, args
, kwargs
);
290 case DBUS_TYPE_INT16
:
291 DBG("%s", "found an int16");
292 dbus_message_iter_get_basic(iter
, &u
.i16
);
293 args
= Py_BuildValue("(i)", (int)u
.i16
);
295 ret
= PyObject_Call((PyObject
*)&DBusPyInt16_Type
, args
, kwargs
);
298 case DBUS_TYPE_UINT16
:
299 DBG("%s", "found a uint16");
300 dbus_message_iter_get_basic(iter
, &u
.u16
);
301 args
= Py_BuildValue("(i)", (int)u
.u16
);
303 ret
= PyObject_Call((PyObject
*)&DBusPyUInt16_Type
, args
, kwargs
);
306 case DBUS_TYPE_INT32
:
307 DBG("%s", "found an int32");
308 dbus_message_iter_get_basic(iter
, &u
.i32
);
309 args
= Py_BuildValue("(l)", (long)u
.i32
);
311 ret
= PyObject_Call((PyObject
*)&DBusPyInt32_Type
, args
, kwargs
);
314 case DBUS_TYPE_UINT32
:
315 DBG("%s", "found a uint32");
316 dbus_message_iter_get_basic(iter
, &u
.u32
);
317 args
= Py_BuildValue("(k)", (unsigned long)u
.u32
);
319 ret
= PyObject_Call((PyObject
*)&DBusPyUInt32_Type
, args
, kwargs
);
322 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
323 case DBUS_TYPE_INT64
:
324 DBG("%s", "found an int64");
325 dbus_message_iter_get_basic(iter
, &u
.i64
);
326 args
= Py_BuildValue("(L)", (PY_LONG_LONG
)u
.i64
);
328 ret
= PyObject_Call((PyObject
*)&DBusPyInt64_Type
, args
, kwargs
);
331 case DBUS_TYPE_UINT64
:
332 DBG("%s", "found a uint64");
333 dbus_message_iter_get_basic(iter
, &u
.u64
);
334 args
= Py_BuildValue("(K)", (unsigned PY_LONG_LONG
)u
.u64
);
336 ret
= PyObject_Call((PyObject
*)&DBusPyUInt64_Type
, args
, kwargs
);
339 case DBUS_TYPE_INT64
:
340 case DBUS_TYPE_UINT64
:
341 PyErr_SetString(PyExc_NotImplementedError
,
342 "64-bit integer types are not supported on "
348 DBG("%s", "found a byte");
349 dbus_message_iter_get_basic(iter
, &u
.y
);
350 args
= Py_BuildValue("(l)", (long)u
.y
);
353 ret
= PyObject_Call((PyObject
*)&DBusPyByte_Type
, args
, kwargs
);
356 case DBUS_TYPE_BOOLEAN
:
357 DBG("%s", "found a bool");
358 dbus_message_iter_get_basic(iter
, &u
.b
);
359 args
= Py_BuildValue("(l)", (long)u
.b
);
362 ret
= PyObject_Call((PyObject
*)&DBusPyBoolean_Type
, args
, kwargs
);
365 case DBUS_TYPE_ARRAY
:
366 DBG("%s", "found an array...");
367 /* Dicts are arrays of DBUS_TYPE_DICT_ENTRY on the wire.
368 Also, we special-case arrays of DBUS_TYPE_BYTE sometimes. */
369 type
= dbus_message_iter_get_element_type(iter
);
370 if (type
== DBUS_TYPE_DICT_ENTRY
) {
371 DBG("%s", "no, actually it's a dict...");
373 kwargs
= PyDict_New();
376 ret
= _message_iter_get_dict(iter
, opts
, kwargs
);
378 else if (opts
->byte_arrays
&& type
== DBUS_TYPE_BYTE
) {
382 DBG("%s", "actually, a byte array...");
383 dbus_message_iter_recurse(iter
, &sub
);
384 dbus_message_iter_get_fixed_array(&sub
,
385 (const unsigned char **)&u
.s
,
387 args
= Py_BuildValue("(s#)", u
.s
, (Py_ssize_t
)n
);
389 ret
= PyObject_Call((PyObject
*)&DBusPyByteArray_Type
,
398 DBG("%s", "a normal array...");
400 kwargs
= PyDict_New();
403 dbus_message_iter_recurse(iter
, &sub
);
404 sig
= dbus_message_iter_get_signature(&sub
);
406 sig_obj
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
410 status
= PyDict_SetItem(kwargs
, dbus_py_signature_const
, sig_obj
);
412 if (status
< 0) break;
413 ret
= PyObject_Call((PyObject
*)&DBusPyArray_Type
,
414 dbus_py_empty_tuple
, kwargs
);
416 if (_message_iter_append_all_to_list(&sub
, ret
, opts
) < 0) {
423 case DBUS_TYPE_STRUCT
:
426 PyObject
*list
= PyList_New(0);
429 DBG("%s", "found a struct...");
431 dbus_message_iter_recurse(iter
, &sub
);
432 if (_message_iter_append_all_to_list(&sub
, list
, opts
) < 0) {
436 tuple
= Py_BuildValue("(O)", list
);
438 ret
= PyObject_Call((PyObject
*)&DBusPyStruct_Type
, tuple
, kwargs
);
443 /* whether successful or not, we take the same action: */
449 case DBUS_TYPE_VARIANT
:
453 DBG("%s", "found a variant...");
454 dbus_message_iter_recurse(iter
, &sub
);
455 ret
= _message_iter_get_pyobject(&sub
, opts
, variant_level
+1);
460 PyErr_Format(PyExc_TypeError
, "Unknown type '\\%x' in D-Bus "
470 dbus_py_Message_get_args_list(Message
*self
, PyObject
*args
, PyObject
*kwargs
)
472 Message_get_args_options opts
= { 0, 0 };
473 static char *argnames
[] = { "byte_arrays", "utf8_strings", NULL
};
475 DBusMessageIter iter
;
478 fprintf(stderr
, "DBG/%ld: called Message_get_args_list(self, *",
480 PyObject_Print(args
, stderr
, 0);
482 fprintf(stderr
, ", **");
483 PyObject_Print(kwargs
, stderr
, 0);
485 fprintf(stderr
, ")\n");
488 if (PyTuple_Size(args
) != 0) {
489 PyErr_SetString(PyExc_TypeError
, "get_args_list takes no positional "
493 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|ii:get_args_list",
496 &(opts
.utf8_strings
))) return NULL
;
497 if (!self
->msg
) return DBusPy_RaiseUnusableMessage();
499 list
= PyList_New(0);
500 if (!list
) return NULL
;
502 /* Iterate over args, if any, appending to list */
503 if (dbus_message_iter_init(self
->msg
, &iter
)) {
504 if (_message_iter_append_all_to_list(&iter
, list
, &opts
) < 0) {
506 DBG_EXC("%s", "Message_get_args: appending all to list failed:");
512 fprintf(stderr
, "DBG/%ld: message has args list ", (long)getpid());
513 PyObject_Print(list
, stderr
, 0);
514 fprintf(stderr
, "\n");
520 /* vim:set ft=c cino< sw=4 sts=4 et: */