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.c371
1 files changed, 321 insertions, 50 deletions
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index e3dd8c38..6519e5ca 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -188,6 +188,7 @@ _pygi_g_type_interface_check_object (GIBaseInfo *info,
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;
@@ -222,22 +223,18 @@ _pygi_g_type_interface_check_object (GIBaseInfo *info,
/* 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)) {
+ 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. */
@@ -245,8 +242,46 @@ _pygi_g_type_interface_check_object (GIBaseInfo *info,
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();
@@ -276,8 +311,18 @@ _pygi_g_type_info_check_object (GITypeInfo *type_info,
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:
+ /* 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:
@@ -373,9 +418,36 @@ check_number_release:
}
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_PyUnicode_Check (object)) {
+ if (!PYGLIB_PyBaseString_Check (object) ) {
PyErr_Format (PyExc_TypeError, "Must be string, not %s",
object->ob_type->tp_name);
retval = 0;
@@ -412,6 +484,10 @@ check_number_release:
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;
@@ -645,8 +721,13 @@ _pygi_argument_from_object (PyObject *object,
arg.v_boolean = PyObject_IsTrue (object);
break;
}
- case GI_TYPE_TAG_INT8:
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:
@@ -680,8 +761,7 @@ _pygi_argument_from_object (PyObject *object,
value = PyInt_AS_LONG (number);
} else
#endif
- if (PyLong_Check (number))
- value = PyLong_AsUnsignedLongLong (number);
+ value = PyLong_AsUnsignedLongLong (number);
arg.v_uint64 = value;
@@ -702,10 +782,9 @@ _pygi_argument_from_object (PyObject *object,
#if PY_VERSION_HEX < 0x03000000
if (PyInt_Check (number)) {
value = PyInt_AS_LONG (number);
- } else
-#endif
- if (PyLong_Check (number))
- value = PyLong_AsLongLong (number);
+ } else
+#endif
+ value = PyLong_AsLongLong (number);
arg.v_int64 = value;
@@ -747,6 +826,42 @@ _pygi_argument_from_object (PyObject *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;
@@ -756,7 +871,17 @@ _pygi_argument_from_object (PyObject *object,
break;
}
#if PY_VERSION_HEX < 0x03000000
- string = g_strdup(PyString_AsString (object));
+ 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);
@@ -835,6 +960,15 @@ _pygi_argument_from_object (PyObject *object,
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++) {
@@ -867,6 +1001,7 @@ array_item_error:
break;
}
+array_success:
arg.v_pointer = array;
g_base_info_unref ( (GIBaseInfo *) item_type_info);
@@ -904,7 +1039,7 @@ array_item_error:
GType object_type;
gint retval;
- object_type = pyg_type_from_object ( (PyObject *) object->ob_type);
+ 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;
@@ -913,25 +1048,39 @@ array_item_error:
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;
+ /* 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;
- 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;
+ 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;
@@ -1246,6 +1395,27 @@ _pygi_argument_to_object (GIArgument *arg,
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;
@@ -1287,23 +1457,36 @@ _pygi_argument_to_object (GIArgument *arg,
GITransfer item_transfer;
gsize i, item_size;
- if (arg->v_pointer == NULL) {
- object = PyList_New (0);
- break;
- }
-
array = arg->v_pointer;
- object = PyList_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_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++) {
@@ -1380,6 +1563,8 @@ _pygi_argument_to_object (GIArgument *arg,
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 (type_info, arg->v_pointer);
} else if (g_type_is_a (type, G_TYPE_BOXED)) {
PyObject *py_type;
@@ -1403,8 +1588,6 @@ _pygi_argument_to_object (GIArgument *arg,
}
Py_XDECREF (py_type);
- } else if ( (type == G_TYPE_NONE) && (g_struct_info_is_foreign (info))) {
- object = pygi_struct_foreign_convert_from_g_argument (type_info, arg->v_pointer);
} else if (type == G_TYPE_NONE) {
PyObject *py_type;
@@ -1589,6 +1772,97 @@ _pygi_argument_to_object (GIArgument *arg,
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 {
+ 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,
@@ -1616,6 +1890,7 @@ _pygi_argument_release (GIArgument *arg,
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:
@@ -1701,10 +1976,6 @@ _pygi_argument_release (GIArgument *arg,
|| (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) {
g_slice_free (GValue, value);
}
- } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
- if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) {
- g_closure_unref (arg->v_pointer);
- }
} 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);