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 : 18 : 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 : 18 : Header *header = (Header *)rinfo->typelib->data;
56 : :
57 : 342 : for (uint16_t i = 0; i < n_vfuncs; i++)
58 : : {
59 : 340 : VFuncBlob *fblob = (VFuncBlob *)&rinfo->typelib->data[offset];
60 : 340 : const char *fname = (const char *)&rinfo->typelib->data[fblob->name];
61 : :
62 : 340 : if (strcmp (name, fname) == 0)
63 : 24 : return (GIVFuncInfo *) gi_base_info_new (GI_INFO_TYPE_VFUNC, (GIBaseInfo*) rinfo,
64 : 8 : rinfo->typelib, offset);
65 : :
66 : 324 : offset += header->vfunc_blob_size;
67 : 162 : }
68 : :
69 : 2 : return NULL;
70 : 9 : }
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 : 0 : }
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 : 0 : }
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 : 0 : }
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 : 6 : gi_vfunc_info_get_invoker (GIVFuncInfo *info)
180 : : {
181 : 6 : GIRealInfo *rinfo = (GIRealInfo *)info;
182 : : VFuncBlob *blob;
183 : : GIBaseInfo *container;
184 : : GIInfoType parent_type;
185 : :
186 : 6 : g_return_val_if_fail (info != NULL, 0);
187 : 9 : g_return_val_if_fail (GI_IS_VFUNC_INFO (info), 0);
188 : :
189 : 6 : blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset];
190 : :
191 : : /* 1023 = 0x3ff is the maximum of the 10 bits for invoker index */
192 : 6 : if (blob->invoker == 1023)
193 : 2 : return NULL;
194 : :
195 : 4 : container = rinfo->container;
196 : 4 : parent_type = gi_base_info_get_info_type (container);
197 : 4 : if (parent_type == GI_INFO_TYPE_OBJECT)
198 : 2 : return gi_object_info_get_method ((GIObjectInfo*)container, blob->invoker);
199 : 2 : else if (parent_type == GI_INFO_TYPE_INTERFACE)
200 : 2 : return gi_interface_info_get_method ((GIInterfaceInfo*)container, blob->invoker);
201 : : else
202 : : g_assert_not_reached ();
203 : 3 : }
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 : : size_t offset;
228 : : unsigned int length, i;
229 : : void *implementor_class, *implementor_vtable;
230 : 0 : void *func = NULL;
231 : :
232 : 0 : g_return_val_if_fail (vfunc_info != NULL, NULL);
233 : 0 : g_return_val_if_fail (GI_IS_VFUNC_INFO (vfunc_info), NULL);
234 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
235 : :
236 : 0 : container_info = gi_base_info_get_container ((GIBaseInfo *) vfunc_info);
237 : 0 : if (gi_base_info_get_info_type (container_info) == GI_INFO_TYPE_OBJECT)
238 : : {
239 : 0 : object_info = (GIObjectInfo*) container_info;
240 : 0 : interface_info = NULL;
241 : 0 : struct_info = gi_object_info_get_class_struct (object_info);
242 : 0 : }
243 : : else
244 : : {
245 : 0 : interface_info = (GIInterfaceInfo*) container_info;
246 : 0 : object_info = NULL;
247 : 0 : struct_info = gi_interface_info_get_iface_struct (interface_info);
248 : : }
249 : :
250 : 0 : length = gi_struct_info_get_n_fields (struct_info);
251 : 0 : for (i = 0; i < length; i++)
252 : : {
253 : 0 : field_info = gi_struct_info_get_field (struct_info, i);
254 : :
255 : 0 : if (strcmp (gi_base_info_get_name ( (GIBaseInfo*) field_info),
256 : 0 : gi_base_info_get_name ( (GIBaseInfo*) vfunc_info)) != 0) {
257 : 0 : gi_base_info_unref ((GIBaseInfo *) field_info);
258 : 0 : field_info = NULL;
259 : 0 : continue;
260 : : }
261 : :
262 : 0 : break;
263 : : }
264 : :
265 : 0 : if (field_info == NULL)
266 : : {
267 : 0 : g_set_error (error,
268 : 0 : GI_INVOKE_ERROR,
269 : : GI_INVOKE_ERROR_SYMBOL_NOT_FOUND,
270 : : "Couldn't find struct field for this vfunc");
271 : 0 : goto out;
272 : : }
273 : :
274 : 0 : implementor_class = g_type_class_ref (implementor_gtype);
275 : :
276 : 0 : if (object_info)
277 : : {
278 : 0 : implementor_vtable = implementor_class;
279 : 0 : }
280 : : else
281 : : {
282 : : GType interface_type;
283 : :
284 : 0 : interface_type = gi_registered_type_info_get_g_type ((GIRegisteredTypeInfo*) interface_info);
285 : 0 : implementor_vtable = g_type_interface_peek (implementor_class, interface_type);
286 : : }
287 : :
288 : 0 : offset = gi_field_info_get_offset (field_info);
289 : 0 : func = *(void**) G_STRUCT_MEMBER_P (implementor_vtable, offset);
290 : 0 : g_type_class_unref (implementor_class);
291 : 0 : gi_base_info_unref ((GIBaseInfo *) field_info);
292 : :
293 : 0 : if (func == NULL)
294 : : {
295 : 0 : g_set_error (error,
296 : 0 : GI_INVOKE_ERROR,
297 : : GI_INVOKE_ERROR_SYMBOL_NOT_FOUND,
298 : : "Class %s doesn't implement %s",
299 : 0 : g_type_name (implementor_gtype),
300 : 0 : gi_base_info_get_name ( (GIBaseInfo*) vfunc_info));
301 : 0 : goto out;
302 : : }
303 : :
304 : 0 : out:
305 : 0 : gi_base_info_unref ((GIBaseInfo*) struct_info);
306 : :
307 : 0 : return func;
308 : 0 : }
309 : :
310 : : /**
311 : : * gi_vfunc_info_invoke: (skip)
312 : : * @info: a #GIVFuncInfo describing the virtual function to invoke
313 : : * @implementor: [type@GObject.Type] of the type that implements this virtual
314 : : * function
315 : : * @in_args: (array length=n_in_args) (nullable): an array of
316 : : * [struct@GIRepository.Argument]s, one for each ‘in’ parameter of @info. If
317 : : * there are no ‘in’ parameters, @in_args can be `NULL`
318 : : * @n_in_args: the length of the @in_args array
319 : : * @out_args: (array length=n_out_args) (nullable): an array of
320 : : * [struct@GIRepository.Argument]s allocated by the caller, one for each
321 : : * ‘out’ parameter of @info. If there are no ‘out’ parameters, @out_args may
322 : : * be `NULL`
323 : : * @n_out_args: the length of the @out_args array
324 : : * @return_value: (out caller-allocates) (not optional) (nullable): return
325 : : * location for the return value from the vfunc; `NULL` may be returned if
326 : : * the vfunc returns that
327 : : * @error: return location for detailed error information, or `NULL`
328 : : *
329 : : * Invokes the function described in @info with the given
330 : : * arguments.
331 : : *
332 : : * Note that ‘inout’ parameters must appear in both argument lists.
333 : : *
334 : : * Returns: `TRUE` if the vfunc was executed successfully and didn’t throw
335 : : * a [type@GLib.Error]; `FALSE` if @error is set
336 : : * Since: 2.80
337 : : */
338 : : gboolean
339 : 0 : gi_vfunc_info_invoke (GIVFuncInfo *info,
340 : : GType implementor,
341 : : const GIArgument *in_args,
342 : : size_t n_in_args,
343 : : GIArgument *out_args,
344 : : size_t n_out_args,
345 : : GIArgument *return_value,
346 : : GError **error)
347 : : {
348 : : void *func;
349 : 0 : GError *local_error = NULL;
350 : :
351 : 0 : g_return_val_if_fail (info != NULL, FALSE);
352 : 0 : g_return_val_if_fail (GI_IS_VFUNC_INFO (info), FALSE);
353 : 0 : g_return_val_if_fail (in_args != NULL || n_in_args == 0, FALSE);
354 : 0 : g_return_val_if_fail (out_args != NULL || n_out_args == 0, FALSE);
355 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
356 : :
357 : 0 : func = gi_vfunc_info_get_address (info, implementor, &local_error);
358 : 0 : if (local_error != NULL)
359 : : {
360 : 0 : g_propagate_error (error, g_steal_pointer (&local_error));
361 : 0 : return FALSE;
362 : : }
363 : :
364 : 0 : return gi_callable_info_invoke ((GICallableInfo*) info,
365 : 0 : func,
366 : 0 : in_args,
367 : 0 : n_in_args,
368 : 0 : out_args,
369 : 0 : n_out_args,
370 : 0 : return_value,
371 : 0 : error);
372 : 0 : }
373 : :
374 : : void
375 : 10 : gi_vfunc_info_class_init (gpointer g_class,
376 : : gpointer class_data)
377 : : {
378 : 10 : GIBaseInfoClass *info_class = g_class;
379 : :
380 : 10 : info_class->info_type = GI_INFO_TYPE_VFUNC;
381 : 10 : }
|