PyObject * _pygi_marshal_to_py_interface_flags (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, GIArgument *arg) { PyObject *py_obj = NULL; PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; if (iface_cache->g_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 (iface_cache->interface_info); PyObject *py_args = NULL; if (!py_type) return NULL; py_args = PyTuple_New (1); if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (arg->v_long)) != 0) { Py_DECREF (py_args); Py_DECREF (py_type); return NULL; } py_obj = PyObject_CallFunction (py_type, "l", arg->v_long); Py_DECREF (py_args); Py_DECREF (py_type); } else { py_obj = pyg_flags_from_gtype (iface_cache->g_type, arg->v_long); } return py_obj; }
PyObject * _pygi_marshal_to_py_interface_flags (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, GIArgument *arg) { PyObject *py_obj = NULL; PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; GIBaseInfo *interface; long c_long; interface = g_type_info_get_interface (arg_cache->type_info); g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_FLAGS); if (!gi_argument_to_c_long(arg, &c_long, g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { g_base_info_unref (interface); return NULL; } g_base_info_unref (interface); if (iface_cache->g_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 (iface_cache->interface_info); PyObject *py_args = NULL; if (!py_type) return NULL; py_args = PyTuple_New (1); if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (c_long)) != 0) { Py_DECREF (py_args); Py_DECREF (py_type); return NULL; } py_obj = PyObject_CallFunction (py_type, "l", c_long); Py_DECREF (py_args); Py_DECREF (py_type); } else { py_obj = pyg_flags_from_gtype (iface_cache->g_type, c_long); } return py_obj; }
/** * _pygi_argument_to_object: * @arg: The argument to convert to an object. * @type_info: Type info for @arg * @transfer: * * If the argument is of type array, it must be encoded in a GArray, by calling * _pygi_argument_to_array(). This logic can not be folded into this method * as determining array lengths may require access to method call arguments. * * Returns: A PyObject representing @arg */ 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); object = _pygi_marshal_to_py_basic_type (arg, type_tag, transfer); if (object) return object; switch (type_tag) { case GI_TYPE_TAG_VOID: { if (g_type_info_is_pointer (type_info)) { g_warn_if_fail (transfer == GI_TRANSFER_NOTHING); object = PyLong_FromVoidPtr (arg->v_pointer); } break; } case GI_TYPE_TAG_ARRAY: { /* Arrays are assumed to be packed in a GArray */ GArray *array; GITypeInfo *item_type_info; GITypeTag item_type_tag; GITransfer item_transfer; gsize i, item_size; if (arg->v_pointer == NULL) return PyList_New (0); 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; array = arg->v_pointer; item_size = g_array_get_element_size (array); if (G_UNLIKELY (item_size > sizeof(GIArgument))) { g_critical ("Stack overflow protection. " "Can't copy array element into GIArgument."); return PyList_New (0); } if (item_type_tag == GI_TYPE_TAG_UINT8) { /* Return as a byte array */ object = PYGLIB_PyBytes_FromStringAndSize (array->data, array->len); } else { object = PyList_New (array->len); if (object == NULL) { g_critical ("Failure to allocate array for %u items", array->len); g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } for (i = 0; i < array->len; i++) { GIArgument item = { 0 }; PyObject *py_item; memcpy (&item, array->data + i * item_size, 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: { g_assert_not_reached(); } case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { PyObject *py_type; GType g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && (g_struct_info_is_foreign ((GIStructInfo *) info)); /* Special case variant and none to force loading from py module. */ if (g_type == G_TYPE_VARIANT || g_type == G_TYPE_NONE) { py_type = _pygi_type_import_by_gi_info (info); } else { py_type = _pygi_type_get_from_g_type (g_type); } object = pygi_arg_struct_to_py_marshal (arg, info, /*interface_info*/ g_type, py_type, transfer, FALSE, /*is_allocated*/ is_foreign); Py_XDECREF (py_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; if (!py_type) return NULL; py_args = PyTuple_New (1); if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (arg->v_int)) != 0) { Py_DECREF (py_args); Py_DECREF (py_type); return NULL; } object = PyObject_CallFunction (py_type, "i", arg->v_int); Py_DECREF (py_args); Py_DECREF (py_type); } else if (info_type == GI_INFO_TYPE_ENUM) { object = pyg_enum_from_gtype (type, arg->v_int); } else { object = pyg_flags_from_gtype (type, arg->v_uint); } break; } case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: object = pygi_arg_gobject_to_py_called_from_c (arg, transfer); 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; } _pygi_hash_pointer_to_arg (&value, g_type_info_get_tag (value_type_info)); 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: { GError *error = (GError *) arg->v_pointer; if (error != NULL && transfer == GI_TRANSFER_NOTHING) { /* If we have not been transferred the ownership we must copy * the error, because pygi_error_check() is going to free it. */ error = g_error_copy (error); } if (pygi_error_check (&error)) { PyObject *err_type; PyObject *err_value; PyObject *err_trace; PyErr_Fetch (&err_type, &err_value, &err_trace); Py_XDECREF (err_type); Py_XDECREF (err_trace); object = err_value; } else { object = Py_None; Py_INCREF (object); break; } break; } default: { g_assert_not_reached(); } } return object; }
GIArgument _pygi_argument_from_object (PyObject *object, GITypeInfo *type_info, GITransfer transfer) { GIArgument arg; GITypeTag type_tag; gpointer cleanup_data = NULL; memset(&arg, 0, sizeof(GIArgument)); type_tag = g_type_info_get_tag (type_info); /* Ignores cleanup data for now. */ if (_pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer, &cleanup_data) || PyErr_Occurred()) { return arg; } switch (type_tag) { 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; } /* Note, strings are sequences, but we cannot accept them here */ if (!PySequence_Check (object) || #if PY_VERSION_HEX < 0x03000000 PyString_Check (object) || #endif PyUnicode_Check (object)) { PyErr_SetString (PyExc_TypeError, "expected sequence"); 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); /* we handle arrays that are really strings specially, see below */ if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8) item_size = 1; else item_size = sizeof (GIArgument); 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 g_type; PyObject *py_type; gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && (g_struct_info_is_foreign ((GIStructInfo *) info)); g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) info); /* Note for G_TYPE_VALUE g_type: * This will currently leak the GValue that is allocated and * stashed in arg.v_pointer. Out argument marshaling for caller * allocated GValues already pass in memory for the GValue. * Further re-factoring is needed to fix this leak. * See: https://bugzilla.gnome.org/show_bug.cgi?id=693405 */ pygi_arg_struct_from_py_marshal (object, &arg, NULL, /*arg_name*/ info, /*interface_info*/ g_type, py_type, transfer, FALSE, /*copy_reference*/ is_foreign, g_type_info_is_pointer (type_info)); Py_DECREF (py_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_int = PYGLIB_PyLong_AsLong (int_); Py_DECREF (int_); break; } case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: /* An error within this call will result in a NULL arg */ pygi_arg_gobject_out_arg_from_py (object, &arg, transfer); 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, _pygi_arg_to_hash_pointer (&value, g_type_info_get_tag (value_type_info))); 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; default: g_assert_not_reached (); } return arg; }