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