Branch data Line data Source code
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 : 0 : value_to_ffi_type (const GValue *gvalue, void **value)
48 : : {
49 : 0 : ffi_type *rettype = NULL;
50 : 0 : GType type = g_type_fundamental (G_VALUE_TYPE (gvalue));
51 : 0 : g_assert (type != G_TYPE_INVALID);
52 : :
53 : 0 : switch (type)
54 : : {
55 : 0 : case G_TYPE_BOOLEAN:
56 : : case G_TYPE_CHAR:
57 : : case G_TYPE_INT:
58 : 0 : rettype = &ffi_type_sint;
59 : 0 : *value = (void *) &(gvalue->data[0].v_int);
60 : 0 : break;
61 : 0 : case G_TYPE_UCHAR:
62 : : case G_TYPE_UINT:
63 : 0 : rettype = &ffi_type_uint;
64 : 0 : *value = (void *) &(gvalue->data[0].v_uint);
65 : 0 : break;
66 : 0 : 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 : 0 : rettype = &ffi_type_pointer;
72 : 0 : *value = (void *) &(gvalue->data[0].v_pointer);
73 : 0 : break;
74 : 0 : case G_TYPE_FLOAT:
75 : 0 : rettype = &ffi_type_float;
76 : 0 : *value = (void *) &(gvalue->data[0].v_float);
77 : 0 : break;
78 : 0 : case G_TYPE_DOUBLE:
79 : 0 : rettype = &ffi_type_double;
80 : 0 : *value = (void *) &(gvalue->data[0].v_double);
81 : 0 : break;
82 : 0 : case G_TYPE_LONG:
83 : 0 : rettype = &ffi_type_slong;
84 : 0 : *value = (void *) &(gvalue->data[0].v_long);
85 : 0 : break;
86 : 0 : case G_TYPE_ULONG:
87 : 0 : rettype = &ffi_type_ulong;
88 : 0 : *value = (void *) &(gvalue->data[0].v_ulong);
89 : 0 : break;
90 : 0 : case G_TYPE_INT64:
91 : 0 : rettype = &ffi_type_sint64;
92 : 0 : *value = (void *) &(gvalue->data[0].v_int64);
93 : 0 : break;
94 : 0 : case G_TYPE_UINT64:
95 : 0 : rettype = &ffi_type_uint64;
96 : 0 : *value = (void *) &(gvalue->data[0].v_uint64);
97 : 0 : break;
98 : 0 : default:
99 : 0 : rettype = &ffi_type_pointer;
100 : 0 : *value = NULL;
101 : 0 : g_warning ("Unsupported fundamental type: %s", g_type_name (type));
102 : 0 : break;
103 : : }
104 : 0 : 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 : 0 : g_value_to_ffi_return_type (const GValue *gvalue,
124 : : const GIArgument *ffi_value,
125 : : void **value)
126 : : {
127 : 0 : ffi_type *rettype = NULL;
128 : 0 : GType type = g_type_fundamental (G_VALUE_TYPE (gvalue));
129 : 0 : g_assert (type != G_TYPE_INVALID);
130 : :
131 : 0 : *value = (void *) &(ffi_value->v_long);
132 : :
133 : 0 : switch (type) {
134 : 0 : case G_TYPE_CHAR:
135 : 0 : rettype = &ffi_type_sint8;
136 : 0 : break;
137 : 0 : case G_TYPE_UCHAR:
138 : 0 : rettype = &ffi_type_uint8;
139 : 0 : break;
140 : 0 : case G_TYPE_BOOLEAN:
141 : : case G_TYPE_INT:
142 : 0 : rettype = &ffi_type_sint;
143 : 0 : break;
144 : 0 : case G_TYPE_UINT:
145 : 0 : rettype = &ffi_type_uint;
146 : 0 : break;
147 : 0 : 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 : 0 : rettype = &ffi_type_pointer;
153 : 0 : break;
154 : 0 : case G_TYPE_FLOAT:
155 : 0 : rettype = &ffi_type_float;
156 : 0 : *value = (void *) &(ffi_value->v_float);
157 : 0 : break;
158 : 0 : case G_TYPE_DOUBLE:
159 : 0 : rettype = &ffi_type_double;
160 : 0 : *value = (void *) &(ffi_value->v_double);
161 : 0 : break;
162 : 0 : case G_TYPE_LONG:
163 : 0 : rettype = &ffi_type_slong;
164 : 0 : break;
165 : 0 : case G_TYPE_ULONG:
166 : 0 : rettype = &ffi_type_ulong;
167 : 0 : break;
168 : 0 : case G_TYPE_INT64:
169 : 0 : rettype = &ffi_type_sint64;
170 : 0 : *value = (void *) &(ffi_value->v_int64);
171 : 0 : break;
172 : 0 : case G_TYPE_UINT64:
173 : 0 : rettype = &ffi_type_uint64;
174 : 0 : *value = (void *) &(ffi_value->v_uint64);
175 : 0 : break;
176 : 0 : default:
177 : 0 : rettype = &ffi_type_pointer;
178 : 0 : *value = NULL;
179 : 0 : g_warning ("Unsupported fundamental type: %s", g_type_name (type));
180 : 0 : break;
181 : : }
182 : 0 : 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 : 0 : g_value_from_ffi_value (GValue *gvalue,
199 : : const GIArgument *value)
200 : : {
201 : 0 : switch (g_type_fundamental (G_VALUE_TYPE (gvalue))) {
202 : 0 : case G_TYPE_INT:
203 : 0 : g_value_set_int (gvalue, (gint)value->v_long);
204 : 0 : break;
205 : 0 : case G_TYPE_FLOAT:
206 : 0 : g_value_set_float (gvalue, (gfloat)value->v_float);
207 : 0 : break;
208 : 0 : case G_TYPE_DOUBLE:
209 : 0 : g_value_set_double (gvalue, (gdouble)value->v_double);
210 : 0 : break;
211 : 0 : case G_TYPE_BOOLEAN:
212 : 0 : g_value_set_boolean (gvalue, (gboolean)value->v_long);
213 : 0 : break;
214 : 0 : case G_TYPE_STRING:
215 : 0 : g_value_set_string (gvalue, (char*)value->v_pointer);
216 : 0 : break;
217 : 0 : case G_TYPE_CHAR:
218 : 0 : g_value_set_schar (gvalue, (char)value->v_long);
219 : 0 : break;
220 : 0 : case G_TYPE_UCHAR:
221 : 0 : g_value_set_uchar (gvalue, (guchar)value->v_ulong);
222 : 0 : break;
223 : 0 : case G_TYPE_UINT:
224 : 0 : g_value_set_uint (gvalue, (guint)value->v_ulong);
225 : 0 : break;
226 : 0 : case G_TYPE_POINTER:
227 : 0 : g_value_set_pointer (gvalue, (gpointer)value->v_pointer);
228 : 0 : break;
229 : 0 : case G_TYPE_LONG:
230 : 0 : g_value_set_long (gvalue, (glong)value->v_long);
231 : 0 : break;
232 : 0 : case G_TYPE_ULONG:
233 : 0 : g_value_set_ulong (gvalue, (gulong)value->v_ulong);
234 : 0 : break;
235 : 0 : case G_TYPE_INT64:
236 : 0 : g_value_set_int64 (gvalue, (gint64)value->v_int64);
237 : 0 : break;
238 : 0 : case G_TYPE_UINT64:
239 : 0 : g_value_set_uint64 (gvalue, (guint64)value->v_uint64);
240 : 0 : break;
241 : 0 : case G_TYPE_BOXED:
242 : 0 : g_value_set_boxed (gvalue, (gpointer)value->v_pointer);
243 : 0 : break;
244 : 0 : case G_TYPE_PARAM:
245 : 0 : g_value_set_param (gvalue, (gpointer)value->v_pointer);
246 : 0 : break;
247 : 0 : default:
248 : 0 : g_warning ("Unsupported fundamental type: %s",
249 : : g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue))));
250 : : }
251 : :
252 : 0 : }
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 : 0 : gi_cclosure_marshal_generic (GClosure *closure,
272 : : GValue *return_gvalue,
273 : : unsigned int n_param_values,
274 : : const GValue *param_values,
275 : : void *invocation_hint,
276 : : void *marshal_data)
277 : : {
278 : 0 : GIArgument return_ffi_value = { 0, };
279 : : ffi_type *rtype;
280 : : void *rvalue;
281 : : unsigned int n_args;
282 : : ffi_type **atypes;
283 : : void **args;
284 : : unsigned int i;
285 : : ffi_cif cif;
286 : 0 : GCClosure *cc = (GCClosure*) closure;
287 : :
288 : 0 : if (return_gvalue && G_VALUE_TYPE (return_gvalue))
289 : : {
290 : 0 : rtype = g_value_to_ffi_return_type (return_gvalue, &return_ffi_value,
291 : : &rvalue);
292 : : }
293 : : else
294 : : {
295 : 0 : rtype = &ffi_type_void;
296 : 0 : rvalue = &return_ffi_value.v_long;
297 : : }
298 : :
299 : 0 : n_args = n_param_values + 1;
300 : 0 : atypes = g_alloca (sizeof (ffi_type *) * n_args);
301 : 0 : args = g_alloca (sizeof (void *) * n_args);
302 : :
303 : 0 : if (n_param_values > 0)
304 : : {
305 : 0 : if (G_CCLOSURE_SWAP_DATA (closure))
306 : : {
307 : 0 : atypes[n_args-1] = value_to_ffi_type (param_values + 0,
308 : 0 : &args[n_args-1]);
309 : 0 : atypes[0] = &ffi_type_pointer;
310 : 0 : args[0] = &closure->data;
311 : : }
312 : : else
313 : : {
314 : 0 : atypes[0] = value_to_ffi_type (param_values + 0, &args[0]);
315 : 0 : atypes[n_args-1] = &ffi_type_pointer;
316 : 0 : args[n_args-1] = &closure->data;
317 : : }
318 : : }
319 : : else
320 : : {
321 : 0 : atypes[0] = &ffi_type_pointer;
322 : 0 : args[0] = &closure->data;
323 : : }
324 : :
325 : 0 : for (i = 1; i < n_args - 1; i++)
326 : 0 : atypes[i] = value_to_ffi_type (param_values + i, &args[i]);
327 : :
328 : 0 : if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK)
329 : 0 : return;
330 : :
331 : 0 : ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args);
332 : :
333 : 0 : if (return_gvalue && G_VALUE_TYPE (return_gvalue))
334 : 0 : g_value_from_ffi_value (return_gvalue, &return_ffi_value);
335 : : }
|