From b24fd9633cabe1d95cde173a04e9a49833b06a26 Mon Sep 17 00:00:00 2001 From: Simon van der Linden Date: Sun, 8 Nov 2009 12:35:08 +0100 Subject: Initial import --- gi/pygi-argument.c | 1976 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1976 insertions(+) create mode 100644 gi/pygi-argument.c (limited to 'gi/pygi-argument.c') diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c new file mode 100644 index 0000000..34d68e2 --- /dev/null +++ b/gi/pygi-argument.c @@ -0,0 +1,1976 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 Johan Dahlin + * + * pygi-argument.c: GArgument - PyObject conversion functions. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "pygi-private.h" + +#include +#include + +#include +#include + +static void +_pygi_g_type_tag_py_bounds (GITypeTag type_tag, + PyObject **lower, + PyObject **upper) +{ + switch(type_tag) { + case GI_TYPE_TAG_INT8: + *lower = PyInt_FromLong(-128); + *upper = PyInt_FromLong(127); + break; + case GI_TYPE_TAG_UINT8: + *upper = PyInt_FromLong(255); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_INT16: + *lower = PyInt_FromLong(-32768); + *upper = PyInt_FromLong(32767); + break; + case GI_TYPE_TAG_UINT16: + *upper = PyInt_FromLong(65535); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_INT32: + *lower = PyInt_FromLong(-2147483648); + *upper = PyInt_FromLong(2147483647); + break; + case GI_TYPE_TAG_UINT32: + /* Note: On 32-bit archs, this number doesn't fit in a long. */ + *upper = PyLong_FromLongLong(4294967295); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_INT64: + /* Note: On 32-bit archs, these numbers don't fit in a long. */ + *lower = PyLong_FromLongLong(-9223372036854775808u); + *upper = PyLong_FromLongLong(9223372036854775807); + break; + case GI_TYPE_TAG_UINT64: + *upper = PyLong_FromUnsignedLongLong(18446744073709551615u); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_SHORT: + *lower = PyInt_FromLong(G_MINSHORT); + *upper = PyInt_FromLong(G_MAXSHORT); + break; + case GI_TYPE_TAG_USHORT: + *upper = PyInt_FromLong(G_MAXUSHORT); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_INT: + *lower = PyInt_FromLong(G_MININT); + *upper = PyInt_FromLong(G_MAXINT); + break; + case GI_TYPE_TAG_UINT: + /* Note: On 32-bit archs, this number doesn't fit in a long. */ + *upper = PyLong_FromLongLong(G_MAXUINT); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_LONG: + case GI_TYPE_TAG_SSIZE: + *lower = PyInt_FromLong(G_MINLONG); + *upper = PyInt_FromLong(G_MAXLONG); + break; + case GI_TYPE_TAG_ULONG: + case GI_TYPE_TAG_SIZE: + *upper = PyLong_FromUnsignedLongLong(G_MAXULONG); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_FLOAT: + *upper = PyFloat_FromDouble(G_MAXFLOAT); + *lower = PyFloat_FromDouble(-G_MAXFLOAT); + break; + case GI_TYPE_TAG_DOUBLE: + *upper = PyFloat_FromDouble(G_MAXDOUBLE); + *lower = PyFloat_FromDouble(-G_MAXDOUBLE); + break; + default: + PyErr_SetString(PyExc_TypeError, "Non-numeric type tag"); + *lower = *upper = NULL; + return; + } +} + +gint +_pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info, + gboolean is_instance, + PyObject *object) +{ + gint retval; + + GType g_type; + PyObject *py_type; + gchar *type_name_expected = NULL; + + g_type = g_registered_type_info_get_g_type(info); + + if (g_type != G_TYPE_NONE) { + py_type = _pygi_type_get_from_g_type(g_type); + } else { + py_type = _pygi_type_import_by_gi_info((GIBaseInfo *)info); + } + + if (py_type == NULL) { + return FALSE; + } + + g_assert(PyType_Check(py_type)); + + if (is_instance) { + retval = PyObject_IsInstance(object, py_type); + if (!retval) { + type_name_expected = _pygi_g_base_info_get_fullname( + (GIBaseInfo *)info); + } + } else { + if (!PyObject_Type(py_type)) { + type_name_expected = "type"; + retval = 0; + } else if (!PyType_IsSubtype((PyTypeObject *)object, + (PyTypeObject *)py_type)) { + type_name_expected = _pygi_g_base_info_get_fullname( + (GIBaseInfo *)info); + retval = 0; + } else { + retval = 1; + } + } + + Py_DECREF(py_type); + + if (!retval) { + PyTypeObject *object_type; + + if (type_name_expected == NULL) { + return -1; + } + + object_type = (PyTypeObject *)PyObject_Type(object); + if (object_type == NULL) { + return -1; + } + + PyErr_Format(PyExc_TypeError, "Must be %s, not %s", + type_name_expected, object_type->tp_name); + + g_free(type_name_expected); + } + + return retval; +} + +gint +_pygi_g_type_info_check_object (GITypeInfo *type_info, + gboolean may_be_null, + PyObject *object) +{ + GITypeTag type_tag; + gboolean is_pointer; + gint retval = 1; + + type_tag = g_type_info_get_tag(type_info); + is_pointer = g_type_info_is_pointer(type_info); + + if (is_pointer && may_be_null && object == Py_None) { + return retval; + } + + switch (type_tag) { + case GI_TYPE_TAG_VOID: + if (object != Py_None) { + PyErr_Format(PyExc_TypeError, "Must be %s, not %s", + Py_None->ob_type->tp_name, object->ob_type->tp_name); + retval = 0; + } + break; + case GI_TYPE_TAG_BOOLEAN: + /* No check; every Python object has a truth value. */ + break; + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_SHORT: + case GI_TYPE_TAG_USHORT: + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_LONG: + case GI_TYPE_TAG_ULONG: + case GI_TYPE_TAG_SSIZE: + case GI_TYPE_TAG_SIZE: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + { + PyObject *number, *lower, *upper; + + if (!PyNumber_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be number, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + + if (type_tag == GI_TYPE_TAG_FLOAT || type_tag == GI_TYPE_TAG_DOUBLE) { + number = PyNumber_Float(object); + } else { + number = PyNumber_Int(object); + } + + _pygi_g_type_tag_py_bounds(type_tag, &lower, &upper); + + if (lower == NULL || upper == NULL || number == NULL) { + retval = -1; + goto check_number_release; + } + + /* Check bounds */ + if (PyObject_Compare(lower, number) > 0 + || PyObject_Compare(upper, number) < 0) { + PyObject *lower_str; + PyObject *upper_str; + + if (PyErr_Occurred()) { + retval = -1; + goto check_number_release; + } + + lower_str = PyObject_Str(lower); + upper_str = PyObject_Str(upper); + if (lower_str == NULL || upper_str == NULL) { + retval = -1; + goto check_number_error_release; + } + + PyErr_Format(PyExc_ValueError, "Must range from %s to %s", + PyString_AS_STRING(lower_str), + PyString_AS_STRING(upper_str)); + + retval = 0; + +check_number_error_release: + Py_XDECREF(lower_str); + Py_XDECREF(upper_str); + } + +check_number_release: + Py_XDECREF(number); + Py_XDECREF(lower); + Py_XDECREF(upper); + break; + } + case GI_TYPE_TAG_TIME_T: + if (!PyDateTime_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be datetime.datetime, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + break; + case GI_TYPE_TAG_GTYPE: + { + gint is_instance; + + is_instance = PyObject_IsInstance(object, (PyObject *)&PyGTypeWrapper_Type); + if (is_instance < 0) { + retval = -1; + break; + } + + if (!is_instance && (!PyType_Check(object) || pyg_type_from_object(object) == 0)) { + PyErr_Format(PyExc_TypeError, "Must be gobject.GType, not %s", + object->ob_type->tp_name); + retval = 0; + } + break; + } + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + if (!PyString_Check(object) && (!may_be_null || object != Py_None)) { + PyErr_Format(PyExc_TypeError, "Must be string, not %s", + object->ob_type->tp_name); + retval = 0; + } + break; + case GI_TYPE_TAG_ARRAY: + { + gssize fixed_size; + Py_ssize_t length; + GITypeInfo *item_type_info; + Py_ssize_t i; + + if (!PySequence_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be sequence, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + + length = PySequence_Length(object); + if (length < 0) { + retval = -1; + break; + } + + fixed_size = g_type_info_get_array_fixed_size(type_info); + if (fixed_size >= 0 && length != fixed_size) { + PyErr_Format(PyExc_ValueError, "Must contain %zd items, not %zd", + fixed_size, length); + retval = 0; + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + for (i = 0; i < length; i++) { + PyObject *item; + + item = PySequence_GetItem(object, i); + if (item == NULL) { + retval = -1; + break; + } + + retval = _pygi_g_type_info_check_object(item_type_info, FALSE, item); + + Py_DECREF(item); + + if (retval < 0) { + break; + } + if (!retval) { + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + + break; + } + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *info; + GIInfoType info_type; + + info = g_type_info_get_interface(type_info); + g_assert(info != NULL); + + info_type = g_base_info_get_type(info); + + switch (info_type) { + case GI_INFO_TYPE_CALLBACK: + /* TODO */ + PyErr_SetString(PyExc_NotImplementedError, "callback marshalling is not supported yet"); + break; + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + retval = _pygi_g_registered_type_info_check_object((GIRegisteredTypeInfo *)info, TRUE, object); + break; + case GI_INFO_TYPE_STRUCT: + { + GType type; + + /* Handle special cases. */ + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info); + if (g_type_is_a(type, G_TYPE_VALUE)) { + GType object_type; + object_type = pyg_type_from_object((PyObject *)object->ob_type); + if (object_type == G_TYPE_INVALID) { + PyErr_Format(PyExc_TypeError, "Must be of a known GType, not %s", + object->ob_type->tp_name); + retval = 0; + } + break; + } else if (g_type_is_a(type, G_TYPE_CLOSURE)) { + if (!PyCallable_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be callable, not %s", + object->ob_type->tp_name); + retval = 0; + } + break; + } + + /* Fallback. */ + } + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_OBJECT: + retval = _pygi_g_registered_type_info_check_object((GIRegisteredTypeInfo *)info, TRUE, object); + break; + case GI_INFO_TYPE_UNION: + /* TODO */ + PyErr_SetString(PyExc_NotImplementedError, "union marshalling is not supported yet"); + break; + default: + g_assert_not_reached(); + } + + g_base_info_unref(info); + break; + } + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + { + Py_ssize_t length; + GITypeInfo *item_type_info; + Py_ssize_t i; + + if (!PySequence_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be sequence, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + + length = PySequence_Length(object); + if (length < 0) { + retval = -1; + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + for (i = 0; i < length; i++) { + PyObject *item; + + item = PySequence_GetItem(object, i); + if (item == NULL) { + retval = -1; + break; + } + + retval = _pygi_g_type_info_check_object(item_type_info, FALSE, item); + + Py_DECREF(item); + + if (retval < 0) { + break; + } + if (!retval) { + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + break; + } + case GI_TYPE_TAG_GHASH: + { + Py_ssize_t length; + PyObject *keys; + PyObject *values; + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + Py_ssize_t i; + + if (!PyMapping_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be mapping, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + + length = PyMapping_Length(object); + if (length < 0) { + retval = -1; + break; + } + + keys = PyMapping_Keys(object); + if (keys == NULL) { + retval = -1; + break; + } + + values = PyMapping_Values(object); + if (values == NULL) { + retval = -1; + Py_DECREF(keys); + break; + } + + key_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(key_type_info != NULL); + + value_type_info = g_type_info_get_param_type(type_info, 1); + g_assert(value_type_info != NULL); + + for (i = 0; i < length; i++) { + PyObject *key; + PyObject *value; + + key = PyList_GET_ITEM(keys, i); + value = PyList_GET_ITEM(values, i); + + retval = _pygi_g_type_info_check_object(key_type_info, FALSE, key); + if (retval < 0) { + break; + } + if (!retval) { + _PyGI_ERROR_PREFIX("Key %zd :", i); + break; + } + + retval = _pygi_g_type_info_check_object(value_type_info, FALSE, value); + if (retval < 0) { + break; + } + if (!retval) { + _PyGI_ERROR_PREFIX("Value %zd :", i); + break; + } + } + + g_base_info_unref((GIBaseInfo *)key_type_info); + g_base_info_unref((GIBaseInfo *)value_type_info); + Py_DECREF(values); + Py_DECREF(keys); + break; + } + case GI_TYPE_TAG_ERROR: + PyErr_SetString(PyExc_NotImplementedError, "Error marshalling is not supported yet"); + /* TODO */ + break; + } + + return retval; +} + +GArray * +_pygi_argument_to_array (GArgument *arg, + GArgument *args[], + GITypeInfo *type_info) +{ + GITypeInfo *item_type_info; + gboolean is_zero_terminated; + gsize item_size; + gssize length; + GArray *g_array; + + is_zero_terminated = g_type_info_is_zero_terminated(type_info); + item_type_info = g_type_info_get_param_type(type_info, 0); + + item_size = _pygi_g_type_info_size(item_type_info); + + g_base_info_unref((GIBaseInfo *)item_type_info); + + if (is_zero_terminated) { + length = g_strv_length(arg->v_pointer); + } else { + length = g_type_info_get_array_fixed_size(type_info); + if (length < 0) { + gint length_arg_pos; + + length_arg_pos = g_type_info_get_array_length(type_info); + g_assert(length_arg_pos >= 0); + + /* FIXME: Take into account the type of the argument. */ + length = args[length_arg_pos]->v_int; + } + } + + g_array = g_array_new(is_zero_terminated, FALSE, item_size); + + g_array->data = arg->v_pointer; + g_array->len = length; + + return g_array; +} + +GArgument +_pygi_argument_from_object (PyObject *object, + GITypeInfo *type_info, + GITransfer transfer) +{ + GArgument arg; + GITypeTag type_tag; + gboolean is_pointer; + + type_tag = g_type_info_get_tag(type_info); + is_pointer = g_type_info_is_pointer(type_info); + + if (object == Py_None && is_pointer + && type_tag != GI_TYPE_TAG_BOOLEAN) { /* We want None == FALSE. */ + arg.v_pointer = NULL; + return arg; + } + + switch (type_tag) { + case GI_TYPE_TAG_VOID: + arg.v_pointer = NULL; + break; + case GI_TYPE_TAG_BOOLEAN: + { + gboolean value; + + value = PyObject_IsTrue(object); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(gboolean, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(gboolean *)arg.v_pointer = value; + } else { + arg.v_boolean = value; + } + + break; + } + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_SHORT: + case GI_TYPE_TAG_USHORT: + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_LONG: + case GI_TYPE_TAG_SSIZE: + { + PyObject *int_; + glong value; + + int_ = PyNumber_Int(object); + if (int_ == NULL) { + break; + } + + value = PyInt_AsLong(int_); + Py_DECREF(int_); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(glong, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(glong *)arg.v_pointer = value; + } else { + arg.v_long = value; + } + + break; + } + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_ULONG: + case GI_TYPE_TAG_SIZE: + { + PyObject *number; + guint64 value; + + number = PyNumber_Int(object); + if (number == NULL) { + break; + } + + if (PyInt_Check(number)) { + value = PyInt_AS_LONG(number); + } else { + value = PyLong_AsUnsignedLongLong(number); + } + + Py_DECREF(number); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(guint64, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(guint64 *)arg.v_pointer = value; + } else { + arg.v_uint64 = value; + } + + break; + } + case GI_TYPE_TAG_INT64: + { + PyObject *number; + gint64 value; + + number = PyNumber_Int(object); + if (number == NULL) { + break; + } + + if (PyInt_Check(number)) { + value = PyInt_AS_LONG(number); + } else { + value = PyLong_AsLongLong(number); + } + + Py_DECREF(number); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(gint64, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(gint64 *)arg.v_pointer = value; + } else { + arg.v_int64 = value; + } + + break; + } + case GI_TYPE_TAG_FLOAT: + { + PyObject *float_; + gfloat value; + + float_ = PyNumber_Float(object); + if (float_ == NULL) { + break; + } + + value = (float)PyFloat_AsDouble(float_); + Py_DECREF(float_); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(gfloat, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(gfloat *)arg.v_pointer = value; + } else { + arg.v_float = value; + } + + break; + } + case GI_TYPE_TAG_DOUBLE: + { + PyObject *float_; + gdouble value; + + float_ = PyNumber_Float(object); + if (float_ == NULL) { + break; + } + + value = PyFloat_AsDouble(float_); + Py_DECREF(float_); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(gdouble, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(gdouble *)arg.v_pointer = value; + } else { + arg.v_double = value; + } + + break; + } + case GI_TYPE_TAG_TIME_T: + { + PyDateTime_DateTime *py_datetime; + struct tm datetime; + time_t time_; + + py_datetime = (PyDateTime_DateTime *)object; + + if (py_datetime->hastzinfo) { + if (PyErr_WarnEx(NULL, "tzinfo ignored; only local time is supported", 1) < 0) { + break; + } + } + + datetime.tm_sec = PyDateTime_DATE_GET_SECOND(py_datetime); + datetime.tm_min = PyDateTime_DATE_GET_MINUTE(py_datetime); + datetime.tm_hour = PyDateTime_DATE_GET_HOUR(py_datetime); + datetime.tm_mday = PyDateTime_GET_DAY(py_datetime); + datetime.tm_mon = PyDateTime_GET_MONTH(py_datetime) - 1; + datetime.tm_year = PyDateTime_GET_YEAR(py_datetime) - 1900; + datetime.tm_isdst = -1; + + time_ = mktime(&datetime); + if (time_ == -1) { + PyErr_SetString(PyExc_RuntimeError, "datetime conversion failed"); + break; + } + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(time_t, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(time_t *)arg.v_pointer = time_; + } else { + arg.v_long = time_; + } + + break; + } + case GI_TYPE_TAG_GTYPE: + { + GType type; + + type = pyg_type_from_object(object); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(GType, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(GType *)arg.v_pointer = type; + } else { + arg.v_long = type; + } + + break; + } + case GI_TYPE_TAG_UTF8: + { + const gchar *string; + + g_assert(is_pointer); + + string = PyString_AsString(object); + + /* Don't need to check for errors, since g_strdup is NULL-proof. */ + arg.v_string = g_strdup(string); + break; + } + case GI_TYPE_TAG_FILENAME: + { + GError *error = NULL; + const gchar *string; + + g_assert(is_pointer); + + string = PyString_AsString(object); + if (string == NULL) { + break; + } + + arg.v_string = g_filename_from_utf8(string, -1, NULL, NULL, &error); + if (arg.v_string == NULL) { + PyErr_SetString(PyExc_Exception, error->message); + /* TODO: Convert the error to an exception. */ + } + + break; + } + case GI_TYPE_TAG_ARRAY: + { + Py_ssize_t length; + gboolean is_zero_terminated; + GITypeInfo *item_type_info; + gsize item_size; + GArray *array; + GITransfer item_transfer; + Py_ssize_t i; + + length = PySequence_Length(object); + if (length < 0) { + break; + } + + is_zero_terminated = g_type_info_is_zero_terminated(type_info); + item_type_info = g_type_info_get_param_type(type_info, 0); + + item_size = _pygi_g_type_info_size(item_type_info); + + array = g_array_sized_new(is_zero_terminated, FALSE, item_size, length); + if (array == NULL) { + g_base_info_unref((GIBaseInfo *)item_type_info); + PyErr_NoMemory(); + break; + } + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for (i = 0; i < length; i++) { + PyObject *py_item; + GArgument item; + + py_item = PySequence_GetItem(object, i); + if (py_item == NULL) { + goto array_item_error; + } + + item = _pygi_argument_from_object(py_item, item_type_info, item_transfer); + + Py_DECREF(py_item); + + if (PyErr_Occurred()) { + goto array_item_error; + } + + g_array_insert_val(array, i, item); + continue; + +array_item_error: + /* Free everything we have converted so far. */ + _pygi_argument_release((GArgument *)&array, type_info, + GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + array = NULL; + + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + + arg.v_pointer = array; + + g_base_info_unref((GIBaseInfo *)item_type_info); + break; + } + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *info; + GIInfoType info_type; + + info = g_type_info_get_interface(type_info); + info_type = g_base_info_get_type(info); + + switch (info_type) { + case GI_INFO_TYPE_CALLBACK: + PyErr_SetString(PyExc_NotImplementedError, "callback marshalling is not supported yet"); + /* TODO */ + break; + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_STRUCT: + { + GType type; + + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info); + + /* Handle special cases first. */ + if (g_type_is_a(type, G_TYPE_VALUE)) { + GValue *value; + GType object_type; + gint retval; + + object_type = pyg_type_from_object((PyObject *)object->ob_type); + if (object_type == G_TYPE_INVALID) { + PyErr_SetString(PyExc_RuntimeError, "unable to retrieve object's GType"); + break; + } + + g_assert(is_pointer); + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + + value = g_slice_new0(GValue); + g_value_init(value, object_type); + + retval = pyg_value_from_pyobject(value, object); + if (retval < 0) { + g_slice_free(GValue, value); + PyErr_SetString(PyExc_RuntimeError, "PyObject conversion to GValue failed"); + break; + } + + arg.v_pointer = value; + } else if (g_type_is_a(type, G_TYPE_CLOSURE)) { + GClosure *closure; + + g_assert(is_pointer); + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + + closure = pyg_closure_new(object, NULL, NULL); + if (closure == NULL) { + PyErr_SetString(PyExc_RuntimeError, "PyObject conversion to GClosure failed"); + break; + } + + arg.v_pointer = closure; + } else if (g_type_is_a(type, G_TYPE_BOXED)) { + g_assert(is_pointer); + arg.v_pointer = pyg_boxed_get(object, void); + if (transfer == GI_TRANSFER_EVERYTHING) { + arg.v_pointer = g_boxed_copy(type, arg.v_pointer); + } + } else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) { + g_warn_if_fail(!is_pointer || transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = pyg_pointer_get(object, void); + } else { + PyErr_Format(PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name(type)); + } + + break; + } + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + { + PyObject *int_; + glong value; + + int_ = PyNumber_Int(object); + if (int_ == NULL) { + break; + } + + value = PyInt_AsLong(int_); + Py_DECREF(int_); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(glong, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(glong *)arg.v_pointer = value; + } else { + arg.v_long = value; + } + + break; + } + case GI_INFO_TYPE_OBJECT: + g_assert(is_pointer); + + arg.v_pointer = pygobject_get(object); + if (transfer == GI_TRANSFER_EVERYTHING) { + g_object_ref(arg.v_pointer); + } + + break; + case GI_INFO_TYPE_UNION: + PyErr_SetString(PyExc_NotImplementedError, "union marshalling is not supported yet"); + /* TODO */ + break; + default: + g_assert_not_reached(); + } + g_base_info_unref(info); + break; + } + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + { + Py_ssize_t length; + GITypeInfo *item_type_info; + GSList *list = NULL; + GITransfer item_transfer; + Py_ssize_t i; + + g_assert(is_pointer); + + length = PySequence_Length(object); + if (length < 0) { + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for (i = length - 1; i >= 0; i--) { + PyObject *py_item; + GArgument item; + + py_item = PySequence_GetItem(object, i); + if (py_item == NULL) { + goto list_item_error; + } + + item = _pygi_argument_from_object(py_item, item_type_info, item_transfer); + + Py_DECREF(py_item); + + if (PyErr_Occurred()) { + goto list_item_error; + } + + if (type_tag == GI_TYPE_TAG_GLIST) { + list = (GSList *)g_list_prepend((GList *)list, item.v_pointer); + } else { + list = g_slist_prepend(list, item.v_pointer); + } + + continue; + +list_item_error: + /* Free everything we have converted so far. */ + _pygi_argument_release((GArgument *)&list, type_info, + GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + list = NULL; + + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + + arg.v_pointer = list; + + g_base_info_unref((GIBaseInfo *)item_type_info); + + break; + } + case GI_TYPE_TAG_GHASH: + { + Py_ssize_t length; + PyObject *keys; + PyObject *values; + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + GITypeTag key_type_tag; + GHashFunc hash_func; + GEqualFunc equal_func; + GHashTable *hash_table; + GITransfer item_transfer; + Py_ssize_t i; + + g_assert(is_pointer); + + length = PyMapping_Length(object); + if (length < 0) { + break; + } + + keys = PyMapping_Keys(object); + if (keys == NULL) { + break; + } + + values = PyMapping_Values(object); + if (values == NULL) { + Py_DECREF(keys); + break; + } + + key_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(key_type_info != NULL); + + value_type_info = g_type_info_get_param_type(type_info, 1); + g_assert(value_type_info != NULL); + + key_type_tag = g_type_info_get_tag(key_type_info); + + switch(key_type_tag) { + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + hash_func = g_str_hash; + equal_func = g_str_equal; + break; + default: + hash_func = NULL; + equal_func = NULL; + } + + hash_table = g_hash_table_new(hash_func, equal_func); + if (hash_table == NULL) { + PyErr_NoMemory(); + goto hash_table_release; + } + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for (i = 0; i < length; i++) { + PyObject *py_key; + PyObject *py_value; + GArgument key; + GArgument value; + + py_key = PyList_GET_ITEM(keys, i); + py_value = PyList_GET_ITEM(values, i); + + key = _pygi_argument_from_object(py_key, key_type_info, item_transfer); + if (PyErr_Occurred()) { + goto hash_table_item_error; + } + + value = _pygi_argument_from_object(py_value, value_type_info, item_transfer); + if (PyErr_Occurred()) { + _pygi_argument_release(&key, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + goto hash_table_item_error; + } + + g_hash_table_insert(hash_table, key.v_pointer, value.v_pointer); + continue; + +hash_table_item_error: + /* Free everything we have converted so far. */ + _pygi_argument_release((GArgument *)&hash_table, type_info, + GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + hash_table = NULL; + + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + + arg.v_pointer = hash_table; + +hash_table_release: + g_base_info_unref((GIBaseInfo *)key_type_info); + g_base_info_unref((GIBaseInfo *)value_type_info); + Py_DECREF(keys); + Py_DECREF(values); + break; + } + case GI_TYPE_TAG_ERROR: + PyErr_SetString(PyExc_NotImplementedError, "error marshalling is not supported yet"); + /* TODO */ + break; + } + + return arg; +} + +PyObject * +_pygi_argument_to_object (GArgument *arg, + GITypeInfo *type_info, + GITransfer transfer) +{ + GITypeTag type_tag; + gboolean is_pointer; + PyObject *object = NULL; + + type_tag = g_type_info_get_tag(type_info); + is_pointer = g_type_info_is_pointer(type_info); + + if (is_pointer && arg->v_pointer == NULL) { + Py_RETURN_NONE; + } + + switch (type_tag) { + case GI_TYPE_TAG_VOID: + Py_INCREF(Py_None); + object = Py_None; + break; + case GI_TYPE_TAG_BOOLEAN: + { + gboolean value; + value = is_pointer ? *(gboolean *)arg->v_pointer : arg->v_boolean; + object = PyBool_FromLong(value); + break; + } + case GI_TYPE_TAG_INT8: + { + gint8 value; + value = is_pointer ? *(gint8 *)arg->v_pointer : arg->v_int8; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_UINT8: + { + guint8 value; + value = is_pointer ? *(guint8 *)arg->v_pointer : arg->v_uint8; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_INT16: + { + gint16 value; + value = is_pointer ? *(gint16 *)arg->v_pointer : arg->v_int16; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_UINT16: + { + guint16 value; + value = is_pointer ? *(guint16 *)arg->v_pointer : arg->v_uint16; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_INT32: + { + gint32 value; + value = is_pointer ? *(gint32 *)arg->v_pointer : arg->v_int32; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_UINT32: + { + guint32 value; + value = is_pointer ? *(guint32 *)arg->v_pointer : arg->v_uint32; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_INT64: + { + gint64 value; + value = is_pointer ? *(gint64 *)arg->v_pointer : arg->v_int64; + object = PyLong_FromLongLong(value); + break; + } + case GI_TYPE_TAG_UINT64: + { + guint64 value; + value = is_pointer ? *(guint64 *)arg->v_pointer : arg->v_uint64; + object = PyLong_FromUnsignedLongLong(value); + break; + } + case GI_TYPE_TAG_SHORT: + { + gshort value; + value = is_pointer ? *(gshort *)arg->v_pointer : arg->v_short; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_USHORT: + { + gushort value; + value = is_pointer ? *(gushort *)arg->v_pointer : arg->v_ushort; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_INT: + { + gint value; + value = is_pointer ? *(gint *)arg->v_pointer : arg->v_int; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_UINT: + { + guint value; + value = is_pointer ? *(guint *)arg->v_pointer : arg->v_uint; + object = PyLong_FromLongLong(value); + break; + } + case GI_TYPE_TAG_LONG: + { + glong value; + value = is_pointer ? *(glong *)arg->v_pointer : arg->v_long; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_ULONG: + { + gulong value; + value = is_pointer ? *(gulong *)arg->v_pointer : arg->v_ulong; + object = PyLong_FromUnsignedLongLong(value); + break; + } + case GI_TYPE_TAG_SSIZE: + { + gssize value; + value = is_pointer ? *(gssize *)arg->v_pointer : arg->v_ssize; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_SIZE: + { + gsize value; + value = is_pointer ? *(gsize *)arg->v_pointer : arg->v_size; + object = PyLong_FromUnsignedLongLong(value); + break; + } + case GI_TYPE_TAG_FLOAT: + { + gfloat value; + value = is_pointer ? *(gfloat *)arg->v_pointer : arg->v_float; + object = PyFloat_FromDouble(value); + break; + } + case GI_TYPE_TAG_DOUBLE: + { + gdouble value; + value = is_pointer ? *(gdouble *)arg->v_pointer : arg->v_double; + object = PyFloat_FromDouble(value); + break; + } + case GI_TYPE_TAG_TIME_T: + { + time_t *time_; + struct tm *datetime; + time_ = is_pointer ? arg->v_pointer : &arg->v_long; + datetime = localtime(time_); + object = PyDateTime_FromDateAndTime( + datetime->tm_year + 1900, + datetime->tm_mon + 1, + datetime->tm_mday, + datetime->tm_hour, + datetime->tm_min, + datetime->tm_sec, + 0); + break; + } + case GI_TYPE_TAG_GTYPE: + { + GType type; + type = is_pointer ? *(GType *)arg->v_pointer : arg->v_long; + object = pyg_type_wrapper_new(type); + break; + } + case GI_TYPE_TAG_UTF8: + g_assert(is_pointer); + object = PyString_FromString(arg->v_string); + break; + case GI_TYPE_TAG_FILENAME: + { + GError *error = NULL; + gchar *string; + + g_assert(is_pointer); + + string = g_filename_to_utf8(arg->v_string, -1, NULL, NULL, &error); + if (string == NULL) { + PyErr_SetString(PyExc_Exception, error->message); + /* TODO: Convert the error to an exception. */ + break; + } + + object = PyString_FromString(string); + + g_free(string); + + break; + } + case GI_TYPE_TAG_ARRAY: + { + GArray *array; + GITypeInfo *item_type_info; + GITransfer item_transfer; + gsize i; + + array = arg->v_pointer; + + object = PyTuple_New(array->len); + if (object == NULL) { + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for(i = 0; i < array->len; i++) { + GArgument item; + PyObject *py_item; + + item = _g_array_index(array, GArgument, i); + py_item = _pygi_argument_to_object(&item, item_type_info, item_transfer); + if (py_item == NULL) { + Py_CLEAR(object); + _PyGI_ERROR_PREFIX("Item %zu: ", i); + break; + } + + PyTuple_SET_ITEM(object, i, py_item); + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + break; + } + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *info; + GIInfoType info_type; + + info = g_type_info_get_interface(type_info); + info_type = g_base_info_get_type(info); + + switch (info_type) { + case GI_INFO_TYPE_CALLBACK: + { + PyErr_SetString(PyExc_NotImplementedError, "callback marshalling is not supported yet"); + /* TODO */ + break; + } + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_STRUCT: + { + GType type; + + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info); + if (g_type_is_a(type, G_TYPE_VALUE)) { + g_assert(is_pointer); + object = pyg_value_as_pyobject(arg->v_pointer, FALSE); + } else if (g_type_is_a(type, G_TYPE_BOXED)) { + g_assert(is_pointer); + object = pyg_boxed_new(type, arg->v_pointer, FALSE, transfer == GI_TRANSFER_EVERYTHING); + } else if (g_type_is_a(type, G_TYPE_POINTER)) { + PyObject *py_type; + + g_assert(is_pointer); + + py_type = _pygi_type_get_from_g_type(type); + + if (py_type == NULL || !PyType_IsSubtype((PyTypeObject *)type, &PyGIStruct_Type)) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + object = pyg_pointer_new(type, arg->v_pointer); + } else { + object = _pygi_struct_new((PyTypeObject *)py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING); + } + + Py_XDECREF(py_type); + } else if (type == G_TYPE_NONE) { + PyObject *py_type; + + py_type = _pygi_type_import_by_gi_info(info); + if (py_type == NULL) { + break; + } + + object = _pygi_struct_new((PyTypeObject *)py_type, arg->v_pointer, + transfer == GI_TRANSFER_EVERYTHING); + + Py_DECREF(py_type); + } else { + PyErr_Format(PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name(type)); + } + + break; + } + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + { + GType type; + glong value; + + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info); + value = is_pointer ? *(glong *)arg->v_pointer : arg->v_long; + + if (info_type == GI_INFO_TYPE_ENUM) { + object = pyg_enum_from_gtype(type, value); + } else { + object = pyg_flags_from_gtype(type, value); + } + + break; + } + case GI_INFO_TYPE_OBJECT: + g_assert(is_pointer); + object = pygobject_new(arg->v_pointer); + break; + case GI_INFO_TYPE_UNION: + /* TODO */ + PyErr_SetString(PyExc_NotImplementedError, "union marshalling is not supported yet"); + break; + default: + g_assert_not_reached(); + } + + g_base_info_unref(info); + break; + } + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + { + GSList *list; + gsize length; + GITypeInfo *item_type_info; + GITransfer item_transfer; + gsize i; + + g_assert(is_pointer); + + list = arg->v_pointer; + length = g_slist_length(list); + + object = PyList_New(length); + if (object == NULL) { + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for (i = 0; list != NULL; list = g_slist_next(list), i++) { + GArgument item; + PyObject *py_item; + + item.v_pointer = list->data; + + py_item = _pygi_argument_to_object(&item, item_type_info, item_transfer); + if (py_item == NULL) { + Py_CLEAR(object); + _PyGI_ERROR_PREFIX("Item %zu: ", i); + break; + } + + PyList_SET_ITEM(object, i, py_item); + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + break; + } + case GI_TYPE_TAG_GHASH: + { + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + GITransfer item_transfer; + GHashTableIter hash_table_iter; + GArgument key; + GArgument value; + + g_assert(is_pointer); + + object = PyDict_New(); + if (object == NULL) { + break; + } + + key_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(key_type_info != NULL); + + value_type_info = g_type_info_get_param_type(type_info, 1); + g_assert(value_type_info != NULL); + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + g_hash_table_iter_init(&hash_table_iter, (GHashTable *)arg->v_pointer); + while (g_hash_table_iter_next(&hash_table_iter, &key.v_pointer, &value.v_pointer)) { + PyObject *py_key; + PyObject *py_value; + int retval; + + py_key = _pygi_argument_to_object(&key, key_type_info, item_transfer); + if (py_key == NULL) { + break; + } + + py_value = _pygi_argument_to_object(&value, value_type_info, item_transfer); + if (py_value == NULL) { + Py_DECREF(py_key); + break; + } + + retval = PyDict_SetItem(object, py_key, py_value); + + Py_DECREF(py_key); + Py_DECREF(py_value); + + if (retval < 0) { + Py_CLEAR(object); + break; + } + } + + g_base_info_unref((GIBaseInfo *)key_type_info); + g_base_info_unref((GIBaseInfo *)value_type_info); + break; + } + case GI_TYPE_TAG_ERROR: + /* Errors should be handled in the invoke wrapper. */ + g_assert_not_reached(); + } + + return object; +} + +void +_pygi_argument_release (GArgument *arg, + GITypeInfo *type_info, + GITransfer transfer, + GIDirection direction) +{ + GITypeTag type_tag; + gboolean is_pointer; + + type_tag = g_type_info_get_tag(type_info); + is_pointer = g_type_info_is_pointer(type_info); + + if (is_pointer && arg->v_pointer == NULL) { + return; + } + + switch(type_tag) { + case GI_TYPE_TAG_VOID: + case GI_TYPE_TAG_BOOLEAN: + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_SHORT: + case GI_TYPE_TAG_USHORT: + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_LONG: + case GI_TYPE_TAG_ULONG: + case GI_TYPE_TAG_SSIZE: + case GI_TYPE_TAG_SIZE: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + case GI_TYPE_TAG_TIME_T: + case GI_TYPE_TAG_GTYPE: + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + g_free(arg->v_pointer); + } + } + break; + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_UTF8: + g_assert(is_pointer); + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + g_free(arg->v_string); + } + break; + case GI_TYPE_TAG_ARRAY: + { + GArray *array; + gsize i; + + g_assert(is_pointer); + + array = arg->v_pointer; + + if ((direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + GITypeInfo *item_type_info; + GITransfer item_transfer; + + item_type_info = g_type_info_get_param_type(type_info, 0); + + item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; + + /* Free the items */ + for (i = 0; i < array->len; i++) { + GArgument item; + item = _g_array_index(array, GArgument, i); + _pygi_argument_release(&item, item_type_info, item_transfer, direction); + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + } + + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { + g_array_free(array, TRUE); + } + + break; + } + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *info; + GIInfoType info_type; + + info = g_type_info_get_interface(type_info); + info_type = g_base_info_get_type(info); + + switch (info_type) { + case GI_INFO_TYPE_CALLBACK: + /* TODO */ + break; + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_STRUCT: + { + GType type; + + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info); + + if (g_type_is_a(type, G_TYPE_VALUE)) { + GValue *value; + + g_assert(is_pointer); + + value = arg->v_pointer; + + if ((direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + g_value_unset(value); + } + + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { + g_slice_free(GValue, value); + } + } else if (g_type_is_a(type, G_TYPE_CLOSURE)) { + g_assert(is_pointer); + if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) { + g_closure_unref(arg->v_pointer); + } + } else if (g_type_is_a(type, G_TYPE_BOXED)) { + g_assert(is_pointer); + } else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) { + g_warn_if_fail(!is_pointer || transfer == GI_TRANSFER_NOTHING); + } + + break; + } + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + g_free(arg->v_pointer); + } + } + break; + case GI_INFO_TYPE_OBJECT: + g_assert(is_pointer); + if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) { + g_object_unref(arg->v_pointer); + } + break; + case GI_INFO_TYPE_UNION: + /* TODO */ + break; + default: + g_assert_not_reached(); + } + + g_base_info_unref(info); + break; + } + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + { + GSList *list; + + g_assert(is_pointer); + + list = arg->v_pointer; + + if ((direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + GITypeInfo *item_type_info; + GITransfer item_transfer; + GSList *item; + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; + + /* Free the items */ + for (item = list; item != NULL; item = g_slist_next(item)) { + _pygi_argument_release((GArgument *)&item->data, item_type_info, + item_transfer, direction); + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + } + + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { + if (type_tag == GI_TYPE_TAG_GLIST) { + g_list_free((GList *)list); + } else { + /* type_tag == GI_TYPE_TAG_GSLIST */ + g_slist_free(list); + } + } + + break; + } + case GI_TYPE_TAG_GHASH: + { + GHashTable *hash_table; + + g_assert(is_pointer); + + hash_table = arg->v_pointer; + + if (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) { + /* We created the table without a destroy function, so keys and + * values need to be released. */ + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + GITransfer item_transfer; + GHashTableIter hash_table_iter; + gpointer key; + gpointer value; + + key_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(key_type_info != NULL); + + value_type_info = g_type_info_get_param_type(type_info, 1); + g_assert(value_type_info != NULL); + + if (direction == GI_DIRECTION_IN) { + item_transfer = GI_TRANSFER_NOTHING; + } else { + item_transfer = GI_TRANSFER_EVERYTHING; + } + + g_hash_table_iter_init(&hash_table_iter, hash_table); + while (g_hash_table_iter_next(&hash_table_iter, &key, &value)) { + _pygi_argument_release((GArgument *)&key, key_type_info, + item_transfer, direction); + _pygi_argument_release((GArgument *)&value, value_type_info, + item_transfer, direction); + } + + g_base_info_unref((GIBaseInfo *)key_type_info); + g_base_info_unref((GIBaseInfo *)value_type_info); + } else if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_CONTAINER) { + /* Be careful to avoid keys and values being freed if the + * callee gave a destroy function. */ + g_hash_table_steal_all(hash_table); + } + + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { + g_hash_table_unref(hash_table); + } + + break; + } + case GI_TYPE_TAG_ERROR: + { + GError *error; + + g_assert(is_pointer); + + error = *(GError **)arg->v_pointer; + + if (error != NULL) { + g_error_free(error); + } + + g_slice_free(GError *, arg->v_pointer); + break; + } + } +} + +void +_pygi_argument_init (void) +{ + PyDateTime_IMPORT; + _pygobject_import(); +} + -- cgit