Add a maintainer-upload target to the Makefile.am, which uploads the current .tar...
[dbus-python-phuang.git] / _dbus_bindings / message-get-args.c
blob7d55ffdc8836ed9943943549b42bee24b9495cd5
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. <http://www.collabora.co.uk/>
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use, copy,
10 * modify, merge, publish, distribute, sublicense, and/or sell copies
11 * of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
27 #define PY_SIZE_T_CLEAN 1
29 #define DBG_IS_TOO_VERBOSE
30 #include "types-internal.h"
31 #include "message-internal.h"
33 char dbus_py_Message_get_args_list__doc__[] = (
34 "get_args_list(**kwargs) -> list\n\n"
35 "Return the message's arguments. Keyword arguments control the translation\n"
36 "of D-Bus types to Python:\n"
37 "\n"
38 ":Keywords:\n"
39 " `byte_arrays` : bool\n"
40 " If true, convert arrays of byte (signature 'ay') into dbus.ByteArray,\n"
41 " a str subclass. In practice, this is usually what you want, but\n"
42 " it's off by default for consistency.\n"
43 "\n"
44 " If false (default), convert them into a dbus.Array of Bytes.\n"
45 " `utf8_strings` : bool\n"
46 " If true, return D-Bus strings as Python 8-bit strings (of UTF-8).\n"
47 " If false (default), return D-Bus strings as Python unicode objects.\n"
48 "\n"
49 "Most of the type mappings should be fairly obvious:\n"
50 "\n"
51 "=============== ===================================================\n"
52 "D-Bus Python\n"
53 "=============== ===================================================\n"
54 "byte (y) dbus.Byte (int subclass)\n"
55 "bool (b) dbus.Boolean (int subclass)\n"
56 "Signature (g) dbus.Signature (str subclass)\n"
57 "intNN, uintNN dbus.IntNN, dbus.UIntNN (int or long subclasses)\n"
58 "double (d) dbus.Double\n"
59 "string (s) dbus.String (unicode subclass)\n"
60 " (or dbus.UTF8String, str subclass, if utf8_strings set)\n"
61 "Object path (o) dbus.ObjectPath (str subclass)\n"
62 "dict (a{...}) dbus.Dictionary\n"
63 "array (a...) dbus.Array (list subclass) containing appropriate types\n"
64 "byte array (ay) dbus.ByteArray (str subclass) if byte_arrays set; or\n"
65 " list of Byte\n"
66 "struct ((...)) dbus.Struct (tuple subclass) of appropriate types\n"
67 "variant (v) contained type, but with variant_level > 0\n"
68 "=============== ===================================================\n"
71 typedef struct {
72 int byte_arrays;
73 int utf8_strings;
74 } Message_get_args_options;
76 static PyObject *_message_iter_get_pyobject(DBusMessageIter *iter,
77 Message_get_args_options *opts,
78 long extra_variants);
80 /* Append all the items iterated over to the given Python list object.
81 * Return 0 on success/-1 with exception on failure. */
82 static int
83 _message_iter_append_all_to_list(DBusMessageIter *iter, PyObject *list,
84 Message_get_args_options *opts)
86 int ret, type;
87 while ((type = dbus_message_iter_get_arg_type(iter))
88 != DBUS_TYPE_INVALID) {
89 PyObject *item;
90 DBG("type == %d '%c'", type, type);
92 item = _message_iter_get_pyobject(iter, opts, 0);
93 if (!item) return -1;
94 #ifdef USING_DBG
95 fprintf(stderr, "DBG/%ld: appending to list: %p == ", (long)getpid(), item);
96 PyObject_Print(item, stderr, 0);
97 fprintf(stderr, " of type %p\n", item->ob_type);
98 #endif
99 ret = PyList_Append(list, item);
100 Py_DECREF(item);
101 item = NULL;
102 if (ret < 0) return -1;
103 #ifdef USING_DBG
104 fprintf(stderr, "DBG/%ld: list now contains: ", (long)getpid());
105 PyObject_Print(list, stderr, 0);
106 fprintf(stderr, "\n");
107 #endif
108 dbus_message_iter_next(iter);
110 return 0;
113 static inline PyObject *
114 _message_iter_get_dict(DBusMessageIter *iter,
115 Message_get_args_options *opts,
116 PyObject *kwargs)
118 DBusMessageIter entries;
119 char *sig_str = dbus_message_iter_get_signature(iter);
120 PyObject *sig;
121 PyObject *ret;
122 int status;
124 if (!sig_str) {
125 PyErr_NoMemory();
126 return NULL;
128 sig = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
129 "(s#)", sig_str+2,
130 (Py_ssize_t)strlen(sig_str)-3);
131 dbus_free(sig_str);
132 if (!sig) {
133 return NULL;
135 status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig);
136 Py_DECREF(sig);
137 if (status < 0) {
138 return NULL;
141 ret = PyObject_Call((PyObject *)&DBusPyDict_Type, dbus_py_empty_tuple, kwargs);
142 if (!ret) {
143 return NULL;
146 dbus_message_iter_recurse(iter, &entries);
147 while (dbus_message_iter_get_arg_type(&entries) == DBUS_TYPE_DICT_ENTRY) {
148 PyObject *key = NULL;
149 PyObject *value = NULL;
150 DBusMessageIter kv;
152 DBG("%s", "dict entry...");
154 dbus_message_iter_recurse(&entries, &kv);
156 key = _message_iter_get_pyobject(&kv, opts, 0);
157 if (!key) {
158 Py_DECREF(ret);
159 return NULL;
161 dbus_message_iter_next(&kv);
163 value = _message_iter_get_pyobject(&kv, opts, 0);
164 if (!value) {
165 Py_DECREF(key);
166 Py_DECREF(ret);
167 return NULL;
170 status = PyDict_SetItem(ret, key, value);
171 Py_DECREF(key);
172 Py_DECREF(value);
174 if (status < 0) {
175 Py_DECREF(ret);
176 return NULL;
178 dbus_message_iter_next(&entries);
181 return ret;
184 /* Returns a new reference. */
185 static PyObject *
186 _message_iter_get_pyobject(DBusMessageIter *iter,
187 Message_get_args_options *opts,
188 long variant_level)
190 union {
191 const char *s;
192 unsigned char y;
193 dbus_bool_t b;
194 double d;
195 float f;
196 dbus_uint16_t u16;
197 dbus_int16_t i16;
198 dbus_uint32_t u32;
199 dbus_int32_t i32;
200 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
201 dbus_uint64_t u64;
202 dbus_int64_t i64;
203 #endif
204 } u;
205 int type = dbus_message_iter_get_arg_type(iter);
206 PyObject *args = NULL;
207 PyObject *kwargs = NULL;
208 PyObject *ret = NULL;
210 /* If the variant-level is >0, prepare a dict for the kwargs.
211 * For variant wrappers optimize slightly by skipping this.
213 if (variant_level > 0 && type != DBUS_TYPE_VARIANT) {
214 PyObject *variant_level_int;
216 variant_level_int = PyInt_FromLong(variant_level);
217 if (!variant_level_int) {
218 return NULL;
220 kwargs = PyDict_New();
221 if (!kwargs) {
222 Py_DECREF(variant_level_int);
223 return NULL;
225 if (PyDict_SetItem(kwargs, dbus_py_variant_level_const,
226 variant_level_int) < 0) {
227 Py_DECREF(variant_level_int);
228 Py_DECREF(kwargs);
229 return NULL;
231 Py_DECREF(variant_level_int);
233 /* From here down you need to break from the switch to exit, so the
234 * dict is freed if necessary
237 switch (type) {
238 case DBUS_TYPE_STRING:
239 DBG("%s", "found a string");
240 dbus_message_iter_get_basic(iter, &u.s);
241 if (opts->utf8_strings) {
242 args = Py_BuildValue("(s)", u.s);
243 if (!args) break;
244 ret = PyObject_Call((PyObject *)&DBusPyUTF8String_Type,
245 args, kwargs);
247 else {
248 args = Py_BuildValue("(N)", PyUnicode_DecodeUTF8(u.s,
249 strlen(u.s),
250 NULL));
251 if (!args) {
252 break;
254 ret = PyObject_Call((PyObject *)&DBusPyString_Type,
255 args, kwargs);
257 break;
259 case DBUS_TYPE_SIGNATURE:
260 DBG("%s", "found a signature");
261 dbus_message_iter_get_basic(iter, &u.s);
262 args = Py_BuildValue("(s)", u.s);
263 if (!args) break;
264 ret = PyObject_Call((PyObject *)&DBusPySignature_Type, args, kwargs);
265 break;
267 case DBUS_TYPE_OBJECT_PATH:
268 DBG("%s", "found an object path");
269 dbus_message_iter_get_basic(iter, &u.s);
270 args = Py_BuildValue("(s)", u.s);
271 if (!args) break;
272 ret = PyObject_Call((PyObject *)&DBusPyObjectPath_Type, args, kwargs);
273 break;
275 case DBUS_TYPE_DOUBLE:
276 DBG("%s", "found a double");
277 dbus_message_iter_get_basic(iter, &u.d);
278 args = Py_BuildValue("(f)", u.d);
279 if (!args) break;
280 ret = PyObject_Call((PyObject *)&DBusPyDouble_Type, args, kwargs);
281 break;
283 #ifdef WITH_DBUS_FLOAT32
284 case DBUS_TYPE_FLOAT:
285 DBG("%s", "found a float");
286 dbus_message_iter_get_basic(iter, &u.f);
287 args = Py_BuildValue("(f)", (double)u.f);
288 if (!args) break;
289 ret = PyObject_Call((PyObject *)&DBusPyFloat_Type, args, kwargs);
290 break;
291 #endif
293 case DBUS_TYPE_INT16:
294 DBG("%s", "found an int16");
295 dbus_message_iter_get_basic(iter, &u.i16);
296 args = Py_BuildValue("(i)", (int)u.i16);
297 if (!args) break;
298 ret = PyObject_Call((PyObject *)&DBusPyInt16_Type, args, kwargs);
299 break;
301 case DBUS_TYPE_UINT16:
302 DBG("%s", "found a uint16");
303 dbus_message_iter_get_basic(iter, &u.u16);
304 args = Py_BuildValue("(i)", (int)u.u16);
305 if (!args) break;
306 ret = PyObject_Call((PyObject *)&DBusPyUInt16_Type, args, kwargs);
307 break;
309 case DBUS_TYPE_INT32:
310 DBG("%s", "found an int32");
311 dbus_message_iter_get_basic(iter, &u.i32);
312 args = Py_BuildValue("(l)", (long)u.i32);
313 if (!args) break;
314 ret = PyObject_Call((PyObject *)&DBusPyInt32_Type, args, kwargs);
315 break;
317 case DBUS_TYPE_UINT32:
318 DBG("%s", "found a uint32");
319 dbus_message_iter_get_basic(iter, &u.u32);
320 args = Py_BuildValue("(k)", (unsigned long)u.u32);
321 if (!args) break;
322 ret = PyObject_Call((PyObject *)&DBusPyUInt32_Type, args, kwargs);
323 break;
325 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
326 case DBUS_TYPE_INT64:
327 DBG("%s", "found an int64");
328 dbus_message_iter_get_basic(iter, &u.i64);
329 args = Py_BuildValue("(L)", (PY_LONG_LONG)u.i64);
330 if (!args) break;
331 ret = PyObject_Call((PyObject *)&DBusPyInt64_Type, args, kwargs);
332 break;
334 case DBUS_TYPE_UINT64:
335 DBG("%s", "found a uint64");
336 dbus_message_iter_get_basic(iter, &u.u64);
337 args = Py_BuildValue("(K)", (unsigned PY_LONG_LONG)u.u64);
338 if (!args) break;
339 ret = PyObject_Call((PyObject *)&DBusPyUInt64_Type, args, kwargs);
340 break;
341 #else
342 case DBUS_TYPE_INT64:
343 case DBUS_TYPE_UINT64:
344 PyErr_SetString(PyExc_NotImplementedError,
345 "64-bit integer types are not supported on "
346 "this platform");
347 break;
348 #endif
350 case DBUS_TYPE_BYTE:
351 DBG("%s", "found a byte");
352 dbus_message_iter_get_basic(iter, &u.y);
353 args = Py_BuildValue("(l)", (long)u.y);
354 if (!args)
355 break;
356 ret = PyObject_Call((PyObject *)&DBusPyByte_Type, args, kwargs);
357 break;
359 case DBUS_TYPE_BOOLEAN:
360 DBG("%s", "found a bool");
361 dbus_message_iter_get_basic(iter, &u.b);
362 args = Py_BuildValue("(l)", (long)u.b);
363 if (!args)
364 break;
365 ret = PyObject_Call((PyObject *)&DBusPyBoolean_Type, args, kwargs);
366 break;
368 case DBUS_TYPE_ARRAY:
369 DBG("%s", "found an array...");
370 /* Dicts are arrays of DBUS_TYPE_DICT_ENTRY on the wire.
371 Also, we special-case arrays of DBUS_TYPE_BYTE sometimes. */
372 type = dbus_message_iter_get_element_type(iter);
373 if (type == DBUS_TYPE_DICT_ENTRY) {
374 DBG("%s", "no, actually it's a dict...");
375 if (!kwargs) {
376 kwargs = PyDict_New();
377 if (!kwargs) break;
379 ret = _message_iter_get_dict(iter, opts, kwargs);
381 else if (opts->byte_arrays && type == DBUS_TYPE_BYTE) {
382 DBusMessageIter sub;
383 int n;
385 DBG("%s", "actually, a byte array...");
386 dbus_message_iter_recurse(iter, &sub);
387 dbus_message_iter_get_fixed_array(&sub,
388 (const unsigned char **)&u.s,
389 &n);
390 args = Py_BuildValue("(s#)", u.s, (Py_ssize_t)n);
391 if (!args) break;
392 ret = PyObject_Call((PyObject *)&DBusPyByteArray_Type,
393 args, kwargs);
395 else {
396 DBusMessageIter sub;
397 char *sig;
398 PyObject *sig_obj;
399 int status;
401 DBG("%s", "a normal array...");
402 if (!kwargs) {
403 kwargs = PyDict_New();
404 if (!kwargs) break;
406 dbus_message_iter_recurse(iter, &sub);
407 sig = dbus_message_iter_get_signature(&sub);
408 if (!sig) break;
409 sig_obj = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
410 "(s)", sig);
411 dbus_free(sig);
412 if (!sig_obj) break;
413 status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig_obj);
414 Py_DECREF(sig_obj);
415 if (status < 0) break;
416 ret = PyObject_Call((PyObject *)&DBusPyArray_Type,
417 dbus_py_empty_tuple, kwargs);
418 if (!ret) break;
419 if (_message_iter_append_all_to_list(&sub, ret, opts) < 0) {
420 Py_DECREF(ret);
421 ret = NULL;
424 break;
426 case DBUS_TYPE_STRUCT:
428 DBusMessageIter sub;
429 PyObject *list = PyList_New(0);
430 PyObject *tuple;
432 DBG("%s", "found a struct...");
433 if (!list) break;
434 dbus_message_iter_recurse(iter, &sub);
435 if (_message_iter_append_all_to_list(&sub, list, opts) < 0) {
436 Py_DECREF(list);
437 break;
439 tuple = Py_BuildValue("(O)", list);
440 if (tuple) {
441 ret = PyObject_Call((PyObject *)&DBusPyStruct_Type, tuple, kwargs);
443 else {
444 ret = NULL;
446 /* whether successful or not, we take the same action: */
447 Py_DECREF(list);
448 Py_XDECREF(tuple);
450 break;
452 case DBUS_TYPE_VARIANT:
454 DBusMessageIter sub;
456 DBG("%s", "found a variant...");
457 dbus_message_iter_recurse(iter, &sub);
458 ret = _message_iter_get_pyobject(&sub, opts, variant_level+1);
460 break;
462 default:
463 PyErr_Format(PyExc_TypeError, "Unknown type '\\%x' in D-Bus "
464 "message", type);
467 Py_XDECREF(args);
468 Py_XDECREF(kwargs);
469 return ret;
472 PyObject *
473 dbus_py_Message_get_args_list(Message *self, PyObject *args, PyObject *kwargs)
475 Message_get_args_options opts = { 0, 0 };
476 static char *argnames[] = { "byte_arrays", "utf8_strings", NULL };
477 PyObject *list;
478 DBusMessageIter iter;
480 #ifdef USING_DBG
481 fprintf(stderr, "DBG/%ld: called Message_get_args_list(self, *",
482 (long)getpid());
483 PyObject_Print(args, stderr, 0);
484 if (kwargs) {
485 fprintf(stderr, ", **");
486 PyObject_Print(kwargs, stderr, 0);
488 fprintf(stderr, ")\n");
489 #endif
491 if (PyTuple_Size(args) != 0) {
492 PyErr_SetString(PyExc_TypeError, "get_args_list takes no positional "
493 "arguments");
494 return NULL;
496 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:get_args_list",
497 argnames,
498 &(opts.byte_arrays),
499 &(opts.utf8_strings))) return NULL;
500 if (!self->msg) return DBusPy_RaiseUnusableMessage();
502 list = PyList_New(0);
503 if (!list) return NULL;
505 /* Iterate over args, if any, appending to list */
506 if (dbus_message_iter_init(self->msg, &iter)) {
507 if (_message_iter_append_all_to_list(&iter, list, &opts) < 0) {
508 Py_DECREF(list);
509 DBG_EXC("%s", "Message_get_args: appending all to list failed:");
510 return NULL;
514 #ifdef USING_DBG
515 fprintf(stderr, "DBG/%ld: message has args list ", (long)getpid());
516 PyObject_Print(list, stderr, 0);
517 fprintf(stderr, "\n");
518 #endif
520 return list;
523 /* vim:set ft=c cino< sw=4 sts=4 et: */