Imported Upstream version 3.7.3
[platform/upstream/python-gobject.git] / gi / pygi-marshal-cleanup.c
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * vim: tabstop=4 shiftwidth=4 expandtab
3  *
4  * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19  * USA
20  */
21  
22  #include "pygi-marshal-cleanup.h"
23  #include <glib.h>
24 static inline void
25 _cleanup_caller_allocates (PyGIInvokeState    *state,
26                            PyGIArgCache       *cache,
27                            gpointer            data)
28 {
29     PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)cache;
30
31     if (iface_cache->g_type == G_TYPE_BOXED) {
32         gsize size;
33         size = g_struct_info_get_size (iface_cache->interface_info);
34         g_slice_free1 (size, data);
35     } else if (iface_cache->g_type == G_TYPE_VALUE) {
36         g_slice_free (GValue, data);
37     } else if (iface_cache->is_foreign) {
38         pygi_struct_foreign_release ((GIBaseInfo *)iface_cache->interface_info,
39                                      data);
40     } else {
41         g_free (data);
42     }
43 }
44
45 /**
46  * Cleanup during invoke can happen in multiple
47  * stages, each of which can be the result of a
48  * successful compleation of that stage or an error
49  * occured which requires partial cleanup.
50  *
51  * For the most part, either the C interface being
52  * invoked or the python object which wraps the
53  * parameters, handle their lifecycles but in some
54  * cases, where we have intermediate objects,
55  * or when we fail processing a parameter, we need
56  * to handle the clean up manually.
57  *
58  * There are two argument processing stages.
59  * They are the in stage, where we process python
60  * parameters into their C counterparts, and the out
61  * stage, where we process out C parameters back
62  * into python objects. The in stage also sets up
63  * temporary out structures for caller allocated
64  * parameters which need to be cleaned up either on
65  * in stage failure or at the completion of the out
66  * stage (either success or failure)
67  *
68  * The in stage must call one of these cleanup functions:
69  *    - pygi_marshal_cleanup_args_from_py_marshal_success
70  *       (continue to out stage)
71  *    - pygi_marshal_cleanup_args_from_py_parameter_fail
72  *       (final, exit from invoke)
73  *
74  * The out stage must call one of these cleanup functions which are all final:
75  *    - pygi_marshal_cleanup_args_to_py_marshal_success
76  *    - pygi_marshal_cleanup_args_return_fail
77  *    - pygi_marshal_cleanup_args_to_py_parameter_fail
78  *
79  **/
80 void
81 pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState   *state,
82                                                    PyGICallableCache *cache)
83 {
84     gssize i;
85
86     /* For in success, call cleanup for all GI_DIRECTION_IN values only. */
87     for (i = 0; i < cache->n_args; i++) {
88         PyGIArgCache *arg_cache = cache->args_cache[i];
89         PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
90
91         if (cleanup_func &&
92                 arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON &&
93                     state->args[i]->v_pointer != NULL)
94             cleanup_func (state, arg_cache, state->args[i]->v_pointer, TRUE);
95     }
96 }
97
98 void
99 pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState   *state,
100                                                  PyGICallableCache *cache)
101 {
102     /* clean up the return if available */
103     if (cache->return_cache != NULL) {
104         PyGIMarshalCleanupFunc cleanup_func = cache->return_cache->to_py_cleanup;
105         if (cleanup_func && state->return_arg.v_pointer != NULL)
106             cleanup_func (state,
107                           cache->return_cache,
108                           state->return_arg.v_pointer,
109                           TRUE);
110     }
111
112     /* Now clean up args */
113     GSList *cache_item = cache->to_py_args;
114     while (cache_item) {
115         PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data;
116         PyGIMarshalCleanupFunc cleanup_func = arg_cache->to_py_cleanup;
117         gpointer data = state->args[arg_cache->c_arg_index]->v_pointer;
118
119         if (cleanup_func != NULL && data != NULL)
120             cleanup_func (state,
121                           arg_cache,
122                           data,
123                           TRUE);
124
125         cache_item = cache_item->next;
126     }
127 }
128
129 void
130 pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState   *state,
131                                                   PyGICallableCache *cache,
132                                                   gssize failed_arg_index)
133 {
134     gssize i;
135
136     state->failed = TRUE;
137
138     for (i = 0; i < cache->n_args  && i <= failed_arg_index; i++) {
139         PyGIArgCache *arg_cache = cache->args_cache[i];
140         PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
141         gpointer data = state->args[i]->v_pointer;
142
143         if (cleanup_func &&
144                 arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON &&
145                     data != NULL) {
146             cleanup_func (state,
147                           arg_cache,
148                           data,
149                           i < failed_arg_index);
150
151         } else if (arg_cache->is_caller_allocates && data != NULL) {
152             _cleanup_caller_allocates (state,
153                                        arg_cache,
154                                        data);
155         }
156     }
157 }
158
159 void
160 pygi_marshal_cleanup_args_return_fail (PyGIInvokeState   *state,
161                                        PyGICallableCache *cache)
162 {
163     state->failed = TRUE;
164 }
165
166 void
167 pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState   *state,
168                                               PyGICallableCache *cache,
169                                               gssize failed_to_py_arg_index)
170 {
171     state->failed = TRUE;
172 }
173
174 void
175 _pygi_marshal_cleanup_from_py_utf8 (PyGIInvokeState *state,
176                                     PyGIArgCache    *arg_cache,
177                                     gpointer         data,
178                                     gboolean         was_processed)
179 {
180     /* We strdup strings so always free if we have processed this
181        parameter for input */
182     if (was_processed)
183         g_free (data);
184 }
185
186 void
187 _pygi_marshal_cleanup_to_py_utf8 (PyGIInvokeState *state,
188                                   PyGIArgCache    *arg_cache,
189                                   gpointer         data,
190                                   gboolean         was_processed)
191 {
192     /* Python copies the string so we need to free it
193        if the interface is transfering ownership, 
194        whether or not it has been processed yet */
195     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
196         g_free (data);
197 }
198
199 void
200 _pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
201                                                 PyGIArgCache    *arg_cache,
202                                                 gpointer         data,
203                                                 gboolean         was_processed)
204 {
205     /* If we processed the parameter but fail before invoking the method,
206        we need to remove the ref we added */
207     if (was_processed && state->failed && data != NULL &&
208             arg_cache->transfer == GI_TRANSFER_EVERYTHING)
209         g_object_unref (G_OBJECT(data));
210 }
211
212 void
213 _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
214                                               PyGIArgCache    *arg_cache,
215                                               gpointer         data,
216                                               gboolean         was_processed)
217 {
218     /* If we error out and the object is not marshalled into a PyGObject
219        we must take care of removing the ref */
220     if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
221         g_object_unref (G_OBJECT(data));
222 }
223
224
225 void
226 _pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state,
227                                                   PyGIArgCache    *arg_cache,
228                                                   gpointer         data,
229                                                   gboolean         was_processed)
230 {
231     PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
232     if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) {
233         _pygi_invoke_closure_free (state->args_data[arg_cache->c_arg_index]);
234         state->args_data[arg_cache->c_arg_index] = NULL;
235     }
236 }
237
238 void 
239 _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
240                                                        PyGIArgCache    *arg_cache,
241                                                        gpointer         data,
242                                                        gboolean         was_processed)
243 {
244     if (was_processed) {
245         PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
246                                              arg_cache->py_arg_index);
247         GType py_object_type =
248             pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
249
250         if (py_object_type != G_TYPE_VALUE) {
251             g_value_unset ((GValue *) data);
252             g_slice_free (GValue, data);
253         }
254     }
255 }
256
257 void
258 _pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state,
259                                                         PyGIArgCache    *arg_cache,
260                                                         gpointer         data,
261                                                         gboolean         was_processed)
262 {
263     if (state->failed && was_processed)
264         pygi_struct_foreign_release (
265             ( (PyGIInterfaceCache *)arg_cache)->interface_info,
266             data);
267 }
268
269 void
270 _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
271                                                       PyGIArgCache    *arg_cache,
272                                                       gpointer         data,
273                                                       gboolean         was_processed)
274 {
275     if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
276         pygi_struct_foreign_release ( 
277             ( (PyGIInterfaceCache *)arg_cache)->interface_info,
278             data);
279 }
280
281 static GArray*
282 _wrap_c_array (PyGIInvokeState   *state,
283                PyGISequenceCache *sequence_cache,
284                gpointer           data)
285 {
286     GArray *array_;
287     gsize   len = 0;
288   
289     if (sequence_cache->fixed_size >= 0) {
290         len = sequence_cache->fixed_size;
291     } else if (sequence_cache->is_zero_terminated) {
292         len = g_strv_length ((gchar **)data);
293     } else if (sequence_cache->len_arg_index >= 0) {
294         GIArgument *len_arg = state->args[sequence_cache->len_arg_index];
295         len = len_arg->v_long;
296     }
297
298     array_ = g_array_new (FALSE,
299                           FALSE,
300                           sequence_cache->item_size);
301
302     if (array_ == NULL)
303         return NULL;
304
305     g_free (array_->data);
306     array_->data = data;
307     array_->len = len;
308
309     return array_;
310 }
311
312 void
313 _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
314                                      PyGIArgCache    *arg_cache,
315                                      gpointer         data,
316                                      gboolean         was_processed)
317 {
318     if (was_processed) {
319         GArray *array_ = NULL;
320         GPtrArray *ptr_array_ = NULL;
321         PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
322
323         /* If this isn't a garray create one to help process variable sized
324            array elements */
325         if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
326             array_ = _wrap_c_array (state, sequence_cache, data);
327             
328             if (array_ == NULL)
329                 return;
330             
331         } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
332             ptr_array_ = (GPtrArray *) data;
333         } else {
334             array_ = (GArray *) data;
335         }
336
337         /* clean up items first */
338         if (sequence_cache->item_cache->from_py_cleanup != NULL) {
339             gsize i;
340             guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
341             PyGIMarshalCleanupFunc cleanup_func =
342                 sequence_cache->item_cache->from_py_cleanup;
343
344             for (i = 0; i < len; i++) {
345                 gpointer item;
346
347                 /* case 1: GPtrArray */
348                 if (ptr_array_ != NULL)
349                     item = g_ptr_array_index (ptr_array_, i);
350                 /* case 2: C array or GArray with object pointers */
351                 else if (sequence_cache->item_cache->is_pointer)
352                     item = g_array_index (array_, gpointer, i);
353                 /* case 3: C array or GArray with simple types or structs */
354                 else
355                     item = array_->data + i * sequence_cache->item_size;
356
357                 cleanup_func (state, sequence_cache->item_cache, item, TRUE);
358             }
359         }
360
361         /* Only free the array when we didn't transfer ownership */
362         if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
363             g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING);
364         } else if (state->failed ||
365                    arg_cache->transfer == GI_TRANSFER_NOTHING) {
366             if (array_ != NULL)
367                 g_array_free (array_, TRUE);
368             else
369                 g_ptr_array_free (ptr_array_, TRUE);
370         }
371     }
372 }
373
374 void
375 _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
376                                    PyGIArgCache    *arg_cache,
377                                    gpointer         data,
378                                    gboolean         was_processed)
379 {
380     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
381         arg_cache->transfer == GI_TRANSFER_CONTAINER) {
382         GArray *array_ = NULL;
383         GPtrArray *ptr_array_ = NULL;
384         PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
385
386         /* If this isn't a garray create one to help process variable sized
387            array elements */
388         if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
389             array_ = _wrap_c_array (state, sequence_cache, data);
390             
391             if (array_ == NULL)
392                 return;
393
394         } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
395             ptr_array_ = (GPtrArray *) data;
396         } else {
397             array_ = (GArray *) data;
398         }
399
400         if (sequence_cache->item_cache->to_py_cleanup != NULL) {
401             gsize i;
402             guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
403
404             PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup;
405             for (i = 0; i < len; i++) {
406                 cleanup_func (state,
407                               sequence_cache->item_cache,
408                               (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i),
409                               was_processed);
410             }
411         }
412
413         if (array_ != NULL)
414             g_array_free (array_, TRUE);
415         else
416             g_ptr_array_free (ptr_array_, TRUE);
417     }
418 }
419
420 void
421 _pygi_marshal_cleanup_from_py_glist  (PyGIInvokeState *state,
422                                       PyGIArgCache    *arg_cache,
423                                       gpointer         data,
424                                       gboolean         was_processed)
425 {
426     if (was_processed) {
427         GSList *list_;
428         PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
429
430         list_ = (GSList *)data;
431
432         /* clean up items first */
433         if (sequence_cache->item_cache->from_py_cleanup != NULL) {
434             PyGIMarshalCleanupFunc cleanup_func =
435                 sequence_cache->item_cache->from_py_cleanup;
436             GSList *node = list_;
437             while (node != NULL) {
438                 cleanup_func (state,
439                               sequence_cache->item_cache,
440                               node->data,
441                               TRUE);
442                 node = node->next;
443             }
444         }
445
446         if (state->failed ||
447                arg_cache->transfer == GI_TRANSFER_NOTHING ||
448                   arg_cache->transfer == GI_TRANSFER_CONTAINER) {
449             switch (arg_cache->type_tag) {
450                 case GI_TYPE_TAG_GLIST:
451                     g_list_free ( (GList *)list_);
452                     break;
453                 case GI_TYPE_TAG_GSLIST:
454                     g_slist_free (list_);
455                     break;
456                 default:
457                     g_assert_not_reached();
458             }
459         }
460     }
461 }
462
463 void
464 _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state,
465                                    PyGIArgCache    *arg_cache,
466                                    gpointer         data,
467                                    gboolean         was_processed)
468 {
469     PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
470
471     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
472             arg_cache->transfer == GI_TRANSFER_CONTAINER) {
473         GSList *list_ = (GSList *)data;
474
475         if (sequence_cache->item_cache->to_py_cleanup != NULL) {
476             PyGIMarshalCleanupFunc cleanup_func =
477                 sequence_cache->item_cache->to_py_cleanup;
478             GSList *node = list_;
479
480             while (node != NULL) {
481                 cleanup_func (state,
482                               sequence_cache->item_cache,
483                               node->data,
484                               was_processed);
485                 node = node->next;
486             }
487         }
488
489         if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
490             switch (arg_cache->type_tag) {
491                 case GI_TYPE_TAG_GLIST:
492                     g_list_free ( (GList *)list_);
493                     break;
494                 case GI_TYPE_TAG_GSLIST:
495                     g_slist_free (list_);
496                     break;
497                 default:
498                     g_assert_not_reached();
499             }
500         }
501     }
502 }
503
504 void
505 _pygi_marshal_cleanup_from_py_ghash  (PyGIInvokeState *state,
506                                       PyGIArgCache    *arg_cache,
507                                       gpointer         data,
508                                       gboolean         was_processed)
509 {
510     if (data == NULL)
511         return;
512
513     if (was_processed) {
514         GHashTable *hash_;
515         PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
516
517         hash_ = (GHashTable *)data;
518
519         /* clean up keys and values first */
520         if (hash_cache->key_cache->from_py_cleanup != NULL ||
521                 hash_cache->value_cache->from_py_cleanup != NULL) {
522             GHashTableIter hiter;
523             gpointer key;
524             gpointer value;
525
526             PyGIMarshalCleanupFunc key_cleanup_func =
527                 hash_cache->key_cache->from_py_cleanup;
528             PyGIMarshalCleanupFunc value_cleanup_func =
529                 hash_cache->value_cache->from_py_cleanup;
530
531             g_hash_table_iter_init (&hiter, hash_);
532             while (g_hash_table_iter_next (&hiter, &key, &value)) {
533                 if (key != NULL && key_cleanup_func != NULL)
534                     key_cleanup_func (state,
535                                       hash_cache->key_cache,
536                                       key,
537                                       TRUE);
538                 if (value != NULL && value_cleanup_func != NULL)
539                     value_cleanup_func (state,
540                                         hash_cache->value_cache,
541                                         value,
542                                         TRUE);
543             }
544         }
545
546         if (state->failed ||
547                arg_cache->transfer == GI_TRANSFER_NOTHING ||
548                   arg_cache->transfer == GI_TRANSFER_CONTAINER)
549             g_hash_table_destroy (hash_);
550
551     }
552 }
553
554 void
555 _pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state,
556                                    PyGIArgCache    *arg_cache,
557                                    gpointer         data,
558                                    gboolean         was_processed)
559 {
560     if (data == NULL)
561         return;
562
563     /* assume hashtable has boxed key and value */
564     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
565         g_hash_table_destroy ( (GHashTable *)data);
566 }