f80ebfa2b7af4a94796d84dadfa6b4e8cd515631
[platform/upstream/pygobject2.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_closure_unref (PyGIInvokeState *state,
176                                      PyGIArgCache    *arg_cache,
177                                      gpointer         data,
178                                      gboolean         was_processed)
179 {
180     g_closure_unref ( (GClosure *)data);
181 }
182
183 void
184 _pygi_marshal_cleanup_from_py_utf8 (PyGIInvokeState *state,
185                                     PyGIArgCache    *arg_cache,
186                                     gpointer         data,
187                                     gboolean         was_processed)
188 {
189     /* We strdup strings so always free if we have processed this
190        parameter for input */
191     if (was_processed)
192         g_free (data);
193 }
194
195 void
196 _pygi_marshal_cleanup_to_py_utf8 (PyGIInvokeState *state,
197                                   PyGIArgCache    *arg_cache,
198                                   gpointer         data,
199                                   gboolean         was_processed)
200 {
201     /* Python copies the string so we need to free it
202        if the interface is transfering ownership, 
203        whether or not it has been processed yet */
204     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
205         g_free (data);
206 }
207
208 void
209 _pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
210                                                 PyGIArgCache    *arg_cache,
211                                                 gpointer         data,
212                                                 gboolean         was_processed)
213 {
214     /* If we processed the parameter but fail before invoking the method,
215        we need to remove the ref we added */
216     if (was_processed && state->failed && data != NULL &&
217             arg_cache->transfer == GI_TRANSFER_EVERYTHING)
218         g_object_unref (G_OBJECT(data));
219 }
220
221 void
222 _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
223                                               PyGIArgCache    *arg_cache,
224                                               gpointer         data,
225                                               gboolean         was_processed)
226 {
227     /* If we error out and the object is not marshalled into a PyGObject
228        we must take care of removing the ref */
229     if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
230         g_object_unref (G_OBJECT(data));
231 }
232
233 void 
234 _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
235                                                        PyGIArgCache    *arg_cache,
236                                                        gpointer         data,
237                                                        gboolean         was_processed)
238 {
239     if (was_processed) {
240         PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
241                                              arg_cache->py_arg_index);
242         GType py_object_type =
243             pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
244
245         if (py_object_type != G_TYPE_VALUE) {
246             g_value_unset ((GValue *) data);
247             g_slice_free (GValue, data);
248         }
249     }
250 }
251
252 void
253 _pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state,
254                                                         PyGIArgCache    *arg_cache,
255                                                         gpointer         data,
256                                                         gboolean         was_processed)
257 {
258     if (state->failed && was_processed)
259         pygi_struct_foreign_release (
260             ( (PyGIInterfaceCache *)arg_cache)->interface_info,
261             data);
262 }
263
264 void
265 _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
266                                                       PyGIArgCache    *arg_cache,
267                                                       gpointer         data,
268                                                       gboolean         was_processed)
269 {
270     if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
271         pygi_struct_foreign_release ( 
272             ( (PyGIInterfaceCache *)arg_cache)->interface_info,
273             data);
274 }
275
276 static GArray*
277 _wrap_c_array (PyGIInvokeState   *state,
278                PyGISequenceCache *sequence_cache,
279                gpointer           data)
280 {
281     GArray *array_;
282     gsize   len;
283   
284     if (sequence_cache->fixed_size >= 0) {
285         len = sequence_cache->fixed_size;
286     } else if (sequence_cache->is_zero_terminated) {
287         len = g_strv_length ((gchar **)data);
288     } else {
289         GIArgument *len_arg = state->args[sequence_cache->len_arg_index];
290         len = len_arg->v_long;
291     }
292
293     array_ = g_array_new (FALSE,
294                           FALSE,
295                           sequence_cache->item_size);
296
297     if (array_ == NULL)
298         return NULL;
299
300     g_free (array_->data);
301     array_->data = data;
302     array_->len = len;
303
304     return array_;
305 }
306
307 void
308 _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
309                                      PyGIArgCache    *arg_cache,
310                                      gpointer         data,
311                                      gboolean         was_processed)
312 {
313     if (was_processed) {
314         GArray *array_;
315         PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
316
317         /* If this isn't a garray create one to help process variable sized
318            array elements */
319         if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
320             array_ = _wrap_c_array (state, sequence_cache, data);
321             
322             if (array_ == NULL)
323                 return;
324             
325         } else {
326             array_ = (GArray *) data;
327         }
328
329         /* clean up items first */
330         if (sequence_cache->item_cache->from_py_cleanup != NULL) {
331             gsize i;
332             PyGIMarshalCleanupFunc cleanup_func =
333                 sequence_cache->item_cache->from_py_cleanup;
334
335             for(i = 0; i < array_->len; i++) {
336                 cleanup_func (state,
337                               sequence_cache->item_cache,
338                               g_array_index (array_, gpointer, i),
339                               TRUE);
340             }
341         }
342
343         /* Only free the array when we didn't transfer ownership */
344         if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
345             g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING);
346         } else if (state->failed ||
347                    arg_cache->transfer == GI_TRANSFER_NOTHING) {
348             g_array_free (array_, TRUE);
349         }
350     }
351 }
352
353 void
354 _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
355                                    PyGIArgCache    *arg_cache,
356                                    gpointer         data,
357                                    gboolean         was_processed)
358 {
359     PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
360
361     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
362         arg_cache->transfer == GI_TRANSFER_CONTAINER) {
363         GArray *array_;
364         PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
365
366         /* If this isn't a garray create one to help process variable sized
367            array elements */
368         if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
369             array_ = _wrap_c_array (state, sequence_cache, data);
370             
371             if (array_ == NULL)
372                 return;
373             
374         } else {
375             array_ = (GArray *) data;
376         }
377
378         if (sequence_cache->item_cache->to_py_cleanup != NULL) {
379             gsize i;
380
381             PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup;
382             for (i = 0; i < array_->len; i++) {
383                 cleanup_func (state,
384                               sequence_cache->item_cache,
385                               g_array_index (array_, gpointer, i),
386                               was_processed);
387             }
388         }
389
390         g_array_free (array_, TRUE);
391     }
392 }
393
394 void
395 _pygi_marshal_cleanup_from_py_glist  (PyGIInvokeState *state,
396                                       PyGIArgCache    *arg_cache,
397                                       gpointer         data,
398                                       gboolean         was_processed)
399 {
400     if (was_processed) {
401         GSList *list_;
402         PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
403
404         list_ = (GSList *)data;
405
406         /* clean up items first */
407         if (sequence_cache->item_cache->from_py_cleanup != NULL) {
408             PyGIMarshalCleanupFunc cleanup_func =
409                 sequence_cache->item_cache->from_py_cleanup;
410             GSList *node = list_;
411             while (node != NULL) {
412                 cleanup_func (state,
413                               sequence_cache->item_cache,
414                               node->data,
415                               TRUE);
416                 node = node->next;
417             }
418         }
419
420         if (state->failed ||
421                arg_cache->transfer == GI_TRANSFER_NOTHING ||
422                   arg_cache->transfer == GI_TRANSFER_CONTAINER) {
423             switch (arg_cache->type_tag) {
424                 case GI_TYPE_TAG_GLIST:
425                     g_list_free ( (GList *)list_);
426                     break;
427                 case GI_TYPE_TAG_GSLIST:
428                     g_slist_free (list_);
429                     break;
430                 default:
431                     g_assert_not_reached();
432             }
433         }
434     }
435 }
436
437 void
438 _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state,
439                                    PyGIArgCache    *arg_cache,
440                                    gpointer         data,
441                                    gboolean         was_processed)
442 {
443     PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
444
445     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
446             arg_cache->transfer == GI_TRANSFER_CONTAINER) {
447         GSList *list_ = (GSList *)data;
448
449         if (sequence_cache->item_cache->to_py_cleanup != NULL) {
450             PyGIMarshalCleanupFunc cleanup_func =
451                 sequence_cache->item_cache->to_py_cleanup;
452             GSList *node = list_;
453
454             while (node != NULL) {
455                 cleanup_func (state,
456                               sequence_cache->item_cache,
457                               node->data,
458                               was_processed);
459                 node = node->next;
460             }
461         }
462
463         if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
464             switch (arg_cache->type_tag) {
465                 case GI_TYPE_TAG_GLIST:
466                     g_list_free ( (GList *)list_);
467                     break;
468                 case GI_TYPE_TAG_GSLIST:
469                     g_slist_free (list_);
470                     break;
471                 default:
472                     g_assert_not_reached();
473             }
474         }
475     }
476 }
477
478 void
479 _pygi_marshal_cleanup_from_py_ghash  (PyGIInvokeState *state,
480                                       PyGIArgCache    *arg_cache,
481                                       gpointer         data,
482                                       gboolean         was_processed)
483 {
484     if (data == NULL)
485         return;
486
487     if (was_processed) {
488         GHashTable *hash_;
489         PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
490
491         hash_ = (GHashTable *)data;
492
493         /* clean up keys and values first */
494         if (hash_cache->key_cache->from_py_cleanup != NULL ||
495                 hash_cache->value_cache->from_py_cleanup != NULL) {
496             GHashTableIter hiter;
497             gpointer key;
498             gpointer value;
499
500             PyGIMarshalCleanupFunc key_cleanup_func =
501                 hash_cache->key_cache->from_py_cleanup;
502             PyGIMarshalCleanupFunc value_cleanup_func =
503                 hash_cache->value_cache->from_py_cleanup;
504
505             g_hash_table_iter_init (&hiter, hash_);
506             while (g_hash_table_iter_next (&hiter, &key, &value)) {
507                 if (key != NULL && key_cleanup_func != NULL)
508                     key_cleanup_func (state,
509                                       hash_cache->key_cache,
510                                       key,
511                                       TRUE);
512                 if (value != NULL && value_cleanup_func != NULL)
513                     value_cleanup_func (state,
514                                         hash_cache->value_cache,
515                                         value,
516                                         TRUE);
517             }
518         }
519
520         if (state->failed ||
521                arg_cache->transfer == GI_TRANSFER_NOTHING ||
522                   arg_cache->transfer == GI_TRANSFER_CONTAINER)
523             g_hash_table_destroy (hash_);
524
525     }
526 }
527
528 void
529 _pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state,
530                                    PyGIArgCache    *arg_cache,
531                                    gpointer         data,
532                                    gboolean         was_processed)
533 {
534     if (data == NULL)
535         return;
536
537     /* assume hashtable has boxed key and value */
538     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
539         g_hash_table_destroy ( (GHashTable *)data);
540 }