summaryrefslogtreecommitdiff
path: root/_dbus_bindings/message-get-args.c
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2006-12-11 21:45:29 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2006-12-11 21:45:29 +0000
commit830f94f31010d4783490217d4b02f6f87927ae4c (patch)
tree864d939a308e7e27ef4f08fd702850ee00611897 /_dbus_bindings/message-get-args.c
parent8ab339978d34b8c14dcf53aa6fbf228efb9130c6 (diff)
Convert generic glue, main loop integration, message append/get_args, validation into separate translation units - no *-impl.h remaining
Diffstat (limited to '_dbus_bindings/message-get-args.c')
-rw-r--r--_dbus_bindings/message-get-args.c512
1 files changed, 512 insertions, 0 deletions
diff --git a/_dbus_bindings/message-get-args.c b/_dbus_bindings/message-get-args.c
new file mode 100644
index 0000000..cb67a73
--- /dev/null
+++ b/_dbus_bindings/message-get-args.c
@@ -0,0 +1,512 @@
+/* D-Bus Message unserialization. This contains all the logic to map from
+ * D-Bus types to Python objects.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "types-internal.h"
+#include "message-internal.h"
+
+char dbus_py_Message_get_args_list__doc__[] = (
+"get_args_list(**kwargs) -> list\n\n"
+"Return the message's arguments. Keyword arguments control the translation\n"
+"of D-Bus types to Python:\n"
+"\n"
+":Parameters:\n"
+" `byte_arrays` : bool\n"
+" If true, convert arrays of byte (signature 'ay') into ByteArray,\n"
+" a str subclass whose subscript operator returns Byte objects.\n"
+" If false (default), convert them like any other array (into a\n"
+" list of Bytes, or a list of ints if integer_bytes is true)."
+" `utf8_strings` : bool\n"
+" If true, return D-Bus strings as Python 8-bit strings (of UTF-8).\n"
+" If false (default), return D-Bus strings as Python unicode objects.\n"
+"\n"
+"Most of the type mappings should be fairly obvious:\n"
+"\n"
+"=============== ===================================================\n"
+"D-Bus Python\n"
+"=============== ===================================================\n"
+"byte (y) Byte (int if integer_bytes set)\n"
+"bool (b) Boolean (int subclass)\n"
+"Signature (g) Signature (str subclass)\n"
+"intNN, uintNN IntNN, UIntNN (int/long subclass)\n"
+"double (d) float\n"
+"string (s) unicode (str if utf8_strings set)\n"
+"Object path (o) ObjectPath (str subclass)\n"
+"dict (a{...}) dict\n"
+"array (a...) list of appropriate types\n"
+"byte array (ay) ByteArray (str subclass) if byte_arrays set; or\n"
+" list of Byte\n"
+"struct ((...)) tuple of appropriate types\n"
+"variant (v) contained type, but with variant_level > 0\n"
+"=============== ===================================================\n"
+);
+
+typedef struct {
+ int byte_arrays;
+ int utf8_strings;
+} Message_get_args_options;
+
+static PyObject *_message_iter_get_pyobject(DBusMessageIter *iter,
+ Message_get_args_options *opts,
+ long extra_variants);
+
+/* Append all the items iterated over to the given Python list object.
+ * Return 0 on success/-1 with exception on failure. */
+static int
+_message_iter_append_all_to_list(DBusMessageIter *iter, PyObject *list,
+ Message_get_args_options *opts)
+{
+ int ret, type;
+ while ((type = dbus_message_iter_get_arg_type (iter))
+ != DBUS_TYPE_INVALID) {
+ PyObject *item;
+ DBG("type == %d '%c'", type, type);
+
+ item = _message_iter_get_pyobject(iter, opts, 0);
+ if (!item) return -1;
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: appending to list: %p == ", (long)getpid(), item);
+ PyObject_Print(item, stderr, 0);
+ fprintf(stderr, " of type %p\n", item->ob_type);
+#endif
+ ret = PyList_Append(list, item);
+ Py_DECREF(item);
+ item = NULL;
+ if (ret < 0) return -1;
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: list now contains: ", (long)getpid());
+ PyObject_Print(list, stderr, 0);
+ fprintf(stderr, "\n");
+#endif
+ dbus_message_iter_next(iter);
+ }
+ return 0;
+}
+
+static inline PyObject *
+_message_iter_get_dict(DBusMessageIter *iter,
+ Message_get_args_options *opts,
+ PyObject *kwargs)
+{
+ DBusMessageIter entries;
+ char *sig_str = dbus_message_iter_get_signature(iter);
+ PyObject *sig;
+ PyObject *ret;
+ int status;
+
+ sig = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(s#)", sig_str+2, strlen(sig_str)-3);
+ status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig);
+ Py_DECREF(sig);
+ if (status < 0) {
+ return NULL;
+ }
+
+ ret = PyObject_Call((PyObject *)&DBusPyDict_Type, dbus_py_empty_tuple, kwargs);
+ if (!ret) {
+ return NULL;
+ }
+
+ dbus_message_iter_recurse(iter, &entries);
+ while (dbus_message_iter_get_arg_type(&entries) == DBUS_TYPE_DICT_ENTRY) {
+ PyObject *key = NULL;
+ PyObject *value = NULL;
+ DBusMessageIter kv;
+
+ DBG("%s", "dict entry...");
+
+ dbus_message_iter_recurse(&entries, &kv);
+
+ key = _message_iter_get_pyobject(&kv, opts, 0);
+ if (!key) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ dbus_message_iter_next(&kv);
+
+ value = _message_iter_get_pyobject(&kv, opts, 0);
+ if (!value) {
+ Py_DECREF(key);
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ status = PyDict_SetItem(ret, key, value);
+ Py_DECREF(key);
+ Py_DECREF(value);
+
+ if (status < 0) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ dbus_message_iter_next(&entries);
+ }
+
+ return ret;
+}
+
+/* Returns a new reference. */
+static PyObject *
+_message_iter_get_pyobject(DBusMessageIter *iter,
+ Message_get_args_options *opts,
+ long variant_level)
+{
+ union {
+ const char *s;
+ unsigned char y;
+ dbus_bool_t b;
+ double d;
+ float f;
+ dbus_uint16_t u16;
+ dbus_int16_t i16;
+ dbus_uint32_t u32;
+ dbus_int32_t i32;
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+ dbus_uint64_t u64;
+ dbus_int64_t i64;
+#endif
+ } u;
+ int type = dbus_message_iter_get_arg_type(iter);
+ PyObject *args = NULL;
+ PyObject *kwargs = NULL;
+ PyObject *ret = NULL;
+
+ /* If the variant-level is >0, prepare a dict for the kwargs.
+ * For variant wrappers optimize slightly by skipping this.
+ */
+ if (variant_level > 0 && type != DBUS_TYPE_VARIANT) {
+ PyObject *variant_level_int;
+
+ variant_level_int = PyInt_FromLong(variant_level);
+ if (!variant_level_int) {
+ return NULL;
+ }
+ kwargs = PyDict_New();
+ if (!kwargs) {
+ Py_DECREF(variant_level_int);
+ return NULL;
+ }
+ if (PyDict_SetItem(kwargs, dbus_py_variant_level_const,
+ variant_level_int) < 0) {
+ Py_DECREF(variant_level_int);
+ Py_DECREF(kwargs);
+ return NULL;
+ }
+ Py_DECREF(variant_level_int);
+ }
+ /* From here down you need to break from the switch to exit, so the
+ * dict is freed if necessary
+ */
+
+ switch (type) {
+ case DBUS_TYPE_STRING:
+ DBG("%s", "found a string");
+ dbus_message_iter_get_basic(iter, &u.s);
+ if (opts->utf8_strings) {
+ args = Py_BuildValue("(s)", u.s);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyUTF8String_Type,
+ args, kwargs);
+ }
+ else {
+ args = Py_BuildValue("(O)", PyUnicode_DecodeUTF8(u.s,
+ strlen(u.s),
+ NULL));
+ if (!args) {
+ break;
+ }
+ ret = PyObject_Call((PyObject *)&DBusPyString_Type,
+ args, kwargs);
+ }
+ break;
+
+ case DBUS_TYPE_SIGNATURE:
+ DBG("%s", "found a signature");
+ dbus_message_iter_get_basic(iter, &u.s);
+ args = Py_BuildValue("(s)", u.s);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPySignature_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_OBJECT_PATH:
+ DBG("%s", "found an object path");
+ dbus_message_iter_get_basic(iter, &u.s);
+ args = Py_BuildValue("(s)", u.s);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyObjectPath_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_DOUBLE:
+ DBG("%s", "found a double");
+ dbus_message_iter_get_basic(iter, &u.d);
+ args = Py_BuildValue("(f)", u.d);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyDouble_Type, args, kwargs);
+ break;
+
+#ifdef WITH_DBUS_FLOAT32
+ case DBUS_TYPE_FLOAT:
+ DBG("%s", "found a float");
+ dbus_message_iter_get_basic(iter, &u.f);
+ args = Py_BuildValue("(f)", (double)u.f);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyFloat_Type, args, kwargs);
+ break;
+#endif
+
+ case DBUS_TYPE_INT16:
+ DBG("%s", "found an int16");
+ dbus_message_iter_get_basic(iter, &u.i16);
+ args = Py_BuildValue("(i)", (int)u.i16);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyInt16_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_UINT16:
+ DBG("%s", "found a uint16");
+ dbus_message_iter_get_basic(iter, &u.u16);
+ args = Py_BuildValue("(i)", (int)u.u16);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyUInt16_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_INT32:
+ DBG("%s", "found an int32");
+ dbus_message_iter_get_basic(iter, &u.i32);
+ args = Py_BuildValue("(l)", (long)u.i32);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyInt32_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_UINT32:
+ DBG("%s", "found a uint32");
+ dbus_message_iter_get_basic(iter, &u.u32);
+ args = Py_BuildValue("(k)", (unsigned long)u.u32);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyUInt32_Type, args, kwargs);
+ break;
+
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+ case DBUS_TYPE_INT64:
+ DBG("%s", "found an int64");
+ dbus_message_iter_get_basic(iter, &u.i64);
+ args = Py_BuildValue("(L)", (PY_LONG_LONG)u.i64);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyInt64_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_UINT64:
+ DBG("%s", "found a uint64");
+ dbus_message_iter_get_basic(iter, &u.u64);
+ args = Py_BuildValue("(K)", (unsigned PY_LONG_LONG)u.u64);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyUInt64_Type, args, kwargs);
+ break;
+#else
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ PyErr_SetString(PyExc_NotImplementedError,
+ "64-bit integer types are not supported on "
+ "this platform");
+ break;
+#endif
+
+ case DBUS_TYPE_BYTE:
+ DBG("%s", "found a byte");
+ dbus_message_iter_get_basic(iter, &u.y);
+ args = Py_BuildValue("(l)", (long)u.y);
+ if (!args)
+ break;
+ ret = PyObject_Call((PyObject *)&DBusPyByte_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_BOOLEAN:
+ DBG("%s", "found a bool");
+ dbus_message_iter_get_basic(iter, &u.b);
+ args = Py_BuildValue("(l)", (long)u.b);
+ if (!args)
+ break;
+ ret = PyObject_Call((PyObject *)&DBusPyBoolean_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_ARRAY:
+ DBG("%s", "found an array...");
+ /* Dicts are arrays of DBUS_TYPE_DICT_ENTRY on the wire.
+ Also, we special-case arrays of DBUS_TYPE_BYTE sometimes. */
+ type = dbus_message_iter_get_element_type(iter);
+ if (type == DBUS_TYPE_DICT_ENTRY) {
+ DBG("%s", "no, actually it's a dict...");
+ if (!kwargs) {
+ kwargs = PyDict_New();
+ if (!kwargs) break;
+ }
+ ret = _message_iter_get_dict(iter, opts, kwargs);
+ }
+ else if (opts->byte_arrays && type == DBUS_TYPE_BYTE) {
+ DBusMessageIter sub;
+ int n;
+
+ DBG("%s", "actually, a byte array...");
+ dbus_message_iter_recurse(iter, &sub);
+ dbus_message_iter_get_fixed_array(&sub,
+ (const unsigned char **)&u.s,
+ &n);
+ args = Py_BuildValue("(s#)", u.s, n);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyByteArray_Type,
+ args, kwargs);
+ }
+ else {
+ DBusMessageIter sub;
+ char *sig;
+ PyObject *sig_obj;
+ int status;
+
+ DBG("%s", "a normal array...");
+ if (!kwargs) {
+ kwargs = PyDict_New();
+ if (!kwargs) break;
+ }
+ dbus_message_iter_recurse(iter, &sub);
+ sig = dbus_message_iter_get_signature(&sub);
+ if (!sig) break;
+ sig_obj = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(s)", sig);
+ dbus_free(sig);
+ if (!sig_obj) break;
+ status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig_obj);
+ Py_DECREF(sig_obj);
+ if (status < 0) break;
+ ret = PyObject_Call((PyObject *)&DBusPyArray_Type,
+ dbus_py_empty_tuple, kwargs);
+ if (!ret) break;
+ if (_message_iter_append_all_to_list(&sub, ret, opts) < 0) {
+ Py_DECREF(ret);
+ ret = NULL;
+ }
+ }
+ break;
+
+ case DBUS_TYPE_STRUCT:
+ {
+ DBusMessageIter sub;
+ PyObject *list = PyList_New(0);
+ PyObject *tuple;
+
+ DBG("%s", "found a struct...");
+ if (!list) break;
+ dbus_message_iter_recurse(iter, &sub);
+ if (_message_iter_append_all_to_list (&sub, list, opts) < 0) {
+ Py_DECREF(list);
+ break;
+ }
+ tuple = Py_BuildValue("(O)", list);
+ if (tuple) {
+ ret = PyObject_Call((PyObject *)&DBusPyStruct_Type, tuple, kwargs);
+ }
+ else {
+ ret = NULL;
+ }
+ /* whether successful or not, we take the same action: */
+ Py_DECREF(list);
+ Py_XDECREF(tuple);
+ }
+ break;
+
+ case DBUS_TYPE_VARIANT:
+ {
+ DBusMessageIter sub;
+
+ DBG("%s", "found a variant...");
+ dbus_message_iter_recurse(iter, &sub);
+ ret = _message_iter_get_pyobject(&sub, opts, variant_level+1);
+ }
+ break;
+
+ default:
+ PyErr_Format(PyExc_TypeError, "Unknown type '\\%x' in D-Bus "
+ "message", type);
+ }
+
+ if (args) {
+ Py_DECREF(args);
+ }
+ if (kwargs) {
+ Py_DECREF(kwargs);
+ }
+ return ret;
+}
+
+PyObject *
+dbus_py_Message_get_args_list(Message *self, PyObject *args, PyObject *kwargs)
+{
+ Message_get_args_options opts = { 0, 0 };
+ static char *argnames[] = { "byte_arrays", "utf8_strings", NULL };
+ PyObject *list;
+ DBusMessageIter iter;
+
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: called Message_get_args_list(self, *",
+ (long)getpid());
+ PyObject_Print(args, stderr, 0);
+ if (kwargs) {
+ fprintf(stderr, ", **");
+ PyObject_Print(kwargs, stderr, 0);
+ }
+ fprintf(stderr, ")\n");
+#endif
+
+ if (PyTuple_Size(args) != 0) {
+ PyErr_SetString(PyExc_TypeError, "get_args_list takes no positional "
+ "arguments");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:get_args_list",
+ argnames,
+ &(opts.byte_arrays),
+ &(opts.utf8_strings))) return NULL;
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+
+ list = PyList_New(0);
+ if (!list) return NULL;
+
+ /* Iterate over args, if any, appending to list */
+ if (dbus_message_iter_init(self->msg, &iter)) {
+ if (_message_iter_append_all_to_list(&iter, list, &opts) < 0) {
+ Py_DECREF(list);
+ DBG_EXC("%s", "Message_get_args: appending all to list failed:");
+ return NULL;
+ }
+ }
+
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: message has args list ", (long)getpid());
+ PyObject_Print(list, stderr, 0);
+ fprintf(stderr, "\n");
+#endif
+
+ return list;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */