* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <glib.h>
#include <Python.h>
-#include <pyglib-python-compat.h>
+#include <glib.h>
+#include "pygi-python-compat.h"
#include "pygi-array.h"
-#include "pygi-private.h"
+#include "pygi-info.h"
#include "pygi-marshal-cleanup.h"
+#include "pygi-basictype.h"
+#include "pygi-util.h"
/* Needed for _pygi_marshal_cleanup_from_py_interface_struct_gvalue hack */
#include "pygi-struct-marshal.h"
case GI_TYPE_TAG_INT8:
if (size_in >= G_MININT8 && size_in <= G_MAXINT8) {
- arg_out->v_int8 = size_in;
+ arg_out->v_int8 = (gint8)size_in;
return TRUE;
} else {
goto overflow;
case GI_TYPE_TAG_UINT8:
if (size_in >= 0 && size_in <= G_MAXUINT8) {
- arg_out->v_uint8 = size_in;
+ arg_out->v_uint8 = (guint8)size_in;
return TRUE;
} else {
goto overflow;
case GI_TYPE_TAG_INT16:
if (size_in >= G_MININT16 && size_in <= G_MAXINT16) {
- arg_out->v_int16 = size_in;
+ arg_out->v_int16 = (gint16)size_in;
return TRUE;
} else {
goto overflow;
case GI_TYPE_TAG_UINT16:
if (size_in >= 0 && size_in <= G_MAXUINT16) {
- arg_out->v_uint16 = size_in;
+ arg_out->v_uint16 = (guint16)size_in;
return TRUE;
} else {
goto overflow;
/* Ranges assume two's complement */
case GI_TYPE_TAG_INT32:
if (size_in >= G_MININT32 && size_in <= G_MAXINT32) {
- arg_out->v_int32 = size_in;
+ arg_out->v_int32 = (gint32)size_in;
return TRUE;
} else {
goto overflow;
}
case GI_TYPE_TAG_UINT32:
- if (size_in >= 0 && size_in <= G_MAXUINT32) {
- arg_out->v_uint32 = size_in;
+ if (size_in >= 0 && (gsize)size_in <= G_MAXUINT32) {
+ arg_out->v_uint32 = (guint32)size_in;
return TRUE;
} else {
goto overflow;
*gsize_out = arg_in->v_uint32;
return TRUE;
case GI_TYPE_TAG_INT64:
- *gsize_out = arg_in->v_int64;
+ if (arg_in->v_uint64 > G_MAXSIZE) {
+ PyErr_Format (PyExc_TypeError,
+ "Unable to marshal %s to gsize",
+ g_type_tag_to_string (type_tag));
+ return FALSE;
+ }
+ *gsize_out = (gsize)arg_in->v_int64;
return TRUE;
case GI_TYPE_TAG_UINT64:
- *gsize_out = arg_in->v_uint64;
+ if (arg_in->v_uint64 > G_MAXSIZE) {
+ PyErr_Format (PyExc_TypeError,
+ "Unable to marshal %s to gsize",
+ g_type_tag_to_string (type_tag));
+ return FALSE;
+ }
+ *gsize_out = (gsize)arg_in->v_uint64;
return TRUE;
default:
PyErr_Format (PyExc_TypeError,
gpointer *cleanup_data)
{
PyGIMarshalFromPyFunc from_py_marshaller;
- int i = 0;
- int success_count = 0;
- Py_ssize_t length;
- gssize item_size;
+ guint i = 0;
+ gsize success_count = 0;
+ Py_ssize_t py_length;
+ guint length;
+ guint item_size;
gboolean is_ptr_array;
GArray *array_ = NULL;
PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
+ GITransfer cleanup_transfer = arg_cache->transfer;
if (py_arg == Py_None) {
if (!PySequence_Check (py_arg)) {
PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
- py_arg->ob_type->tp_name);
+ Py_TYPE (py_arg)->tp_name);
return FALSE;
}
- length = PySequence_Length (py_arg);
- if (length < 0)
+ py_length = PySequence_Length (py_arg);
+ if (py_length < 0)
+ return FALSE;
+
+ if (!pygi_guint_from_pyssize (py_length, &length))
return FALSE;
if (array_cache->fixed_size >= 0 &&
- array_cache->fixed_size != length) {
- PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+ (guint)array_cache->fixed_size != length) {
+ PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %u",
array_cache->fixed_size, length);
return FALSE;
}
- item_size = array_cache->item_size;
+ item_size = (guint)array_cache->item_size;
is_ptr_array = (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY);
if (is_ptr_array) {
array_ = (GArray *)g_ptr_array_sized_new (length);
if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8 &&
PYGLIB_PyBytes_Check (py_arg)) {
- memcpy(array_->data, PYGLIB_PyBytes_AsString (py_arg), length);
+ gchar *data = PYGLIB_PyBytes_AsString (py_arg);
+
+ /* Avoid making a copy if the data
+ * is not transferred to the C function
+ * and cannot not be modified by it.
+ */
+ if (array_cache->array_type == GI_ARRAY_TYPE_C &&
+ arg_cache->transfer == GI_TRANSFER_NOTHING &&
+ !array_cache->is_zero_terminated) {
+ g_free (array_->data);
+ array_->data = data;
+ cleanup_transfer = GI_TRANSFER_EVERYTHING;
+ } else {
+ memcpy (array_->data, data, length);
+ }
array_->len = length;
if (array_cache->is_zero_terminated) {
/* If array_ has been created with zero_termination, space for the
if (g_type_is_a (item_iface_cache->g_type, G_TYPE_VALUE)) {
/* Special case GValue flat arrays to properly init and copy the contents. */
- GValue* dest = (GValue*) (array_->data + (i * item_size));
+ GValue* dest = (GValue*)(void*)(array_->data + (i * item_size));
if (item.v_pointer != NULL) {
memset (dest, 0, item_size);
g_value_init (dest, G_VALUE_TYPE ((GValue*) item.v_pointer));
}
success_count++;
- continue;
-err:
- if (sequence_cache->item_cache->from_py_cleanup != NULL) {
- gsize j;
- PyGIMarshalCleanupFunc cleanup_func =
- sequence_cache->item_cache->from_py_cleanup;
+ }
+ goto array_success;
- /* Only attempt per item cleanup on pointer items */
- if (sequence_cache->item_cache->is_pointer) {
- for(j = 0; j < success_count; j++) {
- PyObject *py_item = PySequence_GetItem (py_arg, j);
- cleanup_func (state,
- sequence_cache->item_cache,
- py_item,
- is_ptr_array ?
- g_ptr_array_index ((GPtrArray *)array_, j) :
- g_array_index (array_, gpointer, j),
- TRUE);
- Py_DECREF (py_item);
- }
+err:
+ if (sequence_cache->item_cache->from_py_cleanup != NULL) {
+ gsize j;
+ PyGIMarshalCleanupFunc cleanup_func =
+ sequence_cache->item_cache->from_py_cleanup;
+
+ /* Only attempt per item cleanup on pointer items */
+ if (sequence_cache->item_cache->is_pointer) {
+ for(j = 0; j < success_count; j++) {
+ PyObject *py_seq_item = PySequence_GetItem (py_arg, j);
+ cleanup_func (state,
+ sequence_cache->item_cache,
+ py_seq_item,
+ is_ptr_array ?
+ g_ptr_array_index ((GPtrArray *)array_, j) :
+ g_array_index (array_, gpointer, j),
+ TRUE);
+ Py_DECREF (py_seq_item);
}
}
-
- if (is_ptr_array)
- g_ptr_array_free ( ( GPtrArray *)array_, TRUE);
- else
- g_array_free (array_, TRUE);
- _PyGI_ERROR_PREFIX ("Item %i: ", i);
- return FALSE;
}
+ if (is_ptr_array)
+ g_ptr_array_free ( ( GPtrArray *)array_, TRUE);
+ else
+ g_array_free (array_, TRUE);
+ _PyGI_ERROR_PREFIX ("Item %u: ", i);
+ return FALSE;
+
array_success:
if (array_cache->len_arg_index >= 0) {
/* we have an child arg to handle */
PyGIArgCache *child_cache =
- _pygi_callable_cache_get_arg (callable_cache, array_cache->len_arg_index);
-
- if (child_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL) {
- gint *len_arg = (gint *)state->in_args[child_cache->c_arg_index].v_pointer;
- /* if we are not setup yet just set the in arg */
- if (len_arg == NULL) {
- if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index],
- length,
- child_cache->type_tag)) {
- goto err;
- }
- } else {
- *len_arg = length;
- }
- } else {
- if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index],
- length,
- child_cache->type_tag)) {
- goto err;
- }
+ _pygi_callable_cache_get_arg (callable_cache, (guint)array_cache->len_arg_index);
+
+ if (!gi_argument_from_py_ssize_t (&state->args[child_cache->c_arg_index].arg_value,
+ length,
+ child_cache->type_tag)) {
+ goto err;
}
}
*/
arg->v_pointer = array_->data;
- if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
+ if (cleanup_transfer == GI_TRANSFER_EVERYTHING) {
g_array_free (array_, FALSE);
*cleanup_data = NULL;
} else {
} else {
arg->v_pointer = array_;
- if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
+ if (cleanup_transfer == GI_TRANSFER_NOTHING) {
/* Free everything in cleanup. */
*cleanup_data = array_;
- } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+ } else if (cleanup_transfer == GI_TRANSFER_CONTAINER) {
/* Make a shallow copy so we can free the elements later in cleanup
* because it is possible invoke will free the list before our cleanup. */
*cleanup_data = is_ptr_array ?
/* clean up items first */
if (sequence_cache->item_cache->from_py_cleanup != NULL) {
gsize i;
- guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
+ guint len;
PyGIMarshalCleanupFunc cleanup_func =
sequence_cache->item_cache->from_py_cleanup;
+ g_assert (array_ || ptr_array_);
+ len = (array_ != NULL) ? array_->len : ptr_array_->len;
+
for (i = 0; i < len; i++) {
gpointer item;
PyObject *py_item = NULL;
* allocated in _pygi_marshal_from_py_array(), so we must
* not try to deallocate it as a slice and thus
* short-circuit cleanup_func. */
- if (cleanup_func == _pygi_marshal_cleanup_from_py_interface_struct_gvalue) {
+ if (cleanup_func == pygi_arg_gvalue_from_py_cleanup) {
g_value_unset ((GValue*) item);
continue;
}
_pygi_marshal_to_py_array (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
- GIArgument *arg)
+ GIArgument *arg,
+ gpointer *cleanup_data)
{
GArray *array_;
PyObject *py_obj = NULL;
PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
- gsize processed_items = 0;
+ guint processed_items = 0;
/* GArrays make it easier to iterate over arrays
* with different element sizes but requires that
len = g_strv_length ((gchar **)arg->v_pointer);
}
} else {
- GIArgument *len_arg = state->args[array_cache->len_arg_index];
- PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache,
- array_cache->len_arg_index);
+ GIArgument *len_arg = &state->args[array_cache->len_arg_index].arg_value;
+ PyGIArgCache *sub_cache = _pygi_callable_cache_get_arg (callable_cache,
+ (guint)array_cache->len_arg_index);
- if (!gi_argument_to_gsize (len_arg, &len, arg_cache->type_tag)) {
+ if (!gi_argument_to_gsize (len_arg, &len, sub_cache->type_tag)) {
return NULL;
}
}
array_ = g_array_new (FALSE,
FALSE,
- array_cache->item_size);
+ (guint)array_cache->item_size);
if (array_ == NULL) {
PyErr_NoMemory ();
if (array_->data != NULL)
g_free (array_->data);
array_->data = arg->v_pointer;
- array_->len = len;
+ array_->len = (guint)len;
} else {
array_ = arg->v_pointer;
}
if (arg->v_pointer == NULL) {
py_obj = PyList_New (0);
} else {
- int i;
+ guint i;
gsize item_size;
PyGIMarshalToPyFunc item_to_py_marshaller;
PyGIArgCache *item_arg_cache;
+ GPtrArray *item_cleanups;
py_obj = PyList_New (array_->len);
if (py_obj == NULL)
goto err;
+ item_cleanups = g_ptr_array_sized_new (array_->len);
+ *cleanup_data = item_cleanups;
item_arg_cache = seq_cache->item_cache;
item_to_py_marshaller = item_arg_cache->to_py_marshaller;
for (i = 0; i < array_->len; i++) {
GIArgument item_arg = {0};
PyObject *py_item;
+ gpointer item_cleanup_data = NULL;
/* If we are receiving an array of pointers, simply assign the pointer
* and move on, letting the per-item marshaler deal with the
} 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()
+ /* 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 &&
item_arg.v_pointer = array_->data + i * item_size;
}
break;
+ case GI_INFO_TYPE_ENUM:
+ memcpy (&item_arg, array_->data + i * item_size, item_size);
+ break;
default:
item_arg.v_pointer = g_array_index (array_, gpointer, i);
break;
py_item = item_to_py_marshaller ( state,
callable_cache,
item_arg_cache,
- &item_arg);
+ &item_arg,
+ &item_cleanup_data);
+
+ g_ptr_array_index (item_cleanups, i) = item_cleanup_data;
if (py_item == NULL) {
Py_CLEAR (py_obj);
if (array_cache->array_type == GI_ARRAY_TYPE_C)
g_array_unref (array_);
+ g_ptr_array_unref (item_cleanups);
+
goto err;
}
PyList_SET_ITEM (py_obj, i, py_item);
} 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;
+ guint j;
+ PyGIMarshalToPyCleanupFunc cleanup_func = seq_cache->item_cache->to_py_cleanup;
for (j = processed_items; j < array_->len; j++) {
cleanup_func (state,
seq_cache->item_cache,
} else if (array_cache->is_zero_terminated) {
len = g_strv_length ((gchar **)data);
} else if (array_cache->len_arg_index >= 0) {
- GIArgument *len_arg = state->args[array_cache->len_arg_index];
+ GIArgument *len_arg = &state->args[array_cache->len_arg_index].arg_value;
len = len_arg->v_long;
}
array_ = g_array_new (FALSE,
FALSE,
- array_cache->item_size);
+ (guint)array_cache->item_size);
if (array_ == NULL)
return NULL;
g_free (array_->data);
array_->data = data;
- array_->len = len;
+ array_->len = (guint)len;
return array_;
}
static void
_pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
- PyObject *dummy,
+ gpointer cleanup_data,
gpointer data,
gboolean was_processed)
{
+ GArray *array_ = NULL;
+ GPtrArray *ptr_array_ = NULL;
+ PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+ PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
+ gboolean free_array = FALSE;
+ gboolean free_array_full = TRUE;
+
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
arg_cache->transfer == GI_TRANSFER_CONTAINER) {
- GArray *array_ = NULL;
- GPtrArray *ptr_array_ = NULL;
- PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
- PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
+ free_array = TRUE;
+ }
- /* If this isn't a garray create one to help process variable sized
- array elements */
- if (array_cache->array_type == GI_ARRAY_TYPE_C) {
- array_ = _wrap_c_array (state, array_cache, data);
+ /* If this isn't a garray create one to help process variable sized
+ array elements */
+ if (array_cache->array_type == GI_ARRAY_TYPE_C) {
+ array_ = _wrap_c_array (state, array_cache, data);
- if (array_ == NULL)
- return;
+ if (array_ == NULL)
+ return;
- } else if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
- ptr_array_ = (GPtrArray *) data;
- } else {
- array_ = (GArray *) data;
- }
-
- if (sequence_cache->item_cache->to_py_cleanup != NULL) {
- gsize i;
- guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
+ free_array = TRUE;
+ free_array_full = arg_cache->transfer != GI_TRANSFER_NOTHING;
+ } else if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
+ ptr_array_ = (GPtrArray *) data;
+ } else {
+ array_ = (GArray *) data;
+ }
- PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup;
- for (i = 0; i < len; i++) {
- cleanup_func (state,
- sequence_cache->item_cache,
- NULL,
- (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i),
- was_processed);
- }
+ if (sequence_cache->item_cache->to_py_cleanup != NULL) {
+ GPtrArray *item_cleanups = (GPtrArray *) cleanup_data;
+ gsize i;
+ guint len;
+ PyGIMarshalToPyCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup;
+
+ g_assert (array_ || ptr_array_);
+ len = (array_ != NULL) ? array_->len : ptr_array_->len;
+
+ for (i = 0; i < len; i++) {
+ cleanup_func (state,
+ sequence_cache->item_cache,
+ g_ptr_array_index(item_cleanups, i),
+ (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i),
+ was_processed);
}
+ }
+
+ if (cleanup_data)
+ g_ptr_array_unref ((GPtrArray *) cleanup_data);
+ if (free_array) {
if (array_ != NULL)
- g_array_free (array_, TRUE);
+ g_array_free (array_, free_array_full);
else
- g_ptr_array_free (ptr_array_, TRUE);
+ g_ptr_array_free (ptr_array_, free_array_full);
}
}
seq_cache->len_arg_index = g_type_info_get_array_length (type_info);
/* offset by self arg for methods and vfuncs */
- if (seq_cache->len_arg_index >= 0 && callable_cache != NULL &&
- (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
- callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC)) {
- seq_cache->len_arg_index += 1;
+ if (seq_cache->len_arg_index >= 0 && callable_cache != NULL) {
+ seq_cache->len_arg_index += callable_cache->args_offset;
}
}
PyGIArgCache *child_cache = NULL;
child_cache = _pygi_callable_cache_get_arg (callable_cache,
- seq_cache->len_arg_index);
+ (guint)seq_cache->len_arg_index);
if (child_cache == NULL) {
child_cache = pygi_arg_cache_alloc ();
} else {
child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
child_cache->direction = direction;
- child_cache->to_py_marshaller = NULL;
- child_cache->from_py_marshaller = NULL;
+ child_cache->to_py_marshaller = pygi_marshal_to_py_basic_type_cache_adapter;
+ child_cache->from_py_marshaller = pygi_marshal_from_py_basic_type_cache_adapter;
+ child_cache->py_arg_index = -1;
/* ugly edge case code:
*
* indexes of arguments after the index argument.
*/
if (seq_cache->len_arg_index < arg_index && direction & PYGI_DIRECTION_FROM_PYTHON) {
- gssize i;
+ guint i;
(*py_arg_index) -= 1;
callable_cache->n_py_args -= 1;
- for (i = seq_cache->len_arg_index + 1;
- i < _pygi_callable_cache_args_len (callable_cache); i++) {
+ for (i = (guint)seq_cache->len_arg_index + 1;
+ (gsize)i < _pygi_callable_cache_args_len (callable_cache); i++) {
PyGIArgCache *update_cache = _pygi_callable_cache_get_arg (callable_cache, i);
if (update_cache == NULL)
break;
}
}
- _pygi_callable_cache_set_arg (callable_cache, seq_cache->len_arg_index, child_cache);
+ _pygi_callable_cache_set_arg (callable_cache, (guint)seq_cache->len_arg_index, child_cache);
return child_cache;
}
}
static gboolean
-pygi_arg_garray_setup (PyGIArgGArray *sc,
- GITypeInfo *type_info,
- GIArgInfo *arg_info, /* may be NULL for return arguments */
- GITransfer transfer,
- PyGIDirection direction)
+pygi_arg_garray_setup (PyGIArgGArray *sc,
+ GITypeInfo *type_info,
+ GIArgInfo *arg_info, /* may be NULL for return arguments */
+ GITransfer transfer,
+ PyGIDirection direction,
+ PyGICallableCache *callable_cache)
{
GITypeInfo *item_type_info;
PyGIArgCache *arg_cache = (PyGIArgCache *)sc;
type_info,
arg_info,
transfer,
- direction)) {
+ direction,
+ callable_cache)) {
return FALSE;
}
pygi_arg_garray_new_from_info (GITypeInfo *type_info,
GIArgInfo *arg_info,
GITransfer transfer,
- PyGIDirection direction)
+ PyGIDirection direction,
+ PyGICallableCache *callable_cache)
{
PyGIArgGArray *array_cache = g_slice_new0 (PyGIArgGArray);
if (array_cache == NULL)
type_info,
arg_info,
transfer,
- direction)) {
+ direction,
+ callable_cache)) {
pygi_arg_cache_free ( (PyGIArgCache *)array_cache);
return NULL;
}