_dbus_bindings/pending-call.c: Fix memory leak of one Message per method call.
[dbus-python-phuang.git] / _dbus_bindings / message-get-args.c
blobdd8d425f74c2a3f9cd7077876e562715f9b2f11c
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"
34 "\n"
35 ":Keywords:\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"
40 "\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"
45 "\n"
46 "Most of the type mappings should be fairly obvious:\n"
47 "\n"
48 "=============== ===================================================\n"
49 "D-Bus Python\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"
62 " list of Byte\n"
63 "struct ((...)) dbus.Struct (tuple subclass) of appropriate types\n"
64 "variant (v) contained type, but with variant_level > 0\n"
65 "=============== ===================================================\n"
68 typedef struct {
69 int byte_arrays;
70 int utf8_strings;
71 } Message_get_args_options;
73 static PyObject *_message_iter_get_pyobject(DBusMessageIter *iter,
74 Message_get_args_options *opts,
75 long extra_variants);
77 /* Append all the items iterated over to the given Python list object.
78 * Return 0 on success/-1 with exception on failure. */
79 static int
80 _message_iter_append_all_to_list(DBusMessageIter *iter, PyObject *list,
81 Message_get_args_options *opts)
83 int ret, type;
84 while ((type = dbus_message_iter_get_arg_type(iter))
85 != DBUS_TYPE_INVALID) {
86 PyObject *item;
87 DBG("type == %d '%c'", type, type);
89 item = _message_iter_get_pyobject(iter, opts, 0);
90 if (!item) return -1;
91 #ifdef USING_DBG
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);
95 #endif
96 ret = PyList_Append(list, item);
97 Py_DECREF(item);
98 item = NULL;
99 if (ret < 0) return -1;
100 #ifdef USING_DBG
101 fprintf(stderr, "DBG/%ld: list now contains: ", (long)getpid());
102 PyObject_Print(list, stderr, 0);
103 fprintf(stderr, "\n");
104 #endif
105 dbus_message_iter_next(iter);
107 return 0;
110 static inline PyObject *
111 _message_iter_get_dict(DBusMessageIter *iter,
112 Message_get_args_options *opts,
113 PyObject *kwargs)
115 DBusMessageIter entries;
116 char *sig_str = dbus_message_iter_get_signature(iter);
117 PyObject *sig;
118 PyObject *ret;
119 int status;
121 sig = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
122 "(s#)", sig_str+2,
123 (Py_ssize_t)strlen(sig_str)-3);
124 status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig);
125 Py_DECREF(sig);
126 if (status < 0) {
127 return NULL;
130 ret = PyObject_Call((PyObject *)&DBusPyDict_Type, dbus_py_empty_tuple, kwargs);
131 if (!ret) {
132 return NULL;
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;
139 DBusMessageIter kv;
141 DBG("%s", "dict entry...");
143 dbus_message_iter_recurse(&entries, &kv);
145 key = _message_iter_get_pyobject(&kv, opts, 0);
146 if (!key) {
147 Py_DECREF(ret);
148 return NULL;
150 dbus_message_iter_next(&kv);
152 value = _message_iter_get_pyobject(&kv, opts, 0);
153 if (!value) {
154 Py_DECREF(key);
155 Py_DECREF(ret);
156 return NULL;
159 status = PyDict_SetItem(ret, key, value);
160 Py_DECREF(key);
161 Py_DECREF(value);
163 if (status < 0) {
164 Py_DECREF(ret);
165 return NULL;
167 dbus_message_iter_next(&entries);
170 return ret;
173 /* Returns a new reference. */
174 static PyObject *
175 _message_iter_get_pyobject(DBusMessageIter *iter,
176 Message_get_args_options *opts,
177 long variant_level)
179 union {
180 const char *s;
181 unsigned char y;
182 dbus_bool_t b;
183 double d;
184 float f;
185 dbus_uint16_t u16;
186 dbus_int16_t i16;
187 dbus_uint32_t u32;
188 dbus_int32_t i32;
189 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
190 dbus_uint64_t u64;
191 dbus_int64_t i64;
192 #endif
193 } u;
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) {
207 return NULL;
209 kwargs = PyDict_New();
210 if (!kwargs) {
211 Py_DECREF(variant_level_int);
212 return NULL;
214 if (PyDict_SetItem(kwargs, dbus_py_variant_level_const,
215 variant_level_int) < 0) {
216 Py_DECREF(variant_level_int);
217 Py_DECREF(kwargs);
218 return NULL;
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
226 switch (type) {
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);
232 if (!args) break;
233 ret = PyObject_Call((PyObject *)&DBusPyUTF8String_Type,
234 args, kwargs);
236 else {
237 args = Py_BuildValue("(O)", PyUnicode_DecodeUTF8(u.s,
238 strlen(u.s),
239 NULL));
240 if (!args) {
241 break;
243 ret = PyObject_Call((PyObject *)&DBusPyString_Type,
244 args, kwargs);
246 break;
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);
252 if (!args) break;
253 ret = PyObject_Call((PyObject *)&DBusPySignature_Type, args, kwargs);
254 break;
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);
260 if (!args) break;
261 ret = PyObject_Call((PyObject *)&DBusPyObjectPath_Type, args, kwargs);
262 break;
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);
268 if (!args) break;
269 ret = PyObject_Call((PyObject *)&DBusPyDouble_Type, args, kwargs);
270 break;
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);
277 if (!args) break;
278 ret = PyObject_Call((PyObject *)&DBusPyFloat_Type, args, kwargs);
279 break;
280 #endif
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);
286 if (!args) break;
287 ret = PyObject_Call((PyObject *)&DBusPyInt16_Type, args, kwargs);
288 break;
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);
294 if (!args) break;
295 ret = PyObject_Call((PyObject *)&DBusPyUInt16_Type, args, kwargs);
296 break;
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);
302 if (!args) break;
303 ret = PyObject_Call((PyObject *)&DBusPyInt32_Type, args, kwargs);
304 break;
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);
310 if (!args) break;
311 ret = PyObject_Call((PyObject *)&DBusPyUInt32_Type, args, kwargs);
312 break;
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);
319 if (!args) break;
320 ret = PyObject_Call((PyObject *)&DBusPyInt64_Type, args, kwargs);
321 break;
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);
327 if (!args) break;
328 ret = PyObject_Call((PyObject *)&DBusPyUInt64_Type, args, kwargs);
329 break;
330 #else
331 case DBUS_TYPE_INT64:
332 case DBUS_TYPE_UINT64:
333 PyErr_SetString(PyExc_NotImplementedError,
334 "64-bit integer types are not supported on "
335 "this platform");
336 break;
337 #endif
339 case DBUS_TYPE_BYTE:
340 DBG("%s", "found a byte");
341 dbus_message_iter_get_basic(iter, &u.y);
342 args = Py_BuildValue("(l)", (long)u.y);
343 if (!args)
344 break;
345 ret = PyObject_Call((PyObject *)&DBusPyByte_Type, args, kwargs);
346 break;
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);
352 if (!args)
353 break;
354 ret = PyObject_Call((PyObject *)&DBusPyBoolean_Type, args, kwargs);
355 break;
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...");
364 if (!kwargs) {
365 kwargs = PyDict_New();
366 if (!kwargs) break;
368 ret = _message_iter_get_dict(iter, opts, kwargs);
370 else if (opts->byte_arrays && type == DBUS_TYPE_BYTE) {
371 DBusMessageIter sub;
372 int n;
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,
378 &n);
379 args = Py_BuildValue("(s#)", u.s, (Py_ssize_t)n);
380 if (!args) break;
381 ret = PyObject_Call((PyObject *)&DBusPyByteArray_Type,
382 args, kwargs);
384 else {
385 DBusMessageIter sub;
386 char *sig;
387 PyObject *sig_obj;
388 int status;
390 DBG("%s", "a normal array...");
391 if (!kwargs) {
392 kwargs = PyDict_New();
393 if (!kwargs) break;
395 dbus_message_iter_recurse(iter, &sub);
396 sig = dbus_message_iter_get_signature(&sub);
397 if (!sig) break;
398 sig_obj = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
399 "(s)", sig);
400 dbus_free(sig);
401 if (!sig_obj) break;
402 status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig_obj);
403 Py_DECREF(sig_obj);
404 if (status < 0) break;
405 ret = PyObject_Call((PyObject *)&DBusPyArray_Type,
406 dbus_py_empty_tuple, kwargs);
407 if (!ret) break;
408 if (_message_iter_append_all_to_list(&sub, ret, opts) < 0) {
409 Py_DECREF(ret);
410 ret = NULL;
413 break;
415 case DBUS_TYPE_STRUCT:
417 DBusMessageIter sub;
418 PyObject *list = PyList_New(0);
419 PyObject *tuple;
421 DBG("%s", "found a struct...");
422 if (!list) break;
423 dbus_message_iter_recurse(iter, &sub);
424 if (_message_iter_append_all_to_list(&sub, list, opts) < 0) {
425 Py_DECREF(list);
426 break;
428 tuple = Py_BuildValue("(O)", list);
429 if (tuple) {
430 ret = PyObject_Call((PyObject *)&DBusPyStruct_Type, tuple, kwargs);
432 else {
433 ret = NULL;
435 /* whether successful or not, we take the same action: */
436 Py_DECREF(list);
437 Py_XDECREF(tuple);
439 break;
441 case DBUS_TYPE_VARIANT:
443 DBusMessageIter sub;
445 DBG("%s", "found a variant...");
446 dbus_message_iter_recurse(iter, &sub);
447 ret = _message_iter_get_pyobject(&sub, opts, variant_level+1);
449 break;
451 default:
452 PyErr_Format(PyExc_TypeError, "Unknown type '\\%x' in D-Bus "
453 "message", type);
456 if (args) {
457 Py_DECREF(args);
459 if (kwargs) {
460 Py_DECREF(kwargs);
462 return ret;
465 PyObject *
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 };
470 PyObject *list;
471 DBusMessageIter iter;
473 #ifdef USING_DBG
474 fprintf(stderr, "DBG/%ld: called Message_get_args_list(self, *",
475 (long)getpid());
476 PyObject_Print(args, stderr, 0);
477 if (kwargs) {
478 fprintf(stderr, ", **");
479 PyObject_Print(kwargs, stderr, 0);
481 fprintf(stderr, ")\n");
482 #endif
484 if (PyTuple_Size(args) != 0) {
485 PyErr_SetString(PyExc_TypeError, "get_args_list takes no positional "
486 "arguments");
487 return NULL;
489 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:get_args_list",
490 argnames,
491 &(opts.byte_arrays),
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) {
501 Py_DECREF(list);
502 DBG_EXC("%s", "Message_get_args: appending all to list failed:");
503 return NULL;
507 #ifdef USING_DBG
508 fprintf(stderr, "DBG/%ld: message has args list ", (long)getpid());
509 PyObject_Print(list, stderr, 0);
510 fprintf(stderr, "\n");
511 #endif
513 return list;
516 /* vim:set ft=c cino< sw=4 sts=4 et: */