Remove from EXTRA_DIST files we'd already be distributing
[dbus-python-phuang.git] / _dbus_bindings / message-get-args.c
blob41f3404f7218b19d02a60b112c23c9fcc24fe826
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"
36 "\n"
37 ":Keywords:\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"
42 "\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"
47 "\n"
48 "Most of the type mappings should be fairly obvious:\n"
49 "\n"
50 "=============== ===================================================\n"
51 "D-Bus Python\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"
64 " list of Byte\n"
65 "struct ((...)) dbus.Struct (tuple subclass) of appropriate types\n"
66 "variant (v) contained type, but with variant_level > 0\n"
67 "=============== ===================================================\n"
70 typedef struct {
71 int byte_arrays;
72 int utf8_strings;
73 } Message_get_args_options;
75 static PyObject *_message_iter_get_pyobject(DBusMessageIter *iter,
76 Message_get_args_options *opts,
77 long extra_variants);
79 /* Append all the items iterated over to the given Python list object.
80 * Return 0 on success/-1 with exception on failure. */
81 static int
82 _message_iter_append_all_to_list(DBusMessageIter *iter, PyObject *list,
83 Message_get_args_options *opts)
85 int ret, type;
86 while ((type = dbus_message_iter_get_arg_type(iter))
87 != DBUS_TYPE_INVALID) {
88 PyObject *item;
89 DBG("type == %d '%c'", type, type);
91 item = _message_iter_get_pyobject(iter, opts, 0);
92 if (!item) return -1;
93 #ifdef USING_DBG
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);
97 #endif
98 ret = PyList_Append(list, item);
99 Py_DECREF(item);
100 item = NULL;
101 if (ret < 0) return -1;
102 #ifdef USING_DBG
103 fprintf(stderr, "DBG/%ld: list now contains: ", (long)getpid());
104 PyObject_Print(list, stderr, 0);
105 fprintf(stderr, "\n");
106 #endif
107 dbus_message_iter_next(iter);
109 return 0;
112 static inline PyObject *
113 _message_iter_get_dict(DBusMessageIter *iter,
114 Message_get_args_options *opts,
115 PyObject *kwargs)
117 DBusMessageIter entries;
118 char *sig_str = dbus_message_iter_get_signature(iter);
119 PyObject *sig;
120 PyObject *ret;
121 int status;
123 sig = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
124 "(s#)", sig_str+2,
125 (Py_ssize_t)strlen(sig_str)-3);
126 status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig);
127 Py_DECREF(sig);
128 if (status < 0) {
129 return NULL;
132 ret = PyObject_Call((PyObject *)&DBusPyDict_Type, dbus_py_empty_tuple, kwargs);
133 if (!ret) {
134 return NULL;
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;
141 DBusMessageIter kv;
143 DBG("%s", "dict entry...");
145 dbus_message_iter_recurse(&entries, &kv);
147 key = _message_iter_get_pyobject(&kv, opts, 0);
148 if (!key) {
149 Py_DECREF(ret);
150 return NULL;
152 dbus_message_iter_next(&kv);
154 value = _message_iter_get_pyobject(&kv, opts, 0);
155 if (!value) {
156 Py_DECREF(key);
157 Py_DECREF(ret);
158 return NULL;
161 status = PyDict_SetItem(ret, key, value);
162 Py_DECREF(key);
163 Py_DECREF(value);
165 if (status < 0) {
166 Py_DECREF(ret);
167 return NULL;
169 dbus_message_iter_next(&entries);
172 return ret;
175 /* Returns a new reference. */
176 static PyObject *
177 _message_iter_get_pyobject(DBusMessageIter *iter,
178 Message_get_args_options *opts,
179 long variant_level)
181 union {
182 const char *s;
183 unsigned char y;
184 dbus_bool_t b;
185 double d;
186 float f;
187 dbus_uint16_t u16;
188 dbus_int16_t i16;
189 dbus_uint32_t u32;
190 dbus_int32_t i32;
191 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
192 dbus_uint64_t u64;
193 dbus_int64_t i64;
194 #endif
195 } u;
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) {
209 return NULL;
211 kwargs = PyDict_New();
212 if (!kwargs) {
213 Py_DECREF(variant_level_int);
214 return NULL;
216 if (PyDict_SetItem(kwargs, dbus_py_variant_level_const,
217 variant_level_int) < 0) {
218 Py_DECREF(variant_level_int);
219 Py_DECREF(kwargs);
220 return NULL;
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
228 switch (type) {
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);
234 if (!args) break;
235 ret = PyObject_Call((PyObject *)&DBusPyUTF8String_Type,
236 args, kwargs);
238 else {
239 args = Py_BuildValue("(O)", PyUnicode_DecodeUTF8(u.s,
240 strlen(u.s),
241 NULL));
242 if (!args) {
243 break;
245 ret = PyObject_Call((PyObject *)&DBusPyString_Type,
246 args, kwargs);
248 break;
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);
254 if (!args) break;
255 ret = PyObject_Call((PyObject *)&DBusPySignature_Type, args, kwargs);
256 break;
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);
262 if (!args) break;
263 ret = PyObject_Call((PyObject *)&DBusPyObjectPath_Type, args, kwargs);
264 break;
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);
270 if (!args) break;
271 ret = PyObject_Call((PyObject *)&DBusPyDouble_Type, args, kwargs);
272 break;
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);
279 if (!args) break;
280 ret = PyObject_Call((PyObject *)&DBusPyFloat_Type, args, kwargs);
281 break;
282 #endif
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);
288 if (!args) break;
289 ret = PyObject_Call((PyObject *)&DBusPyInt16_Type, args, kwargs);
290 break;
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);
296 if (!args) break;
297 ret = PyObject_Call((PyObject *)&DBusPyUInt16_Type, args, kwargs);
298 break;
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);
304 if (!args) break;
305 ret = PyObject_Call((PyObject *)&DBusPyInt32_Type, args, kwargs);
306 break;
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);
312 if (!args) break;
313 ret = PyObject_Call((PyObject *)&DBusPyUInt32_Type, args, kwargs);
314 break;
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);
321 if (!args) break;
322 ret = PyObject_Call((PyObject *)&DBusPyInt64_Type, args, kwargs);
323 break;
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);
329 if (!args) break;
330 ret = PyObject_Call((PyObject *)&DBusPyUInt64_Type, args, kwargs);
331 break;
332 #else
333 case DBUS_TYPE_INT64:
334 case DBUS_TYPE_UINT64:
335 PyErr_SetString(PyExc_NotImplementedError,
336 "64-bit integer types are not supported on "
337 "this platform");
338 break;
339 #endif
341 case DBUS_TYPE_BYTE:
342 DBG("%s", "found a byte");
343 dbus_message_iter_get_basic(iter, &u.y);
344 args = Py_BuildValue("(l)", (long)u.y);
345 if (!args)
346 break;
347 ret = PyObject_Call((PyObject *)&DBusPyByte_Type, args, kwargs);
348 break;
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);
354 if (!args)
355 break;
356 ret = PyObject_Call((PyObject *)&DBusPyBoolean_Type, args, kwargs);
357 break;
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...");
366 if (!kwargs) {
367 kwargs = PyDict_New();
368 if (!kwargs) break;
370 ret = _message_iter_get_dict(iter, opts, kwargs);
372 else if (opts->byte_arrays && type == DBUS_TYPE_BYTE) {
373 DBusMessageIter sub;
374 int n;
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,
380 &n);
381 args = Py_BuildValue("(s#)", u.s, (Py_ssize_t)n);
382 if (!args) break;
383 ret = PyObject_Call((PyObject *)&DBusPyByteArray_Type,
384 args, kwargs);
386 else {
387 DBusMessageIter sub;
388 char *sig;
389 PyObject *sig_obj;
390 int status;
392 DBG("%s", "a normal array...");
393 if (!kwargs) {
394 kwargs = PyDict_New();
395 if (!kwargs) break;
397 dbus_message_iter_recurse(iter, &sub);
398 sig = dbus_message_iter_get_signature(&sub);
399 if (!sig) break;
400 sig_obj = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
401 "(s)", sig);
402 dbus_free(sig);
403 if (!sig_obj) break;
404 status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig_obj);
405 Py_DECREF(sig_obj);
406 if (status < 0) break;
407 ret = PyObject_Call((PyObject *)&DBusPyArray_Type,
408 dbus_py_empty_tuple, kwargs);
409 if (!ret) break;
410 if (_message_iter_append_all_to_list(&sub, ret, opts) < 0) {
411 Py_DECREF(ret);
412 ret = NULL;
415 break;
417 case DBUS_TYPE_STRUCT:
419 DBusMessageIter sub;
420 PyObject *list = PyList_New(0);
421 PyObject *tuple;
423 DBG("%s", "found a struct...");
424 if (!list) break;
425 dbus_message_iter_recurse(iter, &sub);
426 if (_message_iter_append_all_to_list(&sub, list, opts) < 0) {
427 Py_DECREF(list);
428 break;
430 tuple = Py_BuildValue("(O)", list);
431 if (tuple) {
432 ret = PyObject_Call((PyObject *)&DBusPyStruct_Type, tuple, kwargs);
434 else {
435 ret = NULL;
437 /* whether successful or not, we take the same action: */
438 Py_DECREF(list);
439 Py_XDECREF(tuple);
441 break;
443 case DBUS_TYPE_VARIANT:
445 DBusMessageIter sub;
447 DBG("%s", "found a variant...");
448 dbus_message_iter_recurse(iter, &sub);
449 ret = _message_iter_get_pyobject(&sub, opts, variant_level+1);
451 break;
453 default:
454 PyErr_Format(PyExc_TypeError, "Unknown type '\\%x' in D-Bus "
455 "message", type);
458 if (args) {
459 Py_DECREF(args);
461 if (kwargs) {
462 Py_DECREF(kwargs);
464 return ret;
467 PyObject *
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 };
472 PyObject *list;
473 DBusMessageIter iter;
475 #ifdef USING_DBG
476 fprintf(stderr, "DBG/%ld: called Message_get_args_list(self, *",
477 (long)getpid());
478 PyObject_Print(args, stderr, 0);
479 if (kwargs) {
480 fprintf(stderr, ", **");
481 PyObject_Print(kwargs, stderr, 0);
483 fprintf(stderr, ")\n");
484 #endif
486 if (PyTuple_Size(args) != 0) {
487 PyErr_SetString(PyExc_TypeError, "get_args_list takes no positional "
488 "arguments");
489 return NULL;
491 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:get_args_list",
492 argnames,
493 &(opts.byte_arrays),
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) {
503 Py_DECREF(list);
504 DBG_EXC("%s", "Message_get_args: appending all to list failed:");
505 return NULL;
509 #ifdef USING_DBG
510 fprintf(stderr, "DBG/%ld: message has args list ", (long)getpid());
511 PyObject_Print(list, stderr, 0);
512 fprintf(stderr, "\n");
513 #endif
515 return list;
518 /* vim:set ft=c cino< sw=4 sts=4 et: */