Split out exceptions, pending call, message into separate .c files
[dbus-python-phuang.git] / _dbus_bindings / message-append-impl.h
blob2f36670f80688a3ac358cd2f1ab0dd3485784a1b
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 * 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 #include "types-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 PyDoc_STRVAR(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 "variant Variant\n"
72 " any object (guess type as below)\n"
73 "string, signature, object path str (must be UTF-8) or unicode\n"
74 "dict (a{...}) any mapping\n"
75 "array (a...) any iterable over appropriate objects\n"
76 "struct ((...)) any iterable over appropriate objects\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 PyDoc_STRVAR(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 "D-Bus type, variant_level == 0 the corresponding type\n"
99 "bool boolean (y)\n"
100 "any other int subclass int32 (i) (FIXME: make this error?)\n"
101 "any other long subclass int64 (x) (FIXME: make this error?)\n"
102 "any other float subclass double (d)\n"
103 "any other str subclass string (s)\n"
104 "any other unicode subclass string (s)\n"
105 "any other tuple subclass struct ((...)), guess contents' types\n"
106 "any other list subclass array (a...), guess contents' type\n"
107 " according to type of first item\n"
108 "any other dict subclass dict (a{...}), guess key, value type\n"
109 " according to types for an arbitrary item\n"
110 "anything else raise TypeError\n"
111 "=============================== ===========================\n"
114 /* Return a new reference. If the object is a variant and variant_level_ptr
115 * is not NULL, put the variant level in the variable pointed to, and
116 * return the contained type instead of "v". */
117 static PyObject *
118 _signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr)
120 long variant_level = get_variant_level(obj);
121 if (variant_level_ptr) {
122 *variant_level_ptr = variant_level;
124 else if (variant_level > 0) {
125 return PyString_FromString(DBUS_TYPE_VARIANT_AS_STRING);
128 /* Ordering is important: some of these are subclasses of each other. */
129 if (obj == Py_True || obj == Py_False) {
130 return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
132 else if (PyInt_Check(obj)) {
133 if (DBusPyInt16_Check(obj))
134 return PyString_FromString(DBUS_TYPE_INT16_AS_STRING);
135 else if (DBusPyInt32_Check(obj))
136 return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
137 else if (DBusPyByte_Check(obj))
138 return PyString_FromString(DBUS_TYPE_BYTE_AS_STRING);
139 else if (DBusPyUInt16_Check(obj))
140 return PyString_FromString(DBUS_TYPE_UINT16_AS_STRING);
141 else if (DBusPyBoolean_Check(obj))
142 return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
143 else
144 return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
146 else if (PyLong_Check(obj)) {
147 if (DBusPyInt64_Check(obj))
148 return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
149 else if (DBusPyUInt32_Check (obj))
150 return PyString_FromString(DBUS_TYPE_UINT32_AS_STRING);
151 else if (DBusPyUInt64_Check (obj))
152 return PyString_FromString(DBUS_TYPE_UINT64_AS_STRING);
153 else
154 return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
156 else if (PyUnicode_Check(obj))
157 return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
158 else if (PyFloat_Check(obj)) {
159 #ifdef WITH_DBUS_FLOAT32
160 if (DBusPyDouble_Check(obj))
161 return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
162 else if (DBusPyFloat_Check(obj))
163 return PyString_FromString(DBUS_TYPE_FLOAT_AS_STRING);
164 else
165 #endif
166 return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
168 else if (PyString_Check(obj)) {
169 if (DBusPyObjectPath_Check(obj))
170 return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
171 else if (DBusPySignature_Check(obj))
172 return PyString_FromString(DBUS_TYPE_SIGNATURE_AS_STRING);
173 else if (DBusPyByteArray_Check(obj))
174 return PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING
175 DBUS_TYPE_BYTE_AS_STRING);
176 else
177 return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
179 else if (PyTuple_Check (obj)) {
180 int len = PyTuple_GET_SIZE(obj);
181 PyObject *list = PyList_New(len + 2); /* new ref */
182 PyObject *item; /* temporary new ref */
183 PyObject *empty_str; /* temporary new ref */
184 PyObject *ret;
185 int i;
187 if (!list) return NULL;
188 if (len == 0) {
189 PyErr_SetString(PyExc_ValueError, "D-Bus structs cannot be empty");
190 Py_DECREF (list);
191 return NULL;
193 /* Set the first and last elements of list to be the parentheses */
194 item = PyString_FromString(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
195 if (PyList_SetItem(list, 0, item) < 0) {
196 Py_DECREF(list);
197 return NULL;
199 item = PyString_FromString(DBUS_STRUCT_END_CHAR_AS_STRING);
200 if (PyList_SetItem(list, len + 1, item) < 0) {
201 Py_DECREF(list);
202 return NULL;
204 if (!item || !PyList_GET_ITEM(list, 0)) {
205 Py_DECREF(list);
206 return NULL;
208 item = NULL;
210 for (i = 0; i < len; i++) {
211 item = PyTuple_GetItem(obj, i);
212 if (!item) {
213 Py_DECREF(list);
214 return NULL;
216 item = _signature_string_from_pyobject(item, NULL);
217 if (!item) {
218 Py_DECREF(list);
219 return NULL;
221 if (PyList_SetItem(list, i + 1, item) < 0) {
222 Py_DECREF(list);
223 return NULL;
225 item = NULL;
227 empty_str = PyString_FromString("");
228 if (!empty_str) {
229 /* really shouldn't happen */
230 Py_DECREF(list);
231 return NULL;
233 ret = PyObject_CallMethod(empty_str, "join", "(O)", list); /* new ref */
234 /* whether ret is NULL or not, */
235 Py_DECREF(empty_str);
236 Py_DECREF(list);
237 return ret;
239 else if (PyList_Check(obj)) {
240 PyObject *tmp;
241 PyObject *ret = PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING);
242 if (!ret) return NULL;
243 if (DBusPyArray_Check(obj) && PyString_Check(((DBusPyArray *)obj)->signature)) {
244 PyString_Concat(&ret, ((DBusPyArray *)obj)->signature);
245 return ret;
247 if (PyList_GET_SIZE(obj) == 0) {
248 /* No items, so fail. Or should we guess "av"? */
249 PyErr_SetString (PyExc_ValueError, "Unable to guess signature "
250 "from an empty list");
251 return NULL;
253 tmp = PyList_GetItem(obj, 0);
254 tmp = _signature_string_from_pyobject(tmp, NULL);
255 if (!tmp) return NULL;
256 PyString_ConcatAndDel (&ret, tmp);
257 return ret;
259 else if (PyDict_Check(obj)) {
260 PyObject *key, *value, *keysig, *valuesig;
261 int pos = 0;
262 PyObject *ret = NULL;
264 if (DBusPyDict_Check(obj) && PyString_Check(((DBusPyDict *)obj)->signature)) {
265 const char *sig = PyString_AS_STRING(((DBusPyDict *)obj)->signature);
267 return PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
268 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
269 "%s"
270 DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
271 sig);
273 if (!PyDict_Next(obj, &pos, &key, &value)) {
274 /* No items, so fail. Or should we guess "a{vv}"? */
275 PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
276 "from an empty dict");
277 return NULL;
279 keysig = _signature_string_from_pyobject(key, NULL);
280 valuesig = _signature_string_from_pyobject(value, NULL);
281 if (keysig && valuesig) {
282 ret = PyString_FromFormat ((DBUS_TYPE_ARRAY_AS_STRING
283 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
284 "%s%s"
285 DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
286 PyString_AS_STRING(keysig),
287 PyString_AS_STRING(valuesig));
289 Py_XDECREF(keysig);
290 Py_XDECREF(valuesig);
291 return ret;
293 else {
294 PyErr_Format(PyExc_TypeError, "Don't know how which D-Bus type "
295 "to use to encode type \"%s\"",
296 obj->ob_type->tp_name);
297 return NULL;
301 static PyObject *
302 Message_guess_signature(PyObject *unused UNUSED, PyObject *args)
304 PyObject *tmp, *ret = NULL;
306 if (!args) {
307 if (!PyErr_Occurred()) {
308 PyErr_BadInternalCall();
310 return NULL;
313 #ifdef USING_DBG
314 fprintf(stderr, "DBG/%ld: called Message_guess_signature", (long)getpid());
315 PyObject_Print(args, stderr, 0);
316 fprintf(stderr, "\n");
317 #endif
319 if (!PyTuple_Check(args)) {
320 DBG("%s", "Message_guess_signature: args not a tuple");
321 PyErr_BadInternalCall();
322 return NULL;
325 /* if there were no args, easy */
326 if (PyTuple_GET_SIZE(args) == 0) {
327 DBG("%s", "Message_guess_signature: no args, so return Signature('')");
328 return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", "");
331 /* if there were args, the signature we want is, by construction,
332 * exactly the signature we get for the tuple args, except that we don't
333 * want the parentheses. */
334 tmp = _signature_string_from_pyobject(args, NULL);
335 if (!tmp) {
336 DBG("%s", "Message_guess_signature: failed");
337 return NULL;
339 if (!PyString_Check(tmp) || PyString_GET_SIZE(tmp) < 2) {
340 PyErr_SetString(PyExc_RuntimeError, "Internal error: "
341 "_signature_string_from_pyobject returned "
342 "a bad result");
343 Py_DECREF(tmp);
344 return NULL;
346 ret = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s#)",
347 PyString_AS_STRING (tmp) + 1,
348 PyString_GET_SIZE (tmp) - 2);
349 DBG("Message_guess_signature: returning Signature at %p \"%s\"", ret,
350 ret ? PyString_AS_STRING(ret) : "(NULL)");
351 Py_DECREF (tmp);
352 return ret;
355 static int _message_iter_append_pyobject(DBusMessageIter *appender,
356 DBusSignatureIter *sig_iter,
357 PyObject *obj);
359 static int
360 _message_iter_append_string(DBusMessageIter *appender,
361 int sig_type, PyObject *obj)
363 char *s;
365 if (PyString_Check (obj)) {
366 PyObject *unicode;
368 /* Raise TypeError if the string has embedded NULs */
369 if (PyString_AsStringAndSize (obj, &s, NULL) < 0) return -1;
370 /* Surely there's a faster stdlib way to validate UTF-8... */
371 unicode = PyUnicode_DecodeUTF8 (s, PyString_GET_SIZE (obj), NULL);
372 if (!unicode) {
373 PyErr_SetString (PyExc_UnicodeError, "String parameters "
374 "to be sent over D-Bus must be valid UTF-8");
375 return -1;
377 Py_DECREF (unicode);
378 unicode = NULL;
380 DBG("Performing actual append: string %s", s);
381 if (!dbus_message_iter_append_basic (appender, sig_type,
382 &s)) {
383 PyErr_NoMemory();
384 return -1;
387 else if (PyUnicode_Check (obj)) {
388 PyObject *utf8 = PyUnicode_AsUTF8String (obj);
389 if (!utf8) return -1;
390 /* Raise TypeError if the string has embedded NULs */
391 if (PyString_AsStringAndSize (utf8, &s, NULL) < 0) return -1;
392 DBG("Performing actual append: string (from unicode) %s", s);
393 if (!dbus_message_iter_append_basic (appender, sig_type, &s)) {
394 PyErr_NoMemory();
395 return -1;
397 Py_DECREF (utf8);
399 else {
400 PyErr_SetString (PyExc_TypeError,
401 "Expected a string or unicode object");
402 return -1;
404 return 0;
407 static int
408 _message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
410 unsigned char y;
412 if (PyString_Check(obj)) {
413 if (PyString_GET_SIZE(obj) != 1) {
414 PyErr_Format(PyExc_ValueError, "Expected a string of "
415 "length 1 byte, but found %d bytes",
416 PyString_GET_SIZE (obj));
417 return -1;
419 y = *(unsigned char *)PyString_AS_STRING(obj);
421 else {
422 long i = PyInt_AsLong (obj);
424 if (i == -1 && PyErr_Occurred()) return -1;
425 if (i < 0 || i > 0xff) {
426 PyErr_Format(PyExc_ValueError, "%d outside range for a "
427 "byte value", (int)i);
428 return -1;
430 y = i;
432 DBG("Performing actual append: byte (from unicode) \\x%02x", (unsigned)y);
433 if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
434 PyErr_NoMemory();
435 return -1;
437 return 0;
440 static int
441 _message_iter_append_dictentry(DBusMessageIter *appender,
442 DBusSignatureIter *sig_iter,
443 PyObject *dict, PyObject *key)
445 DBusSignatureIter sub_sig_iter;
446 DBusMessageIter sub;
447 int ret = -1;
448 PyObject *value = PyObject_GetItem(dict, key);
450 if (!value) return -1;
452 #ifdef USING_DBG
453 fprintf(stderr, "Append dictentry: ");
454 PyObject_Print(key, stderr, 0);
455 fprintf(stderr, " => ");
456 PyObject_Print(value, stderr, 0);
457 fprintf(stderr, "\n");
458 #endif
460 DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
461 dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
462 #ifdef USING_DBG
464 char *s;
465 s = dbus_signature_iter_get_signature(sig_iter);
466 DBG("Signature of parent iterator %p is %s", sig_iter, s);
467 dbus_free(s);
468 s = dbus_signature_iter_get_signature(&sub_sig_iter);
469 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
470 dbus_free(s);
472 #endif
474 DBG("%s", "Opening DICT_ENTRY container");
475 if (!dbus_message_iter_open_container(appender, DBUS_TYPE_DICT_ENTRY,
476 NULL, &sub)) {
477 PyErr_NoMemory();
478 goto out;
480 ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key);
481 if (ret == 0) {
482 ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value);
484 DBG("%s", "Closing DICT_ENTRY container");
485 if (!dbus_message_iter_close_container(appender, &sub)) {
486 PyErr_NoMemory();
487 ret = -1;
489 out:
490 Py_DECREF(value);
491 return ret;
494 static int
495 _message_iter_append_multi(DBusMessageIter *appender,
496 const DBusSignatureIter *sig_iter,
497 int mode, PyObject *obj)
499 DBusMessageIter sub_appender;
500 DBusSignatureIter sub_sig_iter;
501 PyObject *contents;
502 int ret;
503 PyObject *iterator = PyObject_GetIter(obj);
504 char *sig = NULL;
505 int container = mode;
507 #ifdef USING_DBG
508 fprintf(stderr, "Appending multiple: ");
509 PyObject_Print(obj, stderr, 0);
510 fprintf(stderr, "\n");
511 #endif
513 if (!iterator) return -1;
514 if (mode == DBUS_TYPE_DICT_ENTRY) container = DBUS_TYPE_ARRAY;
516 DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
517 dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
518 #ifdef USING_DBG
520 char *s;
521 s = dbus_signature_iter_get_signature(sig_iter);
522 DBG("Signature of parent iterator %p is %s", sig_iter, s);
523 dbus_free(s);
524 s = dbus_signature_iter_get_signature(&sub_sig_iter);
525 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
526 dbus_free(s);
528 #endif
530 if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
531 sig = dbus_signature_iter_get_signature(&sub_sig_iter);
532 if (!sig) {
533 PyErr_NoMemory();
534 ret = -1;
535 goto out;
538 /* else leave sig set to NULL. */
540 DBG("Opening %c container", container);
541 if (!dbus_message_iter_open_container(appender, container,
542 sig, &sub_appender)) {
543 PyErr_NoMemory();
544 ret = -1;
545 goto out;
547 ret = 0;
548 while ((contents = PyIter_Next(iterator))) {
550 if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
551 DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
552 dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
553 #ifdef USING_DBG
555 char *s;
556 s = dbus_signature_iter_get_signature(sig_iter);
557 DBG("Signature of parent iterator %p is %s", sig_iter, s);
558 dbus_free(s);
559 s = dbus_signature_iter_get_signature(&sub_sig_iter);
560 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
561 dbus_free(s);
563 #endif
566 if (mode == DBUS_TYPE_DICT_ENTRY) {
567 ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
568 obj, contents);
570 else {
571 ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
572 contents);
574 Py_DECREF(contents);
575 if (ret < 0) {
576 break;
579 if (PyErr_Occurred()) ret = -1;
580 /* This must be run as cleanup, even on failure. */
581 DBG("Closing %c container", container);
582 if (!dbus_message_iter_close_container(appender, &sub_appender)) {
583 PyErr_NoMemory();
584 ret = -1;
587 out:
588 Py_XDECREF(iterator);
589 dbus_free(sig);
590 return ret;
593 static int
594 _message_iter_append_string_as_byte_array (DBusMessageIter *appender,
595 PyObject *obj)
597 /* a bit of a faster path for byte arrays that are strings */
598 int len = PyString_GET_SIZE(obj);
599 const char *s;
600 DBusMessageIter sub;
601 int ret;
603 s = PyString_AS_STRING(obj);
604 DBG("%s", "Opening ARRAY container");
605 if (!dbus_message_iter_open_container(appender, DBUS_TYPE_ARRAY,
606 DBUS_TYPE_BYTE_AS_STRING, &sub)) {
607 PyErr_NoMemory();
608 return -1;
610 DBG("Appending fixed array of %d bytes", len);
611 if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
612 ret = 0;
614 else {
615 PyErr_NoMemory();
616 ret = -1;
618 DBG("%s", "Closing ARRAY container");
619 if (!dbus_message_iter_close_container(appender, &sub)) {
620 PyErr_NoMemory();
621 return -1;
623 return ret;
626 /* Encode some Python object into a D-Bus variant slot. */
627 static int
628 _message_iter_append_variant(DBusMessageIter *appender, PyObject *obj)
630 DBusSignatureIter obj_sig_iter;
631 const char *obj_sig_str;
632 PyObject *obj_sig;
633 int ret;
634 long variant_level;
636 /* Separate the object into the contained object, and the number of
637 * variants it's wrapped in. */
638 obj_sig = _signature_string_from_pyobject(obj, &variant_level);
639 if (!obj_sig) return -1;
641 obj_sig_str = PyString_AsString(obj_sig);
642 if (!obj_sig_str) return -1;
644 if (variant_level < 1) {
645 variant_level = 1;
648 dbus_signature_iter_init(&obj_sig_iter, obj_sig_str);
650 { /* scope for variant_iters */
651 DBusMessageIter variant_iters[variant_level];
652 long i;
654 for (i = 0; i < variant_level; i++) {
655 DBusMessageIter *child = &variant_iters[i];
656 /* The first is a special case: its parent is the iter passed in
657 * to this function, instead of being the previous one in the
658 * stack
660 DBusMessageIter *parent = (i == 0
661 ? appender
662 : &(variant_iters[i-1]));
663 /* The last is also a special case: it contains the actual
664 * object, rather than another variant
666 const char *sig_str = (i == variant_level-1
667 ? obj_sig_str
668 : DBUS_TYPE_VARIANT_AS_STRING);
670 DBG("Opening VARIANT container %p inside %p containing '%s'",
671 child, parent, sig_str);
672 if (!dbus_message_iter_open_container (parent, DBUS_TYPE_VARIANT,
673 sig_str, child)) {
674 PyErr_NoMemory();
675 ret = -1;
676 goto out;
680 /* Put the object itself into the innermost variant */
681 ret = _message_iter_append_pyobject(&variant_iters[variant_level-1],
682 &obj_sig_iter, obj);
684 /* here we rely on i (and variant_level) being a signed long */
685 for (i = variant_level - 1; i >= 0; i--) {
686 DBusMessageIter *child = &variant_iters[i];
687 /* The first is a special case: its parent is the iter passed in
688 * to this function, instead of being the previous one in the
689 * stack
691 DBusMessageIter *parent = (i == 0 ? appender
692 : &(variant_iters[i-1]));
694 DBG("Closing VARIANT container %p inside %p", child, parent);
695 if (!dbus_message_iter_close_container (parent, child)) {
696 PyErr_NoMemory();
697 ret = -1;
698 goto out;
704 out:
705 Py_XDECREF (obj_sig);
706 return ret;
709 static int
710 _message_iter_append_pyobject(DBusMessageIter *appender,
711 DBusSignatureIter *sig_iter,
712 PyObject *obj)
714 int sig_type = dbus_signature_iter_get_current_type (sig_iter);
715 union {
716 dbus_bool_t b;
717 double d;
718 dbus_uint16_t uint16;
719 dbus_int16_t int16;
720 dbus_uint32_t uint32;
721 dbus_int32_t int32;
722 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
723 dbus_uint64_t uint64;
724 dbus_int64_t int64;
725 #endif
726 } u;
727 int ret = -1;
729 #ifdef USING_DBG
730 fprintf(stderr, "Appending object at %p: ", obj);
731 PyObject_Print(obj, stderr, 0);
732 fprintf(stderr, " into appender at %p, dbus wants type %c\n",
733 appender, sig_type);
734 #endif
736 switch (sig_type) {
737 /* The numeric types are relatively simple to deal with, so are
738 * inlined here. */
740 case DBUS_TYPE_BOOLEAN:
741 if (PyObject_IsTrue(obj)) {
742 u.b = 1;
744 else {
745 u.b = 0;
747 DBG("Performing actual append: bool(%ld)", (long)u.b);
748 if (!dbus_message_iter_append_basic (appender, sig_type, &u.b)) {
749 PyErr_NoMemory();
750 ret = -1;
751 break;
753 ret = 0;
754 break;
756 case DBUS_TYPE_DOUBLE:
757 u.d = PyFloat_AsDouble (obj);
758 if (PyErr_Occurred()) {
759 ret = -1;
760 break;
762 DBG("Performing actual append: double(%f)", u.d);
763 if (!dbus_message_iter_append_basic(appender, sig_type, &u.d)) {
764 PyErr_NoMemory();
765 ret = -1;
766 break;
768 ret = 0;
769 break;
771 #ifdef WITH_DBUS_FLOAT32
772 case DBUS_TYPE_FLOAT:
773 u.d = PyFloat_AsDouble (obj);
774 if (PyErr_Occurred()) {
775 ret = -1;
776 break;
778 u.f = (float)u.d;
779 DBG("Performing actual append: float(%f)", u.f);
780 if (!dbus_message_iter_append_basic(appender, sig_type, &u.f)) {
781 PyErr_NoMemory();
782 ret = -1;
783 break;
785 ret = 0;
786 break;
787 #endif
789 /* The integer types are all basically the same - we delegate to
790 intNN_range_check() */
791 #define PROCESS_INTEGER(size) \
792 u.size = dbus_py_##size##_range_check (obj);\
793 if (u.size == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
794 ret = -1; \
795 break; \
797 DBG("Performing actual append: " #size "(%lld)", (long long)u.size); \
798 if (!dbus_message_iter_append_basic(appender, sig_type, &u.size)) {\
799 PyErr_NoMemory();\
800 ret = -1;\
801 break;\
803 ret = 0;
805 case DBUS_TYPE_INT16:
806 PROCESS_INTEGER(int16)
807 break;
808 case DBUS_TYPE_UINT16:
809 PROCESS_INTEGER(uint16)
810 break;
811 case DBUS_TYPE_INT32:
812 PROCESS_INTEGER(int32)
813 break;
814 case DBUS_TYPE_UINT32:
815 PROCESS_INTEGER(uint32)
816 break;
817 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
818 case DBUS_TYPE_INT64:
819 PROCESS_INTEGER(int64)
820 break;
821 case DBUS_TYPE_UINT64:
822 PROCESS_INTEGER(uint64)
823 break;
824 #else
825 case DBUS_TYPE_INT64:
826 case DBUS_TYPE_UINT64:
827 PyErr_SetString(PyExc_NotImplementedError, "64-bit integer "
828 "types are not supported on this platform");
829 ret = -1;
830 break;
831 #endif
832 #undef PROCESS_INTEGER
834 /* Now the more complicated cases, which are delegated to helper
835 * functions (although in practice, the compiler will hopefully
836 * inline them anyway). */
838 case DBUS_TYPE_STRING:
839 case DBUS_TYPE_SIGNATURE:
840 case DBUS_TYPE_OBJECT_PATH:
841 ret = _message_iter_append_string(appender, sig_type, obj);
842 break;
844 case DBUS_TYPE_BYTE:
845 ret = _message_iter_append_byte(appender, obj);
846 break;
848 case DBUS_TYPE_ARRAY:
849 /* 3 cases - it might actually be a dict, or it might be a byte array
850 * being copied from a string (for which we have a faster path),
851 * or it might be a generic array. */
853 sig_type = dbus_signature_iter_get_element_type(sig_iter);
854 if (sig_type == DBUS_TYPE_DICT_ENTRY)
855 ret = _message_iter_append_multi(appender, sig_iter,
856 DBUS_TYPE_DICT_ENTRY, obj);
857 else if (sig_type == DBUS_TYPE_BYTE && PyString_Check(obj))
858 ret = _message_iter_append_string_as_byte_array(appender, obj);
859 else
860 ret = _message_iter_append_multi(appender, sig_iter,
861 DBUS_TYPE_ARRAY, obj);
862 DBG("_message_iter_append_multi(): %d", ret);
863 break;
865 case DBUS_TYPE_STRUCT:
866 ret = _message_iter_append_multi(appender, sig_iter, sig_type, obj);
867 break;
869 case DBUS_TYPE_VARIANT:
870 ret = _message_iter_append_variant(appender, obj);
871 break;
873 case DBUS_TYPE_INVALID:
874 PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
875 "signature than in Python arguments");
876 ret = -1;
877 break;
879 default:
880 PyErr_Format(PyExc_TypeError, "Unknown type '\\x%x' in D-Bus "
881 "signature", sig_type);
882 ret = -1;
883 break;
885 if (ret < 0) return -1;
887 DBG("Advancing signature iter at %p", sig_iter);
888 #ifdef USING_DBG
890 dbus_bool_t b =
891 #endif
892 dbus_signature_iter_next(sig_iter);
893 #ifdef USING_DBG
894 DBG("- result: %ld, type %02x '%c'", (long)b,
895 (int)dbus_signature_iter_get_current_type(sig_iter),
896 (int)dbus_signature_iter_get_current_type(sig_iter));
898 #endif
899 return 0;
903 static PyObject *
904 Message_append(Message *self, PyObject *args, PyObject *kwargs)
906 const char *signature = NULL;
907 PyObject *signature_obj = NULL;
908 DBusSignatureIter sig_iter;
909 DBusMessageIter appender;
910 int i;
911 static char *argnames[] = {"signature", NULL};
913 if (!self->msg) return DBusException_UnusableMessage ();
915 #ifdef USING_DBG
916 fprintf(stderr, "DBG/%ld: called Message_append(*", (long)getpid());
917 PyObject_Print(args, stderr, 0);
918 if (kwargs) {
919 fprintf(stderr, ", **");
920 PyObject_Print(kwargs, stderr, 0);
922 fprintf(stderr, ")\n");
923 #endif
925 /* only use kwargs for this step: deliberately ignore args for now */
926 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, "|z:append",
927 argnames, &signature)) return NULL;
929 if (!signature) {
930 DBG("%s", "No signature for message, guessing...");
931 signature_obj = Message_guess_signature(NULL, args);
932 if (!signature_obj) return NULL;
933 signature = PyString_AS_STRING (signature_obj);
935 /* from here onwards, you have to do a goto rather than returning NULL
936 to make sure signature_obj gets freed */
938 /* iterate over args and the signature, together */
939 if (!dbus_signature_validate(signature, NULL)) {
940 PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
941 goto err;
943 dbus_signature_iter_init(&sig_iter, signature);
944 dbus_message_iter_init_append(self->msg, &appender);
945 for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
946 if (_message_iter_append_pyobject(&appender, &sig_iter,
947 PyTuple_GET_ITEM (args, i)) < 0) {
948 goto hosed;
951 if (dbus_signature_iter_get_current_type(&sig_iter)
952 != DBUS_TYPE_INVALID) {
953 PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
954 "signature than in Python arguments");
955 goto hosed;
958 /* success! */
959 Py_XDECREF(signature_obj);
960 Py_RETURN_NONE;
962 hosed:
963 /* "If appending any of the arguments fails due to lack of memory,
964 * generally the message is hosed and you have to start over" -libdbus docs
965 * Enforce this by throwing away the message structure.
967 dbus_message_unref(self->msg);
968 self->msg = NULL;
969 err:
970 Py_XDECREF(signature_obj);
971 return NULL;
974 /* vim:set ft=c cino< sw=4 sts=4 et: */