|
Packit |
130fc8 |
/* D-Bus Message serialization. This contains all the logic to map from
|
|
Packit |
130fc8 |
* Python objects to D-Bus types.
|
|
Packit |
130fc8 |
*
|
|
Packit |
130fc8 |
* Copyright (C) 2006 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 <assert.h>
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#define DBG_IS_TOO_VERBOSE
|
|
Packit |
130fc8 |
#include "compat-internal.h"
|
|
Packit |
130fc8 |
#include "types-internal.h"
|
|
Packit |
130fc8 |
#include "message-internal.h"
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* Return the number of variants wrapping the given object. Return 0
|
|
Packit |
130fc8 |
* if the object is not a D-Bus type.
|
|
Packit |
130fc8 |
*/
|
|
Packit |
130fc8 |
static long
|
|
Packit |
130fc8 |
get_variant_level(PyObject *obj)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
if (DBusPyString_Check(obj)) {
|
|
Packit |
130fc8 |
return ((DBusPyString *)obj)->variant_level;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#ifndef PY3
|
|
Packit |
130fc8 |
else if (DBusPyIntBase_Check(obj)) {
|
|
Packit |
130fc8 |
return ((DBusPyIntBase *)obj)->variant_level;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
else if (DBusPyFloatBase_Check(obj)) {
|
|
Packit |
130fc8 |
return ((DBusPyFloatBase *)obj)->variant_level;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (DBusPyArray_Check(obj)) {
|
|
Packit |
130fc8 |
return ((DBusPyArray *)obj)->variant_level;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (DBusPyDict_Check(obj)) {
|
|
Packit |
130fc8 |
return ((DBusPyDict *)obj)->variant_level;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (DBusPyLongBase_Check(obj) ||
|
|
Packit |
130fc8 |
#ifdef PY3
|
|
Packit |
130fc8 |
DBusPyBytesBase_Check(obj) ||
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
DBusPyStrBase_Check(obj) ||
|
|
Packit |
130fc8 |
DBusPyStruct_Check(obj)) {
|
|
Packit |
130fc8 |
return dbus_py_variant_level_get(obj);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
return 0;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
char dbus_py_Message_append__doc__[] = (
|
|
Packit |
130fc8 |
"set_args(*args[, **kwargs])\n\n"
|
|
Packit |
130fc8 |
"Set the message's arguments from the positional parameter, according to\n"
|
|
Packit |
130fc8 |
"the signature given by the ``signature`` keyword parameter.\n"
|
|
Packit |
130fc8 |
"\n"
|
|
Packit |
130fc8 |
"The following type conversions are supported:\n\n"
|
|
Packit |
130fc8 |
"=============================== ===========================\n"
|
|
Packit |
130fc8 |
"D-Bus (in signature) Python\n"
|
|
Packit |
130fc8 |
"=============================== ===========================\n"
|
|
Packit |
130fc8 |
"boolean (b) any object (via bool())\n"
|
|
Packit |
130fc8 |
"byte (y) string of length 1\n"
|
|
Packit |
130fc8 |
" any integer\n"
|
|
Packit |
130fc8 |
"any integer type any integer\n"
|
|
Packit |
130fc8 |
"double (d) any float\n"
|
|
Packit |
130fc8 |
"object path anything with a __dbus_object_path__ attribute\n"
|
|
Packit |
130fc8 |
"string, signature, object path str (must be UTF-8) or unicode\n"
|
|
Packit |
130fc8 |
"dict (a{...}) any mapping\n"
|
|
Packit |
130fc8 |
"array (a...) any iterable over appropriate objects\n"
|
|
Packit |
130fc8 |
"struct ((...)) any iterable over appropriate objects\n"
|
|
Packit |
130fc8 |
"variant any object above (guess type as below)\n"
|
|
Packit |
130fc8 |
"=============================== ===========================\n"
|
|
Packit |
130fc8 |
"\n"
|
|
Packit |
130fc8 |
"Here 'any integer' means anything on which int() or long()\n"
|
|
Packit |
130fc8 |
"(as appropriate) will work, except for basestring subclasses.\n"
|
|
Packit |
130fc8 |
"'Any float' means anything on which float() will work, except\n"
|
|
Packit |
130fc8 |
"for basestring subclasses.\n"
|
|
Packit |
130fc8 |
"\n"
|
|
Packit |
130fc8 |
"If there is no signature, guess from the arguments using\n"
|
|
Packit |
130fc8 |
"the static method `Message.guess_signature`.\n"
|
|
Packit |
130fc8 |
);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
char dbus_py_Message_guess_signature__doc__[] = (
|
|
Packit |
130fc8 |
"guess_signature(*args) -> Signature [static method]\n\n"
|
|
Packit |
130fc8 |
"Guess a D-Bus signature which should be used to encode the given\n"
|
|
Packit |
130fc8 |
"Python objects.\n"
|
|
Packit |
130fc8 |
"\n"
|
|
Packit |
130fc8 |
"The signature is constructed as follows:\n\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|Python |D-Bus |\n"
|
|
Packit |
130fc8 |
"+===============================+===========================+\n"
|
|
Packit |
130fc8 |
"|D-Bus type, variant_level > 0 |variant (v) |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|D-Bus type, variant_level == 0 |the corresponding type |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|anything with a |object path |\n"
|
|
Packit |
130fc8 |
"|__dbus_object_path__ attribute | |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|bool |boolean (y) |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|any other int subclass |int32 (i) |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|any other long subclass |int64 (x) |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|any other float subclass |double (d) |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|any other str subclass |string (s) |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|any other unicode subclass |string (s) |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|any other tuple subclass |struct ((...)) |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|any other list subclass |array (a...), guess |\n"
|
|
Packit |
130fc8 |
"| |contents' type according to|\n"
|
|
Packit |
130fc8 |
"| |type of first item |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|any other dict subclass |dict (a{...}), guess key, |\n"
|
|
Packit |
130fc8 |
"| |value type according to |\n"
|
|
Packit |
130fc8 |
"| |types for an arbitrary item|\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
"|anything else |raise TypeError |\n"
|
|
Packit |
130fc8 |
"+-------------------------------+---------------------------+\n"
|
|
Packit |
130fc8 |
);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* return a new reference, possibly to None */
|
|
Packit |
130fc8 |
static PyObject *
|
|
Packit |
130fc8 |
get_object_path(PyObject *obj)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
PyObject *magic_attr = PyObject_GetAttr(obj, dbus_py__dbus_object_path__const);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (magic_attr) {
|
|
Packit |
130fc8 |
if (PyUnicode_Check(magic_attr) || PyBytes_Check(magic_attr)) {
|
|
Packit |
130fc8 |
return magic_attr;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
Py_CLEAR(magic_attr);
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_TypeError, "__dbus_object_path__ must be "
|
|
Packit |
130fc8 |
"a string");
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
/* Ignore exceptions, except for SystemExit and KeyboardInterrupt */
|
|
Packit |
130fc8 |
if (PyErr_ExceptionMatches(PyExc_SystemExit) ||
|
|
Packit |
130fc8 |
PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
PyErr_Clear();
|
|
Packit |
130fc8 |
Py_RETURN_NONE;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* Return a new reference. If the object is a variant and variant_level_ptr
|
|
Packit |
130fc8 |
* is not NULL, put the variant level in the variable pointed to, and
|
|
Packit |
130fc8 |
* return the contained type instead of "v". */
|
|
Packit |
130fc8 |
static PyObject *
|
|
Packit |
130fc8 |
_signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
PyObject *magic_attr;
|
|
Packit |
130fc8 |
long variant_level = get_variant_level(obj);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (variant_level < 0)
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (variant_level_ptr) {
|
|
Packit |
130fc8 |
*variant_level_ptr = variant_level;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (variant_level > 0) {
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_VARIANT_AS_STRING);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (obj == Py_True || obj == Py_False) {
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_BOOLEAN_AS_STRING);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
magic_attr = get_object_path(obj);
|
|
Packit |
130fc8 |
if (!magic_attr)
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
if (magic_attr != Py_None) {
|
|
Packit |
130fc8 |
Py_CLEAR(magic_attr);
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
Py_CLEAR(magic_attr);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* Ordering is important: some of these are subclasses of each other. */
|
|
Packit |
130fc8 |
#ifdef PY3
|
|
Packit |
130fc8 |
if (PyLong_Check(obj)) {
|
|
Packit |
130fc8 |
if (DBusPyUInt64_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_UINT64_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyInt64_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyUInt32_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_UINT32_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyInt32_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyUInt16_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_UINT16_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyInt16_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_INT16_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyByte_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_BYTE_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyBoolean_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_BOOLEAN_AS_STRING);
|
|
Packit |
130fc8 |
else
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#else /* !PY3 */
|
|
Packit |
130fc8 |
if (PyInt_Check(obj)) {
|
|
Packit |
130fc8 |
if (DBusPyInt16_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_INT16_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyInt32_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyByte_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_BYTE_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyUInt16_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_UINT16_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyBoolean_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_BOOLEAN_AS_STRING);
|
|
Packit |
130fc8 |
else
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (PyLong_Check(obj)) {
|
|
Packit |
130fc8 |
if (DBusPyInt64_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyUInt32_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_UINT32_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyUInt64_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_UINT64_AS_STRING);
|
|
Packit |
130fc8 |
else
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#endif /* PY3 */
|
|
Packit |
130fc8 |
else if (PyUnicode_Check(obj)) {
|
|
Packit |
130fc8 |
/* Object paths and signatures are unicode subtypes in Python 3
|
|
Packit |
130fc8 |
* (the first two cases will never be true in Python 2) */
|
|
Packit |
130fc8 |
if (DBusPyObjectPath_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPySignature_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_SIGNATURE_AS_STRING);
|
|
Packit |
130fc8 |
else
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_STRING_AS_STRING);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#if defined(DBUS_TYPE_UNIX_FD)
|
|
Packit |
130fc8 |
else if (DBusPyUnixFd_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_UNIX_FD_AS_STRING);
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
else if (PyFloat_Check(obj)) {
|
|
Packit |
130fc8 |
#ifdef WITH_DBUS_FLOAT32
|
|
Packit |
130fc8 |
if (DBusPyDouble_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_DOUBLE_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyFloat_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_FLOAT_AS_STRING);
|
|
Packit |
130fc8 |
else
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_DOUBLE_AS_STRING);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (PyBytes_Check(obj)) {
|
|
Packit |
130fc8 |
/* Object paths and signatures are bytes subtypes in Python 2
|
|
Packit |
130fc8 |
* (the first two cases will never be true in Python 3) */
|
|
Packit |
130fc8 |
if (DBusPyObjectPath_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPySignature_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_SIGNATURE_AS_STRING);
|
|
Packit |
130fc8 |
else if (DBusPyByteArray_Check(obj))
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_ARRAY_AS_STRING
|
|
Packit |
130fc8 |
DBUS_TYPE_BYTE_AS_STRING);
|
|
Packit |
130fc8 |
else
|
|
Packit |
130fc8 |
return NATIVESTR_FROMSTR(DBUS_TYPE_STRING_AS_STRING);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (PyTuple_Check(obj)) {
|
|
Packit |
130fc8 |
Py_ssize_t len = PyTuple_GET_SIZE(obj);
|
|
Packit |
130fc8 |
PyObject *list = PyList_New(len + 2); /* new ref */
|
|
Packit |
130fc8 |
PyObject *item; /* temporary new ref */
|
|
Packit |
130fc8 |
PyObject *empty_str; /* temporary new ref */
|
|
Packit |
130fc8 |
PyObject *ret;
|
|
Packit |
130fc8 |
Py_ssize_t i;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (!list) return NULL;
|
|
Packit |
130fc8 |
if (len == 0) {
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_ValueError, "D-Bus structs cannot be empty");
|
|
Packit |
130fc8 |
Py_CLEAR(list);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
/* Set the first and last elements of list to be the parentheses */
|
|
Packit |
130fc8 |
item = NATIVESTR_FROMSTR(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
|
|
Packit |
130fc8 |
if (PyList_SetItem(list, 0, item) < 0) {
|
|
Packit |
130fc8 |
Py_CLEAR(list);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
item = NATIVESTR_FROMSTR(DBUS_STRUCT_END_CHAR_AS_STRING);
|
|
Packit |
130fc8 |
if (PyList_SetItem(list, len + 1, item) < 0) {
|
|
Packit |
130fc8 |
Py_CLEAR(list);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
if (!item || !PyList_GET_ITEM(list, 0)) {
|
|
Packit |
130fc8 |
Py_CLEAR(list);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
item = NULL;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
for (i = 0; i < len; i++) {
|
|
Packit |
130fc8 |
item = PyTuple_GetItem(obj, i);
|
|
Packit |
130fc8 |
if (!item) {
|
|
Packit |
130fc8 |
Py_CLEAR(list);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
item = _signature_string_from_pyobject(item, NULL);
|
|
Packit |
130fc8 |
if (!item) {
|
|
Packit |
130fc8 |
Py_CLEAR(list);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
if (PyList_SetItem(list, i + 1, item) < 0) {
|
|
Packit |
130fc8 |
Py_CLEAR(list);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
item = NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
empty_str = NATIVESTR_FROMSTR("");
|
|
Packit |
130fc8 |
if (!empty_str) {
|
|
Packit |
130fc8 |
/* really shouldn't happen */
|
|
Packit |
130fc8 |
Py_CLEAR(list);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
ret = PyObject_CallMethod(empty_str, "join", "(O)", list); /* new ref */
|
|
Packit |
130fc8 |
/* whether ret is NULL or not, */
|
|
Packit |
130fc8 |
Py_CLEAR(empty_str);
|
|
Packit |
130fc8 |
Py_CLEAR(list);
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (PyList_Check(obj)) {
|
|
Packit |
130fc8 |
PyObject *tmp;
|
|
Packit |
130fc8 |
PyObject *ret = NATIVESTR_FROMSTR(DBUS_TYPE_ARRAY_AS_STRING);
|
|
Packit |
130fc8 |
if (!ret) return NULL;
|
|
Packit |
130fc8 |
#ifdef PY3
|
|
Packit |
130fc8 |
if (DBusPyArray_Check(obj) &&
|
|
Packit |
130fc8 |
PyUnicode_Check(((DBusPyArray *)obj)->signature))
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
PyObject *concat = PyUnicode_Concat(
|
|
Packit |
130fc8 |
ret, ((DBusPyArray *)obj)->signature);
|
|
Packit |
130fc8 |
Py_CLEAR(ret);
|
|
Packit |
130fc8 |
return concat;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#else
|
|
Packit |
130fc8 |
if (DBusPyArray_Check(obj) &&
|
|
Packit |
130fc8 |
PyBytes_Check(((DBusPyArray *)obj)->signature))
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
PyBytes_Concat(&ret, ((DBusPyArray *)obj)->signature);
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
if (PyList_GET_SIZE(obj) == 0) {
|
|
Packit |
130fc8 |
/* No items, so fail. Or should we guess "av"? */
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
|
|
Packit |
130fc8 |
"from an empty list");
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
tmp = PyList_GetItem(obj, 0);
|
|
Packit |
130fc8 |
tmp = _signature_string_from_pyobject(tmp, NULL);
|
|
Packit |
130fc8 |
if (!tmp) return NULL;
|
|
Packit |
130fc8 |
#ifdef PY3
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
PyObject *concat = PyUnicode_Concat(ret, tmp);
|
|
Packit |
130fc8 |
Py_CLEAR(ret);
|
|
Packit |
130fc8 |
Py_CLEAR(tmp);
|
|
Packit |
130fc8 |
return concat;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#else
|
|
Packit |
130fc8 |
PyBytes_ConcatAndDel(&ret, tmp);
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (PyDict_Check(obj)) {
|
|
Packit |
130fc8 |
PyObject *key, *value, *keysig, *valuesig;
|
|
Packit |
130fc8 |
Py_ssize_t pos = 0;
|
|
Packit |
130fc8 |
PyObject *ret = NULL;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#ifdef PY3
|
|
Packit |
130fc8 |
if (DBusPyDict_Check(obj) &&
|
|
Packit |
130fc8 |
PyUnicode_Check(((DBusPyDict *)obj)->signature))
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
return PyUnicode_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
|
|
Packit |
130fc8 |
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
|
Packit |
130fc8 |
"%U"
|
|
Packit |
130fc8 |
DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
|
|
Packit |
130fc8 |
((DBusPyDict *)obj)->signature);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#else
|
|
Packit |
130fc8 |
if (DBusPyDict_Check(obj) &&
|
|
Packit |
130fc8 |
PyBytes_Check(((DBusPyDict *)obj)->signature))
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
const char *sig = PyBytes_AS_STRING(((DBusPyDict *)obj)->signature);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
return PyBytes_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
|
|
Packit |
130fc8 |
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
|
Packit |
130fc8 |
"%s"
|
|
Packit |
130fc8 |
DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
|
|
Packit |
130fc8 |
sig);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
if (!PyDict_Next(obj, &pos, &key, &value)) {
|
|
Packit |
130fc8 |
/* No items, so fail. Or should we guess "a{vv}"? */
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
|
|
Packit |
130fc8 |
"from an empty dict");
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
keysig = _signature_string_from_pyobject(key, NULL);
|
|
Packit |
130fc8 |
valuesig = _signature_string_from_pyobject(value, NULL);
|
|
Packit |
130fc8 |
if (keysig && valuesig) {
|
|
Packit |
130fc8 |
#ifdef PY3
|
|
Packit |
130fc8 |
ret = PyUnicode_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
|
|
Packit |
130fc8 |
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
|
Packit |
130fc8 |
"%U%U"
|
|
Packit |
130fc8 |
DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
|
|
Packit |
130fc8 |
keysig, valuesig);
|
|
Packit |
130fc8 |
#else
|
|
Packit |
130fc8 |
ret = PyBytes_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
|
|
Packit |
130fc8 |
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
|
Packit |
130fc8 |
"%s%s"
|
|
Packit |
130fc8 |
DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
|
|
Packit |
130fc8 |
PyBytes_AS_STRING(keysig),
|
|
Packit |
130fc8 |
PyBytes_AS_STRING(valuesig));
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
Py_CLEAR(keysig);
|
|
Packit |
130fc8 |
Py_CLEAR(valuesig);
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
PyErr_Format(PyExc_TypeError, "Don't know which D-Bus type "
|
|
Packit |
130fc8 |
"to use to encode type \"%s\"",
|
|
Packit |
130fc8 |
Py_TYPE(obj)->tp_name);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
PyObject *
|
|
Packit |
130fc8 |
dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
PyObject *tmp, *ret = NULL;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (!args) {
|
|
Packit |
130fc8 |
if (!PyErr_Occurred()) {
|
|
Packit |
130fc8 |
PyErr_BadInternalCall();
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#ifdef USING_DBG
|
|
Packit |
130fc8 |
fprintf(stderr, "DBG/%ld: called Message_guess_signature", (long)getpid());
|
|
Packit |
130fc8 |
PyObject_Print(args, stderr, 0);
|
|
Packit |
130fc8 |
fprintf(stderr, "\n");
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (!PyTuple_Check(args)) {
|
|
Packit |
130fc8 |
DBG("%s", "Message_guess_signature: args not a tuple");
|
|
Packit |
130fc8 |
PyErr_BadInternalCall();
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* if there were no args, easy */
|
|
Packit |
130fc8 |
if (PyTuple_GET_SIZE(args) == 0) {
|
|
Packit |
130fc8 |
DBG("%s", "Message_guess_signature: no args, so return Signature('')");
|
|
Packit |
130fc8 |
return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", "");
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* if there were args, the signature we want is, by construction,
|
|
Packit |
130fc8 |
* exactly the signature we get for the tuple args, except that we don't
|
|
Packit |
130fc8 |
* want the parentheses. */
|
|
Packit |
130fc8 |
tmp = _signature_string_from_pyobject(args, NULL);
|
|
Packit |
130fc8 |
if (!tmp) {
|
|
Packit |
130fc8 |
DBG("%s", "Message_guess_signature: failed");
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
if (PyUnicode_Check(tmp)) {
|
|
Packit |
130fc8 |
PyObject *as_bytes = PyUnicode_AsUTF8String(tmp);
|
|
Packit |
130fc8 |
Py_CLEAR(tmp);
|
|
Packit |
130fc8 |
if (!as_bytes)
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
if (PyBytes_GET_SIZE(as_bytes) < 2) {
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_RuntimeError, "Internal error: "
|
|
Packit |
130fc8 |
"_signature_string_from_pyobject returned "
|
|
Packit |
130fc8 |
"a bad result");
|
|
Packit |
130fc8 |
Py_CLEAR(as_bytes);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
tmp = as_bytes;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
if (!PyBytes_Check(tmp) || PyBytes_GET_SIZE(tmp) < 2) {
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_RuntimeError, "Internal error: "
|
|
Packit |
130fc8 |
"_signature_string_from_pyobject returned "
|
|
Packit |
130fc8 |
"a bad result");
|
|
Packit |
130fc8 |
Py_CLEAR(tmp);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
ret = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s#)",
|
|
Packit |
130fc8 |
PyBytes_AS_STRING(tmp) + 1,
|
|
Packit |
130fc8 |
PyBytes_GET_SIZE(tmp) - 2);
|
|
Packit |
130fc8 |
Py_CLEAR(tmp);
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
static int _message_iter_append_pyobject(DBusMessageIter *appender,
|
|
Packit |
130fc8 |
DBusSignatureIter *sig_iter,
|
|
Packit |
130fc8 |
PyObject *obj,
|
|
Packit |
130fc8 |
dbus_bool_t *more);
|
|
Packit |
130fc8 |
static int _message_iter_append_variant(DBusMessageIter *appender,
|
|
Packit |
130fc8 |
PyObject *obj);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
static int
|
|
Packit |
130fc8 |
_message_iter_append_string(DBusMessageIter *appender,
|
|
Packit |
130fc8 |
int sig_type, PyObject *obj,
|
|
Packit |
130fc8 |
dbus_bool_t allow_object_path_attr)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
char *s;
|
|
Packit |
130fc8 |
PyObject *utf8;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (sig_type == DBUS_TYPE_OBJECT_PATH && allow_object_path_attr) {
|
|
Packit |
130fc8 |
PyObject *object_path = get_object_path (obj);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (object_path == Py_None) {
|
|
Packit |
130fc8 |
Py_CLEAR(object_path);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (!object_path) {
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
int ret = _message_iter_append_string(appender, sig_type,
|
|
Packit |
130fc8 |
object_path, FALSE);
|
|
Packit |
130fc8 |
Py_CLEAR(object_path);
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (PyBytes_Check(obj)) {
|
|
Packit |
130fc8 |
utf8 = obj;
|
|
Packit |
130fc8 |
Py_INCREF(obj);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (PyUnicode_Check(obj)) {
|
|
Packit |
130fc8 |
utf8 = PyUnicode_AsUTF8String(obj);
|
|
Packit |
130fc8 |
if (!utf8) return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_TypeError,
|
|
Packit |
130fc8 |
"Expected a string or unicode object");
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* Raise TypeError if the string has embedded NULs */
|
|
Packit |
130fc8 |
if (PyBytes_AsStringAndSize(utf8, &s, NULL) < 0)
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* Validate UTF-8, strictly */
|
|
Packit |
130fc8 |
if (!dbus_validate_utf8(s, NULL)) {
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_UnicodeError, "String parameters "
|
|
Packit |
130fc8 |
"to be sent over D-Bus must be valid UTF-8 "
|
|
Packit |
130fc8 |
"with no noncharacter code points");
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBG("Performing actual append: string (from unicode) %s", s);
|
|
Packit |
130fc8 |
if (!dbus_message_iter_append_basic(appender, sig_type, &s)) {
|
|
Packit |
130fc8 |
Py_CLEAR(utf8);
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Py_CLEAR(utf8);
|
|
Packit |
130fc8 |
return 0;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
static int
|
|
Packit |
130fc8 |
_message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
unsigned char y;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (PyBytes_Check(obj)) {
|
|
Packit |
130fc8 |
if (PyBytes_GET_SIZE(obj) != 1) {
|
|
Packit |
130fc8 |
PyErr_Format(PyExc_ValueError,
|
|
Packit |
130fc8 |
"Expected a length-1 bytes but found %d bytes",
|
|
Packit |
130fc8 |
(int)PyBytes_GET_SIZE(obj));
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
y = *(unsigned char *)PyBytes_AS_STRING(obj);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
/* on Python 2 this accepts either int or long */
|
|
Packit |
130fc8 |
long i = PyLong_AsLong(obj);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (i == -1 && PyErr_Occurred()) return -1;
|
|
Packit |
130fc8 |
if (i < 0 || i > 0xff) {
|
|
Packit |
130fc8 |
PyErr_Format(PyExc_ValueError,
|
|
Packit |
130fc8 |
"%d outside range for a byte value",
|
|
Packit |
130fc8 |
(int)i);
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
y = i;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
DBG("Performing actual append: byte \\x%02x", (unsigned)y);
|
|
Packit |
130fc8 |
if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
return 0;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
static dbus_bool_t
|
|
Packit |
130fc8 |
dbuspy_message_iter_close_container(DBusMessageIter *iter,
|
|
Packit |
130fc8 |
DBusMessageIter *sub,
|
|
Packit |
130fc8 |
dbus_bool_t is_ok)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
if (!is_ok) {
|
|
Packit |
130fc8 |
dbus_message_iter_abandon_container(iter, sub);
|
|
Packit |
130fc8 |
return TRUE;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
return dbus_message_iter_close_container(iter, sub);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#if defined(DBUS_TYPE_UNIX_FD)
|
|
Packit |
130fc8 |
static int
|
|
Packit |
130fc8 |
_message_iter_append_unixfd(DBusMessageIter *appender, PyObject *obj)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
int fd;
|
|
Packit |
130fc8 |
long original_fd;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (INTORLONG_CHECK(obj))
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
/* on Python 2 this accepts either int or long */
|
|
Packit |
130fc8 |
original_fd = PyLong_AsLong(obj);
|
|
Packit |
130fc8 |
if (original_fd == -1 && PyErr_Occurred())
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
if (original_fd < INT_MIN || original_fd > INT_MAX) {
|
|
Packit |
130fc8 |
PyErr_Format(PyExc_ValueError, "out of int range: %ld",
|
|
Packit |
130fc8 |
original_fd);
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
fd = (int)original_fd;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (PyObject_IsInstance(obj, (PyObject*) &DBusPyUnixFd_Type)) {
|
|
Packit |
130fc8 |
fd = dbus_py_unix_fd_get_fd(obj);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBG("Performing actual append: fd %d", fd);
|
|
Packit |
130fc8 |
if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_UNIX_FD, &fd)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
return 0;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
static int
|
|
Packit |
130fc8 |
_message_iter_append_dictentry(DBusMessageIter *appender,
|
|
Packit |
130fc8 |
DBusSignatureIter *sig_iter,
|
|
Packit |
130fc8 |
PyObject *dict, PyObject *key)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
DBusSignatureIter sub_sig_iter;
|
|
Packit |
130fc8 |
DBusMessageIter sub;
|
|
Packit |
130fc8 |
int ret = -1;
|
|
Packit |
130fc8 |
PyObject *value = PyObject_GetItem(dict, key);
|
|
Packit |
130fc8 |
dbus_bool_t more;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (!value) return -1;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#ifdef USING_DBG
|
|
Packit |
130fc8 |
fprintf(stderr, "Append dictentry: ");
|
|
Packit |
130fc8 |
PyObject_Print(key, stderr, 0);
|
|
Packit |
130fc8 |
fprintf(stderr, " => ");
|
|
Packit |
130fc8 |
PyObject_Print(value, stderr, 0);
|
|
Packit |
130fc8 |
fprintf(stderr, "\n");
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
|
|
Packit |
130fc8 |
dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
|
|
Packit |
130fc8 |
#ifdef USING_DBG
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
char *s;
|
|
Packit |
130fc8 |
s = dbus_signature_iter_get_signature(sig_iter);
|
|
Packit |
130fc8 |
DBG("Signature of parent iterator %p is %s", sig_iter, s);
|
|
Packit |
130fc8 |
dbus_free(s);
|
|
Packit |
130fc8 |
s = dbus_signature_iter_get_signature(&sub_sig_iter);
|
|
Packit |
130fc8 |
DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
|
|
Packit |
130fc8 |
dbus_free(s);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBG("%s", "Opening DICT_ENTRY container");
|
|
Packit |
130fc8 |
if (!dbus_message_iter_open_container(appender, DBUS_TYPE_DICT_ENTRY,
|
|
Packit |
130fc8 |
NULL, &sub)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
goto out;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key, &more);
|
|
Packit |
130fc8 |
if (ret == 0) {
|
|
Packit |
130fc8 |
ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value, &more);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
DBG("%s", "Closing DICT_ENTRY container");
|
|
Packit |
130fc8 |
if (!dbuspy_message_iter_close_container(appender, &sub, (ret == 0))) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
out:
|
|
Packit |
130fc8 |
Py_CLEAR(value);
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
static int
|
|
Packit |
130fc8 |
_message_iter_append_multi(DBusMessageIter *appender,
|
|
Packit |
130fc8 |
const DBusSignatureIter *sig_iter,
|
|
Packit |
130fc8 |
int mode, PyObject *obj)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
DBusMessageIter sub_appender;
|
|
Packit |
130fc8 |
DBusSignatureIter sub_sig_iter;
|
|
Packit |
130fc8 |
PyObject *contents;
|
|
Packit |
130fc8 |
int ret;
|
|
Packit |
130fc8 |
PyObject *iterator = PyObject_GetIter(obj);
|
|
Packit |
130fc8 |
char *sig = NULL;
|
|
Packit |
130fc8 |
int container = mode;
|
|
Packit |
130fc8 |
dbus_bool_t is_byte_array = DBusPyByteArray_Check(obj);
|
|
Packit |
130fc8 |
int inner_type;
|
|
Packit |
130fc8 |
dbus_bool_t more;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
assert(mode == DBUS_TYPE_DICT_ENTRY || mode == DBUS_TYPE_ARRAY ||
|
|
Packit |
130fc8 |
mode == DBUS_TYPE_STRUCT);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#ifdef USING_DBG
|
|
Packit |
130fc8 |
fprintf(stderr, "Appending multiple: ");
|
|
Packit |
130fc8 |
PyObject_Print(obj, stderr, 0);
|
|
Packit |
130fc8 |
fprintf(stderr, "\n");
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (!iterator) return -1;
|
|
Packit |
130fc8 |
if (mode == DBUS_TYPE_DICT_ENTRY) container = DBUS_TYPE_ARRAY;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
|
|
Packit |
130fc8 |
dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
|
|
Packit |
130fc8 |
#ifdef USING_DBG
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
char *s;
|
|
Packit |
130fc8 |
s = dbus_signature_iter_get_signature(sig_iter);
|
|
Packit |
130fc8 |
DBG("Signature of parent iterator %p is %s", sig_iter, s);
|
|
Packit |
130fc8 |
dbus_free(s);
|
|
Packit |
130fc8 |
s = dbus_signature_iter_get_signature(&sub_sig_iter);
|
|
Packit |
130fc8 |
DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
|
|
Packit |
130fc8 |
dbus_free(s);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
inner_type = dbus_signature_iter_get_current_type(&sub_sig_iter);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
|
|
Packit |
130fc8 |
sig = dbus_signature_iter_get_signature(&sub_sig_iter);
|
|
Packit |
130fc8 |
if (!sig) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
goto out;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
/* else leave sig set to NULL. */
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBG("Opening '%c' container", container);
|
|
Packit |
130fc8 |
if (!dbus_message_iter_open_container(appender, container,
|
|
Packit |
130fc8 |
sig, &sub_appender)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
goto out;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
ret = 0;
|
|
Packit |
130fc8 |
more = TRUE;
|
|
Packit |
130fc8 |
while ((contents = PyIter_Next(iterator))) {
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
|
|
Packit |
130fc8 |
DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
|
|
Packit |
130fc8 |
dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
|
|
Packit |
130fc8 |
#ifdef USING_DBG
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
char *s;
|
|
Packit |
130fc8 |
s = dbus_signature_iter_get_signature(sig_iter);
|
|
Packit |
130fc8 |
DBG("Signature of parent iterator %p is %s", sig_iter, s);
|
|
Packit |
130fc8 |
dbus_free(s);
|
|
Packit |
130fc8 |
s = dbus_signature_iter_get_signature(&sub_sig_iter);
|
|
Packit |
130fc8 |
DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
|
|
Packit |
130fc8 |
dbus_free(s);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else /* struct */ {
|
|
Packit |
130fc8 |
if (!more) {
|
|
Packit |
130fc8 |
PyErr_Format(PyExc_TypeError, "Fewer items found in struct's "
|
|
Packit |
130fc8 |
"D-Bus signature than in Python arguments ");
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (mode == DBUS_TYPE_DICT_ENTRY) {
|
|
Packit |
130fc8 |
ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
|
|
Packit |
130fc8 |
obj, contents);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (mode == DBUS_TYPE_ARRAY && is_byte_array
|
|
Packit |
130fc8 |
&& inner_type == DBUS_TYPE_VARIANT) {
|
|
Packit |
130fc8 |
/* Subscripting a ByteArray gives a str of length 1, but if the
|
|
Packit |
130fc8 |
* container is a ByteArray and the parameter is an array of
|
|
Packit |
130fc8 |
* variants, we want to produce an array of variants containing
|
|
Packit |
130fc8 |
* bytes, not strings.
|
|
Packit |
130fc8 |
*/
|
|
Packit |
130fc8 |
PyObject *args = Py_BuildValue("(O)", contents);
|
|
Packit |
130fc8 |
PyObject *byte;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (!args)
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
byte = PyObject_Call((PyObject *)&DBusPyByte_Type, args, NULL);
|
|
Packit |
130fc8 |
Py_CLEAR(args);
|
|
Packit |
130fc8 |
if (!byte)
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
ret = _message_iter_append_variant(&sub_appender, byte);
|
|
Packit |
130fc8 |
Py_CLEAR(byte);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
/* advances sub_sig_iter and sets more on success - for array
|
|
Packit |
130fc8 |
* this doesn't matter, for struct it's essential */
|
|
Packit |
130fc8 |
ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
|
|
Packit |
130fc8 |
contents, &more);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Py_CLEAR(contents);
|
|
Packit |
130fc8 |
if (ret < 0) {
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (PyErr_Occurred()) {
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else if (mode == DBUS_TYPE_STRUCT && more) {
|
|
Packit |
130fc8 |
PyErr_Format(PyExc_TypeError, "More items found in struct's D-Bus "
|
|
Packit |
130fc8 |
"signature than in Python arguments ");
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* This must be run as cleanup, even on failure. */
|
|
Packit |
130fc8 |
DBG("Closing '%c' container", container);
|
|
Packit |
130fc8 |
if (!dbuspy_message_iter_close_container(appender, &sub_appender, (ret == 0))) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
out:
|
|
Packit |
130fc8 |
Py_CLEAR(iterator);
|
|
Packit |
130fc8 |
dbus_free(sig);
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
static int
|
|
Packit |
130fc8 |
_message_iter_append_string_as_byte_array(DBusMessageIter *appender,
|
|
Packit |
130fc8 |
PyObject *obj)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
/* a bit of a faster path for byte arrays that are strings */
|
|
Packit |
130fc8 |
Py_ssize_t len = PyBytes_GET_SIZE(obj);
|
|
Packit |
130fc8 |
const char *s;
|
|
Packit |
130fc8 |
DBusMessageIter sub;
|
|
Packit |
130fc8 |
int ret;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
s = PyBytes_AS_STRING(obj);
|
|
Packit |
130fc8 |
DBG("%s", "Opening ARRAY container");
|
|
Packit |
130fc8 |
if (!dbus_message_iter_open_container(appender, DBUS_TYPE_ARRAY,
|
|
Packit |
130fc8 |
DBUS_TYPE_BYTE_AS_STRING, &sub)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
DBG("Appending fixed array of %d bytes", (int)len);
|
|
Packit |
130fc8 |
if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
|
|
Packit |
130fc8 |
ret = 0;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
DBG("%s", "Closing ARRAY container");
|
|
Packit |
130fc8 |
if (!dbus_message_iter_close_container(appender, &sub)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* Encode some Python object into a D-Bus variant slot. */
|
|
Packit |
130fc8 |
static int
|
|
Packit |
130fc8 |
_message_iter_append_variant(DBusMessageIter *appender, PyObject *obj)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
DBusSignatureIter obj_sig_iter;
|
|
Packit |
130fc8 |
const char *obj_sig_str;
|
|
Packit |
130fc8 |
PyObject *obj_sig;
|
|
Packit |
130fc8 |
int ret;
|
|
Packit |
130fc8 |
long variant_level;
|
|
Packit |
130fc8 |
dbus_bool_t dummy;
|
|
Packit |
130fc8 |
DBusMessageIter *variant_iters = NULL;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* Separate the object into the contained object, and the number of
|
|
Packit |
130fc8 |
* variants it's wrapped in. */
|
|
Packit |
130fc8 |
obj_sig = _signature_string_from_pyobject(obj, &variant_level);
|
|
Packit |
130fc8 |
if (!obj_sig) return -1;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (PyUnicode_Check(obj_sig)) {
|
|
Packit |
130fc8 |
PyObject *obj_sig_as_bytes = PyUnicode_AsUTF8String(obj_sig);
|
|
Packit |
130fc8 |
Py_CLEAR(obj_sig);
|
|
Packit |
130fc8 |
if (!obj_sig_as_bytes)
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
obj_sig = obj_sig_as_bytes;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
obj_sig_str = PyBytes_AsString(obj_sig);
|
|
Packit |
130fc8 |
if (!obj_sig_str) {
|
|
Packit |
130fc8 |
Py_CLEAR(obj_sig);
|
|
Packit |
130fc8 |
return -1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (variant_level < 1) {
|
|
Packit |
130fc8 |
variant_level = 1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
dbus_signature_iter_init(&obj_sig_iter, obj_sig_str);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
long i;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
variant_iters = calloc (variant_level, sizeof (DBusMessageIter));
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (!variant_iters) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
goto out;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
for (i = 0; i < variant_level; i++) {
|
|
Packit |
130fc8 |
DBusMessageIter *child = &variant_iters[i];
|
|
Packit |
130fc8 |
/* The first is a special case: its parent is the iter passed in
|
|
Packit |
130fc8 |
* to this function, instead of being the previous one in the
|
|
Packit |
130fc8 |
* stack
|
|
Packit |
130fc8 |
*/
|
|
Packit |
130fc8 |
DBusMessageIter *parent = (i == 0
|
|
Packit |
130fc8 |
? appender
|
|
Packit |
130fc8 |
: &(variant_iters[i-1]));
|
|
Packit |
130fc8 |
/* The last is also a special case: it contains the actual
|
|
Packit |
130fc8 |
* object, rather than another variant
|
|
Packit |
130fc8 |
*/
|
|
Packit |
130fc8 |
const char *sig_str = (i == variant_level-1
|
|
Packit |
130fc8 |
? obj_sig_str
|
|
Packit |
130fc8 |
: DBUS_TYPE_VARIANT_AS_STRING);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBG("Opening VARIANT container %p inside %p containing '%s'",
|
|
Packit |
130fc8 |
child, parent, sig_str);
|
|
Packit |
130fc8 |
if (!dbus_message_iter_open_container(parent, DBUS_TYPE_VARIANT,
|
|
Packit |
130fc8 |
sig_str, child)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
goto out;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* Put the object itself into the innermost variant */
|
|
Packit |
130fc8 |
ret = _message_iter_append_pyobject(&variant_iters[variant_level-1],
|
|
Packit |
130fc8 |
&obj_sig_iter, obj, &dummy);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* here we rely on i (and variant_level) being a signed long */
|
|
Packit |
130fc8 |
for (i = variant_level - 1; i >= 0; i--) {
|
|
Packit |
130fc8 |
DBusMessageIter *child = &variant_iters[i];
|
|
Packit |
130fc8 |
/* The first is a special case: its parent is the iter passed in
|
|
Packit |
130fc8 |
* to this function, instead of being the previous one in the
|
|
Packit |
130fc8 |
* stack
|
|
Packit |
130fc8 |
*/
|
|
Packit |
130fc8 |
DBusMessageIter *parent = (i == 0 ? appender
|
|
Packit |
130fc8 |
: &(variant_iters[i-1]));
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBG("Closing VARIANT container %p inside %p", child, parent);
|
|
Packit |
130fc8 |
if (!dbus_message_iter_close_container(parent, child)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
goto out;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
out:
|
|
Packit |
130fc8 |
if (variant_iters != NULL)
|
|
Packit |
130fc8 |
free (variant_iters);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Py_CLEAR(obj_sig);
|
|
Packit |
130fc8 |
return ret;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* On success, *more is set to whether there's more in the signature. */
|
|
Packit |
130fc8 |
static int
|
|
Packit |
130fc8 |
_message_iter_append_pyobject(DBusMessageIter *appender,
|
|
Packit |
130fc8 |
DBusSignatureIter *sig_iter,
|
|
Packit |
130fc8 |
PyObject *obj,
|
|
Packit |
130fc8 |
dbus_bool_t *more)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
int sig_type = dbus_signature_iter_get_current_type(sig_iter);
|
|
Packit |
130fc8 |
DBusBasicValue u;
|
|
Packit |
130fc8 |
int ret = -1;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#ifdef USING_DBG
|
|
Packit |
130fc8 |
fprintf(stderr, "Appending object at %p: ", obj);
|
|
Packit |
130fc8 |
PyObject_Print(obj, stderr, 0);
|
|
Packit |
130fc8 |
fprintf(stderr, " into appender at %p, dbus wants type %c\n",
|
|
Packit |
130fc8 |
appender, sig_type);
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
switch (sig_type) {
|
|
Packit |
130fc8 |
/* The numeric types are relatively simple to deal with, so are
|
|
Packit |
130fc8 |
* inlined here. */
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
case DBUS_TYPE_BOOLEAN:
|
|
Packit |
130fc8 |
if (PyObject_IsTrue(obj)) {
|
|
Packit |
130fc8 |
u.bool_val = 1;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
u.bool_val = 0;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
DBG("Performing actual append: bool(%ld)", (long)u.bool_val);
|
|
Packit |
130fc8 |
if (!dbus_message_iter_append_basic(appender, sig_type, &u.bool_val)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
ret = 0;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
case DBUS_TYPE_DOUBLE:
|
|
Packit |
130fc8 |
u.dbl = PyFloat_AsDouble(obj);
|
|
Packit |
130fc8 |
if (PyErr_Occurred()) {
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
DBG("Performing actual append: double(%f)", u.dbl);
|
|
Packit |
130fc8 |
if (!dbus_message_iter_append_basic(appender, sig_type, &u.dbl)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
ret = 0;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#ifdef WITH_DBUS_FLOAT32
|
|
Packit |
130fc8 |
case DBUS_TYPE_FLOAT:
|
|
Packit |
130fc8 |
u.dbl = PyFloat_AsDouble(obj);
|
|
Packit |
130fc8 |
if (PyErr_Occurred()) {
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
/* FIXME: DBusBasicValue will need to grow a float member if
|
|
Packit |
130fc8 |
* float32 becomes supported */
|
|
Packit |
130fc8 |
u.f = (float)u.dbl;
|
|
Packit |
130fc8 |
DBG("Performing actual append: float(%f)", u.f);
|
|
Packit |
130fc8 |
if (!dbus_message_iter_append_basic(appender, sig_type, &u.f)) {
|
|
Packit |
130fc8 |
PyErr_NoMemory();
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
ret = 0;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* The integer types are all basically the same - we delegate to
|
|
Packit |
130fc8 |
intNN_range_check() */
|
|
Packit |
130fc8 |
#define PROCESS_INTEGER(size, member) \
|
|
Packit |
130fc8 |
u.member = dbus_py_##size##_range_check(obj);\
|
|
Packit |
130fc8 |
if (u.member == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
|
|
Packit |
130fc8 |
ret = -1; \
|
|
Packit |
130fc8 |
break; \
|
|
Packit |
130fc8 |
}\
|
|
Packit |
130fc8 |
DBG("Performing actual append: " #size "(%lld)", (long long)u.member); \
|
|
Packit |
130fc8 |
if (!dbus_message_iter_append_basic(appender, sig_type, &u.member)) {\
|
|
Packit |
130fc8 |
PyErr_NoMemory();\
|
|
Packit |
130fc8 |
ret = -1;\
|
|
Packit |
130fc8 |
break;\
|
|
Packit |
130fc8 |
} \
|
|
Packit |
130fc8 |
ret = 0;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
case DBUS_TYPE_INT16:
|
|
Packit |
130fc8 |
PROCESS_INTEGER(int16, i16)
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
case DBUS_TYPE_UINT16:
|
|
Packit |
130fc8 |
PROCESS_INTEGER(uint16, u16)
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
case DBUS_TYPE_INT32:
|
|
Packit |
130fc8 |
PROCESS_INTEGER(int32, i32)
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
case DBUS_TYPE_UINT32:
|
|
Packit |
130fc8 |
PROCESS_INTEGER(uint32, u32)
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
|
|
Packit |
130fc8 |
case DBUS_TYPE_INT64:
|
|
Packit |
130fc8 |
PROCESS_INTEGER(int64, i64)
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
case DBUS_TYPE_UINT64:
|
|
Packit |
130fc8 |
PROCESS_INTEGER(uint64, u64)
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
#else
|
|
Packit |
130fc8 |
case DBUS_TYPE_INT64:
|
|
Packit |
130fc8 |
case DBUS_TYPE_UINT64:
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_NotImplementedError, "64-bit integer "
|
|
Packit |
130fc8 |
"types are not supported on this platform");
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
#undef PROCESS_INTEGER
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* Now the more complicated cases, which are delegated to helper
|
|
Packit |
130fc8 |
* functions (although in practice, the compiler will hopefully
|
|
Packit |
130fc8 |
* inline them anyway). */
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
case DBUS_TYPE_STRING:
|
|
Packit |
130fc8 |
case DBUS_TYPE_SIGNATURE:
|
|
Packit |
130fc8 |
case DBUS_TYPE_OBJECT_PATH:
|
|
Packit |
130fc8 |
ret = _message_iter_append_string(appender, sig_type, obj, TRUE);
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
case DBUS_TYPE_BYTE:
|
|
Packit |
130fc8 |
ret = _message_iter_append_byte(appender, obj);
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
case DBUS_TYPE_ARRAY:
|
|
Packit |
130fc8 |
/* 3 cases - it might actually be a dict, or it might be a byte array
|
|
Packit |
130fc8 |
* being copied from a string (for which we have a faster path),
|
|
Packit |
130fc8 |
* or it might be a generic array. */
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
sig_type = dbus_signature_iter_get_element_type(sig_iter);
|
|
Packit |
130fc8 |
if (sig_type == DBUS_TYPE_DICT_ENTRY)
|
|
Packit |
130fc8 |
ret = _message_iter_append_multi(appender, sig_iter,
|
|
Packit |
130fc8 |
DBUS_TYPE_DICT_ENTRY, obj);
|
|
Packit |
130fc8 |
else if (sig_type == DBUS_TYPE_BYTE && PyBytes_Check(obj))
|
|
Packit |
130fc8 |
ret = _message_iter_append_string_as_byte_array(appender, obj);
|
|
Packit |
130fc8 |
else
|
|
Packit |
130fc8 |
ret = _message_iter_append_multi(appender, sig_iter,
|
|
Packit |
130fc8 |
DBUS_TYPE_ARRAY, obj);
|
|
Packit |
130fc8 |
DBG("_message_iter_append_multi(): %d", ret);
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
case DBUS_TYPE_STRUCT:
|
|
Packit |
130fc8 |
ret = _message_iter_append_multi(appender, sig_iter, sig_type, obj);
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
case DBUS_TYPE_VARIANT:
|
|
Packit |
130fc8 |
ret = _message_iter_append_variant(appender, obj);
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
case DBUS_TYPE_INVALID:
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
|
|
Packit |
130fc8 |
"signature than in Python arguments");
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#if defined(DBUS_TYPE_UNIX_FD)
|
|
Packit |
130fc8 |
case DBUS_TYPE_UNIX_FD:
|
|
Packit |
130fc8 |
ret = _message_iter_append_unixfd(appender, obj);
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
default:
|
|
Packit |
130fc8 |
PyErr_Format(PyExc_TypeError, "Unknown type '\\x%x' in D-Bus "
|
|
Packit |
130fc8 |
"signature", sig_type);
|
|
Packit |
130fc8 |
ret = -1;
|
|
Packit |
130fc8 |
break;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
if (ret < 0) return -1;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBG("Advancing signature iter at %p", sig_iter);
|
|
Packit |
130fc8 |
*more = dbus_signature_iter_next(sig_iter);
|
|
Packit |
130fc8 |
#ifdef USING_DBG
|
|
Packit |
130fc8 |
DBG("- result: %ld, type %02x '%c'", (long)(*more),
|
|
Packit |
130fc8 |
(int)dbus_signature_iter_get_current_type(sig_iter),
|
|
Packit |
130fc8 |
(int)dbus_signature_iter_get_current_type(sig_iter));
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
return 0;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
PyObject *
|
|
Packit |
130fc8 |
dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs)
|
|
Packit |
130fc8 |
{
|
|
Packit |
130fc8 |
const char *signature = NULL;
|
|
Packit |
130fc8 |
PyObject *signature_obj = NULL;
|
|
Packit |
130fc8 |
DBusSignatureIter sig_iter;
|
|
Packit |
130fc8 |
DBusMessageIter appender;
|
|
Packit |
130fc8 |
static char *argnames[] = {"signature", NULL};
|
|
Packit |
130fc8 |
dbus_bool_t more;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (!self->msg) return DBusPy_RaiseUnusableMessage();
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
#ifdef USING_DBG
|
|
Packit |
130fc8 |
fprintf(stderr, "DBG/%ld: called Message_append(*", (long)getpid());
|
|
Packit |
130fc8 |
PyObject_Print(args, stderr, 0);
|
|
Packit |
130fc8 |
if (kwargs) {
|
|
Packit |
130fc8 |
fprintf(stderr, ", **");
|
|
Packit |
130fc8 |
PyObject_Print(kwargs, stderr, 0);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
fprintf(stderr, ")\n");
|
|
Packit |
130fc8 |
#endif
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* only use kwargs for this step: deliberately ignore args for now */
|
|
Packit |
130fc8 |
if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, "|z:append",
|
|
Packit |
130fc8 |
argnames, &signature)) return NULL;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (!signature) {
|
|
Packit |
130fc8 |
DBG("%s", "No signature for message, guessing...");
|
|
Packit |
130fc8 |
signature_obj = dbus_py_Message_guess_signature(NULL, args);
|
|
Packit |
130fc8 |
if (!signature_obj) return NULL;
|
|
Packit |
130fc8 |
if (PyUnicode_Check(signature_obj)) {
|
|
Packit |
130fc8 |
PyObject *signature_as_bytes;
|
|
Packit |
130fc8 |
signature_as_bytes = PyUnicode_AsUTF8String(signature_obj);
|
|
Packit |
130fc8 |
Py_CLEAR(signature_obj);
|
|
Packit |
130fc8 |
if (!signature_as_bytes)
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
signature_obj = signature_as_bytes;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
else {
|
|
Packit |
130fc8 |
assert(PyBytes_Check(signature_obj));
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
signature = PyBytes_AS_STRING(signature_obj);
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
/* from here onwards, you have to do a goto rather than returning NULL
|
|
Packit |
130fc8 |
to make sure signature_obj gets freed */
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* iterate over args and the signature, together */
|
|
Packit |
130fc8 |
if (!dbus_signature_validate(signature, NULL)) {
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
|
|
Packit |
130fc8 |
goto err;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
dbus_message_iter_init_append(self->msg, &appender);
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
if (signature[0] != '\0') {
|
|
Packit |
130fc8 |
int i = 0;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
more = TRUE;
|
|
Packit |
130fc8 |
dbus_signature_iter_init(&sig_iter, signature);
|
|
Packit |
130fc8 |
while (more) {
|
|
Packit |
130fc8 |
if (i >= PyTuple_GET_SIZE(args)) {
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
|
|
Packit |
130fc8 |
"signature than in Python arguments");
|
|
Packit |
130fc8 |
goto hosed;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
if (_message_iter_append_pyobject(&appender, &sig_iter,
|
|
Packit |
130fc8 |
PyTuple_GET_ITEM(args, i),
|
|
Packit |
130fc8 |
&more) < 0) {
|
|
Packit |
130fc8 |
goto hosed;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
i++;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
if (i < PyTuple_GET_SIZE(args)) {
|
|
Packit |
130fc8 |
PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
|
|
Packit |
130fc8 |
"signature than in Python arguments");
|
|
Packit |
130fc8 |
goto hosed;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* success! */
|
|
Packit |
130fc8 |
Py_CLEAR(signature_obj);
|
|
Packit |
130fc8 |
Py_RETURN_NONE;
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
hosed:
|
|
Packit |
130fc8 |
/* "If appending any of the arguments fails due to lack of memory,
|
|
Packit |
130fc8 |
* generally the message is hosed and you have to start over" -libdbus docs
|
|
Packit |
130fc8 |
* Enforce this by throwing away the message structure.
|
|
Packit |
130fc8 |
*/
|
|
Packit |
130fc8 |
dbus_message_unref(self->msg);
|
|
Packit |
130fc8 |
self->msg = NULL;
|
|
Packit |
130fc8 |
err:
|
|
Packit |
130fc8 |
Py_CLEAR(signature_obj);
|
|
Packit |
130fc8 |
return NULL;
|
|
Packit |
130fc8 |
}
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
/* vim:set ft=c cino< sw=4 sts=4 et: */
|