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