(root)/
glib-2.79.0/
girepository/
ginvoke.c
       1  /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
       2   * GObject introspection: Invoke functionality
       3   *
       4   * Copyright (C) 2005 Matthias Clasen
       5   *
       6   * SPDX-License-Identifier: LGPL-2.1-or-later
       7   *
       8   * This library is free software; you can redistribute it and/or
       9   * modify it under the terms of the GNU Lesser General Public
      10   * License as published by the Free Software Foundation; either
      11   * version 2 of the License, or (at your option) any later version.
      12   *
      13   * This library is distributed in the hope that it will be useful,
      14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16   * Lesser General Public License for more details.
      17   *
      18   * You should have received a copy of the GNU Lesser General Public
      19   * License along with this library; if not, write to the
      20   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      21   * Boston, MA 02111-1307, USA.
      22   */
      23  
      24  #include "config.h"
      25  
      26  #include <stdlib.h>
      27  
      28  #include <glib.h>
      29  #include <glib-object.h>
      30  
      31  #include <girepository/girepository.h>
      32  #include "girffi.h"
      33  
      34  /**
      35   * value_to_ffi_type:
      36   * @gvalue: (transfer none): a [type@GObject.Value] to convert
      37   * @value: (out caller-allocates): return location for the ffi data
      38   *
      39   * Convert @gvalue to a format suitable for passing to ffi.
      40   *
      41   * @value is only valid as long as @gvalue is alive.
      42   *
      43   * Returns: pointer to the `ffi_type` associated with @value
      44   * Since: 2.80
      45   */
      46  static ffi_type *
      47  value_to_ffi_type (const GValue *gvalue, gpointer *value)
      48  {
      49    ffi_type *rettype = NULL;
      50    GType type = g_type_fundamental (G_VALUE_TYPE (gvalue));
      51    g_assert (type != G_TYPE_INVALID);
      52  
      53    switch (type)
      54      {
      55      case G_TYPE_BOOLEAN:
      56      case G_TYPE_CHAR:
      57      case G_TYPE_INT:
      58        rettype = &ffi_type_sint;
      59        *value = (gpointer)&(gvalue->data[0].v_int);
      60        break;
      61      case G_TYPE_UCHAR:
      62      case G_TYPE_UINT:
      63        rettype = &ffi_type_uint;
      64        *value = (gpointer)&(gvalue->data[0].v_uint);
      65        break;
      66      case G_TYPE_STRING:
      67      case G_TYPE_OBJECT:
      68      case G_TYPE_BOXED:
      69      case G_TYPE_POINTER:
      70      case G_TYPE_PARAM:
      71        rettype = &ffi_type_pointer;
      72        *value = (gpointer)&(gvalue->data[0].v_pointer);
      73        break;
      74      case G_TYPE_FLOAT:
      75        rettype = &ffi_type_float;
      76        *value = (gpointer)&(gvalue->data[0].v_float);
      77        break;
      78      case G_TYPE_DOUBLE:
      79        rettype = &ffi_type_double;
      80        *value = (gpointer)&(gvalue->data[0].v_double);
      81        break;
      82      case G_TYPE_LONG:
      83        rettype = &ffi_type_slong;
      84        *value = (gpointer)&(gvalue->data[0].v_long);
      85        break;
      86      case G_TYPE_ULONG:
      87        rettype = &ffi_type_ulong;
      88        *value = (gpointer)&(gvalue->data[0].v_ulong);
      89        break;
      90      case G_TYPE_INT64:
      91        rettype = &ffi_type_sint64;
      92        *value = (gpointer)&(gvalue->data[0].v_int64);
      93        break;
      94      case G_TYPE_UINT64:
      95        rettype = &ffi_type_uint64;
      96        *value = (gpointer)&(gvalue->data[0].v_uint64);
      97        break;
      98      default:
      99        rettype = &ffi_type_pointer;
     100        *value = NULL;
     101        g_warning ("Unsupported fundamental type: %s", g_type_name (type));
     102        break;
     103      }
     104    return rettype;
     105  }
     106  
     107  /**
     108   * g_value_to_ffi_return_type:
     109   * @gvalue: (transfer none): a [type@GObject.Value] to convert
     110   * @ffi_value: (transfer none): a [type@GIRepository.Argument] containing the
     111   *   data to use
     112   * @value: (out caller-allocates): return location for the ffi data
     113   *
     114   * Convert @ffi_value to a format suitable for passing to ffi, using the type
     115   * data from @gvalue.
     116   *
     117   * @value is only valid as long as @gvalue and @ffi_value are alive.
     118   *
     119   * Returns: pointer to the `ffi_type` associated with @value
     120   * Since: 2.80
     121   */
     122  static ffi_type *
     123  g_value_to_ffi_return_type (const GValue *gvalue,
     124  			    const GIArgument *ffi_value,
     125  			    gpointer *value)
     126  {
     127    ffi_type *rettype = NULL;
     128    GType type = g_type_fundamental (G_VALUE_TYPE (gvalue));
     129    g_assert (type != G_TYPE_INVALID);
     130  
     131    *value = (gpointer)&(ffi_value->v_long);
     132  
     133    switch (type) {
     134    case G_TYPE_CHAR:
     135      rettype = &ffi_type_sint8;
     136      break;
     137    case G_TYPE_UCHAR:
     138      rettype = &ffi_type_uint8;
     139      break;
     140    case G_TYPE_BOOLEAN:
     141    case G_TYPE_INT:
     142      rettype = &ffi_type_sint;
     143      break;
     144    case G_TYPE_UINT:
     145      rettype = &ffi_type_uint;
     146      break;
     147    case G_TYPE_STRING:
     148    case G_TYPE_OBJECT:
     149    case G_TYPE_BOXED:
     150    case G_TYPE_POINTER:
     151    case G_TYPE_PARAM:
     152      rettype = &ffi_type_pointer;
     153      break;
     154    case G_TYPE_FLOAT:
     155      rettype = &ffi_type_float;
     156      *value = (gpointer)&(ffi_value->v_float);
     157      break;
     158    case G_TYPE_DOUBLE:
     159      rettype = &ffi_type_double;
     160      *value = (gpointer)&(ffi_value->v_double);
     161      break;
     162    case G_TYPE_LONG:
     163      rettype = &ffi_type_slong;
     164      break;
     165    case G_TYPE_ULONG:
     166      rettype = &ffi_type_ulong;
     167      break;
     168    case G_TYPE_INT64:
     169      rettype = &ffi_type_sint64;
     170      *value = (gpointer)&(ffi_value->v_int64);
     171      break;
     172    case G_TYPE_UINT64:
     173      rettype = &ffi_type_uint64;
     174      *value = (gpointer)&(ffi_value->v_uint64);
     175      break;
     176    default:
     177      rettype = &ffi_type_pointer;
     178      *value = NULL;
     179      g_warning ("Unsupported fundamental type: %s", g_type_name (type));
     180      break;
     181    }
     182    return rettype;
     183  }
     184  
     185  /**
     186   * g_value_from_ffi_value:
     187   * @gvalue: (inout): a [type@GObject.Value] to set
     188   * @value: (transfer none): ffi data to convert
     189   *
     190   * Convert @value to a [type@GObject.Value] according to the type already set
     191   * on @gvalue.
     192   *
     193   * @gvalue is valid even after @value is finalised.
     194   *
     195   * Since: 2.80
     196   */
     197  static void
     198  g_value_from_ffi_value (GValue           *gvalue,
     199                          const GIArgument *value)
     200  {
     201    switch (g_type_fundamental (G_VALUE_TYPE (gvalue))) {
     202    case G_TYPE_INT:
     203        g_value_set_int (gvalue, (gint)value->v_long);
     204        break;
     205    case G_TYPE_FLOAT:
     206        g_value_set_float (gvalue, (gfloat)value->v_float);
     207        break;
     208    case G_TYPE_DOUBLE:
     209        g_value_set_double (gvalue, (gdouble)value->v_double);
     210        break;
     211    case G_TYPE_BOOLEAN:
     212        g_value_set_boolean (gvalue, (gboolean)value->v_long);
     213        break;
     214    case G_TYPE_STRING:
     215        g_value_set_string (gvalue, (gchar*)value->v_pointer);
     216        break;
     217    case G_TYPE_CHAR:
     218        g_value_set_schar (gvalue, (gchar)value->v_long);
     219        break;
     220    case G_TYPE_UCHAR:
     221        g_value_set_uchar (gvalue, (guchar)value->v_ulong);
     222        break;
     223    case G_TYPE_UINT:
     224        g_value_set_uint (gvalue, (guint)value->v_ulong);
     225        break;
     226    case G_TYPE_POINTER:
     227        g_value_set_pointer (gvalue, (gpointer)value->v_pointer);
     228        break;
     229    case G_TYPE_LONG:
     230        g_value_set_long (gvalue, (glong)value->v_long);
     231        break;
     232    case G_TYPE_ULONG:
     233        g_value_set_ulong (gvalue, (gulong)value->v_ulong);
     234        break;
     235    case G_TYPE_INT64:
     236        g_value_set_int64 (gvalue, (gint64)value->v_int64);
     237        break;
     238    case G_TYPE_UINT64:
     239        g_value_set_uint64 (gvalue, (guint64)value->v_uint64);
     240        break;
     241    case G_TYPE_BOXED:
     242        g_value_set_boxed (gvalue, (gpointer)value->v_pointer);
     243        break;
     244    case G_TYPE_PARAM:
     245        g_value_set_param (gvalue, (gpointer)value->v_pointer);
     246        break;
     247    default:
     248      g_warning ("Unsupported fundamental type: %s",
     249  	       g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue))));
     250    }
     251  
     252  }
     253  
     254  /**
     255   * gi_cclosure_marshal_generic: (skip)
     256   * @closure: a [type@GObject.Closure]
     257   * @return_gvalue: (optional) (out caller-allocates): return location for the
     258   *   return value from the closure, or `NULL` to ignore
     259   * @n_param_values: number of param values
     260   * @param_values: (array length=n_param_values): values to pass to the closure
     261   *   parameters
     262   * @invocation_hint: invocation hint
     263   * @marshal_data: marshal data
     264   *
     265   * A generic C closure marshal function using ffi and
     266   * [type@GIRepository.Argument].
     267   *
     268   * Since: 2.80
     269   */
     270  void
     271  gi_cclosure_marshal_generic (GClosure *closure,
     272                               GValue *return_gvalue,
     273                               guint n_param_values,
     274                               const GValue *param_values,
     275                               gpointer invocation_hint,
     276                               gpointer marshal_data)
     277  {
     278    GIArgument return_ffi_value = { 0, };
     279    ffi_type *rtype;
     280    void *rvalue;
     281    int n_args;
     282    ffi_type **atypes;
     283    void **args;
     284    int i;
     285    ffi_cif cif;
     286    GCClosure *cc = (GCClosure*) closure;
     287  
     288    if (return_gvalue && G_VALUE_TYPE (return_gvalue))
     289      {
     290        rtype = g_value_to_ffi_return_type (return_gvalue, &return_ffi_value,
     291  					  &rvalue);
     292      }
     293    else
     294      {
     295        rtype = &ffi_type_void;
     296        rvalue = &return_ffi_value.v_long;
     297      }
     298  
     299    n_args = n_param_values + 1;
     300    atypes = g_alloca (sizeof (ffi_type *) * n_args);
     301    args =  g_alloca (sizeof (gpointer) * n_args);
     302  
     303    if (n_param_values > 0)
     304      {
     305        if (G_CCLOSURE_SWAP_DATA (closure))
     306          {
     307            atypes[n_args-1] = value_to_ffi_type (param_values + 0,
     308                                                  &args[n_args-1]);
     309            atypes[0] = &ffi_type_pointer;
     310            args[0] = &closure->data;
     311          }
     312        else
     313          {
     314            atypes[0] = value_to_ffi_type (param_values + 0, &args[0]);
     315            atypes[n_args-1] = &ffi_type_pointer;
     316            args[n_args-1] = &closure->data;
     317          }
     318      }
     319    else
     320      {
     321        atypes[0] = &ffi_type_pointer;
     322        args[0] = &closure->data;
     323      }
     324  
     325    for (i = 1; i < n_args - 1; i++)
     326      atypes[i] = value_to_ffi_type (param_values + i, &args[i]);
     327  
     328    if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK)
     329      return;
     330  
     331    ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args);
     332  
     333    if (return_gvalue && G_VALUE_TYPE (return_gvalue))
     334      g_value_from_ffi_value (return_gvalue, &return_ffi_value);
     335  }