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.
31
#define DBG_IS_TOO_VERBOSE
32
#include "types-internal.h"
33
#include "message-internal.h"
35
/* Return the number of variants wrapping the given object. Return 0
36
* if the object is not a D-Bus type.
39
get_variant_level(PyObject *obj)
41
if (DBusPyIntBase_Check(obj)) {
42
return ((DBusPyIntBase *)obj)->variant_level;
44
else if (DBusPyFloatBase_Check(obj)) {
45
return ((DBusPyFloatBase *)obj)->variant_level;
47
else if (DBusPyArray_Check(obj)) {
48
return ((DBusPyArray *)obj)->variant_level;
50
else if (DBusPyDict_Check(obj)) {
51
return ((DBusPyDict *)obj)->variant_level;
53
else if (DBusPyString_Check(obj)) {
54
return ((DBusPyString *)obj)->variant_level;
56
else if (DBusPyLongBase_Check(obj) ||
57
DBusPyStrBase_Check(obj) ||
58
DBusPyStruct_Check(obj)) {
59
return dbus_py_variant_level_get(obj);
66
char dbus_py_Message_append__doc__[] = (
67
"set_args(*args[, **kwargs])\n\n"
68
"Set the message's arguments from the positional parameter, according to\n"
69
"the signature given by the ``signature`` keyword parameter.\n"
71
"The following type conversions are supported:\n\n"
72
"=============================== ===========================\n"
73
"D-Bus (in signature) Python\n"
74
"=============================== ===========================\n"
75
"boolean (b) any object (via bool())\n"
76
"byte (y) string of length 1\n"
78
"any integer type any integer\n"
79
"double (d) any float\n"
80
"object path anything with a __dbus_object_path__ attribute\n"
81
"string, signature, object path str (must be UTF-8) or unicode\n"
82
"dict (a{...}) any mapping\n"
83
"array (a...) any iterable over appropriate objects\n"
84
"struct ((...)) any iterable over appropriate objects\n"
85
"variant any object above (guess type as below)\n"
86
"=============================== ===========================\n"
88
"Here 'any integer' means anything on which int() or long()\n"
89
"(as appropriate) will work, except for basestring subclasses.\n"
90
"'Any float' means anything on which float() will work, except\n"
91
"for basestring subclasses.\n"
93
"If there is no signature, guess from the arguments using\n"
94
"the static method `Message.guess_signature`.\n"
97
char dbus_py_Message_guess_signature__doc__[] = (
98
"guess_signature(*args) -> Signature [static method]\n\n"
99
"Guess a D-Bus signature which should be used to encode the given\n"
102
"The signature is constructed as follows:\n\n"
103
"+-------------------------------+---------------------------+\n"
105
"+===============================+===========================+\n"
106
"|D-Bus type, variant_level > 0 |variant (v) |\n"
107
"+-------------------------------+---------------------------+\n"
108
"|D-Bus type, variant_level == 0 |the corresponding type |\n"
109
"+-------------------------------+---------------------------+\n"
110
"|anything with a |object path |\n"
111
"|__dbus_object_path__ attribute | |\n"
112
"+-------------------------------+---------------------------+\n"
113
"|bool |boolean (y) |\n"
114
"+-------------------------------+---------------------------+\n"
115
"|any other int subclass |int32 (i) |\n"
116
"+-------------------------------+---------------------------+\n"
117
"|any other long subclass |int64 (x) |\n"
118
"+-------------------------------+---------------------------+\n"
119
"|any other float subclass |double (d) |\n"
120
"+-------------------------------+---------------------------+\n"
121
"|any other str subclass |string (s) |\n"
122
"+-------------------------------+---------------------------+\n"
123
"|any other unicode subclass |string (s) |\n"
124
"+-------------------------------+---------------------------+\n"
125
"|any other tuple subclass |struct ((...)) |\n"
126
"+-------------------------------+---------------------------+\n"
127
"|any other list subclass |array (a...), guess |\n"
128
"| |contents' type according to|\n"
129
"| |type of first item |\n"
130
"+-------------------------------+---------------------------+\n"
131
"|any other dict subclass |dict (a{...}), guess key, |\n"
132
"| |value type according to |\n"
133
"| |types for an arbitrary item|\n"
134
"+-------------------------------+---------------------------+\n"
135
"|anything else |raise TypeError |\n"
136
"+-------------------------------+---------------------------+\n"
139
/* return a new reference, possibly to None */
141
get_object_path(PyObject *obj)
143
PyObject *magic_attr = PyObject_GetAttr(obj, dbus_py__dbus_object_path__const);
146
if (PyString_Check(magic_attr)) {
150
Py_CLEAR(magic_attr);
151
PyErr_SetString(PyExc_TypeError, "__dbus_object_path__ must be "
157
/* Ignore exceptions, except for SystemExit and KeyboardInterrupt */
158
if (PyErr_ExceptionMatches(PyExc_SystemExit) ||
159
PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
166
/* Return a new reference. If the object is a variant and variant_level_ptr
167
* is not NULL, put the variant level in the variable pointed to, and
168
* return the contained type instead of "v". */
170
_signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr)
172
PyObject *magic_attr;
173
long variant_level = get_variant_level(obj);
174
if (variant_level_ptr) {
175
*variant_level_ptr = variant_level;
177
else if (variant_level > 0) {
178
return PyString_FromString(DBUS_TYPE_VARIANT_AS_STRING);
181
if (obj == Py_True || obj == Py_False) {
182
return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
185
magic_attr = get_object_path(obj);
188
if (magic_attr != Py_None) {
189
Py_CLEAR(magic_attr);
190
return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
192
Py_CLEAR(magic_attr);
194
/* Ordering is important: some of these are subclasses of each other. */
195
if (PyInt_Check(obj)) {
196
if (DBusPyInt16_Check(obj))
197
return PyString_FromString(DBUS_TYPE_INT16_AS_STRING);
198
else if (DBusPyInt32_Check(obj))
199
return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
200
else if (DBusPyByte_Check(obj))
201
return PyString_FromString(DBUS_TYPE_BYTE_AS_STRING);
202
else if (DBusPyUInt16_Check(obj))
203
return PyString_FromString(DBUS_TYPE_UINT16_AS_STRING);
204
else if (DBusPyBoolean_Check(obj))
205
return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
207
return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
209
else if (PyLong_Check(obj)) {
210
if (DBusPyInt64_Check(obj))
211
return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
212
else if (DBusPyUInt32_Check(obj))
213
return PyString_FromString(DBUS_TYPE_UINT32_AS_STRING);
214
else if (DBusPyUInt64_Check(obj))
215
return PyString_FromString(DBUS_TYPE_UINT64_AS_STRING);
217
return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
219
else if (PyUnicode_Check(obj))
220
return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
221
#if defined(DBUS_TYPE_UNIX_FD)
222
else if (DBusPyUnixFd_Check(obj))
223
return PyString_FromString(DBUS_TYPE_UNIX_FD_AS_STRING);
225
else if (PyFloat_Check(obj)) {
226
#ifdef WITH_DBUS_FLOAT32
227
if (DBusPyDouble_Check(obj))
228
return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
229
else if (DBusPyFloat_Check(obj))
230
return PyString_FromString(DBUS_TYPE_FLOAT_AS_STRING);
233
return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
235
else if (PyString_Check(obj)) {
236
if (DBusPyObjectPath_Check(obj))
237
return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
238
else if (DBusPySignature_Check(obj))
239
return PyString_FromString(DBUS_TYPE_SIGNATURE_AS_STRING);
240
else if (DBusPyByteArray_Check(obj))
241
return PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING
242
DBUS_TYPE_BYTE_AS_STRING);
244
return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
246
else if (PyTuple_Check(obj)) {
247
Py_ssize_t len = PyTuple_GET_SIZE(obj);
248
PyObject *list = PyList_New(len + 2); /* new ref */
249
PyObject *item; /* temporary new ref */
250
PyObject *empty_str; /* temporary new ref */
254
if (!list) return NULL;
256
PyErr_SetString(PyExc_ValueError, "D-Bus structs cannot be empty");
260
/* Set the first and last elements of list to be the parentheses */
261
item = PyString_FromString(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
262
if (PyList_SetItem(list, 0, item) < 0) {
266
item = PyString_FromString(DBUS_STRUCT_END_CHAR_AS_STRING);
267
if (PyList_SetItem(list, len + 1, item) < 0) {
271
if (!item || !PyList_GET_ITEM(list, 0)) {
277
for (i = 0; i < len; i++) {
278
item = PyTuple_GetItem(obj, i);
283
item = _signature_string_from_pyobject(item, NULL);
288
if (PyList_SetItem(list, i + 1, item) < 0) {
294
empty_str = PyString_FromString("");
296
/* really shouldn't happen */
300
ret = PyObject_CallMethod(empty_str, "join", "(O)", list); /* new ref */
301
/* whether ret is NULL or not, */
306
else if (PyList_Check(obj)) {
308
PyObject *ret = PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING);
309
if (!ret) return NULL;
310
if (DBusPyArray_Check(obj) && PyString_Check(((DBusPyArray *)obj)->signature)) {
311
PyString_Concat(&ret, ((DBusPyArray *)obj)->signature);
314
if (PyList_GET_SIZE(obj) == 0) {
315
/* No items, so fail. Or should we guess "av"? */
316
PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
317
"from an empty list");
320
tmp = PyList_GetItem(obj, 0);
321
tmp = _signature_string_from_pyobject(tmp, NULL);
322
if (!tmp) return NULL;
323
PyString_ConcatAndDel(&ret, tmp);
326
else if (PyDict_Check(obj)) {
327
PyObject *key, *value, *keysig, *valuesig;
329
PyObject *ret = NULL;
331
if (DBusPyDict_Check(obj) && PyString_Check(((DBusPyDict *)obj)->signature)) {
332
const char *sig = PyString_AS_STRING(((DBusPyDict *)obj)->signature);
334
return PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
335
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
337
DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
340
if (!PyDict_Next(obj, &pos, &key, &value)) {
341
/* No items, so fail. Or should we guess "a{vv}"? */
342
PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
343
"from an empty dict");
346
keysig = _signature_string_from_pyobject(key, NULL);
347
valuesig = _signature_string_from_pyobject(value, NULL);
348
if (keysig && valuesig) {
349
ret = PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
350
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
352
DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
353
PyString_AS_STRING(keysig),
354
PyString_AS_STRING(valuesig));
361
PyErr_Format(PyExc_TypeError, "Don't know how which D-Bus type "
362
"to use to encode type \"%s\"",
363
Py_TYPE(obj)->tp_name);
369
dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args)
371
PyObject *tmp, *ret = NULL;
374
if (!PyErr_Occurred()) {
375
PyErr_BadInternalCall();
381
fprintf(stderr, "DBG/%ld: called Message_guess_signature", (long)getpid());
382
PyObject_Print(args, stderr, 0);
383
fprintf(stderr, "\n");
386
if (!PyTuple_Check(args)) {
387
DBG("%s", "Message_guess_signature: args not a tuple");
388
PyErr_BadInternalCall();
392
/* if there were no args, easy */
393
if (PyTuple_GET_SIZE(args) == 0) {
394
DBG("%s", "Message_guess_signature: no args, so return Signature('')");
395
return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", "");
398
/* if there were args, the signature we want is, by construction,
399
* exactly the signature we get for the tuple args, except that we don't
400
* want the parentheses. */
401
tmp = _signature_string_from_pyobject(args, NULL);
403
DBG("%s", "Message_guess_signature: failed");
406
if (!PyString_Check(tmp) || PyString_GET_SIZE(tmp) < 2) {
407
PyErr_SetString(PyExc_RuntimeError, "Internal error: "
408
"_signature_string_from_pyobject returned "
413
ret = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s#)",
414
PyString_AS_STRING(tmp) + 1,
415
PyString_GET_SIZE(tmp) - 2);
416
DBG("Message_guess_signature: returning Signature at %p \"%s\"", ret,
417
ret ? PyString_AS_STRING(ret) : "(NULL)");
422
static int _message_iter_append_pyobject(DBusMessageIter *appender,
423
DBusSignatureIter *sig_iter,
426
static int _message_iter_append_variant(DBusMessageIter *appender,
430
_message_iter_append_string(DBusMessageIter *appender,
431
int sig_type, PyObject *obj,
432
dbus_bool_t allow_object_path_attr)
436
if (sig_type == DBUS_TYPE_OBJECT_PATH && allow_object_path_attr) {
437
PyObject *object_path = get_object_path (obj);
439
if (object_path == Py_None) {
440
Py_CLEAR(object_path);
442
else if (!object_path) {
446
int ret = _message_iter_append_string(appender, sig_type,
448
Py_CLEAR(object_path);
453
if (PyString_Check(obj)) {
456
/* Raise TypeError if the string has embedded NULs */
457
if (PyString_AsStringAndSize(obj, &s, NULL) < 0) return -1;
458
/* Surely there's a faster stdlib way to validate UTF-8... */
459
unicode = PyUnicode_DecodeUTF8(s, PyString_GET_SIZE(obj), NULL);
461
PyErr_SetString(PyExc_UnicodeError, "String parameters "
462
"to be sent over D-Bus must be valid UTF-8");
467
DBG("Performing actual append: string %s", s);
468
if (!dbus_message_iter_append_basic(appender, sig_type,
474
else if (PyUnicode_Check(obj)) {
475
PyObject *utf8 = PyUnicode_AsUTF8String(obj);
476
if (!utf8) return -1;
477
/* Raise TypeError if the string has embedded NULs */
478
if (PyString_AsStringAndSize(utf8, &s, NULL) < 0) return -1;
479
DBG("Performing actual append: string (from unicode) %s", s);
480
if (!dbus_message_iter_append_basic(appender, sig_type, &s)) {
488
PyErr_SetString(PyExc_TypeError,
489
"Expected a string or unicode object");
496
_message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
500
if (PyString_Check(obj)) {
501
if (PyString_GET_SIZE(obj) != 1) {
502
PyErr_Format(PyExc_ValueError, "Expected a string of "
503
"length 1 byte, but found %d bytes",
504
(int) PyString_GET_SIZE(obj));
507
y = *(unsigned char *)PyString_AS_STRING(obj);
510
long i = PyInt_AsLong(obj);
512
if (i == -1 && PyErr_Occurred()) return -1;
513
if (i < 0 || i > 0xff) {
514
PyErr_Format(PyExc_ValueError, "%d outside range for a "
515
"byte value", (int)i);
520
DBG("Performing actual append: byte \\x%02x", (unsigned)y);
521
if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
529
dbuspy_message_iter_close_container(DBusMessageIter *iter,
530
DBusMessageIter *sub,
534
dbus_message_iter_abandon_container(iter, sub);
537
return dbus_message_iter_close_container(iter, sub);
540
#if defined(DBUS_TYPE_UNIX_FD)
542
_message_iter_append_unixfd(DBusMessageIter *appender, PyObject *obj)
546
if (PyInt_Check(obj)) {
547
fd = PyInt_AsLong(obj);
548
} else if (PyObject_IsInstance(obj, (PyObject*) &DBusPyUnixFd_Type)) {
549
fd = dbus_py_unix_fd_get_fd(obj);
554
DBG("Performing actual append: fd %d", fd);
555
if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_UNIX_FD, &fd)) {
564
_message_iter_append_dictentry(DBusMessageIter *appender,
565
DBusSignatureIter *sig_iter,
566
PyObject *dict, PyObject *key)
568
DBusSignatureIter sub_sig_iter;
571
PyObject *value = PyObject_GetItem(dict, key);
574
if (!value) return -1;
577
fprintf(stderr, "Append dictentry: ");
578
PyObject_Print(key, stderr, 0);
579
fprintf(stderr, " => ");
580
PyObject_Print(value, stderr, 0);
581
fprintf(stderr, "\n");
584
DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
585
dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
589
s = dbus_signature_iter_get_signature(sig_iter);
590
DBG("Signature of parent iterator %p is %s", sig_iter, s);
592
s = dbus_signature_iter_get_signature(&sub_sig_iter);
593
DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
598
DBG("%s", "Opening DICT_ENTRY container");
599
if (!dbus_message_iter_open_container(appender, DBUS_TYPE_DICT_ENTRY,
604
ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key, &more);
606
ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value, &more);
608
DBG("%s", "Closing DICT_ENTRY container");
609
if (!dbuspy_message_iter_close_container(appender, &sub, (ret == 0))) {
619
_message_iter_append_multi(DBusMessageIter *appender,
620
const DBusSignatureIter *sig_iter,
621
int mode, PyObject *obj)
623
DBusMessageIter sub_appender;
624
DBusSignatureIter sub_sig_iter;
627
PyObject *iterator = PyObject_GetIter(obj);
629
int container = mode;
630
dbus_bool_t is_byte_array = DBusPyByteArray_Check(obj);
634
assert(mode == DBUS_TYPE_DICT_ENTRY || mode == DBUS_TYPE_ARRAY ||
635
mode == DBUS_TYPE_STRUCT);
638
fprintf(stderr, "Appending multiple: ");
639
PyObject_Print(obj, stderr, 0);
640
fprintf(stderr, "\n");
643
if (!iterator) return -1;
644
if (mode == DBUS_TYPE_DICT_ENTRY) container = DBUS_TYPE_ARRAY;
646
DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
647
dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
651
s = dbus_signature_iter_get_signature(sig_iter);
652
DBG("Signature of parent iterator %p is %s", sig_iter, s);
654
s = dbus_signature_iter_get_signature(&sub_sig_iter);
655
DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
659
inner_type = dbus_signature_iter_get_current_type(&sub_sig_iter);
661
if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
662
sig = dbus_signature_iter_get_signature(&sub_sig_iter);
669
/* else leave sig set to NULL. */
671
DBG("Opening '%c' container", container);
672
if (!dbus_message_iter_open_container(appender, container,
673
sig, &sub_appender)) {
680
while ((contents = PyIter_Next(iterator))) {
682
if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
683
DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
684
dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
688
s = dbus_signature_iter_get_signature(sig_iter);
689
DBG("Signature of parent iterator %p is %s", sig_iter, s);
691
s = dbus_signature_iter_get_signature(&sub_sig_iter);
692
DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
699
PyErr_Format(PyExc_TypeError, "Fewer items found in struct's "
700
"D-Bus signature than in Python arguments ");
706
if (mode == DBUS_TYPE_DICT_ENTRY) {
707
ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
710
else if (mode == DBUS_TYPE_ARRAY && is_byte_array
711
&& inner_type == DBUS_TYPE_VARIANT) {
712
/* Subscripting a ByteArray gives a str of length 1, but if the
713
* container is a ByteArray and the parameter is an array of
714
* variants, we want to produce an array of variants containing
715
* bytes, not strings.
717
PyObject *args = Py_BuildValue("(O)", contents);
722
byte = PyObject_Call((PyObject *)&DBusPyByte_Type, args, NULL);
726
ret = _message_iter_append_variant(&sub_appender, byte);
730
/* advances sub_sig_iter and sets more on success - for array
731
* this doesn't matter, for struct it's essential */
732
ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
742
if (PyErr_Occurred()) {
745
else if (mode == DBUS_TYPE_STRUCT && more) {
746
PyErr_Format(PyExc_TypeError, "More items found in struct's D-Bus "
747
"signature than in Python arguments ");
751
/* This must be run as cleanup, even on failure. */
752
DBG("Closing '%c' container", container);
753
if (!dbuspy_message_iter_close_container(appender, &sub_appender, (ret == 0))) {
765
_message_iter_append_string_as_byte_array(DBusMessageIter *appender,
768
/* a bit of a faster path for byte arrays that are strings */
769
Py_ssize_t len = PyString_GET_SIZE(obj);
774
s = PyString_AS_STRING(obj);
775
DBG("%s", "Opening ARRAY container");
776
if (!dbus_message_iter_open_container(appender, DBUS_TYPE_ARRAY,
777
DBUS_TYPE_BYTE_AS_STRING, &sub)) {
781
DBG("Appending fixed array of %d bytes", (int)len);
782
if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
789
DBG("%s", "Closing ARRAY container");
790
if (!dbus_message_iter_close_container(appender, &sub)) {
797
/* Encode some Python object into a D-Bus variant slot. */
799
_message_iter_append_variant(DBusMessageIter *appender, PyObject *obj)
801
DBusSignatureIter obj_sig_iter;
802
const char *obj_sig_str;
808
/* Separate the object into the contained object, and the number of
809
* variants it's wrapped in. */
810
obj_sig = _signature_string_from_pyobject(obj, &variant_level);
811
if (!obj_sig) return -1;
813
obj_sig_str = PyString_AsString(obj_sig);
814
if (!obj_sig_str) return -1;
816
if (variant_level < 1) {
820
dbus_signature_iter_init(&obj_sig_iter, obj_sig_str);
822
{ /* scope for variant_iters */
823
DBusMessageIter variant_iters[variant_level];
826
for (i = 0; i < variant_level; i++) {
827
DBusMessageIter *child = &variant_iters[i];
828
/* The first is a special case: its parent is the iter passed in
829
* to this function, instead of being the previous one in the
832
DBusMessageIter *parent = (i == 0
834
: &(variant_iters[i-1]));
835
/* The last is also a special case: it contains the actual
836
* object, rather than another variant
838
const char *sig_str = (i == variant_level-1
840
: DBUS_TYPE_VARIANT_AS_STRING);
842
DBG("Opening VARIANT container %p inside %p containing '%s'",
843
child, parent, sig_str);
844
if (!dbus_message_iter_open_container(parent, DBUS_TYPE_VARIANT,
852
/* Put the object itself into the innermost variant */
853
ret = _message_iter_append_pyobject(&variant_iters[variant_level-1],
854
&obj_sig_iter, obj, &dummy);
856
/* here we rely on i (and variant_level) being a signed long */
857
for (i = variant_level - 1; i >= 0; i--) {
858
DBusMessageIter *child = &variant_iters[i];
859
/* The first is a special case: its parent is the iter passed in
860
* to this function, instead of being the previous one in the
863
DBusMessageIter *parent = (i == 0 ? appender
864
: &(variant_iters[i-1]));
866
DBG("Closing VARIANT container %p inside %p", child, parent);
867
if (!dbus_message_iter_close_container(parent, child)) {
881
/* On success, *more is set to whether there's more in the signature. */
883
_message_iter_append_pyobject(DBusMessageIter *appender,
884
DBusSignatureIter *sig_iter,
888
int sig_type = dbus_signature_iter_get_current_type(sig_iter);
892
dbus_uint16_t uint16;
894
dbus_uint32_t uint32;
896
#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
897
dbus_uint64_t uint64;
904
fprintf(stderr, "Appending object at %p: ", obj);
905
PyObject_Print(obj, stderr, 0);
906
fprintf(stderr, " into appender at %p, dbus wants type %c\n",
911
/* The numeric types are relatively simple to deal with, so are
914
case DBUS_TYPE_BOOLEAN:
915
if (PyObject_IsTrue(obj)) {
921
DBG("Performing actual append: bool(%ld)", (long)u.b);
922
if (!dbus_message_iter_append_basic(appender, sig_type, &u.b)) {
930
case DBUS_TYPE_DOUBLE:
931
u.d = PyFloat_AsDouble(obj);
932
if (PyErr_Occurred()) {
936
DBG("Performing actual append: double(%f)", u.d);
937
if (!dbus_message_iter_append_basic(appender, sig_type, &u.d)) {
945
#ifdef WITH_DBUS_FLOAT32
946
case DBUS_TYPE_FLOAT:
947
u.d = PyFloat_AsDouble(obj);
948
if (PyErr_Occurred()) {
953
DBG("Performing actual append: float(%f)", u.f);
954
if (!dbus_message_iter_append_basic(appender, sig_type, &u.f)) {
963
/* The integer types are all basically the same - we delegate to
964
intNN_range_check() */
965
#define PROCESS_INTEGER(size) \
966
u.size = dbus_py_##size##_range_check(obj);\
967
if (u.size == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
971
DBG("Performing actual append: " #size "(%lld)", (long long)u.size); \
972
if (!dbus_message_iter_append_basic(appender, sig_type, &u.size)) {\
979
case DBUS_TYPE_INT16:
980
PROCESS_INTEGER(int16)
982
case DBUS_TYPE_UINT16:
983
PROCESS_INTEGER(uint16)
985
case DBUS_TYPE_INT32:
986
PROCESS_INTEGER(int32)
988
case DBUS_TYPE_UINT32:
989
PROCESS_INTEGER(uint32)
991
#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
992
case DBUS_TYPE_INT64:
993
PROCESS_INTEGER(int64)
995
case DBUS_TYPE_UINT64:
996
PROCESS_INTEGER(uint64)
999
case DBUS_TYPE_INT64:
1000
case DBUS_TYPE_UINT64:
1001
PyErr_SetString(PyExc_NotImplementedError, "64-bit integer "
1002
"types are not supported on this platform");
1006
#undef PROCESS_INTEGER
1008
/* Now the more complicated cases, which are delegated to helper
1009
* functions (although in practice, the compiler will hopefully
1010
* inline them anyway). */
1012
case DBUS_TYPE_STRING:
1013
case DBUS_TYPE_SIGNATURE:
1014
case DBUS_TYPE_OBJECT_PATH:
1015
ret = _message_iter_append_string(appender, sig_type, obj, TRUE);
1018
case DBUS_TYPE_BYTE:
1019
ret = _message_iter_append_byte(appender, obj);
1022
case DBUS_TYPE_ARRAY:
1023
/* 3 cases - it might actually be a dict, or it might be a byte array
1024
* being copied from a string (for which we have a faster path),
1025
* or it might be a generic array. */
1027
sig_type = dbus_signature_iter_get_element_type(sig_iter);
1028
if (sig_type == DBUS_TYPE_DICT_ENTRY)
1029
ret = _message_iter_append_multi(appender, sig_iter,
1030
DBUS_TYPE_DICT_ENTRY, obj);
1031
else if (sig_type == DBUS_TYPE_BYTE && PyString_Check(obj))
1032
ret = _message_iter_append_string_as_byte_array(appender, obj);
1034
ret = _message_iter_append_multi(appender, sig_iter,
1035
DBUS_TYPE_ARRAY, obj);
1036
DBG("_message_iter_append_multi(): %d", ret);
1039
case DBUS_TYPE_STRUCT:
1040
ret = _message_iter_append_multi(appender, sig_iter, sig_type, obj);
1043
case DBUS_TYPE_VARIANT:
1044
ret = _message_iter_append_variant(appender, obj);
1047
case DBUS_TYPE_INVALID:
1048
PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
1049
"signature than in Python arguments");
1053
#if defined(DBUS_TYPE_UNIX_FD)
1054
case DBUS_TYPE_UNIX_FD:
1055
ret = _message_iter_append_unixfd(appender, obj);
1060
PyErr_Format(PyExc_TypeError, "Unknown type '\\x%x' in D-Bus "
1061
"signature", sig_type);
1065
if (ret < 0) return -1;
1067
DBG("Advancing signature iter at %p", sig_iter);
1068
*more = dbus_signature_iter_next(sig_iter);
1070
DBG("- result: %ld, type %02x '%c'", (long)(*more),
1071
(int)dbus_signature_iter_get_current_type(sig_iter),
1072
(int)dbus_signature_iter_get_current_type(sig_iter));
1079
dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs)
1081
const char *signature = NULL;
1082
PyObject *signature_obj = NULL;
1083
DBusSignatureIter sig_iter;
1084
DBusMessageIter appender;
1085
static char *argnames[] = {"signature", NULL};
1088
if (!self->msg) return DBusPy_RaiseUnusableMessage();
1091
fprintf(stderr, "DBG/%ld: called Message_append(*", (long)getpid());
1092
PyObject_Print(args, stderr, 0);
1094
fprintf(stderr, ", **");
1095
PyObject_Print(kwargs, stderr, 0);
1097
fprintf(stderr, ")\n");
1100
/* only use kwargs for this step: deliberately ignore args for now */
1101
if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, "|z:append",
1102
argnames, &signature)) return NULL;
1105
DBG("%s", "No signature for message, guessing...");
1106
signature_obj = dbus_py_Message_guess_signature(NULL, args);
1107
if (!signature_obj) return NULL;
1108
signature = PyString_AS_STRING(signature_obj);
1110
/* from here onwards, you have to do a goto rather than returning NULL
1111
to make sure signature_obj gets freed */
1113
/* iterate over args and the signature, together */
1114
if (!dbus_signature_validate(signature, NULL)) {
1115
PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
1118
dbus_message_iter_init_append(self->msg, &appender);
1120
if (signature[0] != '\0') {
1124
dbus_signature_iter_init(&sig_iter, signature);
1126
if (i >= PyTuple_GET_SIZE(args)) {
1127
PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
1128
"signature than in Python arguments");
1131
if (_message_iter_append_pyobject(&appender, &sig_iter,
1132
PyTuple_GET_ITEM(args, i),
1138
if (i < PyTuple_GET_SIZE(args)) {
1139
PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
1140
"signature than in Python arguments");
1146
Py_CLEAR(signature_obj);
1150
/* "If appending any of the arguments fails due to lack of memory,
1151
* generally the message is hosed and you have to start over" -libdbus docs
1152
* Enforce this by throwing away the message structure.
1154
dbus_message_unref(self->msg);
1157
Py_CLEAR(signature_obj);
1161
/* vim:set ft=c cino< sw=4 sts=4 et: */