Imported Upstream version 3.32.1
[platform/upstream/python-gobject.git] / gi / pygi-array.c
index 121992b..890e7c5 100644 (file)
  * 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"
@@ -46,7 +47,7 @@ gi_argument_from_py_ssize_t (GIArgument   *arg_out,
 
     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;
@@ -54,7 +55,7 @@ gi_argument_from_py_ssize_t (GIArgument   *arg_out,
 
     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;
@@ -62,7 +63,7 @@ gi_argument_from_py_ssize_t (GIArgument   *arg_out,
 
     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;
@@ -70,7 +71,7 @@ gi_argument_from_py_ssize_t (GIArgument   *arg_out,
 
     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;
@@ -79,15 +80,15 @@ gi_argument_from_py_ssize_t (GIArgument   *arg_out,
         /* 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;
@@ -161,10 +162,22 @@ gi_argument_to_gsize (GIArgument *arg_in,
           *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,
@@ -183,10 +196,11 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
                              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;
@@ -201,23 +215,26 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
 
     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);
@@ -317,7 +334,7 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
 
                     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));
@@ -349,44 +366,45 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
         }
 
         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);
+            _pygi_callable_cache_get_arg (callable_cache, (guint)array_cache->len_arg_index);
 
-        if (!gi_argument_from_py_ssize_t (&state->arg_values[child_cache->c_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;
@@ -449,10 +467,13 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
         /* 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;
@@ -504,13 +525,14 @@ static PyObject *
 _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
@@ -530,18 +552,18 @@ _pygi_marshal_to_py_array (PyGIInvokeState   *state,
                 len = g_strv_length ((gchar **)arg->v_pointer);
             }
         } else {
-            GIArgument *len_arg = &state->arg_values[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 ();
 
@@ -554,7 +576,7 @@ _pygi_marshal_to_py_array (PyGIInvokeState   *state,
         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;
     }
@@ -569,16 +591,19 @@ _pygi_marshal_to_py_array (PyGIInvokeState   *state,
         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;
@@ -588,6 +613,7 @@ _pygi_marshal_to_py_array (PyGIInvokeState   *state,
             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
@@ -617,6 +643,9 @@ _pygi_marshal_to_py_array (PyGIInvokeState   *state,
                                 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;
@@ -628,7 +657,10 @@ _pygi_marshal_to_py_array (PyGIInvokeState   *state,
                 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);
@@ -636,6 +668,8 @@ _pygi_marshal_to_py_array (PyGIInvokeState   *state,
                     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);
@@ -655,8 +689,8 @@ err:
     } 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,
@@ -686,20 +720,20 @@ _wrap_c_array (PyGIInvokeState   *state,
     } 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->arg_values[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_;
 }
@@ -707,49 +741,64 @@ _wrap_c_array (PyGIInvokeState   *state,
 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;
-
-        /* 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);
+        free_array = TRUE;
+    }
 
-            if (array_ == NULL)
-                return;
+    /* 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);
 
-        } else if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
-            ptr_array_ = (GPtrArray *) data;
-        } else {
-            array_ = (GArray *) data;
-        }
+        if (array_ == NULL)
+            return;
 
-        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);
     }
 }
 
@@ -786,7 +835,7 @@ pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache,
         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 {
@@ -816,8 +865,8 @@ pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache,
 
         child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
         child_cache->direction = direction;
-        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->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:
@@ -826,12 +875,12 @@ pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache,
          * 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;
@@ -840,7 +889,7 @@ pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache,
             }
         }
 
-        _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;
     }