_dbus_bindings/pending-call.c: Fix memory leak of one Message per method call.
[dbus-python-phuang.git] / _dbus_bindings / message-append.c
blobd4a56b07c336f1e77993ca25ff6e978b6f48e7a5
1 /* D-Bus Message serialization. This contains all the logic to map from
2 * Python objects to D-Bus types.
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 DBG_IS_TOO_VERBOSE
25 #include "types-internal.h"
26 #include "message-internal.h"
28 /* Return the number of variants wrapping the given object. Return 0
29 * if the object is not a D-Bus type.
31 static long
32 get_variant_level(PyObject *obj)
34 if (DBusPyIntBase_Check(obj)) {
35 return ((DBusPyIntBase *)obj)->variant_level;
37 else if (DBusPyFloatBase_Check(obj)) {
38 return ((DBusPyFloatBase *)obj)->variant_level;
40 else if (DBusPyArray_Check(obj)) {
41 return ((DBusPyArray *)obj)->variant_level;
43 else if (DBusPyDict_Check(obj)) {
44 return ((DBusPyDict *)obj)->variant_level;
46 else if (DBusPyLongBase_Check(obj) ||
47 DBusPyStrBase_Check(obj) ||
48 DBusPyString_Check(obj) ||
49 DBusPyStruct_Check(obj)) {
50 return PyInt_AsLong(PyObject_GetAttr(obj, dbus_py_variant_level_const));
52 else {
53 return 0;
57 char dbus_py_Message_append__doc__[] = (
58 "set_args(*args[, **kwargs])\n\n"
59 "Set the message's arguments from the positional parameter, according to\n"
60 "the signature given by the ``signature`` keyword parameter.\n"
61 "\n"
62 "The following type conversions are supported:\n\n"
63 "=============================== ===========================\n"
64 "D-Bus (in signature) Python\n"
65 "=============================== ===========================\n"
66 "boolean (b) any object (via bool())\n"
67 "byte (y) string of length 1\n"
68 " any integer\n"
69 "any integer type any integer\n"
70 "double (d) any float\n"
71 "object path anything with a __dbus_object_path__ attribute\n"
72 "string, signature, object path str (must be UTF-8) or unicode\n"
73 "dict (a{...}) any mapping\n"
74 "array (a...) any iterable over appropriate objects\n"
75 "struct ((...)) any iterable over appropriate objects\n"
76 "variant any object above (guess type as below)\n"
77 "=============================== ===========================\n"
78 "\n"
79 "Here 'any integer' means anything on which int() or long()\n"
80 "(as appropriate) will work, except for basestring subclasses.\n"
81 "'Any float' means anything on which float() will work, except\n"
82 "for basestring subclasses.\n"
83 "\n"
84 "If there is no signature, guess from the arguments using\n"
85 "the static method `Message.guess_signature`.\n"
88 char dbus_py_Message_guess_signature__doc__[] = (
89 "guess_signature(*args) -> Signature [static method]\n\n"
90 "Guess a D-Bus signature which should be used to encode the given\n"
91 "Python objects.\n"
92 "\n"
93 "The signature is constructed as follows:\n\n"
94 "+-------------------------------+---------------------------+\n"
95 "|Python |D-Bus |\n"
96 "+===============================+===========================+\n"
97 "|D-Bus type, variant_level > 0 |variant (v) |\n"
98 "+-------------------------------+---------------------------+\n"
99 "|D-Bus type, variant_level == 0 |the corresponding type |\n"
100 "+-------------------------------+---------------------------+\n"
101 "|anything with a |object path |\n"
102 "|__dbus_object_path__ attribute | |\n"
103 "+-------------------------------+---------------------------+\n"
104 "|bool |boolean (y) |\n"
105 "+-------------------------------+---------------------------+\n"
106 "|any other int subclass |int32 (i) |\n"
107 "+-------------------------------+---------------------------+\n"
108 "|any other long subclass |int64 (x) |\n"
109 "+-------------------------------+---------------------------+\n"
110 "|any other float subclass |double (d) |\n"
111 "+-------------------------------+---------------------------+\n"
112 "|any other str subclass |string (s) |\n"
113 "+-------------------------------+---------------------------+\n"
114 "|any other unicode subclass |string (s) |\n"
115 "+-------------------------------+---------------------------+\n"
116 "|any other tuple subclass |struct ((...)) |\n"
117 "+-------------------------------+---------------------------+\n"
118 "|any other list subclass |array (a...), guess |\n"
119 "| |contents' type according to|\n"
120 "| |type of first item |\n"
121 "+-------------------------------+---------------------------+\n"
122 "|any other dict subclass |dict (a{...}), guess key, |\n"
123 "| |value type according to |\n"
124 "| |types for an arbitrary item|\n"
125 "+-------------------------------+---------------------------+\n"
126 "|anything else |raise TypeError |\n"
127 "+-------------------------------+---------------------------+\n"
130 /* return a new reference, possibly to None */
131 static PyObject *
132 get_object_path(PyObject *obj)
134 PyObject *magic_attr = PyObject_GetAttr(obj, dbus_py__dbus_object_path__const);
136 if (magic_attr) {
137 if (PyString_Check(magic_attr)) {
138 return magic_attr;
140 else {
141 Py_DECREF(magic_attr);
142 PyErr_SetString(PyExc_TypeError, "__dbus_object_path__ must be "
143 "a string");
144 return NULL;
147 else {
148 /* Ignore exceptions, except for SystemExit and KeyboardInterrupt */
149 if (PyErr_ExceptionMatches(PyExc_SystemExit) ||
150 PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
151 return NULL;
152 PyErr_Clear();
153 Py_RETURN_NONE;
157 /* Return a new reference. If the object is a variant and variant_level_ptr
158 * is not NULL, put the variant level in the variable pointed to, and
159 * return the contained type instead of "v". */
160 static PyObject *
161 _signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr)
163 PyObject *magic_attr;
164 long variant_level = get_variant_level(obj);
165 if (variant_level_ptr) {
166 *variant_level_ptr = variant_level;
168 else if (variant_level > 0) {
169 return PyString_FromString(DBUS_TYPE_VARIANT_AS_STRING);
172 if (obj == Py_True || obj == Py_False) {
173 return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
176 magic_attr = get_object_path(obj);
177 if (!magic_attr)
178 return NULL;
179 if (magic_attr != Py_None) {
180 Py_DECREF(magic_attr);
181 return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
183 Py_DECREF(magic_attr);
185 /* Ordering is important: some of these are subclasses of each other. */
186 if (PyInt_Check(obj)) {
187 if (DBusPyInt16_Check(obj))
188 return PyString_FromString(DBUS_TYPE_INT16_AS_STRING);
189 else if (DBusPyInt32_Check(obj))
190 return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
191 else if (DBusPyByte_Check(obj))
192 return PyString_FromString(DBUS_TYPE_BYTE_AS_STRING);
193 else if (DBusPyUInt16_Check(obj))
194 return PyString_FromString(DBUS_TYPE_UINT16_AS_STRING);
195 else if (DBusPyBoolean_Check(obj))
196 return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
197 else
198 return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
200 else if (PyLong_Check(obj)) {
201 if (DBusPyInt64_Check(obj))
202 return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
203 else if (DBusPyUInt32_Check(obj))
204 return PyString_FromString(DBUS_TYPE_UINT32_AS_STRING);
205 else if (DBusPyUInt64_Check(obj))
206 return PyString_FromString(DBUS_TYPE_UINT64_AS_STRING);
207 else
208 return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
210 else if (PyUnicode_Check(obj))
211 return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
212 else if (PyFloat_Check(obj)) {
213 #ifdef WITH_DBUS_FLOAT32
214 if (DBusPyDouble_Check(obj))
215 return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
216 else if (DBusPyFloat_Check(obj))
217 return PyString_FromString(DBUS_TYPE_FLOAT_AS_STRING);
218 else
219 #endif
220 return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
222 else if (PyString_Check(obj)) {
223 if (DBusPyObjectPath_Check(obj))
224 return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
225 else if (DBusPySignature_Check(obj))
226 return PyString_FromString(DBUS_TYPE_SIGNATURE_AS_STRING);
227 else if (DBusPyByteArray_Check(obj))
228 return PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING
229 DBUS_TYPE_BYTE_AS_STRING);
230 else
231 return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
233 else if (PyTuple_Check(obj)) {
234 Py_ssize_t len = PyTuple_GET_SIZE(obj);
235 PyObject *list = PyList_New(len + 2); /* new ref */
236 PyObject *item; /* temporary new ref */
237 PyObject *empty_str; /* temporary new ref */
238 PyObject *ret;
239 Py_ssize_t i;
241 if (!list) return NULL;
242 if (len == 0) {
243 PyErr_SetString(PyExc_ValueError, "D-Bus structs cannot be empty");
244 Py_DECREF(list);
245 return NULL;
247 /* Set the first and last elements of list to be the parentheses */
248 item = PyString_FromString(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
249 if (PyList_SetItem(list, 0, item) < 0) {
250 Py_DECREF(list);
251 return NULL;
253 item = PyString_FromString(DBUS_STRUCT_END_CHAR_AS_STRING);
254 if (PyList_SetItem(list, len + 1, item) < 0) {
255 Py_DECREF(list);
256 return NULL;
258 if (!item || !PyList_GET_ITEM(list, 0)) {
259 Py_DECREF(list);
260 return NULL;
262 item = NULL;
264 for (i = 0; i < len; i++) {
265 item = PyTuple_GetItem(obj, i);
266 if (!item) {
267 Py_DECREF(list);
268 return NULL;
270 item = _signature_string_from_pyobject(item, NULL);
271 if (!item) {
272 Py_DECREF(list);
273 return NULL;
275 if (PyList_SetItem(list, i + 1, item) < 0) {
276 Py_DECREF(list);
277 return NULL;
279 item = NULL;
281 empty_str = PyString_FromString("");
282 if (!empty_str) {
283 /* really shouldn't happen */
284 Py_DECREF(list);
285 return NULL;
287 ret = PyObject_CallMethod(empty_str, "join", "(O)", list); /* new ref */
288 /* whether ret is NULL or not, */
289 Py_DECREF(empty_str);
290 Py_DECREF(list);
291 return ret;
293 else if (PyList_Check(obj)) {
294 PyObject *tmp;
295 PyObject *ret = PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING);
296 if (!ret) return NULL;
297 if (DBusPyArray_Check(obj) && PyString_Check(((DBusPyArray *)obj)->signature)) {
298 PyString_Concat(&ret, ((DBusPyArray *)obj)->signature);
299 return ret;
301 if (PyList_GET_SIZE(obj) == 0) {
302 /* No items, so fail. Or should we guess "av"? */
303 PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
304 "from an empty list");
305 return NULL;
307 tmp = PyList_GetItem(obj, 0);
308 tmp = _signature_string_from_pyobject(tmp, NULL);
309 if (!tmp) return NULL;
310 PyString_ConcatAndDel(&ret, tmp);
311 return ret;
313 else if (PyDict_Check(obj)) {
314 PyObject *key, *value, *keysig, *valuesig;
315 Py_ssize_t pos = 0;
316 PyObject *ret = NULL;
318 if (DBusPyDict_Check(obj) && PyString_Check(((DBusPyDict *)obj)->signature)) {
319 const char *sig = PyString_AS_STRING(((DBusPyDict *)obj)->signature);
321 return PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
322 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
323 "%s"
324 DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
325 sig);
327 if (!PyDict_Next(obj, &pos, &key, &value)) {
328 /* No items, so fail. Or should we guess "a{vv}"? */
329 PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
330 "from an empty dict");
331 return NULL;
333 keysig = _signature_string_from_pyobject(key, NULL);
334 valuesig = _signature_string_from_pyobject(value, NULL);
335 if (keysig && valuesig) {
336 ret = PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
337 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
338 "%s%s"
339 DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
340 PyString_AS_STRING(keysig),
341 PyString_AS_STRING(valuesig));
343 Py_XDECREF(keysig);
344 Py_XDECREF(valuesig);
345 return ret;
347 else {
348 PyErr_Format(PyExc_TypeError, "Don't know how which D-Bus type "
349 "to use to encode type \"%s\"",
350 obj->ob_type->tp_name);
351 return NULL;
355 PyObject *
356 dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args)
358 PyObject *tmp, *ret = NULL;
360 if (!args) {
361 if (!PyErr_Occurred()) {
362 PyErr_BadInternalCall();
364 return NULL;
367 #ifdef USING_DBG
368 fprintf(stderr, "DBG/%ld: called Message_guess_signature", (long)getpid());
369 PyObject_Print(args, stderr, 0);
370 fprintf(stderr, "\n");
371 #endif
373 if (!PyTuple_Check(args)) {
374 DBG("%s", "Message_guess_signature: args not a tuple");
375 PyErr_BadInternalCall();
376 return NULL;
379 /* if there were no args, easy */
380 if (PyTuple_GET_SIZE(args) == 0) {
381 DBG("%s", "Message_guess_signature: no args, so return Signature('')");
382 return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", "");
385 /* if there were args, the signature we want is, by construction,
386 * exactly the signature we get for the tuple args, except that we don't
387 * want the parentheses. */
388 tmp = _signature_string_from_pyobject(args, NULL);
389 if (!tmp) {
390 DBG("%s", "Message_guess_signature: failed");
391 return NULL;
393 if (!PyString_Check(tmp) || PyString_GET_SIZE(tmp) < 2) {
394 PyErr_SetString(PyExc_RuntimeError, "Internal error: "
395 "_signature_string_from_pyobject returned "
396 "a bad result");
397 Py_DECREF(tmp);
398 return NULL;
400 ret = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s#)",
401 PyString_AS_STRING(tmp) + 1,
402 PyString_GET_SIZE(tmp) - 2);
403 DBG("Message_guess_signature: returning Signature at %p \"%s\"", ret,
404 ret ? PyString_AS_STRING(ret) : "(NULL)");
405 Py_DECREF(tmp);
406 return ret;
409 static int _message_iter_append_pyobject(DBusMessageIter *appender,
410 DBusSignatureIter *sig_iter,
411 PyObject *obj,
412 dbus_bool_t *more);
413 static int _message_iter_append_variant(DBusMessageIter *appender,
414 PyObject *obj);
416 static int
417 _message_iter_append_string(DBusMessageIter *appender,
418 int sig_type, PyObject *obj,
419 dbus_bool_t allow_object_path_attr)
421 char *s;
423 if (sig_type == DBUS_TYPE_OBJECT_PATH && allow_object_path_attr) {
424 PyObject *object_path = get_object_path (obj);
426 if (object_path == Py_None) {
427 Py_DECREF(object_path);
429 else if (!object_path) {
430 return -1;
432 else {
433 int ret = _message_iter_append_string(appender, sig_type,
434 object_path, FALSE);
435 Py_DECREF(object_path);
436 return ret;
440 if (PyString_Check(obj)) {
441 PyObject *unicode;
443 /* Raise TypeError if the string has embedded NULs */
444 if (PyString_AsStringAndSize(obj, &s, NULL) < 0) return -1;
445 /* Surely there's a faster stdlib way to validate UTF-8... */
446 unicode = PyUnicode_DecodeUTF8(s, PyString_GET_SIZE(obj), NULL);
447 if (!unicode) {
448 PyErr_SetString(PyExc_UnicodeError, "String parameters "
449 "to be sent over D-Bus must be valid UTF-8");
450 return -1;
452 Py_DECREF(unicode);
453 unicode = NULL;
455 DBG("Performing actual append: string %s", s);
456 if (!dbus_message_iter_append_basic(appender, sig_type,
457 &s)) {
458 PyErr_NoMemory();
459 return -1;
462 else if (PyUnicode_Check(obj)) {
463 PyObject *utf8 = PyUnicode_AsUTF8String(obj);
464 if (!utf8) return -1;
465 /* Raise TypeError if the string has embedded NULs */
466 if (PyString_AsStringAndSize(utf8, &s, NULL) < 0) return -1;
467 DBG("Performing actual append: string (from unicode) %s", s);
468 if (!dbus_message_iter_append_basic(appender, sig_type, &s)) {
469 PyErr_NoMemory();
470 return -1;
472 Py_DECREF(utf8);
474 else {
475 PyErr_SetString(PyExc_TypeError,
476 "Expected a string or unicode object");
477 return -1;
479 return 0;
482 static int
483 _message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
485 unsigned char y;
487 if (PyString_Check(obj)) {
488 if (PyString_GET_SIZE(obj) != 1) {
489 PyErr_Format(PyExc_ValueError, "Expected a string of "
490 "length 1 byte, but found %d bytes",
491 PyString_GET_SIZE(obj));
492 return -1;
494 y = *(unsigned char *)PyString_AS_STRING(obj);
496 else {
497 long i = PyInt_AsLong(obj);
499 if (i == -1 && PyErr_Occurred()) return -1;
500 if (i < 0 || i > 0xff) {
501 PyErr_Format(PyExc_ValueError, "%d outside range for a "
502 "byte value", (int)i);
503 return -1;
505 y = i;
507 DBG("Performing actual append: byte \\x%02x", (unsigned)y);
508 if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
509 PyErr_NoMemory();
510 return -1;
512 return 0;
515 static int
516 _message_iter_append_dictentry(DBusMessageIter *appender,
517 DBusSignatureIter *sig_iter,
518 PyObject *dict, PyObject *key)
520 DBusSignatureIter sub_sig_iter;
521 DBusMessageIter sub;
522 int ret = -1;
523 PyObject *value = PyObject_GetItem(dict, key);
524 dbus_bool_t more;
526 if (!value) return -1;
528 #ifdef USING_DBG
529 fprintf(stderr, "Append dictentry: ");
530 PyObject_Print(key, stderr, 0);
531 fprintf(stderr, " => ");
532 PyObject_Print(value, stderr, 0);
533 fprintf(stderr, "\n");
534 #endif
536 DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
537 dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
538 #ifdef USING_DBG
540 char *s;
541 s = dbus_signature_iter_get_signature(sig_iter);
542 DBG("Signature of parent iterator %p is %s", sig_iter, s);
543 dbus_free(s);
544 s = dbus_signature_iter_get_signature(&sub_sig_iter);
545 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
546 dbus_free(s);
548 #endif
550 DBG("%s", "Opening DICT_ENTRY container");
551 if (!dbus_message_iter_open_container(appender, DBUS_TYPE_DICT_ENTRY,
552 NULL, &sub)) {
553 PyErr_NoMemory();
554 goto out;
556 ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key, &more);
557 if (ret == 0) {
558 ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value, &more);
560 DBG("%s", "Closing DICT_ENTRY container");
561 if (!dbus_message_iter_close_container(appender, &sub)) {
562 PyErr_NoMemory();
563 ret = -1;
565 out:
566 Py_DECREF(value);
567 return ret;
570 static int
571 _message_iter_append_multi(DBusMessageIter *appender,
572 const DBusSignatureIter *sig_iter,
573 int mode, PyObject *obj)
575 DBusMessageIter sub_appender;
576 DBusSignatureIter sub_sig_iter;
577 PyObject *contents;
578 int ret;
579 PyObject *iterator = PyObject_GetIter(obj);
580 char *sig = NULL;
581 int container = mode;
582 dbus_bool_t is_byte_array = DBusPyByteArray_Check(obj);
583 int inner_type;
584 dbus_bool_t more;
586 #ifdef USING_DBG
587 fprintf(stderr, "Appending multiple: ");
588 PyObject_Print(obj, stderr, 0);
589 fprintf(stderr, "\n");
590 #endif
592 if (!iterator) return -1;
593 if (mode == DBUS_TYPE_DICT_ENTRY) container = DBUS_TYPE_ARRAY;
595 DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
596 dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
597 #ifdef USING_DBG
599 char *s;
600 s = dbus_signature_iter_get_signature(sig_iter);
601 DBG("Signature of parent iterator %p is %s", sig_iter, s);
602 dbus_free(s);
603 s = dbus_signature_iter_get_signature(&sub_sig_iter);
604 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
605 dbus_free(s);
607 #endif
608 inner_type = dbus_signature_iter_get_current_type(&sub_sig_iter);
610 if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
611 sig = dbus_signature_iter_get_signature(&sub_sig_iter);
612 if (!sig) {
613 PyErr_NoMemory();
614 ret = -1;
615 goto out;
618 /* else leave sig set to NULL. */
620 DBG("Opening %c container", container);
621 if (!dbus_message_iter_open_container(appender, container,
622 sig, &sub_appender)) {
623 PyErr_NoMemory();
624 ret = -1;
625 goto out;
627 ret = 0;
628 while ((contents = PyIter_Next(iterator))) {
630 if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
631 DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
632 dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
633 #ifdef USING_DBG
635 char *s;
636 s = dbus_signature_iter_get_signature(sig_iter);
637 DBG("Signature of parent iterator %p is %s", sig_iter, s);
638 dbus_free(s);
639 s = dbus_signature_iter_get_signature(&sub_sig_iter);
640 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
641 dbus_free(s);
643 #endif
646 if (mode == DBUS_TYPE_DICT_ENTRY) {
647 ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
648 obj, contents);
650 else if (mode == DBUS_TYPE_ARRAY && is_byte_array
651 && inner_type == DBUS_TYPE_VARIANT) {
652 /* Subscripting a ByteArray gives a str of length 1, but if the
653 * container is a ByteArray and the parameter is an array of
654 * variants, we want to produce an array of variants containing
655 * bytes, not strings.
657 PyObject *args = Py_BuildValue("(O)", contents);
658 PyObject *byte;
660 if (!args)
661 break;
662 byte = PyObject_Call((PyObject *)&DBusPyByte_Type, args, NULL);
663 Py_DECREF(args);
664 if (!byte)
665 break;
666 ret = _message_iter_append_variant(&sub_appender, byte);
667 Py_DECREF(byte);
669 else {
670 /* advances sub_sig_iter and sets more on success - for array
671 * this doesn't matter, for struct it's essential */
672 ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
673 contents, &more);
676 Py_DECREF(contents);
677 if (ret < 0) {
678 break;
682 if (PyErr_Occurred()) {
683 ret = -1;
685 else if (mode == DBUS_TYPE_STRUCT && more) {
686 PyErr_Format(PyExc_TypeError, "More items found in struct's D-Bus "
687 "signature than in Python arguments ");
688 ret = -1;
691 /* This must be run as cleanup, even on failure. */
692 DBG("Closing %c container", container);
693 if (!dbus_message_iter_close_container(appender, &sub_appender)) {
694 PyErr_NoMemory();
695 ret = -1;
698 out:
699 Py_XDECREF(iterator);
700 dbus_free(sig);
701 return ret;
704 static int
705 _message_iter_append_string_as_byte_array(DBusMessageIter *appender,
706 PyObject *obj)
708 /* a bit of a faster path for byte arrays that are strings */
709 Py_ssize_t len = PyString_GET_SIZE(obj);
710 const char *s;
711 DBusMessageIter sub;
712 int ret;
714 s = PyString_AS_STRING(obj);
715 DBG("%s", "Opening ARRAY container");
716 if (!dbus_message_iter_open_container(appender, DBUS_TYPE_ARRAY,
717 DBUS_TYPE_BYTE_AS_STRING, &sub)) {
718 PyErr_NoMemory();
719 return -1;
721 DBG("Appending fixed array of %d bytes", len);
722 if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
723 ret = 0;
725 else {
726 PyErr_NoMemory();
727 ret = -1;
729 DBG("%s", "Closing ARRAY container");
730 if (!dbus_message_iter_close_container(appender, &sub)) {
731 PyErr_NoMemory();
732 return -1;
734 return ret;
737 /* Encode some Python object into a D-Bus variant slot. */
738 static int
739 _message_iter_append_variant(DBusMessageIter *appender, PyObject *obj)
741 DBusSignatureIter obj_sig_iter;
742 const char *obj_sig_str;
743 PyObject *obj_sig;
744 int ret;
745 long variant_level;
746 dbus_bool_t dummy;
748 /* Separate the object into the contained object, and the number of
749 * variants it's wrapped in. */
750 obj_sig = _signature_string_from_pyobject(obj, &variant_level);
751 if (!obj_sig) return -1;
753 obj_sig_str = PyString_AsString(obj_sig);
754 if (!obj_sig_str) return -1;
756 if (variant_level < 1) {
757 variant_level = 1;
760 dbus_signature_iter_init(&obj_sig_iter, obj_sig_str);
762 { /* scope for variant_iters */
763 DBusMessageIter variant_iters[variant_level];
764 long i;
766 for (i = 0; i < variant_level; i++) {
767 DBusMessageIter *child = &variant_iters[i];
768 /* The first is a special case: its parent is the iter passed in
769 * to this function, instead of being the previous one in the
770 * stack
772 DBusMessageIter *parent = (i == 0
773 ? appender
774 : &(variant_iters[i-1]));
775 /* The last is also a special case: it contains the actual
776 * object, rather than another variant
778 const char *sig_str = (i == variant_level-1
779 ? obj_sig_str
780 : DBUS_TYPE_VARIANT_AS_STRING);
782 DBG("Opening VARIANT container %p inside %p containing '%s'",
783 child, parent, sig_str);
784 if (!dbus_message_iter_open_container(parent, DBUS_TYPE_VARIANT,
785 sig_str, child)) {
786 PyErr_NoMemory();
787 ret = -1;
788 goto out;
792 /* Put the object itself into the innermost variant */
793 ret = _message_iter_append_pyobject(&variant_iters[variant_level-1],
794 &obj_sig_iter, obj, &dummy);
796 /* here we rely on i (and variant_level) being a signed long */
797 for (i = variant_level - 1; i >= 0; i--) {
798 DBusMessageIter *child = &variant_iters[i];
799 /* The first is a special case: its parent is the iter passed in
800 * to this function, instead of being the previous one in the
801 * stack
803 DBusMessageIter *parent = (i == 0 ? appender
804 : &(variant_iters[i-1]));
806 DBG("Closing VARIANT container %p inside %p", child, parent);
807 if (!dbus_message_iter_close_container(parent, child)) {
808 PyErr_NoMemory();
809 ret = -1;
810 goto out;
816 out:
817 Py_XDECREF(obj_sig);
818 return ret;
821 /* On success, *more is set to whether there's more in the signature. */
822 static int
823 _message_iter_append_pyobject(DBusMessageIter *appender,
824 DBusSignatureIter *sig_iter,
825 PyObject *obj,
826 dbus_bool_t *more)
828 int sig_type = dbus_signature_iter_get_current_type(sig_iter);
829 union {
830 dbus_bool_t b;
831 double d;
832 dbus_uint16_t uint16;
833 dbus_int16_t int16;
834 dbus_uint32_t uint32;
835 dbus_int32_t int32;
836 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
837 dbus_uint64_t uint64;
838 dbus_int64_t int64;
839 #endif
840 } u;
841 int ret = -1;
843 #ifdef USING_DBG
844 fprintf(stderr, "Appending object at %p: ", obj);
845 PyObject_Print(obj, stderr, 0);
846 fprintf(stderr, " into appender at %p, dbus wants type %c\n",
847 appender, sig_type);
848 #endif
850 switch (sig_type) {
851 /* The numeric types are relatively simple to deal with, so are
852 * inlined here. */
854 case DBUS_TYPE_BOOLEAN:
855 if (PyObject_IsTrue(obj)) {
856 u.b = 1;
858 else {
859 u.b = 0;
861 DBG("Performing actual append: bool(%ld)", (long)u.b);
862 if (!dbus_message_iter_append_basic(appender, sig_type, &u.b)) {
863 PyErr_NoMemory();
864 ret = -1;
865 break;
867 ret = 0;
868 break;
870 case DBUS_TYPE_DOUBLE:
871 u.d = PyFloat_AsDouble(obj);
872 if (PyErr_Occurred()) {
873 ret = -1;
874 break;
876 DBG("Performing actual append: double(%f)", u.d);
877 if (!dbus_message_iter_append_basic(appender, sig_type, &u.d)) {
878 PyErr_NoMemory();
879 ret = -1;
880 break;
882 ret = 0;
883 break;
885 #ifdef WITH_DBUS_FLOAT32
886 case DBUS_TYPE_FLOAT:
887 u.d = PyFloat_AsDouble(obj);
888 if (PyErr_Occurred()) {
889 ret = -1;
890 break;
892 u.f = (float)u.d;
893 DBG("Performing actual append: float(%f)", u.f);
894 if (!dbus_message_iter_append_basic(appender, sig_type, &u.f)) {
895 PyErr_NoMemory();
896 ret = -1;
897 break;
899 ret = 0;
900 break;
901 #endif
903 /* The integer types are all basically the same - we delegate to
904 intNN_range_check() */
905 #define PROCESS_INTEGER(size) \
906 u.size = dbus_py_##size##_range_check(obj);\
907 if (u.size == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
908 ret = -1; \
909 break; \
911 DBG("Performing actual append: " #size "(%lld)", (long long)u.size); \
912 if (!dbus_message_iter_append_basic(appender, sig_type, &u.size)) {\
913 PyErr_NoMemory();\
914 ret = -1;\
915 break;\
917 ret = 0;
919 case DBUS_TYPE_INT16:
920 PROCESS_INTEGER(int16)
921 break;
922 case DBUS_TYPE_UINT16:
923 PROCESS_INTEGER(uint16)
924 break;
925 case DBUS_TYPE_INT32:
926 PROCESS_INTEGER(int32)
927 break;
928 case DBUS_TYPE_UINT32:
929 PROCESS_INTEGER(uint32)
930 break;
931 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
932 case DBUS_TYPE_INT64:
933 PROCESS_INTEGER(int64)
934 break;
935 case DBUS_TYPE_UINT64:
936 PROCESS_INTEGER(uint64)
937 break;
938 #else
939 case DBUS_TYPE_INT64:
940 case DBUS_TYPE_UINT64:
941 PyErr_SetString(PyExc_NotImplementedError, "64-bit integer "
942 "types are not supported on this platform");
943 ret = -1;
944 break;
945 #endif
946 #undef PROCESS_INTEGER
948 /* Now the more complicated cases, which are delegated to helper
949 * functions (although in practice, the compiler will hopefully
950 * inline them anyway). */
952 case DBUS_TYPE_STRING:
953 case DBUS_TYPE_SIGNATURE:
954 case DBUS_TYPE_OBJECT_PATH:
955 ret = _message_iter_append_string(appender, sig_type, obj, TRUE);
956 break;
958 case DBUS_TYPE_BYTE:
959 ret = _message_iter_append_byte(appender, obj);
960 break;
962 case DBUS_TYPE_ARRAY:
963 /* 3 cases - it might actually be a dict, or it might be a byte array
964 * being copied from a string (for which we have a faster path),
965 * or it might be a generic array. */
967 sig_type = dbus_signature_iter_get_element_type(sig_iter);
968 if (sig_type == DBUS_TYPE_DICT_ENTRY)
969 ret = _message_iter_append_multi(appender, sig_iter,
970 DBUS_TYPE_DICT_ENTRY, obj);
971 else if (sig_type == DBUS_TYPE_BYTE && PyString_Check(obj))
972 ret = _message_iter_append_string_as_byte_array(appender, obj);
973 else
974 ret = _message_iter_append_multi(appender, sig_iter,
975 DBUS_TYPE_ARRAY, obj);
976 DBG("_message_iter_append_multi(): %d", ret);
977 break;
979 case DBUS_TYPE_STRUCT:
980 ret = _message_iter_append_multi(appender, sig_iter, sig_type, obj);
981 break;
983 case DBUS_TYPE_VARIANT:
984 ret = _message_iter_append_variant(appender, obj);
985 break;
987 case DBUS_TYPE_INVALID:
988 PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
989 "signature than in Python arguments");
990 ret = -1;
991 break;
993 default:
994 PyErr_Format(PyExc_TypeError, "Unknown type '\\x%x' in D-Bus "
995 "signature", sig_type);
996 ret = -1;
997 break;
999 if (ret < 0) return -1;
1001 DBG("Advancing signature iter at %p", sig_iter);
1002 *more = dbus_signature_iter_next(sig_iter);
1003 #ifdef USING_DBG
1004 DBG("- result: %ld, type %02x '%c'", (long)(*more),
1005 (int)dbus_signature_iter_get_current_type(sig_iter),
1006 (int)dbus_signature_iter_get_current_type(sig_iter));
1007 #endif
1008 return 0;
1012 PyObject *
1013 dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs)
1015 const char *signature = NULL;
1016 PyObject *signature_obj = NULL;
1017 DBusSignatureIter sig_iter;
1018 DBusMessageIter appender;
1019 int i;
1020 static char *argnames[] = {"signature", NULL};
1021 /* must start FALSE for the case where there's nothing there and we
1022 * never iterate at all */
1023 dbus_bool_t more;
1025 if (!self->msg) return DBusPy_RaiseUnusableMessage();
1027 #ifdef USING_DBG
1028 fprintf(stderr, "DBG/%ld: called Message_append(*", (long)getpid());
1029 PyObject_Print(args, stderr, 0);
1030 if (kwargs) {
1031 fprintf(stderr, ", **");
1032 PyObject_Print(kwargs, stderr, 0);
1034 fprintf(stderr, ")\n");
1035 #endif
1037 /* only use kwargs for this step: deliberately ignore args for now */
1038 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, "|z:append",
1039 argnames, &signature)) return NULL;
1041 if (!signature) {
1042 DBG("%s", "No signature for message, guessing...");
1043 signature_obj = dbus_py_Message_guess_signature(NULL, args);
1044 if (!signature_obj) return NULL;
1045 signature = PyString_AS_STRING(signature_obj);
1047 /* from here onwards, you have to do a goto rather than returning NULL
1048 to make sure signature_obj gets freed */
1050 /* iterate over args and the signature, together */
1051 if (!dbus_signature_validate(signature, NULL)) {
1052 PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
1053 goto err;
1055 dbus_signature_iter_init(&sig_iter, signature);
1056 dbus_message_iter_init_append(self->msg, &appender);
1057 more = (signature[0] != '\0');
1058 for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
1059 if (_message_iter_append_pyobject(&appender, &sig_iter,
1060 PyTuple_GET_ITEM(args, i),
1061 &more) < 0) {
1062 goto hosed;
1065 if (more) {
1066 PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
1067 "signature than in Python arguments");
1068 goto hosed;
1071 /* success! */
1072 Py_XDECREF(signature_obj);
1073 Py_RETURN_NONE;
1075 hosed:
1076 /* "If appending any of the arguments fails due to lack of memory,
1077 * generally the message is hosed and you have to start over" -libdbus docs
1078 * Enforce this by throwing away the message structure.
1080 dbus_message_unref(self->msg);
1081 self->msg = NULL;
1082 err:
1083 Py_XDECREF(signature_obj);
1084 return NULL;
1087 /* vim:set ft=c cino< sw=4 sts=4 et: */