Exemplo n.º 1
0
/**
 * pyg_value_as_pyobject:
 * @value: the GValue object.
 * @copy_boxed: true if boxed values should be copied.
 *
 * This function creates/returns a Python wrapper object that
 * represents the GValue passed as an argument.
 *
 * Returns: a PyObject representing the value.
 */
PyObject *
pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed)
{
    gchar buf[128];

    switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value))) {
    case G_TYPE_INTERFACE:
	if (g_type_is_a(G_VALUE_TYPE(value), G_TYPE_OBJECT))
	    return pygobject_new(g_value_get_object(value));
	else
	    break;
    case G_TYPE_CHAR: {
	gint8 val = g_value_get_char(value);
	return PYGLIB_PyUnicode_FromStringAndSize((char *)&val, 1);
    }
    case G_TYPE_UCHAR: {
	guint8 val = g_value_get_uchar(value);
	return PYGLIB_PyBytes_FromStringAndSize((char *)&val, 1);
    }
    case G_TYPE_BOOLEAN: {
	return PyBool_FromLong(g_value_get_boolean(value));
    }
    case G_TYPE_INT:
	return PYGLIB_PyLong_FromLong(g_value_get_int(value));
    case G_TYPE_UINT:
	{
	    /* in Python, the Int object is backed by a long.  If a
	       long can hold the whole value of an unsigned int, use
	       an Int.  Otherwise, use a Long object to avoid overflow.
	       This matches the ULongArg behavior in codegen/argtypes.h */
#if (G_MAXUINT <= G_MAXLONG)
	    return PYGLIB_PyLong_FromLong((glong) g_value_get_uint(value));
#else
	    return PyLong_FromUnsignedLong((gulong) g_value_get_uint(value));
#endif
	}
    case G_TYPE_LONG:
	return PYGLIB_PyLong_FromLong(g_value_get_long(value));
    case G_TYPE_ULONG:
	{
	    gulong val = g_value_get_ulong(value);

	    if (val <= G_MAXLONG)
		return PYGLIB_PyLong_FromLong((glong) val);
	    else
		return PyLong_FromUnsignedLong(val);
	}
    case G_TYPE_INT64:
	{
	    gint64 val = g_value_get_int64(value);

	    if (G_MINLONG <= val && val <= G_MAXLONG)
		return PYGLIB_PyLong_FromLong((glong) val);
	    else
		return PyLong_FromLongLong(val);
	}
    case G_TYPE_UINT64:
	{
	    guint64 val = g_value_get_uint64(value);

	    if (val <= G_MAXLONG)
		return PYGLIB_PyLong_FromLong((glong) val);
	    else
		return PyLong_FromUnsignedLongLong(val);
	}
    case G_TYPE_ENUM:
	return pyg_enum_from_gtype(G_VALUE_TYPE(value), g_value_get_enum(value));
    case G_TYPE_FLAGS:
	return pyg_flags_from_gtype(G_VALUE_TYPE(value), g_value_get_flags(value));
    case G_TYPE_FLOAT:
	return PyFloat_FromDouble(g_value_get_float(value));
    case G_TYPE_DOUBLE:
	return PyFloat_FromDouble(g_value_get_double(value));
    case G_TYPE_STRING:
	{
	    const gchar *str = g_value_get_string(value);

	    if (str)
		return PYGLIB_PyUnicode_FromString(str);
	    Py_INCREF(Py_None);
	    return Py_None;
	}
    case G_TYPE_POINTER:
	return pyg_pointer_new(G_VALUE_TYPE(value),
			       g_value_get_pointer(value));
    case G_TYPE_BOXED: {
	PyGTypeMarshal *bm;

	if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT)) {
	    PyObject *ret = (PyObject *)g_value_dup_boxed(value);
	    if (ret == NULL) {
		Py_INCREF(Py_None);
		return Py_None;
	    }
	    return ret;
        } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) {
            GValue *n_value = g_value_get_boxed (value);
            return pyg_value_as_pyobject(n_value, copy_boxed);
        } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) {
	    GValueArray *array = (GValueArray *) g_value_get_boxed(value);
	    PyObject *ret = PyList_New(array->n_values);
	    int i;
	    for (i = 0; i < array->n_values; ++i)
		PyList_SET_ITEM(ret, i, pyg_value_as_pyobject
                                (array->values + i, copy_boxed));
	    return ret;
	} else if (G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
	    GString *string = (GString *) g_value_get_boxed(value);
	    PyObject *ret = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len);
	    return ret;
	}
	bm = pyg_type_lookup(G_VALUE_TYPE(value));
	if (bm) {
	    return bm->fromvalue(value);
	} else {
	    if (copy_boxed)
		return pyg_boxed_new(G_VALUE_TYPE(value),
				     g_value_get_boxed(value), TRUE, TRUE);
	    else
		return pyg_boxed_new(G_VALUE_TYPE(value),
				     g_value_get_boxed(value),FALSE,FALSE);
	}
    }
    case G_TYPE_PARAM:
	return pyg_param_spec_new(g_value_get_param(value));
    case G_TYPE_OBJECT:
	return pygobject_new(g_value_get_object(value));
    default:
	{
	    PyGTypeMarshal *bm;
	    if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))))
		return bm->fromvalue(value);
	    break;
	}
    }
    g_snprintf(buf, sizeof(buf), "unknown type %s",
	       g_type_name(G_VALUE_TYPE(value)));
    PyErr_SetString(PyExc_TypeError, buf);
    return NULL;
}
Exemplo n.º 2
0
PyObject *
_pygi_marshal_to_py_array (PyGIInvokeState   *state,
                           PyGICallableCache *callable_cache,
                           PyGIArgCache      *arg_cache,
                           GIArgument        *arg)
{
    GArray *array_;
    PyObject *py_obj = NULL;
    PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
    gsize processed_items = 0;

     /* GArrays make it easier to iterate over arrays
      * with different element sizes but requires that
      * we allocate a GArray if the argument was a C array
      */
    if (seq_cache->array_type == GI_ARRAY_TYPE_C) {
        gsize len;
        if (seq_cache->fixed_size >= 0) {
            g_assert(arg->v_pointer != NULL);
            len = seq_cache->fixed_size;
        } else if (seq_cache->is_zero_terminated) {
            if (arg->v_pointer == NULL) {
                len = 0;
            } else if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) {
                len = strlen (arg->v_pointer);
            } else {
                len = g_strv_length ((gchar **)arg->v_pointer);
            }
        } else {
            GIArgument *len_arg = state->args[seq_cache->len_arg_index];
            PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache,
                                                                    seq_cache->len_arg_index);

            if (!gi_argument_to_gsize (len_arg, &len, arg_cache->type_tag)) {
                return NULL;
            }
        }

        array_ = g_array_new (FALSE,
                              FALSE,
                              seq_cache->item_size);
        if (array_ == NULL) {
            PyErr_NoMemory ();

            if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && arg->v_pointer != NULL)
                g_free (arg->v_pointer);

            return NULL;
        }

        if (array_->data != NULL) 
            g_free (array_->data);
        array_->data = arg->v_pointer;
        array_->len = len;
    } else {
        array_ = arg->v_pointer;
    }

    if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) {
        if (arg->v_pointer == NULL) {
            py_obj = PYGLIB_PyBytes_FromString ("");
        } else {
            py_obj = PYGLIB_PyBytes_FromStringAndSize (array_->data, array_->len);
        }
    } else {
        if (arg->v_pointer == NULL) {
            py_obj = PyList_New (0);
        } else {
            int i;

            gsize item_size;
            PyGIMarshalToPyFunc item_to_py_marshaller;
            PyGIArgCache *item_arg_cache;

            py_obj = PyList_New (array_->len);
            if (py_obj == NULL)
                goto err;


            item_arg_cache = seq_cache->item_cache;
            item_to_py_marshaller = item_arg_cache->to_py_marshaller;

            item_size = g_array_get_element_size (array_);

            for (i = 0; i < array_->len; i++) {
                GIArgument item_arg = {0};
                PyObject *py_item;

                /* If we are receiving an array of pointers, simply assign the pointer
                 * and move on, letting the per-item marshaler deal with the
                 * various transfer modes and ref counts (e.g. g_variant_ref_sink).
                 */
                if (seq_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
                    item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i);

                } else if (item_arg_cache->is_pointer) {
                    item_arg.v_pointer = g_array_index (array_, gpointer, i);

                } else if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
                    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *) item_arg_cache;

                    // FIXME: This probably doesn't work with boxed types or gvalues. See fx. _pygi_marshal_from_py_array()
                    switch (g_base_info_get_type (iface_cache->interface_info)) {
                        case GI_INFO_TYPE_STRUCT:
                            if (arg_cache->transfer == GI_TRANSFER_EVERYTHING &&
                                       !g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
                                /* array elements are structs */
                                gpointer *_struct = g_malloc (item_size);
                                memcpy (_struct, array_->data + i * item_size,
                                        item_size);
                                item_arg.v_pointer = _struct;
                            } else {
                                item_arg.v_pointer = array_->data + i * item_size;
                            }
                            break;
                        default:
                            item_arg.v_pointer = g_array_index (array_, gpointer, i);
                            break;
                    }
                } else {
                    memcpy (&item_arg, array_->data + i * item_size, item_size);
                }

                py_item = item_to_py_marshaller ( state,
                                                callable_cache,
                                                item_arg_cache,
                                                &item_arg);

                if (py_item == NULL) {
                    Py_CLEAR (py_obj);

                    if (seq_cache->array_type == GI_ARRAY_TYPE_C)
                        g_array_unref (array_);

                    goto err;
                }
                PyList_SET_ITEM (py_obj, i, py_item);
                processed_items++;
            }
        }
    }

    if (seq_cache->array_type == GI_ARRAY_TYPE_C)
        g_array_free (array_, FALSE);

    return py_obj;

err:
    if (seq_cache->array_type == GI_ARRAY_TYPE_C) {
        g_array_free (array_, arg_cache->transfer == GI_TRANSFER_EVERYTHING);
    } else {
        /* clean up unprocessed items */
        if (seq_cache->item_cache->to_py_cleanup != NULL) {
            int j;
            PyGIMarshalCleanupFunc cleanup_func = seq_cache->item_cache->to_py_cleanup;
            for (j = processed_items; j < array_->len; j++) {
                cleanup_func (state,
                              seq_cache->item_cache,
                              NULL,
                              g_array_index (array_, gpointer, j),
                              FALSE);
            }
        }

        if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
            g_array_free (array_, TRUE);
    }

    return NULL;
}
Exemplo n.º 3
0
/**
 * _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;
}