Blame _dbus_bindings/containers.c

Packit 130fc8
/* D-Bus container types: Array, Dict and Struct.
Packit 130fc8
 *
Packit 130fc8
 * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
Packit 130fc8
 *
Packit 130fc8
 * Permission is hereby granted, free of charge, to any person
Packit 130fc8
 * obtaining a copy of this software and associated documentation
Packit 130fc8
 * files (the "Software"), to deal in the Software without
Packit 130fc8
 * restriction, including without limitation the rights to use, copy,
Packit 130fc8
 * modify, merge, publish, distribute, sublicense, and/or sell copies
Packit 130fc8
 * of the Software, and to permit persons to whom the Software is
Packit 130fc8
 * furnished to do so, subject to the following conditions:
Packit 130fc8
 *
Packit 130fc8
 * The above copyright notice and this permission notice shall be
Packit 130fc8
 * included in all copies or substantial portions of the Software.
Packit 130fc8
 *
Packit 130fc8
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 130fc8
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 130fc8
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 130fc8
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
Packit 130fc8
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
Packit 130fc8
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Packit 130fc8
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Packit 130fc8
 * DEALINGS IN THE SOFTWARE.
Packit 130fc8
 */
Packit 130fc8
Packit 130fc8
#include "dbus_bindings-internal.h"
Packit 130fc8
Packit 130fc8
#include <Python.h>
Packit 130fc8
#include <structmember.h>
Packit 130fc8
Packit 130fc8
#include "types-internal.h"
Packit 130fc8
Packit 130fc8
/* Array ============================================================ */
Packit 130fc8
Packit 130fc8
PyDoc_STRVAR(Array_tp_doc,
Packit 130fc8
"An array of similar items, implemented as a subtype of list.\n"
Packit 130fc8
"\n"
Packit 130fc8
"As currently implemented, an Array behaves just like a list, but\n"
Packit 130fc8
"with the addition of a ``signature`` property set by the constructor;\n"
Packit 130fc8
"conversion of its items to D-Bus types is only done when it's sent in\n"
Packit 130fc8
"a Message. This might change in future so validation is done earlier.\n"
Packit 130fc8
"\n"
Packit 130fc8
"Constructor::\n"
Packit 130fc8
"\n"
Packit 130fc8
"    dbus.Array([iterable][, signature][, variant_level])\n"
Packit 130fc8
"\n"
Packit 130fc8
"``variant_level`` must be non-negative; the default is 0.\n"
Packit 130fc8
"\n"
Packit 130fc8
"``signature`` is the D-Bus signature string for a single element of the\n"
Packit 130fc8
"array, or None. If not None it must represent a single complete type, the\n"
Packit 130fc8
"type of a single array item; the signature of the whole Array may be\n"
Packit 130fc8
"obtained by prepending ``a`` to the given signature.\n"
Packit 130fc8
"\n"
Packit 130fc8
"If None (the default), when the Array is sent over\n"
Packit 130fc8
"D-Bus, the item signature will be guessed from the first element.\n"
Packit 130fc8
"\n"
Packit 130fc8
":IVariables:\n"
Packit 130fc8
"  `variant_level` : int\n"
Packit 130fc8
"    Indicates how many nested Variant containers this object\n"
Packit 130fc8
"    is contained in: if a message's wire format has a variant containing a\n"
Packit 130fc8
"    variant containing an array, this is represented in Python by an\n"
Packit 130fc8
"    Array with variant_level==2.\n"
Packit 130fc8
);
Packit 130fc8
Packit 130fc8
static struct PyMemberDef Array_tp_members[] = {
Packit 130fc8
    {"signature", T_OBJECT, offsetof(DBusPyArray, signature), READONLY,
Packit 130fc8
     "The D-Bus signature of each element of this Array (a Signature "
Packit 130fc8
     "instance)"},
Packit 130fc8
    {"variant_level", T_LONG, offsetof(DBusPyArray, variant_level),
Packit 130fc8
     READONLY,
Packit 130fc8
     "The number of nested variants wrapping the real data. "
Packit 130fc8
     "0 if not in a variant."},
Packit 130fc8
    {NULL},
Packit 130fc8
};
Packit 130fc8
Packit 130fc8
static void
Packit 130fc8
Array_tp_dealloc (DBusPyArray *self)
Packit 130fc8
{
Packit 130fc8
    Py_CLEAR(self->signature);
Packit 130fc8
    (PyList_Type.tp_dealloc)((PyObject *)self);
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static PyObject *
Packit 130fc8
Array_tp_repr(DBusPyArray *self)
Packit 130fc8
{
Packit 130fc8
    PyObject *parent_repr = (PyList_Type.tp_repr)((PyObject *)self);
Packit 130fc8
    PyObject *sig_repr = PyObject_Repr(self->signature);
Packit 130fc8
    PyObject *my_repr = NULL;
Packit 130fc8
    long variant_level = self->variant_level;
Packit 130fc8
Packit 130fc8
    if (!parent_repr) goto finally;
Packit 130fc8
    if (!sig_repr) goto finally;
Packit 130fc8
    if (variant_level > 0) {
Packit 130fc8
        my_repr = PyUnicode_FromFormat("%s(%V, signature=%V, "
Packit 130fc8
                                       "variant_level=%ld)",
Packit 130fc8
                                       Py_TYPE(&self->super)->tp_name,
Packit 130fc8
                                       REPRV(parent_repr),
Packit 130fc8
                                       REPRV(sig_repr),
Packit 130fc8
                                       variant_level);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        my_repr = PyUnicode_FromFormat("%s(%V, signature=%V)",
Packit 130fc8
                                       Py_TYPE(&self->super)->tp_name,
Packit 130fc8
                                       REPRV(parent_repr),
Packit 130fc8
                                       REPRV(sig_repr));
Packit 130fc8
    }
Packit 130fc8
finally:
Packit 130fc8
    Py_CLEAR(parent_repr);
Packit 130fc8
    Py_CLEAR(sig_repr);
Packit 130fc8
    return my_repr;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static PyObject *
Packit 130fc8
Array_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
Packit 130fc8
{
Packit 130fc8
    PyObject *variant_level = NULL;
Packit 130fc8
    DBusPyArray *self = (DBusPyArray *)(PyList_Type.tp_new)(cls, args, kwargs);
Packit 130fc8
Packit 130fc8
    /* variant_level is immutable, so handle it in __new__ rather than
Packit 130fc8
    __init__ */
Packit 130fc8
    if (!self) return NULL;
Packit 130fc8
    Py_INCREF(Py_None);
Packit 130fc8
    self->signature = Py_None;
Packit 130fc8
    self->variant_level = 0;
Packit 130fc8
    if (kwargs) {
Packit 130fc8
        variant_level = PyDict_GetItem(kwargs, dbus_py_variant_level_const);
Packit 130fc8
    }
Packit 130fc8
    if (variant_level) {
Packit 130fc8
        long new_variant_level = PyLong_AsLong(variant_level);
Packit 130fc8
        if (new_variant_level == -1 && PyErr_Occurred()) {
Packit 130fc8
            Py_CLEAR(self);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        self->variant_level = new_variant_level;
Packit 130fc8
    }
Packit 130fc8
    return (PyObject *)self;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static int
Packit 130fc8
Array_tp_init (DBusPyArray *self, PyObject *args, PyObject *kwargs)
Packit 130fc8
{
Packit 130fc8
    PyObject *obj = dbus_py_empty_tuple;
Packit 130fc8
    PyObject *signature = NULL;
Packit 130fc8
    PyObject *tuple;
Packit 130fc8
    PyObject *variant_level;
Packit 130fc8
    /* variant_level is accepted but ignored - it's immutable, so
Packit 130fc8
     * __new__ handles it */
Packit 130fc8
    static char *argnames[] = {"iterable", "signature", "variant_level", NULL};
Packit 130fc8
Packit 130fc8
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:__init__", argnames,
Packit 130fc8
                                     &obj, &signature, &variant_level)) {
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
  /* convert signature from a borrowed ref of unknown type to an owned ref
Packit 130fc8
  of type Signature (or None) */
Packit 130fc8
    if (!signature) signature = Py_None;
Packit 130fc8
    if (signature == Py_None
Packit 130fc8
        || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) {
Packit 130fc8
        Py_INCREF(signature);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
Packit 130fc8
                                          "(O)", signature);
Packit 130fc8
        if (!signature) return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    if (signature != Py_None) {
Packit 130fc8
        const char *c_str;
Packit 130fc8
        PyObject *signature_as_bytes;
Packit 130fc8
Packit 130fc8
        if (
Packit 130fc8
#ifdef PY3
Packit 130fc8
            !PyUnicode_Check(signature)
Packit 130fc8
#else
Packit 130fc8
            !PyBytes_Check(signature)
Packit 130fc8
#endif
Packit 130fc8
            )
Packit 130fc8
        {
Packit 130fc8
            PyErr_SetString(PyExc_TypeError, "str expected");
Packit 130fc8
            Py_CLEAR(signature);
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
#ifdef PY3
Packit 130fc8
        if (!(signature_as_bytes = PyUnicode_AsUTF8String(signature))) {
Packit 130fc8
            Py_CLEAR(signature);
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
#else
Packit 130fc8
        signature_as_bytes = signature;
Packit 130fc8
        Py_INCREF(signature_as_bytes);
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
        c_str = PyBytes_AS_STRING(signature_as_bytes);
Packit 130fc8
Packit 130fc8
        if (!dbus_signature_validate_single(c_str, NULL)) {
Packit 130fc8
            Py_CLEAR(signature);
Packit 130fc8
            Py_CLEAR(signature_as_bytes);
Packit 130fc8
            PyErr_SetString(PyExc_ValueError,
Packit 130fc8
                            "There must be exactly one complete type in "
Packit 130fc8
                            "an Array's signature parameter");
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
        Py_CLEAR(signature_as_bytes);
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    tuple = Py_BuildValue("(O)", obj);
Packit 130fc8
    if (!tuple) {
Packit 130fc8
        Py_CLEAR(signature);
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
    if ((PyList_Type.tp_init)((PyObject *)self, tuple, NULL) < 0) {
Packit 130fc8
        Py_CLEAR(tuple);
Packit 130fc8
        Py_CLEAR(signature);
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
    Py_CLEAR(tuple);
Packit 130fc8
Packit 130fc8
    Py_CLEAR(self->signature);
Packit 130fc8
    self->signature = signature;
Packit 130fc8
    return 0;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
PyTypeObject DBusPyArray_Type = {
Packit 130fc8
    PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
Packit 130fc8
    "dbus.Array",
Packit 130fc8
    sizeof(DBusPyArray),
Packit 130fc8
    0,
Packit 130fc8
    (destructor)Array_tp_dealloc,           /* tp_dealloc */
Packit 130fc8
    0,                                      /* tp_print */
Packit 130fc8
    0,                                      /* tp_getattr */
Packit 130fc8
    0,                                      /* tp_setattr */
Packit 130fc8
    0,                                      /* tp_compare */
Packit 130fc8
    (reprfunc)Array_tp_repr,                /* tp_repr */
Packit 130fc8
    0,                                      /* tp_as_number */
Packit 130fc8
    0,                                      /* tp_as_sequence */
Packit 130fc8
    0,                                      /* tp_as_mapping */
Packit 130fc8
    0,                                      /* tp_hash */
Packit 130fc8
    0,                                      /* tp_call */
Packit 130fc8
    0,                                      /* tp_str */
Packit 130fc8
    0,                                      /* tp_getattro */
Packit 130fc8
    0,                                      /* tp_setattro */
Packit 130fc8
    0,                                      /* tp_as_buffer */
Packit 130fc8
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Packit 130fc8
    Array_tp_doc,                           /* tp_doc */
Packit 130fc8
    0,                                      /* tp_traverse */
Packit 130fc8
    0,                                      /* tp_clear */
Packit 130fc8
    0,                                      /* tp_richcompare */
Packit 130fc8
    0,                                      /* tp_weaklistoffset */
Packit 130fc8
    0,                                      /* tp_iter */
Packit 130fc8
    0,                                      /* tp_iternext */
Packit 130fc8
    0,                                      /* tp_methods */
Packit 130fc8
    Array_tp_members,                       /* tp_members */
Packit 130fc8
    0,                                      /* tp_getset */
Packit 130fc8
    0,                                      /* tp_base */
Packit 130fc8
    0,                                      /* tp_dict */
Packit 130fc8
    0,                                      /* tp_descr_get */
Packit 130fc8
    0,                                      /* tp_descr_set */
Packit 130fc8
    0,                                      /* tp_dictoffset */
Packit 130fc8
    (initproc)Array_tp_init,                /* tp_init */
Packit 130fc8
    0,                                      /* tp_alloc */
Packit 130fc8
    Array_tp_new,                           /* tp_new */
Packit 130fc8
};
Packit 130fc8
Packit 130fc8
/* Dict ============================================================= */
Packit 130fc8
Packit 130fc8
PyDoc_STRVAR(Dict_tp_doc,
Packit 130fc8
"An mapping whose keys are similar and whose values are similar,\n"
Packit 130fc8
"implemented as a subtype of dict.\n"
Packit 130fc8
"\n"
Packit 130fc8
"As currently implemented, a Dictionary behaves just like a dict, but\n"
Packit 130fc8
"with the addition of a ``signature`` property set by the constructor;\n"
Packit 130fc8
"conversion of its items to D-Bus types is only done when it's sent in\n"
Packit 130fc8
"a Message. This may change in future so validation is done earlier.\n"
Packit 130fc8
"\n"
Packit 130fc8
"Constructor::\n"
Packit 130fc8
"\n"
Packit 130fc8
"    Dictionary(mapping_or_iterable=(), signature=None, variant_level=0)\n"
Packit 130fc8
"\n"
Packit 130fc8
"``variant_level`` must be non-negative; the default is 0.\n"
Packit 130fc8
"\n"
Packit 130fc8
"``signature`` is either a string or None. If a string, it must consist\n"
Packit 130fc8
"of exactly two complete type signatures, representing the 'key' type\n"
Packit 130fc8
"(which must be a primitive type, i.e. one of \"bdginoqstuxy\")\n"
Packit 130fc8
"and the 'value' type. The signature of the whole Dictionary will be\n"
Packit 130fc8
"``a{xx}`` where ``xx`` is replaced by the given signature.\n"
Packit 130fc8
"\n"
Packit 130fc8
"If it is None (the default), when the Dictionary is sent over\n"
Packit 130fc8
"D-Bus, the key and value signatures will be guessed from an arbitrary\n"
Packit 130fc8
"element of the Dictionary.\n"
Packit 130fc8
"\n"
Packit 130fc8
":IVariables:\n"
Packit 130fc8
"  `variant_level` : int\n"
Packit 130fc8
"    Indicates how many nested Variant containers this object\n"
Packit 130fc8
"    is contained in: if a message's wire format has a variant containing a\n"
Packit 130fc8
"    variant containing an array of DICT_ENTRY, this is represented in\n"
Packit 130fc8
"    Python by a Dictionary with variant_level==2.\n"
Packit 130fc8
);
Packit 130fc8
Packit 130fc8
static struct PyMemberDef Dict_tp_members[] = {
Packit 130fc8
    {"signature", T_OBJECT, offsetof(DBusPyDict, signature), READONLY,
Packit 130fc8
     "The D-Bus signature of each key in this Dictionary, followed by "
Packit 130fc8
     "that of each value in this Dictionary, as a Signature instance."},
Packit 130fc8
    {"variant_level", T_LONG, offsetof(DBusPyDict, variant_level),
Packit 130fc8
     READONLY,
Packit 130fc8
     "The number of nested variants wrapping the real data. "
Packit 130fc8
     "0 if not in a variant."},
Packit 130fc8
    {NULL},
Packit 130fc8
};
Packit 130fc8
Packit 130fc8
static void
Packit 130fc8
Dict_tp_dealloc (DBusPyDict *self)
Packit 130fc8
{
Packit 130fc8
    Py_CLEAR(self->signature);
Packit 130fc8
    (PyDict_Type.tp_dealloc)((PyObject *)self);
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static PyObject *
Packit 130fc8
Dict_tp_repr(DBusPyDict *self)
Packit 130fc8
{
Packit 130fc8
    PyObject *parent_repr = (PyDict_Type.tp_repr)((PyObject *)self);
Packit 130fc8
    PyObject *sig_repr = PyObject_Repr(self->signature);
Packit 130fc8
    PyObject *my_repr = NULL;
Packit 130fc8
    long variant_level = self->variant_level;
Packit 130fc8
Packit 130fc8
    if (!parent_repr) goto finally;
Packit 130fc8
    if (!sig_repr) goto finally;
Packit 130fc8
    if (variant_level > 0) {
Packit 130fc8
        my_repr = PyUnicode_FromFormat("%s(%V, signature=%V, "
Packit 130fc8
                                       "variant_level=%ld)",
Packit 130fc8
                                       Py_TYPE(&self->super)->tp_name,
Packit 130fc8
                                       REPRV(parent_repr),
Packit 130fc8
                                       REPRV(sig_repr),
Packit 130fc8
                                       variant_level);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        my_repr = PyUnicode_FromFormat("%s(%V, signature=%V)",
Packit 130fc8
                                       Py_TYPE(&self->super)->tp_name,
Packit 130fc8
                                       REPRV(parent_repr),
Packit 130fc8
                                       REPRV(sig_repr));
Packit 130fc8
    }
Packit 130fc8
finally:
Packit 130fc8
    Py_CLEAR(parent_repr);
Packit 130fc8
    Py_CLEAR(sig_repr);
Packit 130fc8
    return my_repr;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static PyObject *
Packit 130fc8
Dict_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
Packit 130fc8
{
Packit 130fc8
    DBusPyDict *self = (DBusPyDict *)(PyDict_Type.tp_new)(cls, args, kwargs);
Packit 130fc8
    PyObject *variant_level = NULL;
Packit 130fc8
Packit 130fc8
    /* variant_level is immutable, so handle it in __new__ rather than
Packit 130fc8
    __init__ */
Packit 130fc8
    if (!self) return NULL;
Packit 130fc8
    Py_INCREF(Py_None);
Packit 130fc8
    self->signature = Py_None;
Packit 130fc8
    self->variant_level = 0;
Packit 130fc8
    if (kwargs) {
Packit 130fc8
        variant_level = PyDict_GetItem(kwargs, dbus_py_variant_level_const);
Packit 130fc8
    }
Packit 130fc8
    if (variant_level) {
Packit 130fc8
        long new_variant_level = PyLong_AsLong(variant_level);
Packit 130fc8
Packit 130fc8
        if (new_variant_level == -1 && PyErr_Occurred()) {
Packit 130fc8
            Py_CLEAR(self);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        self->variant_level = new_variant_level;
Packit 130fc8
    }
Packit 130fc8
    return (PyObject *)self;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static int
Packit 130fc8
Dict_tp_init(DBusPyDict *self, PyObject *args, PyObject *kwargs)
Packit 130fc8
{
Packit 130fc8
    PyObject *obj = dbus_py_empty_tuple;
Packit 130fc8
    PyObject *signature = NULL;
Packit 130fc8
    PyObject *tuple;
Packit 130fc8
    PyObject *variant_level;    /* ignored here - __new__ uses it */
Packit 130fc8
    static char *argnames[] = {"mapping_or_iterable", "signature",
Packit 130fc8
                               "variant_level", NULL};
Packit 130fc8
Packit 130fc8
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:__init__", argnames,
Packit 130fc8
                                     &obj, &signature, &variant_level)) {
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
  /* convert signature from a borrowed ref of unknown type to an owned ref
Packit 130fc8
  of type Signature (or None) */
Packit 130fc8
    if (!signature) signature = Py_None;
Packit 130fc8
    if (signature == Py_None
Packit 130fc8
        || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) {
Packit 130fc8
        Py_INCREF(signature);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
Packit 130fc8
                                          "(O)", signature);
Packit 130fc8
        if (!signature) return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    if (signature != Py_None) {
Packit 130fc8
        const char *c_str;
Packit 130fc8
        PyObject *signature_as_bytes;
Packit 130fc8
Packit 130fc8
        if (!NATIVESTR_CHECK(signature)) {
Packit 130fc8
            PyErr_SetString(PyExc_TypeError, "str expected");
Packit 130fc8
            Py_CLEAR(signature);
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
#ifdef PY3
Packit 130fc8
        if (!(signature_as_bytes = PyUnicode_AsUTF8String(signature))) {
Packit 130fc8
            Py_CLEAR(signature);
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
#else
Packit 130fc8
        signature_as_bytes = signature;
Packit 130fc8
        Py_INCREF(signature_as_bytes);
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
        c_str = PyBytes_AS_STRING(signature_as_bytes);
Packit 130fc8
        switch (c_str[0]) {
Packit 130fc8
            case DBUS_TYPE_BYTE:
Packit 130fc8
            case DBUS_TYPE_BOOLEAN:
Packit 130fc8
            case DBUS_TYPE_INT16:
Packit 130fc8
            case DBUS_TYPE_UINT16:
Packit 130fc8
            case DBUS_TYPE_INT32:
Packit 130fc8
            case DBUS_TYPE_UINT32:
Packit 130fc8
            case DBUS_TYPE_INT64:
Packit 130fc8
            case DBUS_TYPE_UINT64:
Packit 130fc8
            case DBUS_TYPE_DOUBLE:
Packit 130fc8
#ifdef WITH_DBUS_FLOAT32
Packit 130fc8
            case DBUS_TYPE_FLOAT:
Packit 130fc8
#endif
Packit 130fc8
#ifdef DBUS_TYPE_UNIX_FD
Packit 130fc8
            case DBUS_TYPE_UNIX_FD:
Packit 130fc8
#endif
Packit 130fc8
            case DBUS_TYPE_STRING:
Packit 130fc8
            case DBUS_TYPE_OBJECT_PATH:
Packit 130fc8
            case DBUS_TYPE_SIGNATURE:
Packit 130fc8
                break;
Packit 130fc8
            default:
Packit 130fc8
                Py_CLEAR(signature);
Packit 130fc8
                Py_CLEAR(signature_as_bytes);
Packit 130fc8
                PyErr_SetString(PyExc_ValueError,
Packit 130fc8
                                "The key type in a Dictionary's signature "
Packit 130fc8
                                "must be a primitive type");
Packit 130fc8
                return -1;
Packit 130fc8
        }
Packit 130fc8
Packit 130fc8
        if (!dbus_signature_validate_single(c_str + 1, NULL)) {
Packit 130fc8
            Py_CLEAR(signature);
Packit 130fc8
            Py_CLEAR(signature_as_bytes);
Packit 130fc8
            PyErr_SetString(PyExc_ValueError,
Packit 130fc8
                            "There must be exactly two complete types in "
Packit 130fc8
                            "a Dictionary's signature parameter");
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
        Py_CLEAR(signature_as_bytes);
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    tuple = Py_BuildValue("(O)", obj);
Packit 130fc8
    if (!tuple) {
Packit 130fc8
        Py_CLEAR(signature);
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    if ((PyDict_Type.tp_init((PyObject *)self, tuple, NULL)) < 0) {
Packit 130fc8
        Py_CLEAR(tuple);
Packit 130fc8
        Py_CLEAR(signature);
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
    Py_CLEAR(tuple);
Packit 130fc8
Packit 130fc8
    Py_CLEAR(self->signature);
Packit 130fc8
    self->signature = signature;
Packit 130fc8
    return 0;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
PyTypeObject DBusPyDict_Type = {
Packit 130fc8
    PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
Packit 130fc8
    "dbus.Dictionary",
Packit 130fc8
    sizeof(DBusPyDict),
Packit 130fc8
    0,
Packit 130fc8
    (destructor)Dict_tp_dealloc,            /* tp_dealloc */
Packit 130fc8
    0,                                      /* tp_print */
Packit 130fc8
    0,                                      /* tp_getattr */
Packit 130fc8
    0,                                      /* tp_setattr */
Packit 130fc8
    0,                                      /* tp_compare */
Packit 130fc8
    (reprfunc)Dict_tp_repr,                 /* tp_repr */
Packit 130fc8
    0,                                      /* tp_as_number */
Packit 130fc8
    0,                                      /* tp_as_sequence */
Packit 130fc8
    0,                                      /* tp_as_mapping */
Packit 130fc8
    0,                                      /* tp_hash */
Packit 130fc8
    0,                                      /* tp_call */
Packit 130fc8
    0,                                      /* tp_str */
Packit 130fc8
    0,                                      /* tp_getattro */
Packit 130fc8
    0,                                      /* tp_setattro */
Packit 130fc8
    0,                                      /* tp_as_buffer */
Packit 130fc8
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Packit 130fc8
    Dict_tp_doc,                            /* tp_doc */
Packit 130fc8
    0,                                      /* tp_traverse */
Packit 130fc8
    0,                                      /* tp_clear */
Packit 130fc8
    0,                                      /* tp_richcompare */
Packit 130fc8
    0,                                      /* tp_weaklistoffset */
Packit 130fc8
    0,                                      /* tp_iter */
Packit 130fc8
    0,                                      /* tp_iternext */
Packit 130fc8
    0,                                      /* tp_methods */
Packit 130fc8
    Dict_tp_members,                        /* tp_members */
Packit 130fc8
    0,                                      /* tp_getset */
Packit 130fc8
    0,                                      /* tp_base */
Packit 130fc8
    0,                                      /* tp_dict */
Packit 130fc8
    0,                                      /* tp_descr_get */
Packit 130fc8
    0,                                      /* tp_descr_set */
Packit 130fc8
    0,                                      /* tp_dictoffset */
Packit 130fc8
    (initproc)Dict_tp_init,                 /* tp_init */
Packit 130fc8
    0,                                      /* tp_alloc */
Packit 130fc8
    Dict_tp_new,                            /* tp_new */
Packit 130fc8
};
Packit 130fc8
Packit 130fc8
/* Struct =========================================================== */
Packit 130fc8
Packit 130fc8
static PyObject *struct_signatures;
Packit 130fc8
Packit 130fc8
PyDoc_STRVAR(Struct_tp_doc,
Packit 130fc8
"An structure containing items of possibly distinct types.\n"
Packit 130fc8
"\n"
Packit 130fc8
"Constructor::\n"
Packit 130fc8
"\n"
Packit 130fc8
"    dbus.Struct(iterable, signature=None, variant_level=0) -> Struct\n"
Packit 130fc8
"\n"
Packit 130fc8
"D-Bus structs may not be empty, so the iterable argument is required and\n"
Packit 130fc8
"may not be an empty iterable.\n"
Packit 130fc8
"\n"
Packit 130fc8
"``signature`` is either None, or a string representing the contents of the\n"
Packit 130fc8
"struct as one or more complete type signatures. The overall signature of\n"
Packit 130fc8
"the struct will be the given signature enclosed in parentheses, ``()``.\n"
Packit 130fc8
"\n"
Packit 130fc8
"If the signature is None (default) it will be guessed\n"
Packit 130fc8
"from the types of the items during construction.\n"
Packit 130fc8
"\n"
Packit 130fc8
"``variant_level`` must be non-negative; the default is 0.\n"
Packit 130fc8
"\n"
Packit 130fc8
":IVariables:\n"
Packit 130fc8
"  `variant_level` : int\n"
Packit 130fc8
"    Indicates how many nested Variant containers this object\n"
Packit 130fc8
"    is contained in: if a message's wire format has a variant containing a\n"
Packit 130fc8
"    variant containing a struct, this is represented in Python by a\n"
Packit 130fc8
"    Struct with variant_level==2.\n"
Packit 130fc8
);
Packit 130fc8
Packit 130fc8
static PyObject *
Packit 130fc8
Struct_tp_repr(PyObject *self)
Packit 130fc8
{
Packit 130fc8
    PyObject *parent_repr = (PyTuple_Type.tp_repr)((PyObject *)self);
Packit 130fc8
    PyObject *sig;
Packit 130fc8
    PyObject *sig_repr = NULL;
Packit 130fc8
    PyObject *key;
Packit 130fc8
    long variant_level;
Packit 130fc8
    PyObject *my_repr = NULL;
Packit 130fc8
Packit 130fc8
    if (!parent_repr) goto finally;
Packit 130fc8
    key = PyLong_FromVoidPtr(self);
Packit 130fc8
    if (!key) goto finally;
Packit 130fc8
    sig = PyDict_GetItem(struct_signatures, key);
Packit 130fc8
    Py_CLEAR(key);
Packit 130fc8
    if (!sig) sig = Py_None;
Packit 130fc8
    sig_repr = PyObject_Repr(sig);
Packit 130fc8
    if (!sig_repr) goto finally;
Packit 130fc8
Packit 130fc8
    variant_level = dbus_py_variant_level_get(self);
Packit 130fc8
    if (variant_level < 0)
Packit 130fc8
        goto finally;
Packit 130fc8
Packit 130fc8
    if (variant_level > 0) {
Packit 130fc8
        my_repr = PyUnicode_FromFormat("%s(%V, signature=%V, "
Packit 130fc8
                                       "variant_level=%ld)",
Packit 130fc8
                                       Py_TYPE(self)->tp_name,
Packit 130fc8
                                       REPRV(parent_repr),
Packit 130fc8
                                       REPRV(sig_repr),
Packit 130fc8
                                       variant_level);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        my_repr = PyUnicode_FromFormat("%s(%V, signature=%V)",
Packit 130fc8
                                       Py_TYPE(self)->tp_name,
Packit 130fc8
                                       REPRV(parent_repr),
Packit 130fc8
                                       REPRV(sig_repr));
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
finally:
Packit 130fc8
    Py_CLEAR(parent_repr);
Packit 130fc8
    Py_CLEAR(sig_repr);
Packit 130fc8
    return my_repr;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static PyObject *
Packit 130fc8
Struct_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
Packit 130fc8
{
Packit 130fc8
    PyObject *signature = NULL;
Packit 130fc8
    long variantness = 0;
Packit 130fc8
    PyObject *self, *key;
Packit 130fc8
    static char *argnames[] = {"signature", "variant_level", NULL};
Packit 130fc8
Packit 130fc8
    if (PyTuple_Size(args) != 1) {
Packit 130fc8
        PyErr_SetString(PyExc_TypeError,
Packit 130fc8
                        "__new__ takes exactly one positional parameter");
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
    if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
Packit 130fc8
                                     "|Ol:__new__", argnames,
Packit 130fc8
                                     &signature, &variantness)) {
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
    if (variantness < 0) {
Packit 130fc8
        PyErr_SetString(PyExc_ValueError,
Packit 130fc8
                        "variant_level must be non-negative");
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    self = (PyTuple_Type.tp_new)(cls, args, NULL);
Packit 130fc8
    if (!self)
Packit 130fc8
        return NULL;
Packit 130fc8
    if (PyTuple_Size(self) < 1) {
Packit 130fc8
        PyErr_SetString(PyExc_ValueError, "D-Bus structs may not be empty");
Packit 130fc8
        Py_CLEAR(self);
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    if (!dbus_py_variant_level_set(self, variantness)) {
Packit 130fc8
        Py_CLEAR(self);
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    /* convert signature from a borrowed ref of unknown type to an owned ref
Packit 130fc8
    of type Signature (or None) */
Packit 130fc8
    if (!signature) signature = Py_None;
Packit 130fc8
    if (signature == Py_None
Packit 130fc8
        || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) {
Packit 130fc8
        Py_INCREF(signature);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
Packit 130fc8
                                          "(O)", signature);
Packit 130fc8
        if (!signature) {
Packit 130fc8
            Py_CLEAR(self);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    key = PyLong_FromVoidPtr(self);
Packit 130fc8
    if (!key) {
Packit 130fc8
        Py_CLEAR(self);
Packit 130fc8
        Py_CLEAR(signature);
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
    if (PyDict_SetItem(struct_signatures, key, signature) < 0) {
Packit 130fc8
        Py_CLEAR(key);
Packit 130fc8
        Py_CLEAR(self);
Packit 130fc8
        Py_CLEAR(signature);
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    Py_CLEAR(key);
Packit 130fc8
    Py_CLEAR(signature);
Packit 130fc8
    return self;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static void
Packit 130fc8
Struct_tp_dealloc(PyObject *self)
Packit 130fc8
{
Packit 130fc8
    PyObject *et, *ev, *etb, *key;
Packit 130fc8
Packit 130fc8
    dbus_py_variant_level_clear(self);
Packit 130fc8
    PyErr_Fetch(&et, &ev, &etb;;
Packit 130fc8
Packit 130fc8
    key = PyLong_FromVoidPtr(self);
Packit 130fc8
    if (key) {
Packit 130fc8
        if (PyDict_GetItem(struct_signatures, key)) {
Packit 130fc8
            if (PyDict_DelItem(struct_signatures, key) < 0) {
Packit 130fc8
                /* should never happen */
Packit 130fc8
                PyErr_WriteUnraisable(self);
Packit 130fc8
            }
Packit 130fc8
        }
Packit 130fc8
        Py_CLEAR(key);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        /* not enough memory to free all the memory... leak the signature,
Packit 130fc8
         * there's not much else we could do here */
Packit 130fc8
        PyErr_WriteUnraisable(self);
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    PyErr_Restore(et, ev, etb);
Packit 130fc8
    (PyTuple_Type.tp_dealloc)(self);
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static PyObject *
Packit 130fc8
Struct_tp_getattro(PyObject *obj, PyObject *name)
Packit 130fc8
{
Packit 130fc8
    PyObject *key, *value;
Packit 130fc8
Packit 130fc8
#ifdef PY3
Packit 130fc8
    if (PyUnicode_CompareWithASCIIString(name, "signature"))
Packit 130fc8
        return dbus_py_variant_level_getattro(obj, name);
Packit 130fc8
#else
Packit 130fc8
    if (PyBytes_Check(name)) {
Packit 130fc8
        Py_INCREF(name);
Packit 130fc8
    }
Packit 130fc8
    else if (PyUnicode_Check(name)) {
Packit 130fc8
        name = PyUnicode_AsEncodedString(name, NULL, NULL);
Packit 130fc8
        if (!name) {
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        PyErr_SetString(PyExc_TypeError, "attribute name must be string");
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    if (strcmp(PyBytes_AS_STRING(name), "signature")) {
Packit 130fc8
        value = dbus_py_variant_level_getattro(obj, name);
Packit 130fc8
        Py_CLEAR(name);
Packit 130fc8
        return value;
Packit 130fc8
    }
Packit 130fc8
    Py_CLEAR(name);
Packit 130fc8
#endif  /* PY3 */
Packit 130fc8
Packit 130fc8
    key = PyLong_FromVoidPtr(obj);
Packit 130fc8
Packit 130fc8
    if (!key) {
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    value = PyDict_GetItem(struct_signatures, key);
Packit 130fc8
    Py_CLEAR(key);
Packit 130fc8
Packit 130fc8
    if (!value)
Packit 130fc8
        value = Py_None;
Packit 130fc8
    Py_INCREF(value);
Packit 130fc8
    return value;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
PyTypeObject DBusPyStruct_Type = {
Packit 130fc8
    PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
Packit 130fc8
    "dbus.Struct",
Packit 130fc8
    0,
Packit 130fc8
    0,
Packit 130fc8
    Struct_tp_dealloc,                      /* tp_dealloc */
Packit 130fc8
    0,                                      /* tp_print */
Packit 130fc8
    0,                                      /* tp_getattr */
Packit 130fc8
    0,                                      /* tp_setattr */
Packit 130fc8
    0,                                      /* tp_compare */
Packit 130fc8
    (reprfunc)Struct_tp_repr,               /* tp_repr */
Packit 130fc8
    0,                                      /* tp_as_number */
Packit 130fc8
    0,                                      /* tp_as_sequence */
Packit 130fc8
    0,                                      /* tp_as_mapping */
Packit 130fc8
    0,                                      /* tp_hash */
Packit 130fc8
    0,                                      /* tp_call */
Packit 130fc8
    0,                                      /* tp_str */
Packit 130fc8
    Struct_tp_getattro,                     /* tp_getattro */
Packit 130fc8
    dbus_py_immutable_setattro,             /* tp_setattro */
Packit 130fc8
    0,                                      /* tp_as_buffer */
Packit 130fc8
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Packit 130fc8
    Struct_tp_doc,                          /* tp_doc */
Packit 130fc8
    0,                                      /* tp_traverse */
Packit 130fc8
    0,                                      /* tp_clear */
Packit 130fc8
    0,                                      /* tp_richcompare */
Packit 130fc8
    0,                                      /* tp_weaklistoffset */
Packit 130fc8
    0,                                      /* tp_iter */
Packit 130fc8
    0,                                      /* tp_iternext */
Packit 130fc8
    0,                                      /* tp_methods */
Packit 130fc8
    0,                                      /* tp_members */
Packit 130fc8
    0,                                      /* tp_getset */
Packit 130fc8
    0,                                      /* tp_base */
Packit 130fc8
    0,                                      /* tp_dict */
Packit 130fc8
    0,                                      /* tp_descr_get */
Packit 130fc8
    0,                                      /* tp_descr_set */
Packit 130fc8
    0,                                      /* tp_dictoffset */
Packit 130fc8
    0,                                      /* tp_init */
Packit 130fc8
    0,                                      /* tp_alloc */
Packit 130fc8
    Struct_tp_new,                          /* tp_new */
Packit 130fc8
};
Packit 130fc8
Packit 130fc8
dbus_bool_t
Packit 130fc8
dbus_py_init_container_types(void)
Packit 130fc8
{
Packit 130fc8
    struct_signatures = PyDict_New();
Packit 130fc8
    if (!struct_signatures) return 0;
Packit 130fc8
Packit 130fc8
    DBusPyArray_Type.tp_base = &PyList_Type;
Packit 130fc8
    if (PyType_Ready(&DBusPyArray_Type) < 0) return 0;
Packit 130fc8
    DBusPyArray_Type.tp_print = NULL;
Packit 130fc8
Packit 130fc8
    DBusPyDict_Type.tp_base = &PyDict_Type;
Packit 130fc8
    if (PyType_Ready(&DBusPyDict_Type) < 0) return 0;
Packit 130fc8
    DBusPyDict_Type.tp_print = NULL;
Packit 130fc8
Packit 130fc8
    DBusPyStruct_Type.tp_base = &PyTuple_Type;
Packit 130fc8
    if (PyType_Ready(&DBusPyStruct_Type) < 0) return 0;
Packit 130fc8
    DBusPyStruct_Type.tp_print = NULL;
Packit 130fc8
Packit 130fc8
    return 1;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
dbus_bool_t
Packit 130fc8
dbus_py_insert_container_types(PyObject *this_module)
Packit 130fc8
{
Packit 130fc8
    /* PyModule_AddObject steals a ref */
Packit 130fc8
    Py_INCREF(&DBusPyArray_Type);
Packit 130fc8
    if (PyModule_AddObject(this_module, "Array",
Packit 130fc8
                           (PyObject *)&DBusPyArray_Type) < 0) return 0;
Packit 130fc8
Packit 130fc8
    Py_INCREF(&DBusPyDict_Type);
Packit 130fc8
    if (PyModule_AddObject(this_module, "Dictionary",
Packit 130fc8
                           (PyObject *)&DBusPyDict_Type) < 0) return 0;
Packit 130fc8
Packit 130fc8
    Py_INCREF(&DBusPyStruct_Type);
Packit 130fc8
    if (PyModule_AddObject(this_module, "Struct",
Packit 130fc8
                           (PyObject *)&DBusPyStruct_Type) < 0) return 0;
Packit 130fc8
Packit 130fc8
    return 1;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
/* vim:set ft=c cino< sw=4 sts=4 et: */
Packit 130fc8