Unset release flag, and start NEWS for 0.82.5
[dbus-python-phuang.git] / _dbus_bindings / message-append.c
blob93b76c7ea1e252dc63068fefbca42b13295e1f87
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. <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 DBG_IS_TOO_VERBOSE
28 #include "types-internal.h"
29 #include "message-internal.h"
31 /* Return the number of variants wrapping the given object. Return 0
32 * if the object is not a D-Bus type.
34 static long
35 get_variant_level(PyObject *obj)
37 if (DBusPyIntBase_Check(obj)) {
38 return ((DBusPyIntBase *)obj)->variant_level;
40 else if (DBusPyFloatBase_Check(obj)) {
41 return ((DBusPyFloatBase *)obj)->variant_level;
43 else if (DBusPyArray_Check(obj)) {
44 return ((DBusPyArray *)obj)->variant_level;
46 else if (DBusPyDict_Check(obj)) {
47 return ((DBusPyDict *)obj)->variant_level;
49 else if (DBusPyString_Check(obj)) {
50 return ((DBusPyString *)obj)->variant_level;
52 else if (DBusPyLongBase_Check(obj) ||
53 DBusPyStrBase_Check(obj) ||
54 DBusPyStruct_Check(obj)) {
55 return dbus_py_variant_level_get(obj);
57 else {
58 return 0;
62 char dbus_py_Message_append__doc__[] = (
63 "set_args(*args[, **kwargs])\n\n"
64 "Set the message's arguments from the positional parameter, according to\n"
65 "the signature given by the ``signature`` keyword parameter.\n"
66 "\n"
67 "The following type conversions are supported:\n\n"
68 "=============================== ===========================\n"
69 "D-Bus (in signature) Python\n"
70 "=============================== ===========================\n"
71 "boolean (b) any object (via bool())\n"
72 "byte (y) string of length 1\n"
73 " any integer\n"
74 "any integer type any integer\n"
75 "double (d) any float\n"
76 "object path anything with a __dbus_object_path__ attribute\n"
77 "string, signature, object path str (must be UTF-8) or unicode\n"
78 "dict (a{...}) any mapping\n"
79 "array (a...) any iterable over appropriate objects\n"
80 "struct ((...)) any iterable over appropriate objects\n"
81 "variant any object above (guess type as below)\n"
82 "=============================== ===========================\n"
83 "\n"
84 "Here 'any integer' means anything on which int() or long()\n"
85 "(as appropriate) will work, except for basestring subclasses.\n"
86 "'Any float' means anything on which float() will work, except\n"
87 "for basestring subclasses.\n"
88 "\n"
89 "If there is no signature, guess from the arguments using\n"
90 "the static method `Message.guess_signature`.\n"
93 char dbus_py_Message_guess_signature__doc__[] = (
94 "guess_signature(*args) -> Signature [static method]\n\n"
95 "Guess a D-Bus signature which should be used to encode the given\n"
96 "Python objects.\n"
97 "\n"
98 "The signature is constructed as follows:\n\n"
99 "+-------------------------------+---------------------------+\n"
100 "|Python |D-Bus |\n"
101 "+===============================+===========================+\n"
102 "|D-Bus type, variant_level > 0 |variant (v) |\n"
103 "+-------------------------------+---------------------------+\n"
104 "|D-Bus type, variant_level == 0 |the corresponding type |\n"
105 "+-------------------------------+---------------------------+\n"
106 "|anything with a |object path |\n"
107 "|__dbus_object_path__ attribute | |\n"
108 "+-------------------------------+---------------------------+\n"
109 "|bool |boolean (y) |\n"
110 "+-------------------------------+---------------------------+\n"
111 "|any other int subclass |int32 (i) |\n"
112 "+-------------------------------+---------------------------+\n"
113 "|any other long subclass |int64 (x) |\n"
114 "+-------------------------------+---------------------------+\n"
115 "|any other float subclass |double (d) |\n"
116 "+-------------------------------+---------------------------+\n"
117 "|any other str subclass |string (s) |\n"
118 "+-------------------------------+---------------------------+\n"
119 "|any other unicode subclass |string (s) |\n"
120 "+-------------------------------+---------------------------+\n"
121 "|any other tuple subclass |struct ((...)) |\n"
122 "+-------------------------------+---------------------------+\n"
123 "|any other list subclass |array (a...), guess |\n"
124 "| |contents' type according to|\n"
125 "| |type of first item |\n"
126 "+-------------------------------+---------------------------+\n"
127 "|any other dict subclass |dict (a{...}), guess key, |\n"
128 "| |value type according to |\n"
129 "| |types for an arbitrary item|\n"
130 "+-------------------------------+---------------------------+\n"
131 "|anything else |raise TypeError |\n"
132 "+-------------------------------+---------------------------+\n"
135 /* return a new reference, possibly to None */
136 static PyObject *
137 get_object_path(PyObject *obj)
139 PyObject *magic_attr = PyObject_GetAttr(obj, dbus_py__dbus_object_path__const);
141 if (magic_attr) {
142 if (PyString_Check(magic_attr)) {
143 return magic_attr;
145 else {
146 Py_DECREF(magic_attr);
147 PyErr_SetString(PyExc_TypeError, "__dbus_object_path__ must be "
148 "a string");
149 return NULL;
152 else {
153 /* Ignore exceptions, except for SystemExit and KeyboardInterrupt */
154 if (PyErr_ExceptionMatches(PyExc_SystemExit) ||
155 PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
156 return NULL;
157 PyErr_Clear();
158 Py_RETURN_NONE;
162 /* Return a new reference. If the object is a variant and variant_level_ptr
163 * is not NULL, put the variant level in the variable pointed to, and
164 * return the contained type instead of "v". */
165 static PyObject *
166 _signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr)
168 PyObject *magic_attr;
169 long variant_level = get_variant_level(obj);
170 if (variant_level_ptr) {
171 *variant_level_ptr = variant_level;
173 else if (variant_level > 0) {
174 return PyString_FromString(DBUS_TYPE_VARIANT_AS_STRING);
177 if (obj == Py_True || obj == Py_False) {
178 return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
181 magic_attr = get_object_path(obj);
182 if (!magic_attr)
183 return NULL;
184 if (magic_attr != Py_None) {
185 Py_DECREF(magic_attr);
186 return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
188 Py_DECREF(magic_attr);
190 /* Ordering is important: some of these are subclasses of each other. */
191 if (PyInt_Check(obj)) {
192 if (DBusPyInt16_Check(obj))
193 return PyString_FromString(DBUS_TYPE_INT16_AS_STRING);
194 else if (DBusPyInt32_Check(obj))
195 return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
196 else if (DBusPyByte_Check(obj))
197 return PyString_FromString(DBUS_TYPE_BYTE_AS_STRING);
198 else if (DBusPyUInt16_Check(obj))
199 return PyString_FromString(DBUS_TYPE_UINT16_AS_STRING);
200 else if (DBusPyBoolean_Check(obj))
201 return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
202 else
203 return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
205 else if (PyLong_Check(obj)) {
206 if (DBusPyInt64_Check(obj))
207 return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
208 else if (DBusPyUInt32_Check(obj))
209 return PyString_FromString(DBUS_TYPE_UINT32_AS_STRING);
210 else if (DBusPyUInt64_Check(obj))
211 return PyString_FromString(DBUS_TYPE_UINT64_AS_STRING);
212 else
213 return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
215 else if (PyUnicode_Check(obj))
216 return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
217 else if (PyFloat_Check(obj)) {
218 #ifdef WITH_DBUS_FLOAT32
219 if (DBusPyDouble_Check(obj))
220 return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
221 else if (DBusPyFloat_Check(obj))
222 return PyString_FromString(DBUS_TYPE_FLOAT_AS_STRING);
223 else
224 #endif
225 return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
227 else if (PyString_Check(obj)) {
228 if (DBusPyObjectPath_Check(obj))
229 return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
230 else if (DBusPySignature_Check(obj))
231 return PyString_FromString(DBUS_TYPE_SIGNATURE_AS_STRING);
232 else if (DBusPyByteArray_Check(obj))
233 return PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING
234 DBUS_TYPE_BYTE_AS_STRING);
235 else
236 return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
238 else if (PyTuple_Check(obj)) {
239 Py_ssize_t len = PyTuple_GET_SIZE(obj);
240 PyObject *list = PyList_New(len + 2); /* new ref */
241 PyObject *item; /* temporary new ref */
242 PyObject *empty_str; /* temporary new ref */
243 PyObject *ret;
244 Py_ssize_t i;
246 if (!list) return NULL;
247 if (len == 0) {
248 PyErr_SetString(PyExc_ValueError, "D-Bus structs cannot be empty");
249 Py_DECREF(list);
250 return NULL;
252 /* Set the first and last elements of list to be the parentheses */
253 item = PyString_FromString(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
254 if (PyList_SetItem(list, 0, item) < 0) {
255 Py_DECREF(list);
256 return NULL;
258 item = PyString_FromString(DBUS_STRUCT_END_CHAR_AS_STRING);
259 if (PyList_SetItem(list, len + 1, item) < 0) {
260 Py_DECREF(list);
261 return NULL;
263 if (!item || !PyList_GET_ITEM(list, 0)) {
264 Py_DECREF(list);
265 return NULL;
267 item = NULL;
269 for (i = 0; i < len; i++) {
270 item = PyTuple_GetItem(obj, i);
271 if (!item) {
272 Py_DECREF(list);
273 return NULL;
275 item = _signature_string_from_pyobject(item, NULL);
276 if (!item) {
277 Py_DECREF(list);
278 return NULL;
280 if (PyList_SetItem(list, i + 1, item) < 0) {
281 Py_DECREF(list);
282 return NULL;
284 item = NULL;
286 empty_str = PyString_FromString("");
287 if (!empty_str) {
288 /* really shouldn't happen */
289 Py_DECREF(list);
290 return NULL;
292 ret = PyObject_CallMethod(empty_str, "join", "(O)", list); /* new ref */
293 /* whether ret is NULL or not, */
294 Py_DECREF(empty_str);
295 Py_DECREF(list);
296 return ret;
298 else if (PyList_Check(obj)) {
299 PyObject *tmp;
300 PyObject *ret = PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING);
301 if (!ret) return NULL;
302 if (DBusPyArray_Check(obj) && PyString_Check(((DBusPyArray *)obj)->signature)) {
303 PyString_Concat(&ret, ((DBusPyArray *)obj)->signature);
304 return ret;
306 if (PyList_GET_SIZE(obj) == 0) {
307 /* No items, so fail. Or should we guess "av"? */
308 PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
309 "from an empty list");
310 return NULL;
312 tmp = PyList_GetItem(obj, 0);
313 tmp = _signature_string_from_pyobject(tmp, NULL);
314 if (!tmp) return NULL;
315 PyString_ConcatAndDel(&ret, tmp);
316 return ret;
318 else if (PyDict_Check(obj)) {
319 PyObject *key, *value, *keysig, *valuesig;
320 Py_ssize_t pos = 0;
321 PyObject *ret = NULL;
323 if (DBusPyDict_Check(obj) && PyString_Check(((DBusPyDict *)obj)->signature)) {
324 const char *sig = PyString_AS_STRING(((DBusPyDict *)obj)->signature);
326 return PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
327 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
328 "%s"
329 DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
330 sig);
332 if (!PyDict_Next(obj, &pos, &key, &value)) {
333 /* No items, so fail. Or should we guess "a{vv}"? */
334 PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
335 "from an empty dict");
336 return NULL;
338 keysig = _signature_string_from_pyobject(key, NULL);
339 valuesig = _signature_string_from_pyobject(value, NULL);
340 if (keysig && valuesig) {
341 ret = PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
342 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
343 "%s%s"
344 DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
345 PyString_AS_STRING(keysig),
346 PyString_AS_STRING(valuesig));
348 Py_XDECREF(keysig);
349 Py_XDECREF(valuesig);
350 return ret;
352 else {
353 PyErr_Format(PyExc_TypeError, "Don't know how which D-Bus type "
354 "to use to encode type \"%s\"",
355 obj->ob_type->tp_name);
356 return NULL;
360 PyObject *
361 dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args)
363 PyObject *tmp, *ret = NULL;
365 if (!args) {
366 if (!PyErr_Occurred()) {
367 PyErr_BadInternalCall();
369 return NULL;
372 #ifdef USING_DBG
373 fprintf(stderr, "DBG/%ld: called Message_guess_signature", (long)getpid());
374 PyObject_Print(args, stderr, 0);
375 fprintf(stderr, "\n");
376 #endif
378 if (!PyTuple_Check(args)) {
379 DBG("%s", "Message_guess_signature: args not a tuple");
380 PyErr_BadInternalCall();
381 return NULL;
384 /* if there were no args, easy */
385 if (PyTuple_GET_SIZE(args) == 0) {
386 DBG("%s", "Message_guess_signature: no args, so return Signature('')");
387 return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", "");
390 /* if there were args, the signature we want is, by construction,
391 * exactly the signature we get for the tuple args, except that we don't
392 * want the parentheses. */
393 tmp = _signature_string_from_pyobject(args, NULL);
394 if (!tmp) {
395 DBG("%s", "Message_guess_signature: failed");
396 return NULL;
398 if (!PyString_Check(tmp) || PyString_GET_SIZE(tmp) < 2) {
399 PyErr_SetString(PyExc_RuntimeError, "Internal error: "
400 "_signature_string_from_pyobject returned "
401 "a bad result");
402 Py_DECREF(tmp);
403 return NULL;
405 ret = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s#)",
406 PyString_AS_STRING(tmp) + 1,
407 PyString_GET_SIZE(tmp) - 2);
408 DBG("Message_guess_signature: returning Signature at %p \"%s\"", ret,
409 ret ? PyString_AS_STRING(ret) : "(NULL)");
410 Py_DECREF(tmp);
411 return ret;
414 static int _message_iter_append_pyobject(DBusMessageIter *appender,
415 DBusSignatureIter *sig_iter,
416 PyObject *obj,
417 dbus_bool_t *more);
418 static int _message_iter_append_variant(DBusMessageIter *appender,
419 PyObject *obj);
421 static int
422 _message_iter_append_string(DBusMessageIter *appender,
423 int sig_type, PyObject *obj,
424 dbus_bool_t allow_object_path_attr)
426 char *s;
428 if (sig_type == DBUS_TYPE_OBJECT_PATH && allow_object_path_attr) {
429 PyObject *object_path = get_object_path (obj);
431 if (object_path == Py_None) {
432 Py_DECREF(object_path);
434 else if (!object_path) {
435 return -1;
437 else {
438 int ret = _message_iter_append_string(appender, sig_type,
439 object_path, FALSE);
440 Py_DECREF(object_path);
441 return ret;
445 if (PyString_Check(obj)) {
446 PyObject *unicode;
448 /* Raise TypeError if the string has embedded NULs */
449 if (PyString_AsStringAndSize(obj, &s, NULL) < 0) return -1;
450 /* Surely there's a faster stdlib way to validate UTF-8... */
451 unicode = PyUnicode_DecodeUTF8(s, PyString_GET_SIZE(obj), NULL);
452 if (!unicode) {
453 PyErr_SetString(PyExc_UnicodeError, "String parameters "
454 "to be sent over D-Bus must be valid UTF-8");
455 return -1;
457 Py_DECREF(unicode);
458 unicode = NULL;
460 DBG("Performing actual append: string %s", s);
461 if (!dbus_message_iter_append_basic(appender, sig_type,
462 &s)) {
463 PyErr_NoMemory();
464 return -1;
467 else if (PyUnicode_Check(obj)) {
468 PyObject *utf8 = PyUnicode_AsUTF8String(obj);
469 if (!utf8) return -1;
470 /* Raise TypeError if the string has embedded NULs */
471 if (PyString_AsStringAndSize(utf8, &s, NULL) < 0) return -1;
472 DBG("Performing actual append: string (from unicode) %s", s);
473 if (!dbus_message_iter_append_basic(appender, sig_type, &s)) {
474 PyErr_NoMemory();
475 return -1;
477 Py_DECREF(utf8);
479 else {
480 PyErr_SetString(PyExc_TypeError,
481 "Expected a string or unicode object");
482 return -1;
484 return 0;
487 static int
488 _message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
490 unsigned char y;
492 if (PyString_Check(obj)) {
493 if (PyString_GET_SIZE(obj) != 1) {
494 PyErr_Format(PyExc_ValueError, "Expected a string of "
495 "length 1 byte, but found %d bytes",
496 PyString_GET_SIZE(obj));
497 return -1;
499 y = *(unsigned char *)PyString_AS_STRING(obj);
501 else {
502 long i = PyInt_AsLong(obj);
504 if (i == -1 && PyErr_Occurred()) return -1;
505 if (i < 0 || i > 0xff) {
506 PyErr_Format(PyExc_ValueError, "%d outside range for a "
507 "byte value", (int)i);
508 return -1;
510 y = i;
512 DBG("Performing actual append: byte \\x%02x", (unsigned)y);
513 if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
514 PyErr_NoMemory();
515 return -1;
517 return 0;
520 static int
521 _message_iter_append_dictentry(DBusMessageIter *appender,
522 DBusSignatureIter *sig_iter,
523 PyObject *dict, PyObject *key)
525 DBusSignatureIter sub_sig_iter;
526 DBusMessageIter sub;
527 int ret = -1;
528 PyObject *value = PyObject_GetItem(dict, key);
529 dbus_bool_t more;
531 if (!value) return -1;
533 #ifdef USING_DBG
534 fprintf(stderr, "Append dictentry: ");
535 PyObject_Print(key, stderr, 0);
536 fprintf(stderr, " => ");
537 PyObject_Print(value, stderr, 0);
538 fprintf(stderr, "\n");
539 #endif
541 DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
542 dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
543 #ifdef USING_DBG
545 char *s;
546 s = dbus_signature_iter_get_signature(sig_iter);
547 DBG("Signature of parent iterator %p is %s", sig_iter, s);
548 dbus_free(s);
549 s = dbus_signature_iter_get_signature(&sub_sig_iter);
550 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
551 dbus_free(s);
553 #endif
555 DBG("%s", "Opening DICT_ENTRY container");
556 if (!dbus_message_iter_open_container(appender, DBUS_TYPE_DICT_ENTRY,
557 NULL, &sub)) {
558 PyErr_NoMemory();
559 goto out;
561 ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key, &more);
562 if (ret == 0) {
563 ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value, &more);
565 DBG("%s", "Closing DICT_ENTRY container");
566 if (!dbus_message_iter_close_container(appender, &sub)) {
567 PyErr_NoMemory();
568 ret = -1;
570 out:
571 Py_DECREF(value);
572 return ret;
575 static int
576 _message_iter_append_multi(DBusMessageIter *appender,
577 const DBusSignatureIter *sig_iter,
578 int mode, PyObject *obj)
580 DBusMessageIter sub_appender;
581 DBusSignatureIter sub_sig_iter;
582 PyObject *contents;
583 int ret;
584 PyObject *iterator = PyObject_GetIter(obj);
585 char *sig = NULL;
586 int container = mode;
587 dbus_bool_t is_byte_array = DBusPyByteArray_Check(obj);
588 int inner_type;
589 dbus_bool_t more;
591 #ifdef USING_DBG
592 fprintf(stderr, "Appending multiple: ");
593 PyObject_Print(obj, stderr, 0);
594 fprintf(stderr, "\n");
595 #endif
597 if (!iterator) return -1;
598 if (mode == DBUS_TYPE_DICT_ENTRY) container = DBUS_TYPE_ARRAY;
600 DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
601 dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
602 #ifdef USING_DBG
604 char *s;
605 s = dbus_signature_iter_get_signature(sig_iter);
606 DBG("Signature of parent iterator %p is %s", sig_iter, s);
607 dbus_free(s);
608 s = dbus_signature_iter_get_signature(&sub_sig_iter);
609 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
610 dbus_free(s);
612 #endif
613 inner_type = dbus_signature_iter_get_current_type(&sub_sig_iter);
615 if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
616 sig = dbus_signature_iter_get_signature(&sub_sig_iter);
617 if (!sig) {
618 PyErr_NoMemory();
619 ret = -1;
620 goto out;
623 /* else leave sig set to NULL. */
625 DBG("Opening %c container", container);
626 if (!dbus_message_iter_open_container(appender, container,
627 sig, &sub_appender)) {
628 PyErr_NoMemory();
629 ret = -1;
630 goto out;
632 ret = 0;
633 while ((contents = PyIter_Next(iterator))) {
635 if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
636 DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
637 dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
638 #ifdef USING_DBG
640 char *s;
641 s = dbus_signature_iter_get_signature(sig_iter);
642 DBG("Signature of parent iterator %p is %s", sig_iter, s);
643 dbus_free(s);
644 s = dbus_signature_iter_get_signature(&sub_sig_iter);
645 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
646 dbus_free(s);
648 #endif
651 if (mode == DBUS_TYPE_DICT_ENTRY) {
652 ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
653 obj, contents);
655 else if (mode == DBUS_TYPE_ARRAY && is_byte_array
656 && inner_type == DBUS_TYPE_VARIANT) {
657 /* Subscripting a ByteArray gives a str of length 1, but if the
658 * container is a ByteArray and the parameter is an array of
659 * variants, we want to produce an array of variants containing
660 * bytes, not strings.
662 PyObject *args = Py_BuildValue("(O)", contents);
663 PyObject *byte;
665 if (!args)
666 break;
667 byte = PyObject_Call((PyObject *)&DBusPyByte_Type, args, NULL);
668 Py_DECREF(args);
669 if (!byte)
670 break;
671 ret = _message_iter_append_variant(&sub_appender, byte);
672 Py_DECREF(byte);
674 else {
675 /* advances sub_sig_iter and sets more on success - for array
676 * this doesn't matter, for struct it's essential */
677 ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
678 contents, &more);
681 Py_DECREF(contents);
682 if (ret < 0) {
683 break;
687 if (PyErr_Occurred()) {
688 ret = -1;
690 else if (mode == DBUS_TYPE_STRUCT && more) {
691 PyErr_Format(PyExc_TypeError, "More items found in struct's D-Bus "
692 "signature than in Python arguments ");
693 ret = -1;
696 /* This must be run as cleanup, even on failure. */
697 DBG("Closing %c container", container);
698 if (!dbus_message_iter_close_container(appender, &sub_appender)) {
699 PyErr_NoMemory();
700 ret = -1;
703 out:
704 Py_XDECREF(iterator);
705 dbus_free(sig);
706 return ret;
709 static int
710 _message_iter_append_string_as_byte_array(DBusMessageIter *appender,
711 PyObject *obj)
713 /* a bit of a faster path for byte arrays that are strings */
714 Py_ssize_t len = PyString_GET_SIZE(obj);
715 const char *s;
716 DBusMessageIter sub;
717 int ret;
719 s = PyString_AS_STRING(obj);
720 DBG("%s", "Opening ARRAY container");
721 if (!dbus_message_iter_open_container(appender, DBUS_TYPE_ARRAY,
722 DBUS_TYPE_BYTE_AS_STRING, &sub)) {
723 PyErr_NoMemory();
724 return -1;
726 DBG("Appending fixed array of %d bytes", len);
727 if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
728 ret = 0;
730 else {
731 PyErr_NoMemory();
732 ret = -1;
734 DBG("%s", "Closing ARRAY container");
735 if (!dbus_message_iter_close_container(appender, &sub)) {
736 PyErr_NoMemory();
737 return -1;
739 return ret;
742 /* Encode some Python object into a D-Bus variant slot. */
743 static int
744 _message_iter_append_variant(DBusMessageIter *appender, PyObject *obj)
746 DBusSignatureIter obj_sig_iter;
747 const char *obj_sig_str;
748 PyObject *obj_sig;
749 int ret;
750 long variant_level;
751 dbus_bool_t dummy;
753 /* Separate the object into the contained object, and the number of
754 * variants it's wrapped in. */
755 obj_sig = _signature_string_from_pyobject(obj, &variant_level);
756 if (!obj_sig) return -1;
758 obj_sig_str = PyString_AsString(obj_sig);
759 if (!obj_sig_str) return -1;
761 if (variant_level < 1) {
762 variant_level = 1;
765 dbus_signature_iter_init(&obj_sig_iter, obj_sig_str);
767 { /* scope for variant_iters */
768 DBusMessageIter variant_iters[variant_level];
769 long i;
771 for (i = 0; i < variant_level; i++) {
772 DBusMessageIter *child = &variant_iters[i];
773 /* The first is a special case: its parent is the iter passed in
774 * to this function, instead of being the previous one in the
775 * stack
777 DBusMessageIter *parent = (i == 0
778 ? appender
779 : &(variant_iters[i-1]));
780 /* The last is also a special case: it contains the actual
781 * object, rather than another variant
783 const char *sig_str = (i == variant_level-1
784 ? obj_sig_str
785 : DBUS_TYPE_VARIANT_AS_STRING);
787 DBG("Opening VARIANT container %p inside %p containing '%s'",
788 child, parent, sig_str);
789 if (!dbus_message_iter_open_container(parent, DBUS_TYPE_VARIANT,
790 sig_str, child)) {
791 PyErr_NoMemory();
792 ret = -1;
793 goto out;
797 /* Put the object itself into the innermost variant */
798 ret = _message_iter_append_pyobject(&variant_iters[variant_level-1],
799 &obj_sig_iter, obj, &dummy);
801 /* here we rely on i (and variant_level) being a signed long */
802 for (i = variant_level - 1; i >= 0; i--) {
803 DBusMessageIter *child = &variant_iters[i];
804 /* The first is a special case: its parent is the iter passed in
805 * to this function, instead of being the previous one in the
806 * stack
808 DBusMessageIter *parent = (i == 0 ? appender
809 : &(variant_iters[i-1]));
811 DBG("Closing VARIANT container %p inside %p", child, parent);
812 if (!dbus_message_iter_close_container(parent, child)) {
813 PyErr_NoMemory();
814 ret = -1;
815 goto out;
821 out:
822 Py_XDECREF(obj_sig);
823 return ret;
826 /* On success, *more is set to whether there's more in the signature. */
827 static int
828 _message_iter_append_pyobject(DBusMessageIter *appender,
829 DBusSignatureIter *sig_iter,
830 PyObject *obj,
831 dbus_bool_t *more)
833 int sig_type = dbus_signature_iter_get_current_type(sig_iter);
834 union {
835 dbus_bool_t b;
836 double d;
837 dbus_uint16_t uint16;
838 dbus_int16_t int16;
839 dbus_uint32_t uint32;
840 dbus_int32_t int32;
841 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
842 dbus_uint64_t uint64;
843 dbus_int64_t int64;
844 #endif
845 } u;
846 int ret = -1;
848 #ifdef USING_DBG
849 fprintf(stderr, "Appending object at %p: ", obj);
850 PyObject_Print(obj, stderr, 0);
851 fprintf(stderr, " into appender at %p, dbus wants type %c\n",
852 appender, sig_type);
853 #endif
855 switch (sig_type) {
856 /* The numeric types are relatively simple to deal with, so are
857 * inlined here. */
859 case DBUS_TYPE_BOOLEAN:
860 if (PyObject_IsTrue(obj)) {
861 u.b = 1;
863 else {
864 u.b = 0;
866 DBG("Performing actual append: bool(%ld)", (long)u.b);
867 if (!dbus_message_iter_append_basic(appender, sig_type, &u.b)) {
868 PyErr_NoMemory();
869 ret = -1;
870 break;
872 ret = 0;
873 break;
875 case DBUS_TYPE_DOUBLE:
876 u.d = PyFloat_AsDouble(obj);
877 if (PyErr_Occurred()) {
878 ret = -1;
879 break;
881 DBG("Performing actual append: double(%f)", u.d);
882 if (!dbus_message_iter_append_basic(appender, sig_type, &u.d)) {
883 PyErr_NoMemory();
884 ret = -1;
885 break;
887 ret = 0;
888 break;
890 #ifdef WITH_DBUS_FLOAT32
891 case DBUS_TYPE_FLOAT:
892 u.d = PyFloat_AsDouble(obj);
893 if (PyErr_Occurred()) {
894 ret = -1;
895 break;
897 u.f = (float)u.d;
898 DBG("Performing actual append: float(%f)", u.f);
899 if (!dbus_message_iter_append_basic(appender, sig_type, &u.f)) {
900 PyErr_NoMemory();
901 ret = -1;
902 break;
904 ret = 0;
905 break;
906 #endif
908 /* The integer types are all basically the same - we delegate to
909 intNN_range_check() */
910 #define PROCESS_INTEGER(size) \
911 u.size = dbus_py_##size##_range_check(obj);\
912 if (u.size == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
913 ret = -1; \
914 break; \
916 DBG("Performing actual append: " #size "(%lld)", (long long)u.size); \
917 if (!dbus_message_iter_append_basic(appender, sig_type, &u.size)) {\
918 PyErr_NoMemory();\
919 ret = -1;\
920 break;\
922 ret = 0;
924 case DBUS_TYPE_INT16:
925 PROCESS_INTEGER(int16)
926 break;
927 case DBUS_TYPE_UINT16:
928 PROCESS_INTEGER(uint16)
929 break;
930 case DBUS_TYPE_INT32:
931 PROCESS_INTEGER(int32)
932 break;
933 case DBUS_TYPE_UINT32:
934 PROCESS_INTEGER(uint32)
935 break;
936 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
937 case DBUS_TYPE_INT64:
938 PROCESS_INTEGER(int64)
939 break;
940 case DBUS_TYPE_UINT64:
941 PROCESS_INTEGER(uint64)
942 break;
943 #else
944 case DBUS_TYPE_INT64:
945 case DBUS_TYPE_UINT64:
946 PyErr_SetString(PyExc_NotImplementedError, "64-bit integer "
947 "types are not supported on this platform");
948 ret = -1;
949 break;
950 #endif
951 #undef PROCESS_INTEGER
953 /* Now the more complicated cases, which are delegated to helper
954 * functions (although in practice, the compiler will hopefully
955 * inline them anyway). */
957 case DBUS_TYPE_STRING:
958 case DBUS_TYPE_SIGNATURE:
959 case DBUS_TYPE_OBJECT_PATH:
960 ret = _message_iter_append_string(appender, sig_type, obj, TRUE);
961 break;
963 case DBUS_TYPE_BYTE:
964 ret = _message_iter_append_byte(appender, obj);
965 break;
967 case DBUS_TYPE_ARRAY:
968 /* 3 cases - it might actually be a dict, or it might be a byte array
969 * being copied from a string (for which we have a faster path),
970 * or it might be a generic array. */
972 sig_type = dbus_signature_iter_get_element_type(sig_iter);
973 if (sig_type == DBUS_TYPE_DICT_ENTRY)
974 ret = _message_iter_append_multi(appender, sig_iter,
975 DBUS_TYPE_DICT_ENTRY, obj);
976 else if (sig_type == DBUS_TYPE_BYTE && PyString_Check(obj))
977 ret = _message_iter_append_string_as_byte_array(appender, obj);
978 else
979 ret = _message_iter_append_multi(appender, sig_iter,
980 DBUS_TYPE_ARRAY, obj);
981 DBG("_message_iter_append_multi(): %d", ret);
982 break;
984 case DBUS_TYPE_STRUCT:
985 ret = _message_iter_append_multi(appender, sig_iter, sig_type, obj);
986 break;
988 case DBUS_TYPE_VARIANT:
989 ret = _message_iter_append_variant(appender, obj);
990 break;
992 case DBUS_TYPE_INVALID:
993 PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
994 "signature than in Python arguments");
995 ret = -1;
996 break;
998 default:
999 PyErr_Format(PyExc_TypeError, "Unknown type '\\x%x' in D-Bus "
1000 "signature", sig_type);
1001 ret = -1;
1002 break;
1004 if (ret < 0) return -1;
1006 DBG("Advancing signature iter at %p", sig_iter);
1007 *more = dbus_signature_iter_next(sig_iter);
1008 #ifdef USING_DBG
1009 DBG("- result: %ld, type %02x '%c'", (long)(*more),
1010 (int)dbus_signature_iter_get_current_type(sig_iter),
1011 (int)dbus_signature_iter_get_current_type(sig_iter));
1012 #endif
1013 return 0;
1017 PyObject *
1018 dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs)
1020 const char *signature = NULL;
1021 PyObject *signature_obj = NULL;
1022 DBusSignatureIter sig_iter;
1023 DBusMessageIter appender;
1024 int i;
1025 static char *argnames[] = {"signature", NULL};
1026 /* must start FALSE for the case where there's nothing there and we
1027 * never iterate at all */
1028 dbus_bool_t more;
1030 if (!self->msg) return DBusPy_RaiseUnusableMessage();
1032 #ifdef USING_DBG
1033 fprintf(stderr, "DBG/%ld: called Message_append(*", (long)getpid());
1034 PyObject_Print(args, stderr, 0);
1035 if (kwargs) {
1036 fprintf(stderr, ", **");
1037 PyObject_Print(kwargs, stderr, 0);
1039 fprintf(stderr, ")\n");
1040 #endif
1042 /* only use kwargs for this step: deliberately ignore args for now */
1043 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, "|z:append",
1044 argnames, &signature)) return NULL;
1046 if (!signature) {
1047 DBG("%s", "No signature for message, guessing...");
1048 signature_obj = dbus_py_Message_guess_signature(NULL, args);
1049 if (!signature_obj) return NULL;
1050 signature = PyString_AS_STRING(signature_obj);
1052 /* from here onwards, you have to do a goto rather than returning NULL
1053 to make sure signature_obj gets freed */
1055 /* iterate over args and the signature, together */
1056 if (!dbus_signature_validate(signature, NULL)) {
1057 PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
1058 goto err;
1060 dbus_signature_iter_init(&sig_iter, signature);
1061 dbus_message_iter_init_append(self->msg, &appender);
1062 more = (signature[0] != '\0');
1063 for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
1064 if (_message_iter_append_pyobject(&appender, &sig_iter,
1065 PyTuple_GET_ITEM(args, i),
1066 &more) < 0) {
1067 goto hosed;
1070 if (more) {
1071 PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
1072 "signature than in Python arguments");
1073 goto hosed;
1076 /* success! */
1077 Py_XDECREF(signature_obj);
1078 Py_RETURN_NONE;
1080 hosed:
1081 /* "If appending any of the arguments fails due to lack of memory,
1082 * generally the message is hosed and you have to start over" -libdbus docs
1083 * Enforce this by throwing away the message structure.
1085 dbus_message_unref(self->msg);
1086 self->msg = NULL;
1087 err:
1088 Py_XDECREF(signature_obj);
1089 return NULL;
1092 /* vim:set ft=c cino< sw=4 sts=4 et: */