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.
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
);
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"
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"
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"
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"
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"
98 "The signature is constructed as follows:\n\n"
99 "+-------------------------------+---------------------------+\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 */
137 get_object_path(PyObject
*obj
)
139 PyObject
*magic_attr
= PyObject_GetAttr(obj
, dbus_py__dbus_object_path__const
);
142 if (PyString_Check(magic_attr
)) {
146 Py_DECREF(magic_attr
);
147 PyErr_SetString(PyExc_TypeError
, "__dbus_object_path__ must be "
153 /* Ignore exceptions, except for SystemExit and KeyboardInterrupt */
154 if (PyErr_ExceptionMatches(PyExc_SystemExit
) ||
155 PyErr_ExceptionMatches(PyExc_KeyboardInterrupt
))
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". */
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
);
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
);
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
);
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
);
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
);
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 */
246 if (!list
) return NULL
;
248 PyErr_SetString(PyExc_ValueError
, "D-Bus structs cannot be empty");
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) {
258 item
= PyString_FromString(DBUS_STRUCT_END_CHAR_AS_STRING
);
259 if (PyList_SetItem(list
, len
+ 1, item
) < 0) {
263 if (!item
|| !PyList_GET_ITEM(list
, 0)) {
269 for (i
= 0; i
< len
; i
++) {
270 item
= PyTuple_GetItem(obj
, i
);
275 item
= _signature_string_from_pyobject(item
, NULL
);
280 if (PyList_SetItem(list
, i
+ 1, item
) < 0) {
286 empty_str
= PyString_FromString("");
288 /* really shouldn't happen */
292 ret
= PyObject_CallMethod(empty_str
, "join", "(O)", list
); /* new ref */
293 /* whether ret is NULL or not, */
294 Py_DECREF(empty_str
);
298 else if (PyList_Check(obj
)) {
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
);
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");
312 tmp
= PyList_GetItem(obj
, 0);
313 tmp
= _signature_string_from_pyobject(tmp
, NULL
);
314 if (!tmp
) return NULL
;
315 PyString_ConcatAndDel(&ret
, tmp
);
318 else if (PyDict_Check(obj
)) {
319 PyObject
*key
, *value
, *keysig
, *valuesig
;
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
329 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
),
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");
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
344 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
),
345 PyString_AS_STRING(keysig
),
346 PyString_AS_STRING(valuesig
));
349 Py_XDECREF(valuesig
);
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
);
361 dbus_py_Message_guess_signature(PyObject
*unused UNUSED
, PyObject
*args
)
363 PyObject
*tmp
, *ret
= NULL
;
366 if (!PyErr_Occurred()) {
367 PyErr_BadInternalCall();
373 fprintf(stderr
, "DBG/%ld: called Message_guess_signature", (long)getpid());
374 PyObject_Print(args
, stderr
, 0);
375 fprintf(stderr
, "\n");
378 if (!PyTuple_Check(args
)) {
379 DBG("%s", "Message_guess_signature: args not a tuple");
380 PyErr_BadInternalCall();
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
);
395 DBG("%s", "Message_guess_signature: failed");
398 if (!PyString_Check(tmp
) || PyString_GET_SIZE(tmp
) < 2) {
399 PyErr_SetString(PyExc_RuntimeError
, "Internal error: "
400 "_signature_string_from_pyobject returned "
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)");
414 static int _message_iter_append_pyobject(DBusMessageIter
*appender
,
415 DBusSignatureIter
*sig_iter
,
418 static int _message_iter_append_variant(DBusMessageIter
*appender
,
422 _message_iter_append_string(DBusMessageIter
*appender
,
423 int sig_type
, PyObject
*obj
,
424 dbus_bool_t allow_object_path_attr
)
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
) {
438 int ret
= _message_iter_append_string(appender
, sig_type
,
440 Py_DECREF(object_path
);
445 if (PyString_Check(obj
)) {
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
);
453 PyErr_SetString(PyExc_UnicodeError
, "String parameters "
454 "to be sent over D-Bus must be valid UTF-8");
460 DBG("Performing actual append: string %s", s
);
461 if (!dbus_message_iter_append_basic(appender
, sig_type
,
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
)) {
480 PyErr_SetString(PyExc_TypeError
,
481 "Expected a string or unicode object");
488 _message_iter_append_byte(DBusMessageIter
*appender
, PyObject
*obj
)
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
));
499 y
= *(unsigned char *)PyString_AS_STRING(obj
);
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
);
512 DBG("Performing actual append: byte \\x%02x", (unsigned)y
);
513 if (!dbus_message_iter_append_basic(appender
, DBUS_TYPE_BYTE
, &y
)) {
521 _message_iter_append_dictentry(DBusMessageIter
*appender
,
522 DBusSignatureIter
*sig_iter
,
523 PyObject
*dict
, PyObject
*key
)
525 DBusSignatureIter sub_sig_iter
;
528 PyObject
*value
= PyObject_GetItem(dict
, key
);
531 if (!value
) return -1;
534 fprintf(stderr
, "Append dictentry: ");
535 PyObject_Print(key
, stderr
, 0);
536 fprintf(stderr
, " => ");
537 PyObject_Print(value
, stderr
, 0);
538 fprintf(stderr
, "\n");
541 DBG("Recursing signature iterator %p -> %p", sig_iter
, &sub_sig_iter
);
542 dbus_signature_iter_recurse(sig_iter
, &sub_sig_iter
);
546 s
= dbus_signature_iter_get_signature(sig_iter
);
547 DBG("Signature of parent iterator %p is %s", sig_iter
, s
);
549 s
= dbus_signature_iter_get_signature(&sub_sig_iter
);
550 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter
, s
);
555 DBG("%s", "Opening DICT_ENTRY container");
556 if (!dbus_message_iter_open_container(appender
, DBUS_TYPE_DICT_ENTRY
,
561 ret
= _message_iter_append_pyobject(&sub
, &sub_sig_iter
, key
, &more
);
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
)) {
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
;
584 PyObject
*iterator
= PyObject_GetIter(obj
);
586 int container
= mode
;
587 dbus_bool_t is_byte_array
= DBusPyByteArray_Check(obj
);
592 fprintf(stderr
, "Appending multiple: ");
593 PyObject_Print(obj
, stderr
, 0);
594 fprintf(stderr
, "\n");
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
);
605 s
= dbus_signature_iter_get_signature(sig_iter
);
606 DBG("Signature of parent iterator %p is %s", sig_iter
, s
);
608 s
= dbus_signature_iter_get_signature(&sub_sig_iter
);
609 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter
, s
);
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
);
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
)) {
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
);
641 s
= dbus_signature_iter_get_signature(sig_iter
);
642 DBG("Signature of parent iterator %p is %s", sig_iter
, s
);
644 s
= dbus_signature_iter_get_signature(&sub_sig_iter
);
645 DBG("Signature of sub-iterator %p is %s", &sub_sig_iter
, s
);
651 if (mode
== DBUS_TYPE_DICT_ENTRY
) {
652 ret
= _message_iter_append_dictentry(&sub_appender
, &sub_sig_iter
,
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
);
667 byte
= PyObject_Call((PyObject
*)&DBusPyByte_Type
, args
, NULL
);
671 ret
= _message_iter_append_variant(&sub_appender
, byte
);
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
,
687 if (PyErr_Occurred()) {
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 ");
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
)) {
704 Py_XDECREF(iterator
);
710 _message_iter_append_string_as_byte_array(DBusMessageIter
*appender
,
713 /* a bit of a faster path for byte arrays that are strings */
714 Py_ssize_t len
= PyString_GET_SIZE(obj
);
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
)) {
726 DBG("Appending fixed array of %d bytes", len
);
727 if (dbus_message_iter_append_fixed_array(&sub
, DBUS_TYPE_BYTE
, &s
, len
)) {
734 DBG("%s", "Closing ARRAY container");
735 if (!dbus_message_iter_close_container(appender
, &sub
)) {
742 /* Encode some Python object into a D-Bus variant slot. */
744 _message_iter_append_variant(DBusMessageIter
*appender
, PyObject
*obj
)
746 DBusSignatureIter obj_sig_iter
;
747 const char *obj_sig_str
;
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) {
765 dbus_signature_iter_init(&obj_sig_iter
, obj_sig_str
);
767 { /* scope for variant_iters */
768 DBusMessageIter variant_iters
[variant_level
];
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
777 DBusMessageIter
*parent
= (i
== 0
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
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
,
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
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
)) {
826 /* On success, *more is set to whether there's more in the signature. */
828 _message_iter_append_pyobject(DBusMessageIter
*appender
,
829 DBusSignatureIter
*sig_iter
,
833 int sig_type
= dbus_signature_iter_get_current_type(sig_iter
);
837 dbus_uint16_t uint16
;
839 dbus_uint32_t uint32
;
841 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
842 dbus_uint64_t uint64
;
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",
856 /* The numeric types are relatively simple to deal with, so are
859 case DBUS_TYPE_BOOLEAN
:
860 if (PyObject_IsTrue(obj
)) {
866 DBG("Performing actual append: bool(%ld)", (long)u
.b
);
867 if (!dbus_message_iter_append_basic(appender
, sig_type
, &u
.b
)) {
875 case DBUS_TYPE_DOUBLE
:
876 u
.d
= PyFloat_AsDouble(obj
);
877 if (PyErr_Occurred()) {
881 DBG("Performing actual append: double(%f)", u
.d
);
882 if (!dbus_message_iter_append_basic(appender
, sig_type
, &u
.d
)) {
890 #ifdef WITH_DBUS_FLOAT32
891 case DBUS_TYPE_FLOAT
:
892 u
.d
= PyFloat_AsDouble(obj
);
893 if (PyErr_Occurred()) {
898 DBG("Performing actual append: float(%f)", u
.f
);
899 if (!dbus_message_iter_append_basic(appender
, sig_type
, &u
.f
)) {
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()) {\
916 DBG("Performing actual append: " #size "(%lld)", (long long)u.size); \
917 if (!dbus_message_iter_append_basic(appender, sig_type, &u.size)) {\
924 case DBUS_TYPE_INT16
:
925 PROCESS_INTEGER(int16
)
927 case DBUS_TYPE_UINT16
:
928 PROCESS_INTEGER(uint16
)
930 case DBUS_TYPE_INT32
:
931 PROCESS_INTEGER(int32
)
933 case DBUS_TYPE_UINT32
:
934 PROCESS_INTEGER(uint32
)
936 #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
937 case DBUS_TYPE_INT64
:
938 PROCESS_INTEGER(int64
)
940 case DBUS_TYPE_UINT64
:
941 PROCESS_INTEGER(uint64
)
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");
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
);
964 ret
= _message_iter_append_byte(appender
, obj
);
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
);
979 ret
= _message_iter_append_multi(appender
, sig_iter
,
980 DBUS_TYPE_ARRAY
, obj
);
981 DBG("_message_iter_append_multi(): %d", ret
);
984 case DBUS_TYPE_STRUCT
:
985 ret
= _message_iter_append_multi(appender
, sig_iter
, sig_type
, obj
);
988 case DBUS_TYPE_VARIANT
:
989 ret
= _message_iter_append_variant(appender
, obj
);
992 case DBUS_TYPE_INVALID
:
993 PyErr_SetString(PyExc_TypeError
, "Fewer items found in D-Bus "
994 "signature than in Python arguments");
999 PyErr_Format(PyExc_TypeError
, "Unknown type '\\x%x' in D-Bus "
1000 "signature", sig_type
);
1004 if (ret
< 0) return -1;
1006 DBG("Advancing signature iter at %p", sig_iter
);
1007 *more
= dbus_signature_iter_next(sig_iter
);
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
));
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
;
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 */
1030 if (!self
->msg
) return DBusPy_RaiseUnusableMessage();
1033 fprintf(stderr
, "DBG/%ld: called Message_append(*", (long)getpid());
1034 PyObject_Print(args
, stderr
, 0);
1036 fprintf(stderr
, ", **");
1037 PyObject_Print(kwargs
, stderr
, 0);
1039 fprintf(stderr
, ")\n");
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
;
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");
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
),
1071 PyErr_SetString(PyExc_TypeError
, "More items found in D-Bus "
1072 "signature than in Python arguments");
1077 Py_XDECREF(signature_obj
);
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
);
1088 Py_XDECREF(signature_obj
);
1092 /* vim:set ft=c cino< sw=4 sts=4 et: */