Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : * GObject introspection: Virtual Function implementation
3 : : *
4 : : * Copyright (C) 2005 Matthias Clasen
5 : : * Copyright (C) 2008,2009 Red Hat, Inc.
6 : : *
7 : : * SPDX-License-Identifier: LGPL-2.1-or-later
8 : : *
9 : : * This library is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU Lesser General Public
11 : : * License as published by the Free Software Foundation; either
12 : : * version 2 of the License, or (at your option) any later version.
13 : : *
14 : : * This library is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : * Lesser General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU Lesser General Public
20 : : * License along with this library; if not, write to the
21 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 : : * Boston, MA 02111-1307, USA.
23 : : */
24 : :
25 : : #include "config.h"
26 : :
27 : : #include <string.h>
28 : :
29 : : #include <glib.h>
30 : :
31 : : #include <girepository/girepository.h>
32 : : #include "gibaseinfo-private.h"
33 : : #include "girepository-private.h"
34 : : #include "gitypelib-internal.h"
35 : : #include "givfuncinfo.h"
36 : :
37 : : /**
38 : : * GIVFuncInfo:
39 : : *
40 : : * `GIVFuncInfo` represents a virtual function.
41 : : *
42 : : * A virtual function is a callable object that belongs to either a
43 : : * [type@GIRepository.ObjectInfo] or a [type@GIRepository.InterfaceInfo].
44 : : *
45 : : * Since: 2.80
46 : : */
47 : :
48 : : GIVFuncInfo *
49 : 7 : gi_base_info_find_vfunc (GIRealInfo *rinfo,
50 : : uint32_t offset,
51 : : uint16_t n_vfuncs,
52 : : const char *name)
53 : : {
54 : : /* FIXME hash */
55 : 7 : Header *header = (Header *)rinfo->typelib->data;
56 : :
57 : 165 : for (uint16_t i = 0; i < n_vfuncs; i++)
58 : : {
59 : 165 : VFuncBlob *fblob = (VFuncBlob *)&rinfo->typelib->data[offset];
60 : 165 : const char *fname = (const char *)&rinfo->typelib->data[fblob->name];
61 : :
62 : 165 : if (strcmp (name, fname) == 0)
63 : 7 : return (GIVFuncInfo *) gi_base_info_new (GI_INFO_TYPE_VFUNC, (GIBaseInfo*) rinfo,
64 : : rinfo->typelib, offset);
65 : :
66 : 158 : offset += header->vfunc_blob_size;
67 : : }
68 : :
69 : 0 : return NULL;
70 : : }
71 : :
72 : : /**
73 : : * gi_vfunc_info_get_flags:
74 : : * @info: a #GIVFuncInfo
75 : : *
76 : : * Obtain the flags for this virtual function info.
77 : : *
78 : : * See [flags@GIRepository.VFuncInfoFlags] for more information about possible
79 : : * flag values.
80 : : *
81 : : * Returns: the flags
82 : : * Since: 2.80
83 : : */
84 : : GIVFuncInfoFlags
85 : 0 : gi_vfunc_info_get_flags (GIVFuncInfo *info)
86 : : {
87 : : GIVFuncInfoFlags flags;
88 : 0 : GIRealInfo *rinfo = (GIRealInfo *)info;
89 : : VFuncBlob *blob;
90 : :
91 : 0 : g_return_val_if_fail (info != NULL, 0);
92 : 0 : g_return_val_if_fail (GI_IS_VFUNC_INFO (info), 0);
93 : :
94 : 0 : blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset];
95 : :
96 : 0 : flags = 0;
97 : :
98 : 0 : if (blob->must_chain_up)
99 : 0 : flags = flags | GI_VFUNC_MUST_CHAIN_UP;
100 : :
101 : 0 : if (blob->must_be_implemented)
102 : 0 : flags = flags | GI_VFUNC_MUST_OVERRIDE;
103 : :
104 : 0 : if (blob->must_not_be_implemented)
105 : 0 : flags = flags | GI_VFUNC_MUST_NOT_OVERRIDE;
106 : :
107 : 0 : return flags;
108 : : }
109 : :
110 : : /**
111 : : * gi_vfunc_info_get_offset:
112 : : * @info: a #GIVFuncInfo
113 : : *
114 : : * Obtain the offset of the function pointer in the class struct.
115 : : *
116 : : * The value `0xFFFF` indicates that the struct offset is unknown.
117 : : *
118 : : * Returns: the struct offset or `0xFFFF` if it’s unknown
119 : : * Since: 2.80
120 : : */
121 : : size_t
122 : 0 : gi_vfunc_info_get_offset (GIVFuncInfo *info)
123 : : {
124 : 0 : GIRealInfo *rinfo = (GIRealInfo *)info;
125 : : VFuncBlob *blob;
126 : :
127 : 0 : g_return_val_if_fail (info != NULL, 0);
128 : 0 : g_return_val_if_fail (GI_IS_VFUNC_INFO (info), 0);
129 : :
130 : 0 : blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset];
131 : :
132 : 0 : return blob->struct_offset;
133 : : }
134 : :
135 : : /**
136 : : * gi_vfunc_info_get_signal:
137 : : * @info: a #GIVFuncInfo
138 : : *
139 : : * Obtain the signal for the virtual function if one is set.
140 : : *
141 : : * The signal comes from the object or interface to which
142 : : * this virtual function belongs.
143 : : *
144 : : * Returns: (transfer full) (nullable): the signal, or `NULL` if none is set
145 : : * Since: 2.80
146 : : */
147 : : GISignalInfo *
148 : 0 : gi_vfunc_info_get_signal (GIVFuncInfo *info)
149 : : {
150 : 0 : GIRealInfo *rinfo = (GIRealInfo *)info;
151 : : VFuncBlob *blob;
152 : :
153 : 0 : g_return_val_if_fail (info != NULL, 0);
154 : 0 : g_return_val_if_fail (GI_IS_VFUNC_INFO (info), 0);
155 : :
156 : 0 : blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset];
157 : :
158 : 0 : if (blob->class_closure)
159 : 0 : return gi_interface_info_get_signal ((GIInterfaceInfo *)rinfo->container, blob->signal);
160 : :
161 : 0 : return NULL;
162 : : }
163 : :
164 : : /**
165 : : * gi_vfunc_info_get_invoker:
166 : : * @info: a #GIVFuncInfo
167 : : *
168 : : * If this virtual function has an associated invoker method, this
169 : : * method will return it. An invoker method is a C entry point.
170 : : *
171 : : * Not all virtuals will have invokers.
172 : : *
173 : : * Returns: (transfer full) (nullable): The [type@GIRepository.FunctionInfo] or
174 : : * `NULL` if none is set. Free it with [method@GIRepository.BaseInfo.unref]
175 : : * when done.
176 : : * Since: 2.80
177 : : */
178 : : GIFunctionInfo *
179 : 3 : gi_vfunc_info_get_invoker (GIVFuncInfo *info)
180 : : {
181 : 3 : GIRealInfo *rinfo = (GIRealInfo *)info;
182 : : VFuncBlob *blob;
183 : : GIBaseInfo *container;
184 : : GIInfoType parent_type;
185 : :
186 : 3 : g_return_val_if_fail (info != NULL, 0);
187 : 3 : g_return_val_if_fail (GI_IS_VFUNC_INFO (info), 0);
188 : :
189 : 3 : blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset];
190 : :
191 : : /* 1023 = 0x3ff is the maximum of the 10 bits for invoker index */
192 : 3 : if (blob->invoker == 1023)
193 : 1 : return NULL;
194 : :
195 : 2 : container = rinfo->container;
196 : 2 : parent_type = gi_base_info_get_info_type (container);
197 : 2 : if (parent_type == GI_INFO_TYPE_OBJECT)
198 : 1 : return gi_object_info_get_method ((GIObjectInfo*)container, blob->invoker);
199 : 1 : else if (parent_type == GI_INFO_TYPE_INTERFACE)
200 : 1 : return gi_interface_info_get_method ((GIInterfaceInfo*)container, blob->invoker);
201 : : else
202 : : g_assert_not_reached ();
203 : : }
204 : :
205 : : /**
206 : : * gi_vfunc_info_get_address:
207 : : * @info: a #GIVFuncInfo
208 : : * @implementor_gtype: [type@GObject.Type] implementing this virtual function
209 : : * @error: return location for a [type@GLib.Error], or `NULL`
210 : : *
211 : : * Looks up where the implementation for @info is inside the type struct of
212 : : * @implementor_gtype.
213 : : *
214 : : * Returns: address to a function
215 : : * Since: 2.80
216 : : */
217 : : void *
218 : 0 : gi_vfunc_info_get_address (GIVFuncInfo *vfunc_info,
219 : : GType implementor_gtype,
220 : : GError **error)
221 : : {
222 : : GIBaseInfo *container_info;
223 : : GIInterfaceInfo *interface_info;
224 : : GIObjectInfo *object_info;
225 : : GIStructInfo *struct_info;
226 : 0 : GIFieldInfo *field_info = NULL;
227 : : int length, i, offset;
228 : : void *implementor_class, *implementor_vtable;
229 : 0 : void *func = NULL;
230 : :
231 : 0 : g_return_val_if_fail (vfunc_info != NULL, NULL);
232 : 0 : g_return_val_if_fail (GI_IS_VFUNC_INFO (vfunc_info), NULL);
233 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
234 : :
235 : 0 : container_info = gi_base_info_get_container ((GIBaseInfo *) vfunc_info);
236 : 0 : if (gi_base_info_get_info_type (container_info) == GI_INFO_TYPE_OBJECT)
237 : : {
238 : 0 : object_info = (GIObjectInfo*) container_info;
239 : 0 : interface_info = NULL;
240 : 0 : struct_info = gi_object_info_get_class_struct (object_info);
241 : : }
242 : : else
243 : : {
244 : 0 : interface_info = (GIInterfaceInfo*) container_info;
245 : 0 : object_info = NULL;
246 : 0 : struct_info = gi_interface_info_get_iface_struct (interface_info);
247 : : }
248 : :
249 : 0 : length = gi_struct_info_get_n_fields (struct_info);
250 : 0 : for (i = 0; i < length; i++)
251 : : {
252 : 0 : field_info = gi_struct_info_get_field (struct_info, i);
253 : :
254 : 0 : if (strcmp (gi_base_info_get_name ( (GIBaseInfo*) field_info),
255 : : gi_base_info_get_name ( (GIBaseInfo*) vfunc_info)) != 0) {
256 : 0 : gi_base_info_unref ((GIBaseInfo *) field_info);
257 : 0 : field_info = NULL;
258 : 0 : continue;
259 : : }
260 : :
261 : 0 : break;
262 : : }
263 : :
264 : 0 : if (field_info == NULL)
265 : : {
266 : 0 : g_set_error (error,
267 : : GI_INVOKE_ERROR,
268 : : GI_INVOKE_ERROR_SYMBOL_NOT_FOUND,
269 : : "Couldn't find struct field for this vfunc");
270 : 0 : goto out;
271 : : }
272 : :
273 : 0 : implementor_class = g_type_class_ref (implementor_gtype);
274 : :
275 : 0 : if (object_info)
276 : : {
277 : 0 : implementor_vtable = implementor_class;
278 : : }
279 : : else
280 : : {
281 : : GType interface_type;
282 : :
283 : 0 : interface_type = gi_registered_type_info_get_g_type ((GIRegisteredTypeInfo*) interface_info);
284 : 0 : implementor_vtable = g_type_interface_peek (implementor_class, interface_type);
285 : : }
286 : :
287 : 0 : offset = gi_field_info_get_offset (field_info);
288 : 0 : func = *(void**) G_STRUCT_MEMBER_P (implementor_vtable, offset);
289 : 0 : g_type_class_unref (implementor_class);
290 : 0 : gi_base_info_unref ((GIBaseInfo *) field_info);
291 : :
292 : 0 : if (func == NULL)
293 : : {
294 : 0 : g_set_error (error,
295 : : GI_INVOKE_ERROR,
296 : : GI_INVOKE_ERROR_SYMBOL_NOT_FOUND,
297 : : "Class %s doesn't implement %s",
298 : : g_type_name (implementor_gtype),
299 : : gi_base_info_get_name ( (GIBaseInfo*) vfunc_info));
300 : 0 : goto out;
301 : : }
302 : :
303 : 0 : out:
304 : 0 : gi_base_info_unref ((GIBaseInfo*) struct_info);
305 : :
306 : 0 : return func;
307 : : }
308 : :
309 : : /**
310 : : * gi_vfunc_info_invoke: (skip)
311 : : * @info: a #GIVFuncInfo describing the virtual function to invoke
312 : : * @implementor: [type@GObject.Type] of the type that implements this virtual
313 : : * function
314 : : * @in_args: (array length=n_in_args) (nullable): an array of
315 : : * [struct@GIRepository.Argument]s, one for each ‘in’ parameter of @info. If
316 : : * there are no ‘in’ parameters, @in_args can be `NULL`
317 : : * @n_in_args: the length of the @in_args array
318 : : * @out_args: (array length=n_out_args) (nullable): an array of
319 : : * [struct@GIRepository.Argument]s allocated by the caller, one for each
320 : : * ‘out’ parameter of @info. If there are no ‘out’ parameters, @out_args may
321 : : * be `NULL`
322 : : * @n_out_args: the length of the @out_args array
323 : : * @return_value: (out caller-allocates) (not optional) (nullable): return
324 : : * location for the return value from the vfunc; `NULL` may be returned if
325 : : * the vfunc returns that
326 : : * @error: return location for detailed error information, or `NULL`
327 : : *
328 : : * Invokes the function described in @info with the given
329 : : * arguments.
330 : : *
331 : : * Note that ‘inout’ parameters must appear in both argument lists.
332 : : *
333 : : * Returns: `TRUE` if the vfunc was executed successfully and didn’t throw
334 : : * a [type@GLib.Error]; `FALSE` if @error is set
335 : : * Since: 2.80
336 : : */
337 : : gboolean
338 : 0 : gi_vfunc_info_invoke (GIVFuncInfo *info,
339 : : GType implementor,
340 : : const GIArgument *in_args,
341 : : size_t n_in_args,
342 : : GIArgument *out_args,
343 : : size_t n_out_args,
344 : : GIArgument *return_value,
345 : : GError **error)
346 : : {
347 : : void *func;
348 : 0 : GError *local_error = NULL;
349 : :
350 : 0 : g_return_val_if_fail (info != NULL, FALSE);
351 : 0 : g_return_val_if_fail (GI_IS_VFUNC_INFO (info), FALSE);
352 : 0 : g_return_val_if_fail (in_args != NULL || n_in_args == 0, FALSE);
353 : 0 : g_return_val_if_fail (out_args != NULL || n_out_args == 0, FALSE);
354 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
355 : :
356 : 0 : func = gi_vfunc_info_get_address (info, implementor, &local_error);
357 : 0 : if (local_error != NULL)
358 : : {
359 : 0 : g_propagate_error (error, g_steal_pointer (&local_error));
360 : 0 : return FALSE;
361 : : }
362 : :
363 : 0 : return gi_callable_info_invoke ((GICallableInfo*) info,
364 : : func,
365 : : in_args,
366 : : n_in_args,
367 : : out_args,
368 : : n_out_args,
369 : : return_value,
370 : : error);
371 : : }
372 : :
373 : : void
374 : 4 : gi_vfunc_info_class_init (gpointer g_class,
375 : : gpointer class_data)
376 : : {
377 : 4 : GIBaseInfoClass *info_class = g_class;
378 : :
379 : 4 : info_class->info_type = GI_INFO_TYPE_VFUNC;
380 : 4 : }
|