summaryrefslogtreecommitdiff
path: root/gi/pygi-argument.c
diff options
context:
space:
mode:
Diffstat (limited to 'gi/pygi-argument.c')
-rw-r--r--gi/pygi-argument.c2154
1 files changed, 2154 insertions, 0 deletions
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
new file mode 100644
index 0000000..a9b5b60
--- /dev/null
+++ b/gi/pygi-argument.c
@@ -0,0 +1,2154 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ *
+ * pygi-argument.c: GIArgument - 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 <string.h>
+#include <time.h>
+
+#include <datetime.h>
+#include <pygobject.h>
+#include <pyglib-python-compat.h>
+
+static void
+_pygi_g_type_tag_py_bounds (GITypeTag type_tag,
+ PyObject **lower,
+ PyObject **upper)
+{
+ switch (type_tag) {
+ case GI_TYPE_TAG_INT8:
+ *lower = PYGLIB_PyLong_FromLong (-128);
+ *upper = PYGLIB_PyLong_FromLong (127);
+ break;
+ case GI_TYPE_TAG_UINT8:
+ *upper = PYGLIB_PyLong_FromLong (255);
+ *lower = PYGLIB_PyLong_FromLong (0);
+ break;
+ case GI_TYPE_TAG_INT16:
+ *lower = PYGLIB_PyLong_FromLong (-32768);
+ *upper = PYGLIB_PyLong_FromLong (32767);
+ break;
+ case GI_TYPE_TAG_UINT16:
+ *upper = PYGLIB_PyLong_FromLong (65535);
+ *lower = PYGLIB_PyLong_FromLong (0);
+ break;
+ case GI_TYPE_TAG_INT32:
+ *lower = PYGLIB_PyLong_FromLong (G_MININT32);
+ *upper = PYGLIB_PyLong_FromLong (G_MAXINT32);
+ break;
+ case GI_TYPE_TAG_UINT32:
+ /* Note: On 32-bit archs, this number doesn't fit in a long. */
+ *upper = PyLong_FromLongLong (G_MAXUINT32);
+ *lower = PYGLIB_PyLong_FromLong (0);
+ break;
+ case GI_TYPE_TAG_INT64:
+ /* Note: On 32-bit archs, these numbers don't fit in a long. */
+ *lower = PyLong_FromLongLong (G_MININT64);
+ *upper = PyLong_FromLongLong (G_MAXINT64);
+ break;
+ case GI_TYPE_TAG_UINT64:
+ *upper = PyLong_FromUnsignedLongLong (G_MAXUINT64);
+ *lower = PYGLIB_PyLong_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;
+ GIInfoType interface_type;
+
+ interface_type = g_base_info_get_type (info);
+ if ( (interface_type == GI_INFO_TYPE_STRUCT) &&
+ (g_struct_info_is_foreign ( (GIStructInfo*) info))) {
+ /* TODO: Could we check is the correct foreign type? */
+ return 1;
+ }
+
+ 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 0;
+ }
+
+ 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_interface_check_object (GIBaseInfo *info,
+ PyObject *object)
+{
+ gint retval = 1;
+ GIInfoType info_type;
+
+ info_type = g_base_info_get_type (info);
+ switch (info_type) {
+ case GI_INFO_TYPE_CALLBACK:
+ if (!PyCallable_Check (object)) {
+ PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ }
+ break;
+ case GI_INFO_TYPE_ENUM:
+ retval = 0;
+ if (PyNumber_Check (object)) {
+ PyObject *number = PYGLIB_PyNumber_Long (object);
+ if (number == NULL)
+ PyErr_Clear();
+ else {
+ glong value = PYGLIB_PyLong_AsLong (number);
+ int i;
+ for (i = 0; i < g_enum_info_get_n_values (info); i++) {
+ GIValueInfo *value_info = g_enum_info_get_value (info, i);
+ glong enum_value = g_value_info_get_value (value_info);
+ g_base_info_unref (value_info);
+ if (value == enum_value) {
+ retval = 1;
+ break;
+ }
+ }
+ }
+ }
+ if (retval < 1)
+ retval = _pygi_g_registered_type_info_check_object (
+ (GIRegisteredTypeInfo *) info, TRUE, object);
+ break;
+ case GI_INFO_TYPE_FLAGS:
+ if (PyNumber_Check (object)) {
+ /* Accept 0 as a valid flag value */
+ PyObject *number = PYGLIB_PyNumber_Long (object);
+ if (number == NULL)
+ PyErr_Clear();
+ else {
+ long value = PYGLIB_PyLong_AsLong (number);
+ if (value == 0)
+ break;
+ else if (value == -1)
+ PyErr_Clear();
+ }
+ }
+ 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_CLOSURE)) {
+ if (!(PyCallable_Check (object) ||
+ pyg_type_from_object_strict (object, FALSE) == G_TYPE_CLOSURE)) {
+ PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ }
+ break;
+ } else if (g_type_is_a (type, G_TYPE_VALUE)) {
+ /* we can't check g_values because we don't have
+ * enough context so just pass them through */
+ break;
+ }
+
+ /* Fallback. */
+ }
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object);
+ break;
+ case GI_INFO_TYPE_UNION:
+
+
+ retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object);
+
+ /* If not the same type then check to see if the object's type
+ * is the same as one of the union's members
+ */
+ if (retval == 0) {
+ gint i;
+ gint n_fields;
+
+ n_fields = g_union_info_get_n_fields ( (GIUnionInfo *) info);
+
+ for (i = 0; i < n_fields; i++) {
+ gint member_retval;
+ GIFieldInfo *field_info;
+ GITypeInfo *field_type_info;
+
+ field_info =
+ g_union_info_get_field ( (GIUnionInfo *) info, i);
+ field_type_info = g_field_info_get_type (field_info);
+
+ member_retval = _pygi_g_type_info_check_object(
+ field_type_info,
+ object,
+ TRUE);
+
+ g_base_info_unref ( ( GIBaseInfo *) field_type_info);
+ g_base_info_unref ( ( GIBaseInfo *) field_info);
+
+ if (member_retval == 1) {
+ retval = member_retval;
+ break;
+ }
+ }
+ }
+
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return retval;
+}
+
+gint
+_pygi_g_type_info_check_object (GITypeInfo *type_info,
+ PyObject *object,
+ gboolean allow_none)
+{
+ GITypeTag type_tag;
+ gint retval = 1;
+
+ if (allow_none && object == Py_None) {
+ return retval;
+ }
+
+ type_tag = g_type_info_get_tag (type_info);
+
+ switch (type_tag) {
+ case GI_TYPE_TAG_VOID:
+ /* No check; VOID means undefined type */
+ break;
+ case GI_TYPE_TAG_BOOLEAN:
+ /* No check; every Python object has a truth value. */
+ break;
+ case GI_TYPE_TAG_UINT8:
+ /* UINT8 types can be characters */
+ if (PYGLIB_PyBytes_Check(object)) {
+ if (PYGLIB_PyBytes_Size(object) != 1) {
+ PyErr_Format (PyExc_TypeError, "Must be a single character");
+ retval = 0;
+ break;
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_INT8:
+ 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_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 = PYGLIB_PyNumber_Long (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_RichCompareBool (lower, number, Py_GT)
+ || PyObject_RichCompareBool (upper, number, Py_LT)) {
+ 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;
+ }
+
+#if PY_VERSION_HEX < 0x03000000
+ PyErr_Format (PyExc_ValueError, "Must range from %s to %s",
+ PyString_AS_STRING (lower_str),
+ PyString_AS_STRING (upper_str));
+#else
+ {
+ PyObject *lower_pybytes_obj = PyUnicode_AsUTF8String (lower_str);
+ if (!lower_pybytes_obj)
+ goto utf8_fail;
+
+ PyObject *upper_pybytes_obj = PyUnicode_AsUTF8String (upper_str);
+ if (!upper_pybytes_obj) {
+ Py_DECREF(lower_pybytes_obj);
+ goto utf8_fail;
+ }
+
+ PyErr_Format (PyExc_ValueError, "Must range from %s to %s",
+ PyBytes_AsString (lower_pybytes_obj),
+ PyBytes_AsString (upper_pybytes_obj));
+ Py_DECREF (lower_pybytes_obj);
+ Py_DECREF (upper_pybytes_obj);
+ }
+utf8_fail:
+#endif
+ 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_GTYPE:
+ {
+ if (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_UNICHAR:
+ {
+ Py_ssize_t size;
+ if (PyUnicode_Check (object)) {
+ size = PyUnicode_GET_SIZE (object);
+#if PY_VERSION_HEX < 0x03000000
+ } else if (PyString_Check (object)) {
+ PyObject *pyuni = PyUnicode_FromEncodedObject (object, "UTF-8", "strict");
+ size = PyUnicode_GET_SIZE (pyuni);
+ Py_DECREF(pyuni);
+#endif
+ } else {
+ PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ break;
+ }
+
+ if (size != 1) {
+ PyErr_Format (PyExc_TypeError, "Must be a one character string, not %ld characters",
+ size);
+ retval = 0;
+ break;
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ if (!PYGLIB_PyBaseString_Check (object) ) {
+ 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);
+
+ /* FIXME: This is insain. We really should only check the first
+ * object and perhaps have a debugging mode. Large arrays
+ * will cause apps to slow to a crawl.
+ */
+ 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, item, TRUE);
+
+ 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;
+
+ info = g_type_info_get_interface (type_info);
+ g_assert (info != NULL);
+
+ retval = _pygi_g_type_interface_check_object(info, object);
+
+ 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, item, TRUE);
+
+ 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;
+
+ keys = PyMapping_Keys (object);
+ if (keys == NULL) {
+ PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ break;
+ }
+
+ length = PyMapping_Length (object);
+ if (length < 0) {
+ Py_DECREF (keys);
+ 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, key, TRUE);
+ if (retval < 0) {
+ break;
+ }
+ if (!retval) {
+ _PyGI_ERROR_PREFIX ("Key %zd :", i);
+ break;
+ }
+
+ retval = _pygi_g_type_info_check_object (value_type_info, value, TRUE);
+ 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 (GIArgument *arg,
+ GIArgument *args[],
+ GITypeInfo *type_info,
+ gboolean is_method)
+{
+ GITypeInfo *item_type_info;
+ gboolean is_zero_terminated;
+ gsize item_size;
+ gssize length;
+ GArray *g_array;
+
+ if (arg->v_pointer == NULL) {
+ return NULL;
+ }
+
+ 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_assert (length >= 0);
+
+ g_array = g_array_new (is_zero_terminated, FALSE, item_size);
+
+ g_array->data = arg->v_pointer;
+ g_array->len = length;
+
+ return g_array;
+}
+
+GIArgument
+_pygi_argument_from_object (PyObject *object,
+ GITypeInfo *type_info,
+ GITransfer transfer)
+{
+ GIArgument arg;
+ GITypeTag type_tag;
+
+ memset(&arg, 0, sizeof(GIArgument));
+ type_tag = g_type_info_get_tag (type_info);
+
+ switch (type_tag) {
+ case GI_TYPE_TAG_VOID:
+ g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+ arg.v_pointer = object;
+ break;
+ case GI_TYPE_TAG_BOOLEAN:
+ {
+ arg.v_boolean = PyObject_IsTrue (object);
+ break;
+ }
+ case GI_TYPE_TAG_UINT8:
+ if (PYGLIB_PyBytes_Check(object)) {
+ arg.v_long = (long)(PYGLIB_PyBytes_AsString(object)[0]);
+ break;
+ }
+
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ {
+ PyObject *int_;
+
+ int_ = PYGLIB_PyNumber_Long (object);
+ if (int_ == NULL) {
+ break;
+ }
+
+ arg.v_long = PYGLIB_PyLong_AsLong (int_);
+
+ Py_DECREF (int_);
+
+ break;
+ }
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_UINT64:
+ {
+ PyObject *number;
+ guint64 value;
+
+ number = PYGLIB_PyNumber_Long (object);
+ if (number == NULL) {
+ break;
+ }
+
+#if PY_VERSION_HEX < 0x03000000
+ if (PyInt_Check (number)) {
+ value = PyInt_AS_LONG (number);
+ } else
+#endif
+ value = PyLong_AsUnsignedLongLong (number);
+
+ arg.v_uint64 = value;
+
+ Py_DECREF (number);
+
+ break;
+ }
+ case GI_TYPE_TAG_INT64:
+ {
+ PyObject *number;
+ gint64 value;
+
+ number = PYGLIB_PyNumber_Long (object);
+ if (number == NULL) {
+ break;
+ }
+
+#if PY_VERSION_HEX < 0x03000000
+ if (PyInt_Check (number)) {
+ value = PyInt_AS_LONG (number);
+ } else
+#endif
+ value = PyLong_AsLongLong (number);
+
+ arg.v_int64 = value;
+
+ Py_DECREF (number);
+
+ break;
+ }
+ case GI_TYPE_TAG_FLOAT:
+ {
+ PyObject *float_;
+
+ float_ = PyNumber_Float (object);
+ if (float_ == NULL) {
+ break;
+ }
+
+ arg.v_float = (float) PyFloat_AsDouble (float_);
+ Py_DECREF (float_);
+
+ break;
+ }
+ case GI_TYPE_TAG_DOUBLE:
+ {
+ PyObject *float_;
+
+ float_ = PyNumber_Float (object);
+ if (float_ == NULL) {
+ break;
+ }
+
+ arg.v_double = PyFloat_AsDouble (float_);
+ Py_DECREF (float_);
+
+ break;
+ }
+ case GI_TYPE_TAG_GTYPE:
+ {
+ arg.v_long = pyg_type_from_object (object);
+
+ break;
+ }
+ case GI_TYPE_TAG_UNICHAR:
+ {
+ gchar *string;
+
+ if (object == Py_None) {
+ arg.v_uint32 = 0;
+ break;
+ }
+
+#if PY_VERSION_HEX < 0x03000000
+ if (PyUnicode_Check(object)) {
+ PyObject *pystr_obj = PyUnicode_AsUTF8String (object);
+
+ if (!pystr_obj)
+ break;
+
+ string = g_strdup(PyString_AsString (pystr_obj));
+ Py_DECREF(pystr_obj);
+ } else {
+ string = g_strdup(PyString_AsString (object));
+ }
+#else
+ {
+ PyObject *pybytes_obj = PyUnicode_AsUTF8String (object);
+ if (!pybytes_obj)
+ break;
+
+ string = g_strdup(PyBytes_AsString (pybytes_obj));
+ Py_DECREF (pybytes_obj);
+ }
+#endif
+
+ arg.v_uint32 = g_utf8_get_char (string);
+
+ break;
+ }
+ case GI_TYPE_TAG_UTF8:
+ {
+ gchar *string;
+
+ if (object == Py_None) {
+ arg.v_string = NULL;
+ break;
+ }
+#if PY_VERSION_HEX < 0x03000000
+ if (PyUnicode_Check(object)) {
+ PyObject *pystr_obj = PyUnicode_AsUTF8String (object);
+
+ if (!pystr_obj)
+ break;
+
+ string = g_strdup(PyString_AsString (pystr_obj));
+ Py_DECREF(pystr_obj);
+ } else {
+ string = g_strdup(PyString_AsString (object));
+ }
+#else
+ {
+ PyObject *pybytes_obj = PyUnicode_AsUTF8String (object);
+ if (!pybytes_obj)
+ break;
+
+ string = g_strdup(PyBytes_AsString (pybytes_obj));
+ Py_DECREF (pybytes_obj);
+ }
+#endif
+ arg.v_string = string;
+
+ break;
+ }
+ case GI_TYPE_TAG_FILENAME:
+ {
+ GError *error = NULL;
+ gchar *string;
+
+#if PY_VERSION_HEX < 0x03000000
+ string = g_strdup(PyString_AsString (object));
+#else
+ {
+ PyObject *pybytes_obj = PyUnicode_AsUTF8String (object);
+ if (!pybytes_obj)
+ break;
+
+ string = g_strdup(PyBytes_AsString (pybytes_obj));
+ Py_DECREF (pybytes_obj);
+ }
+#endif
+
+ if (string == NULL) {
+ break;
+ }
+
+ arg.v_string = g_filename_from_utf8 (string, -1, NULL, NULL, &error);
+ g_free(string);
+
+ 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;
+
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ 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;
+ }
+
+ if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8 &&
+ PYGLIB_PyBytes_Check(object)) {
+
+ memcpy(array->data, PYGLIB_PyBytes_AsString(object), length);
+ array->len = length;
+ goto array_success;
+ }
+
+
+ item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ for (i = 0; i < length; i++) {
+ PyObject *py_item;
+ GIArgument 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 ( (GIArgument *) &array, type_info,
+ GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
+ array = NULL;
+
+ _PyGI_ERROR_PREFIX ("Item %zd: ", i);
+ break;
+ }
+
+array_success:
+ 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:
+ /* This should be handled in invoke() */
+ g_assert_not_reached();
+ break;
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_UNION:
+ {
+ GType type;
+
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ 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_strict ( (PyObject *) object->ob_type, FALSE);
+ if (object_type == G_TYPE_INVALID) {
+ PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType");
+ break;
+ }
+
+ g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+
+ value = g_slice_new0 (GValue);
+
+ /* if already a gvalue, copy, else marshal into gvalue */
+ if (object_type == G_TYPE_VALUE) {
+ /* src GValue's lifecycle is handled by Python
+ * so we have to copy it into the destination's
+ * GValue which is freed during the cleanup of
+ * invoke.
+ */
+ GValue *src = (GValue *)((PyGObject *) object)->obj;
+ g_value_init (value, G_VALUE_TYPE (src));
+ g_value_copy(src, value);
+ } else {
+ 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;
+
+ if (pyg_type_from_object_strict (object, FALSE) == G_TYPE_CLOSURE) {
+ closure = (GClosure *)pyg_boxed_get (object, void);
+ } else {
+ 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_struct_info_is_foreign (info)) {
+ PyObject *result;
+ result = pygi_struct_foreign_convert_to_g_argument (
+ object, info, transfer, &arg);
+ } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+ 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 (!g_type_info_is_pointer (type_info) || 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_;
+
+ int_ = PYGLIB_PyNumber_Long (object);
+ if (int_ == NULL) {
+ break;
+ }
+
+ arg.v_long = PYGLIB_PyLong_AsLong (int_);
+
+ Py_DECREF (int_);
+
+ break;
+ }
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ arg.v_pointer = pygobject_get (object);
+ if (transfer == GI_TRANSFER_EVERYTHING) {
+ g_object_ref (arg.v_pointer);
+ }
+
+ 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;
+
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ 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;
+ GIArgument 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 ( (GIArgument *) &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;
+
+
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
+ 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;
+ GIArgument key;
+ GIArgument 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 ( (GIArgument *) &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;
+}
+
+static glong
+_pygi_glong_from_argument (GIArgument *arg,
+ GITypeInfo *type_info)
+{
+ gsize item_size = _pygi_g_type_info_size (type_info);
+
+ if (item_size == sizeof (glong))
+ return arg->v_long;
+ else if (item_size == sizeof (gint))
+ return arg->v_int;
+ else
+ {
+ g_warning ("pygi: unsupported item size %ld", item_size);
+ return arg->v_long;
+ }
+}
+
+PyObject *
+_pygi_argument_to_object (GIArgument *arg,
+ GITypeInfo *type_info,
+ GITransfer transfer)
+{
+ GITypeTag type_tag;
+ PyObject *object = NULL;
+
+ type_tag = g_type_info_get_tag (type_info);
+ switch (type_tag) {
+ case GI_TYPE_TAG_VOID:
+ if (g_type_info_is_pointer (type_info)) {
+ /* Raw Python objects are passed to void* args */
+ g_warn_if_fail (transfer == GI_TRANSFER_NOTHING);
+ object = arg->v_pointer;
+ } else
+ object = Py_None;
+ Py_XINCREF (object);
+ break;
+ case GI_TYPE_TAG_BOOLEAN:
+ {
+ object = PyBool_FromLong (arg->v_boolean);
+ break;
+ }
+ case GI_TYPE_TAG_INT8:
+ {
+ object = PYGLIB_PyLong_FromLong (arg->v_int8);
+ break;
+ }
+ case GI_TYPE_TAG_UINT8:
+ {
+ object = PYGLIB_PyLong_FromLong (arg->v_uint8);
+ break;
+ }
+ case GI_TYPE_TAG_INT16:
+ {
+ object = PYGLIB_PyLong_FromLong (arg->v_int16);
+ break;
+ }
+ case GI_TYPE_TAG_UINT16:
+ {
+ object = PYGLIB_PyLong_FromLong (arg->v_uint16);
+ break;
+ }
+ case GI_TYPE_TAG_INT32:
+ {
+ object = PYGLIB_PyLong_FromLong (arg->v_int32);
+ break;
+ }
+ case GI_TYPE_TAG_UINT32:
+ {
+ object = PyLong_FromLongLong (arg->v_uint32);
+ break;
+ }
+ case GI_TYPE_TAG_INT64:
+ {
+ object = PyLong_FromLongLong (arg->v_int64);
+ break;
+ }
+ case GI_TYPE_TAG_UINT64:
+ {
+ object = PyLong_FromUnsignedLongLong (arg->v_uint64);
+ break;
+ }
+ case GI_TYPE_TAG_FLOAT:
+ {
+ object = PyFloat_FromDouble (arg->v_float);
+ break;
+ }
+ case GI_TYPE_TAG_DOUBLE:
+ {
+ object = PyFloat_FromDouble (arg->v_double);
+ break;
+ }
+ case GI_TYPE_TAG_GTYPE:
+ {
+ object = pyg_type_wrapper_new ( (GType) arg->v_long);
+ break;
+ }
+ case GI_TYPE_TAG_UNICHAR:
+ {
+ /* Preserve the bidirectional mapping between 0 and "" */
+ if (arg->v_uint32 == 0) {
+ object = PYGLIB_PyUnicode_FromString ("");
+ } else if (g_unichar_validate (arg->v_uint32)) {
+ gchar utf8[6];
+ gint bytes;
+
+ bytes = g_unichar_to_utf8 (arg->v_uint32, utf8);
+ object = PYGLIB_PyUnicode_FromStringAndSize ((char*)utf8, bytes);
+ } else {
+ /* TODO: Convert the error to an exception. */
+ PyErr_Format (PyExc_TypeError,
+ "Invalid unicode codepoint %" G_GUINT32_FORMAT,
+ arg->v_uint32);
+ object = Py_None;
+ Py_INCREF (object);
+ }
+ break;
+ }
+ case GI_TYPE_TAG_UTF8:
+ if (arg->v_string == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+
+ object = PYGLIB_PyUnicode_FromString (arg->v_string);
+ break;
+ case GI_TYPE_TAG_FILENAME:
+ {
+ GError *error = NULL;
+ gchar *string;
+
+ if (arg->v_string == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+
+ 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 = PYGLIB_PyUnicode_FromString (string);
+
+ g_free (string);
+
+ break;
+ }
+ case GI_TYPE_TAG_ARRAY:
+ {
+ GArray *array;
+ GITypeInfo *item_type_info;
+ GITypeTag item_type_tag;
+ GITransfer item_transfer;
+ gsize i, item_size;
+
+ array = arg->v_pointer;
+
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+ g_assert (item_type_info != NULL);
+
+ item_type_tag = g_type_info_get_tag (item_type_info);
+ item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ if (item_type_tag == GI_TYPE_TAG_UINT8) {
+ /* Return as a byte array */
+ if (arg->v_pointer == NULL) {
+ object = PYGLIB_PyBytes_FromString ("");
+ break;
+ }
+
+ object = PYGLIB_PyBytes_FromStringAndSize(array->data, array->len);
+ break;
+
+ } else {
+ if (arg->v_pointer == NULL) {
+ object = PyList_New (0);
+ break;
+ }
+
+ object = PyList_New (array->len);
+ if (object == NULL) {
+ break;
+ }
+
+ }
+ item_size = g_array_get_element_size (array);
+
+ for (i = 0; i < array->len; i++) {
+ GIArgument item;
+ PyObject *py_item;
+ gboolean is_struct = FALSE;
+
+ if (item_type_tag == GI_TYPE_TAG_INTERFACE) {
+ GIBaseInfo *iface_info = g_type_info_get_interface (item_type_info);
+ switch (g_base_info_get_type (iface_info)) {
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_BOXED:
+ is_struct = TRUE;
+ default:
+ break;
+ }
+ g_base_info_unref ( (GIBaseInfo *) iface_info);
+ }
+
+ if (is_struct) {
+ item.v_pointer = &_g_array_index (array, GIArgument, i);
+ } else {
+ memcpy (&item, &_g_array_index (array, GIArgument, i), item_size);
+ }
+
+ 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_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:
+ {
+ /* There is no way we can support a callback return
+ * as we are never sure if the callback was set from C
+ * or Python. API that return callbacks are broken
+ * so we print a warning and send back a None
+ */
+
+ g_warning ("You are trying to use an API which returns a callback."
+ "Callback returns can not be supported. Returning None instead.");
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_UNION:
+ {
+ GType type;
+
+ if (arg->v_pointer == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+ if (g_type_is_a (type, G_TYPE_VALUE)) {
+ object = pyg_value_as_pyobject (arg->v_pointer, FALSE);
+ } else if (g_struct_info_is_foreign (info)) {
+ object = pygi_struct_foreign_convert_from_g_argument (info, arg->v_pointer);
+ } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+ PyObject *py_type;
+
+ py_type = _pygi_type_get_from_g_type (type);
+ if (py_type == NULL)
+ break;
+
+ object = _pygi_boxed_new ( (PyTypeObject *) py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+
+ Py_DECREF (py_type);
+ } else if (g_type_is_a (type, G_TYPE_POINTER)) {
+ PyObject *py_type;
+
+ 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;
+ }
+
+ /* Only structs created in invoke can be safely marked
+ * GI_TRANSFER_EVERYTHING. Trust that invoke has
+ * filtered correctly
+ */
+ 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;
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+ if (type == G_TYPE_NONE) {
+ /* An enum with a GType of None is an enum without GType */
+ PyObject *py_type = _pygi_type_import_by_gi_info (info);
+ PyObject *py_args = NULL;
+ glong val = _pygi_glong_from_argument (arg, type_info);
+
+ if (!py_type)
+ return NULL;
+
+ py_args = PyTuple_New (1);
+ if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (val)) != 0) {
+ Py_DECREF (py_args);
+ Py_DECREF (py_type);
+ return NULL;
+ }
+
+ object = PyObject_CallFunction (py_type, "l", val);
+
+ Py_DECREF (py_args);
+ Py_DECREF (py_type);
+
+ } else if (info_type == GI_INFO_TYPE_ENUM) {
+ glong val = _pygi_glong_from_argument (arg, type_info);
+ object = pyg_enum_from_gtype (type, val);
+ } else {
+ object = pyg_flags_from_gtype (type, arg->v_long);
+ }
+
+ break;
+ }
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ if (arg->v_pointer == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+ object = pygobject_new (arg->v_pointer);
+ 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;
+
+ 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++) {
+ GIArgument 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;
+ GIArgument key;
+ GIArgument value;
+
+ if (arg->v_pointer == NULL) {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
+
+ 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);
+ g_assert (g_type_info_get_tag (key_type_info) != GI_TYPE_TAG_VOID);
+
+ value_type_info = g_type_info_get_param_type (type_info, 1);
+ g_assert (value_type_info != NULL);
+ g_assert (g_type_info_get_tag (value_type_info) != GI_TYPE_TAG_VOID);
+
+ 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;
+}
+
+
+GIArgument
+_pygi_argument_from_g_value(const GValue *value,
+ GITypeInfo *type_info)
+{
+ GIArgument arg = { 0, };
+
+ GITypeTag type_tag = g_type_info_get_tag (type_info);
+ switch (type_tag) {
+ case GI_TYPE_TAG_BOOLEAN:
+ arg.v_boolean = g_value_get_boolean (value);
+ break;
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_INT64:
+ arg.v_int = g_value_get_int (value);
+ break;
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_UINT64:
+ arg.v_uint = g_value_get_uint (value);
+ break;
+ case GI_TYPE_TAG_UNICHAR:
+ arg.v_uint32 = g_value_get_char (value);
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ arg.v_float = g_value_get_float (value);
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ arg.v_double = g_value_get_double (value);
+ break;
+ case GI_TYPE_TAG_GTYPE:
+ arg.v_long = g_value_get_gtype (value);
+ break;
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ arg.v_string = g_value_dup_string (value);
+ break;
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ arg.v_pointer = g_value_get_pointer (value);
+ break;
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_GHASH:
+ arg.v_pointer = g_value_get_boxed (value);
+ 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);
+
+ g_base_info_unref (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_FLAGS:
+ case GI_INFO_TYPE_ENUM:
+ arg.v_long = g_value_get_enum (value);
+ break;
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ arg.v_pointer = g_value_get_object (value);
+ break;
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_UNION:
+ if (G_VALUE_HOLDS(value, G_TYPE_BOXED)) {
+ arg.v_pointer = g_value_get_boxed (value);
+ } else if (G_VALUE_HOLDS(value, G_TYPE_VARIANT)) {
+ arg.v_pointer = g_value_get_variant (value);
+ } else {
+ arg.v_pointer = g_value_get_pointer (value);
+ }
+ break;
+ default:
+ g_warning("Converting of type '%s' is not implemented", g_info_type_to_string(info_type));
+ g_assert_not_reached();
+ }
+ break;
+ }
+ case GI_TYPE_TAG_ERROR:
+ case GI_TYPE_TAG_VOID:
+ g_critical("Converting of type '%s' is not implemented", g_type_tag_to_string(type_tag));
+ g_assert_not_reached();
+ }
+
+ return arg;
+}
+
+void
+_pygi_argument_release (GIArgument *arg,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GIDirection direction)
+{
+ GITypeTag type_tag;
+ gboolean is_out = (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT);
+
+ type_tag = g_type_info_get_tag (type_info);
+
+ switch (type_tag) {
+ case GI_TYPE_TAG_VOID:
+ /* Don't do anything, it's transparent to the C side */
+ break;
+ 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_FLOAT:
+ case GI_TYPE_TAG_DOUBLE:
+ case GI_TYPE_TAG_GTYPE:
+ case GI_TYPE_TAG_UNICHAR:
+ break;
+ case GI_TYPE_TAG_FILENAME:
+ case GI_TYPE_TAG_UTF8:
+ /* With allow-none support the string could be NULL */
+ if ((arg->v_string != NULL &&
+ (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;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ 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++) {
+ GIArgument *item;
+ item = &_g_array_index (array, GIArgument, 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:
+ case GI_INFO_TYPE_UNION:
+ {
+ GType type;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+
+ if (g_type_is_a (type, G_TYPE_VALUE)) {
+ GValue *value;
+
+ 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_struct_info_is_foreign ( (GIStructInfo*) info)) {
+ if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) {
+ pygi_struct_foreign_release (info, arg->v_pointer);
+ }
+ } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+ } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
+ g_warn_if_fail (!g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING);
+ }
+
+ break;
+ }
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ break;
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+ if (is_out && transfer == GI_TRANSFER_EVERYTHING) {
+ g_object_unref (arg->v_pointer);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ g_base_info_unref (info);
+ break;
+ }
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ {
+ GSList *list;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ 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 ( (GIArgument *) &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;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ 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 ( (GIArgument *) &key, key_type_info,
+ item_transfer, direction);
+ _pygi_argument_release ( (GIArgument *) &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;
+
+ if (arg->v_pointer == NULL) {
+ return;
+ }
+
+ 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();
+}
+