Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : * GObject introspection: Base struct 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 <stdlib.h>
28 : : #include <string.h>
29 : :
30 : : #include <glib.h>
31 : : #include <glib-object.h>
32 : : #include <gobject/gvaluecollector.h>
33 : :
34 : : #include "gitypelib-internal.h"
35 : : #include "girepository-private.h"
36 : : #include "gibaseinfo.h"
37 : : #include "gibaseinfo-private.h"
38 : :
39 : : #define INVALID_REFCOUNT 0x7FFFFFFF
40 : :
41 : : /* Type registration of BaseInfo. */
42 : : #define GI_BASE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_TYPE_BASE_INFO, GIBaseInfoClass))
43 : :
44 : : static void
45 : 0 : value_base_info_init (GValue *value)
46 : : {
47 : 0 : value->data[0].v_pointer = NULL;
48 : 0 : }
49 : :
50 : : static void
51 : 0 : value_base_info_free_value (GValue *value)
52 : : {
53 : 0 : if (value->data[0].v_pointer != NULL)
54 : 0 : gi_base_info_unref (value->data[0].v_pointer);
55 : 0 : }
56 : :
57 : : static void
58 : 0 : value_base_info_copy_value (const GValue *src,
59 : : GValue *dst)
60 : : {
61 : 0 : if (src->data[0].v_pointer != NULL)
62 : 0 : dst->data[0].v_pointer = gi_base_info_ref (src->data[0].v_pointer);
63 : : else
64 : 0 : dst->data[0].v_pointer = NULL;
65 : 0 : }
66 : :
67 : : static void *
68 : 0 : value_base_info_peek_pointer (const GValue *value)
69 : : {
70 : 0 : return value->data[0].v_pointer;
71 : : }
72 : :
73 : : static char *
74 : 0 : value_base_info_collect_value (GValue *value,
75 : : guint n_collect_values,
76 : : GTypeCValue *collect_values,
77 : : guint collect_flags)
78 : : {
79 : 0 : GIBaseInfo *info = collect_values[0].v_pointer;
80 : :
81 : 0 : if (info == NULL)
82 : : {
83 : 0 : value->data[0].v_pointer = NULL;
84 : 0 : return NULL;
85 : : }
86 : :
87 : 0 : if (info->parent_instance.g_class == NULL)
88 : 0 : return g_strconcat ("invalid unclassed GIBaseInfo pointer for "
89 : : "value type '",
90 : : G_VALUE_TYPE_NAME (value),
91 : : "'",
92 : : NULL);
93 : :
94 : 0 : value->data[0].v_pointer = gi_base_info_ref (info);
95 : :
96 : 0 : return NULL;
97 : : }
98 : :
99 : : static char *
100 : 0 : value_base_info_lcopy_value (const GValue *value,
101 : : guint n_collect_values,
102 : : GTypeCValue *collect_values,
103 : : guint collect_flags)
104 : : {
105 : 0 : GIBaseInfo **node_p = collect_values[0].v_pointer;
106 : :
107 : 0 : if (node_p == NULL)
108 : 0 : return g_strconcat ("value location for '",
109 : : G_VALUE_TYPE_NAME (value),
110 : : "' passed as NULL",
111 : : NULL);
112 : :
113 : 0 : if (value->data[0].v_pointer == NULL)
114 : 0 : *node_p = NULL;
115 : 0 : else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
116 : 0 : *node_p = value->data[0].v_pointer;
117 : : else
118 : 0 : *node_p = gi_base_info_ref (value->data[0].v_pointer);
119 : :
120 : 0 : return NULL;
121 : : }
122 : :
123 : : static void
124 : 3045 : gi_base_info_finalize (GIBaseInfo *self)
125 : : {
126 : 3045 : if (self->ref_count != INVALID_REFCOUNT &&
127 : 3033 : self->container && self->container->ref_count != INVALID_REFCOUNT)
128 : 1010 : gi_base_info_unref (self->container);
129 : 3045 : }
130 : :
131 : : static void
132 : 9 : gi_base_info_class_init (GIBaseInfoClass *klass)
133 : : {
134 : 9 : klass->info_type = GI_INFO_TYPE_INVALID;
135 : 9 : klass->finalize = gi_base_info_finalize;
136 : 9 : }
137 : :
138 : : static void
139 : 3033 : gi_base_info_init (GIBaseInfo *self)
140 : : {
141 : : /* Initialise a dynamically allocated #GIBaseInfo’s members.
142 : : *
143 : : * This function *must* be kept in sync with gi_info_init(). */
144 : 3033 : g_atomic_ref_count_init (&self->ref_count);
145 : 3033 : }
146 : :
147 : : GType
148 : 6142 : gi_base_info_get_type (void)
149 : : {
150 : : static GType base_info_type = 0;
151 : :
152 : 6142 : if (g_once_init_enter_pointer (&base_info_type))
153 : : {
154 : : static const GTypeFundamentalInfo finfo = {
155 : : (G_TYPE_FLAG_CLASSED |
156 : : G_TYPE_FLAG_INSTANTIATABLE |
157 : : G_TYPE_FLAG_DERIVABLE |
158 : : G_TYPE_FLAG_DEEP_DERIVABLE),
159 : : };
160 : :
161 : : static const GTypeValueTable value_table = {
162 : : value_base_info_init,
163 : : value_base_info_free_value,
164 : : value_base_info_copy_value,
165 : : value_base_info_peek_pointer,
166 : : "p",
167 : : value_base_info_collect_value,
168 : : "p",
169 : : value_base_info_lcopy_value,
170 : : };
171 : :
172 : 10 : const GTypeInfo type_info = {
173 : : /* Class */
174 : : sizeof (GIBaseInfoClass),
175 : : (GBaseInitFunc) NULL,
176 : : (GBaseFinalizeFunc) NULL,
177 : : (GClassInitFunc) gi_base_info_class_init,
178 : : (GClassFinalizeFunc) NULL,
179 : : NULL,
180 : :
181 : : /* Instance */
182 : : sizeof (GIBaseInfo),
183 : : 0,
184 : : (GInstanceInitFunc) gi_base_info_init,
185 : :
186 : : /* GValue */
187 : : &value_table,
188 : : };
189 : :
190 : : GType _base_info_type =
191 : 10 : g_type_register_fundamental (g_type_fundamental_next (),
192 : : g_intern_static_string ("GIBaseInfo"),
193 : : &type_info, &finfo,
194 : : G_TYPE_FLAG_ABSTRACT);
195 : :
196 : 10 : g_once_init_leave_pointer (&base_info_type, _base_info_type);
197 : : }
198 : :
199 : 6142 : return base_info_type;
200 : : }
201 : :
202 : : /*< private >
203 : : * gi_base_info_type_register_static:
204 : : * @type_name: the name of the type
205 : : * @instance_size: size (in bytes) of the type’s instance struct
206 : : * @class_init: class init function for the type
207 : : * @parent_type: [type@GObject.Type] for the parent type; this will typically be
208 : : * `GI_TYPE_BASE_INFO`
209 : : * @type_flags: flags for the type
210 : : *
211 : : * Registers a new [type@GIRepository.BaseInfo] type for the given @type_name
212 : : * using the type information provided.
213 : : *
214 : : * Returns: the newly registered [type@GObject.Type]
215 : : * Since: 2.80
216 : : */
217 : : GType
218 : 190 : gi_base_info_type_register_static (const char *type_name,
219 : : size_t instance_size,
220 : : GClassInitFunc class_init,
221 : : GType parent_type,
222 : : GTypeFlags type_flags)
223 : : {
224 : : GTypeInfo info;
225 : :
226 : 190 : g_assert (instance_size <= G_MAXUINT16);
227 : :
228 : 190 : info.class_size = sizeof (GIBaseInfoClass);
229 : 190 : info.base_init = NULL;
230 : 190 : info.base_finalize = NULL;
231 : 190 : info.class_init = class_init;
232 : 190 : info.class_finalize = NULL;
233 : 190 : info.class_data = NULL;
234 : 190 : info.instance_size = (guint16) instance_size;
235 : 190 : info.n_preallocs = 0;
236 : 190 : info.instance_init = NULL;
237 : 190 : info.value_table = NULL;
238 : :
239 : 190 : return g_type_register_static (parent_type, type_name, &info, type_flags);
240 : : }
241 : :
242 : : static GType gi_base_info_types[GI_INFO_TYPE_N_TYPES];
243 : :
244 : : #define GI_DEFINE_BASE_INFO_TYPE(type_name, TYPE_ENUM_VALUE) \
245 : : GType \
246 : : type_name ## _get_type (void) \
247 : : { \
248 : : gi_base_info_init_types (); \
249 : : g_assert (gi_base_info_types[TYPE_ENUM_VALUE] != G_TYPE_INVALID); \
250 : : return gi_base_info_types[TYPE_ENUM_VALUE]; \
251 : : }
252 : :
253 : 66 : GI_DEFINE_BASE_INFO_TYPE (gi_callable_info, GI_INFO_TYPE_CALLABLE)
254 : 15 : GI_DEFINE_BASE_INFO_TYPE (gi_function_info, GI_INFO_TYPE_FUNCTION)
255 : 4 : GI_DEFINE_BASE_INFO_TYPE (gi_callback_info, GI_INFO_TYPE_CALLBACK)
256 : 36 : GI_DEFINE_BASE_INFO_TYPE (gi_registered_type_info, GI_INFO_TYPE_REGISTERED_TYPE)
257 : 25 : GI_DEFINE_BASE_INFO_TYPE (gi_struct_info, GI_INFO_TYPE_STRUCT)
258 : 7 : GI_DEFINE_BASE_INFO_TYPE (gi_union_info, GI_INFO_TYPE_UNION)
259 : 2960 : GI_DEFINE_BASE_INFO_TYPE (gi_enum_info, GI_INFO_TYPE_ENUM)
260 : 978 : GI_DEFINE_BASE_INFO_TYPE (gi_flags_info, GI_INFO_TYPE_FLAGS)
261 : 68 : GI_DEFINE_BASE_INFO_TYPE (gi_object_info, GI_INFO_TYPE_OBJECT)
262 : 32 : GI_DEFINE_BASE_INFO_TYPE (gi_interface_info, GI_INFO_TYPE_INTERFACE)
263 : 2 : GI_DEFINE_BASE_INFO_TYPE (gi_constant_info, GI_INFO_TYPE_CONSTANT)
264 : 1 : GI_DEFINE_BASE_INFO_TYPE (gi_value_info, GI_INFO_TYPE_VALUE)
265 : 3 : GI_DEFINE_BASE_INFO_TYPE (gi_signal_info, GI_INFO_TYPE_SIGNAL)
266 : 4 : GI_DEFINE_BASE_INFO_TYPE (gi_vfunc_info, GI_INFO_TYPE_VFUNC)
267 : 1 : GI_DEFINE_BASE_INFO_TYPE (gi_property_info, GI_INFO_TYPE_PROPERTY)
268 : 5 : GI_DEFINE_BASE_INFO_TYPE (gi_field_info, GI_INFO_TYPE_FIELD)
269 : 41 : GI_DEFINE_BASE_INFO_TYPE (gi_arg_info, GI_INFO_TYPE_ARG)
270 : 58 : GI_DEFINE_BASE_INFO_TYPE (gi_type_info, GI_INFO_TYPE_TYPE)
271 : 1 : GI_DEFINE_BASE_INFO_TYPE (gi_unresolved_info, GI_INFO_TYPE_UNRESOLVED)
272 : :
273 : : void
274 : 7340 : gi_base_info_init_types (void)
275 : : {
276 : : static size_t register_types_once = 0;
277 : :
278 : 7340 : if (g_once_init_enter (®ister_types_once))
279 : : {
280 : : const struct
281 : : {
282 : : GIInfoType info_type;
283 : : const char *type_name;
284 : : size_t instance_size;
285 : : GClassInitFunc class_init;
286 : : GIInfoType parent_info_type; /* 0 for GIBaseInfo */
287 : : GTypeFlags type_flags;
288 : : }
289 : 10 : types[] =
290 : : {
291 : : { GI_INFO_TYPE_CALLABLE, "GICallableInfo", sizeof (GICallableInfo), gi_callable_info_class_init, 0, G_TYPE_FLAG_ABSTRACT },
292 : : { GI_INFO_TYPE_FUNCTION, "GIFunctionInfo", sizeof (GIFunctionInfo), gi_function_info_class_init, GI_INFO_TYPE_CALLABLE, G_TYPE_FLAG_NONE },
293 : : { GI_INFO_TYPE_CALLBACK, "GICallbackInfo", sizeof (GICallbackInfo), gi_callback_info_class_init, GI_INFO_TYPE_CALLABLE, G_TYPE_FLAG_NONE },
294 : : { GI_INFO_TYPE_REGISTERED_TYPE, "GIRegisteredTypeInfo", sizeof (GIRegisteredTypeInfo), gi_registered_type_info_class_init, 0, G_TYPE_FLAG_ABSTRACT },
295 : : { GI_INFO_TYPE_STRUCT, "GIStructInfo", sizeof (GIStructInfo), gi_struct_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE },
296 : : { GI_INFO_TYPE_UNION, "GIUnionInfo", sizeof (GIUnionInfo), gi_union_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE },
297 : : { GI_INFO_TYPE_ENUM, "GIEnumInfo", sizeof (GIEnumInfo), gi_enum_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE },
298 : : { GI_INFO_TYPE_FLAGS, "GIFlagsInfo", sizeof (GIFlagsInfo), gi_flags_info_class_init, GI_INFO_TYPE_ENUM, G_TYPE_FLAG_NONE },
299 : : { GI_INFO_TYPE_OBJECT, "GIObjectInfo", sizeof (GIObjectInfo), gi_object_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE },
300 : : { GI_INFO_TYPE_INTERFACE, "GIInterfaceInfo", sizeof (GIInterfaceInfo), gi_interface_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE },
301 : : { GI_INFO_TYPE_CONSTANT, "GIConstantInfo", sizeof (GIConstantInfo), gi_constant_info_class_init, 0, G_TYPE_FLAG_NONE },
302 : : { GI_INFO_TYPE_VALUE, "GIValueInfo", sizeof (GIValueInfo), gi_value_info_class_init, 0, G_TYPE_FLAG_NONE },
303 : : { GI_INFO_TYPE_SIGNAL, "GISignalInfo", sizeof (GISignalInfo), gi_signal_info_class_init, GI_INFO_TYPE_CALLABLE, G_TYPE_FLAG_NONE },
304 : : { GI_INFO_TYPE_VFUNC, "GIVFuncInfo", sizeof (GIVFuncInfo), gi_vfunc_info_class_init, GI_INFO_TYPE_CALLABLE, G_TYPE_FLAG_NONE },
305 : : { GI_INFO_TYPE_PROPERTY, "GIPropertyInfo", sizeof (GIPropertyInfo), gi_property_info_class_init, 0, G_TYPE_FLAG_NONE },
306 : : { GI_INFO_TYPE_FIELD, "GIFieldInfo", sizeof (GIFieldInfo), gi_field_info_class_init, 0, G_TYPE_FLAG_NONE },
307 : : { GI_INFO_TYPE_ARG, "GIArgInfo", sizeof (GIArgInfo), gi_arg_info_class_init, 0, G_TYPE_FLAG_NONE },
308 : : { GI_INFO_TYPE_TYPE, "GITypeInfo", sizeof (GITypeInfo), gi_type_info_class_init, 0, G_TYPE_FLAG_NONE },
309 : : { GI_INFO_TYPE_UNRESOLVED, "GIUnresolvedInfo", sizeof (GIUnresolvedInfo), gi_unresolved_info_class_init, 0, G_TYPE_FLAG_NONE },
310 : : };
311 : :
312 : 200 : for (size_t i = 0; i < G_N_ELEMENTS (types); i++)
313 : : {
314 : : GType registered_type, parent_type;
315 : :
316 : 190 : parent_type = (types[i].parent_info_type == 0) ? GI_TYPE_BASE_INFO : gi_base_info_types[types[i].parent_info_type];
317 : 190 : g_assert (parent_type != G_TYPE_INVALID);
318 : :
319 : 190 : registered_type = gi_base_info_type_register_static (g_intern_static_string (types[i].type_name),
320 : 190 : types[i].instance_size,
321 : 190 : types[i].class_init,
322 : : parent_type,
323 : 190 : types[i].type_flags);
324 : 190 : gi_base_info_types[types[i].info_type] = registered_type;
325 : : }
326 : :
327 : 10 : g_once_init_leave (®ister_types_once, 1);
328 : : }
329 : 7340 : }
330 : :
331 : : /* info creation */
332 : : GIBaseInfo *
333 : 3033 : gi_info_new_full (GIInfoType type,
334 : : GIRepository *repository,
335 : : GIBaseInfo *container,
336 : : GITypelib *typelib,
337 : : uint32_t offset)
338 : : {
339 : : GIRealInfo *info;
340 : :
341 : 3033 : g_return_val_if_fail (container != NULL || repository != NULL, NULL);
342 : 3033 : g_return_val_if_fail (GI_IS_REPOSITORY (repository), NULL);
343 : : g_return_val_if_fail (offset <= G_MAXUINT32, NULL);
344 : :
345 : 3033 : gi_base_info_init_types ();
346 : 3033 : g_assert (gi_base_info_types[type] != G_TYPE_INVALID);
347 : 3033 : info = (GIRealInfo *) g_type_create_instance (gi_base_info_types[type]);
348 : :
349 : 3033 : info->typelib = typelib;
350 : 3033 : info->offset = offset;
351 : :
352 : 3033 : if (container)
353 : 1010 : info->container = container;
354 : 3033 : if (container && container->ref_count != INVALID_REFCOUNT)
355 : 1010 : gi_base_info_ref (info->container);
356 : :
357 : : /* Don’t keep a strong ref, since the repository keeps a cache of #GIBaseInfos
358 : : * and holds refs on them. If we kept a ref here, there’d be a cycle.
359 : : * Don’t keep a weak ref either, as that would make creating/destroying a
360 : : * #GIBaseInfo noticeably more expensive, and infos are performance critical
361 : : * for bindings.
362 : : * As stated in the documentation, the mitigation here is to require the user
363 : : * to keep the #GIRepository alive longer than any of its #GIBaseInfos. */
364 : 3033 : info->repository = repository;
365 : :
366 : 3033 : return (GIBaseInfo*)info;
367 : : }
368 : :
369 : : /**
370 : : * gi_base_info_new:
371 : : * @type: type of the info to create
372 : : * @container: (nullable): info which contains this one
373 : : * @typelib: typelib containing the info
374 : : * @offset: offset of the info within @typelib, in bytes
375 : : *
376 : : * Create a new #GIBaseInfo representing an object of the given @type from
377 : : * @offset of @typelib.
378 : : *
379 : : * Returns: (transfer full): The new #GIBaseInfo, unref with
380 : : * [method@GIRepository.BaseInfo.unref]
381 : : * Since: 2.80
382 : : */
383 : : GIBaseInfo *
384 : 1010 : gi_base_info_new (GIInfoType type,
385 : : GIBaseInfo *container,
386 : : GITypelib *typelib,
387 : : size_t offset)
388 : : {
389 : 1010 : return gi_info_new_full (type, ((GIRealInfo*)container)->repository, container, typelib, offset);
390 : : }
391 : :
392 : : /*< private >
393 : : * gi_info_init:
394 : : * @info: (out caller-allocates): caller-allocated #GIRealInfo to populate
395 : : * @type: type of the info to create
396 : : * @repository: repository the info is in
397 : : * @container: (nullable): info which contains this one
398 : : * @typelib: typelib containing the info
399 : : * @offset: offset of the info within @typelib, in bytes
400 : : *
401 : : * Initialise a stack-allocated #GIBaseInfo representing an object of the given
402 : : * @type from @offset of @typelib.
403 : : *
404 : : * Since: 2.80
405 : : */
406 : : void
407 : 12 : gi_info_init (GIRealInfo *info,
408 : : GType type,
409 : : GIRepository *repository,
410 : : GIBaseInfo *container,
411 : : GITypelib *typelib,
412 : : uint32_t offset)
413 : : {
414 : 12 : memset (info, 0, sizeof (GIRealInfo));
415 : :
416 : : /* Evil setup of a stack allocated #GTypeInstance. This is not something it’s
417 : : * really designed to do.
418 : : *
419 : : * This function *must* be kept in sync with gi_base_info_init(), which is
420 : : * the equivalent function for dynamically allocated types. */
421 : 12 : info->parent_instance.g_class = g_type_class_ref (type);
422 : :
423 : : /* g_type_create_instance() calls the #GInstanceInitFunc for each of the
424 : : * parent types, down to (and including) @type. We don’t need to do that, as
425 : : * #GIBaseInfo is fundamental so doesn’t have a parent type, the instance init
426 : : * function for #GIBaseInfo is gi_base_info_init() (which only sets the
427 : : * refcount, which we already do here), and subtypes of #GIBaseInfo don’t have
428 : : * instance init functions (see gi_base_info_type_register_static()). */
429 : :
430 : : /* Invalid refcount used to flag stack-allocated infos */
431 : 12 : info->ref_count = INVALID_REFCOUNT;
432 : 12 : info->typelib = typelib;
433 : 12 : info->offset = offset;
434 : :
435 : 12 : if (container)
436 : 12 : info->container = container;
437 : :
438 : 12 : g_assert (GI_IS_REPOSITORY (repository));
439 : 12 : info->repository = repository;
440 : 12 : }
441 : :
442 : : /**
443 : : * gi_base_info_clear:
444 : : * @info: (type GIRepository.BaseInfo): a #GIBaseInfo
445 : : *
446 : : * Clears memory allocated internally by a stack-allocated
447 : : * [type@GIRepository.BaseInfo].
448 : : *
449 : : * This does not deallocate the [type@GIRepository.BaseInfo] struct itself. It
450 : : * does clear the struct to zero so that calling this function subsequent times
451 : : * on the same struct is a no-op.
452 : : *
453 : : * This must only be called on stack-allocated [type@GIRepository.BaseInfo]s.
454 : : * Use [method@GIRepository.BaseInfo.unref] for heap-allocated ones.
455 : : *
456 : : * Since: 2.80
457 : : */
458 : : void
459 : 17 : gi_base_info_clear (void *info)
460 : : {
461 : 17 : GIBaseInfo *rinfo = (GIBaseInfo *) info;
462 : :
463 : : /* If @info is zero-filled, do nothing. This allows gi_base_info_clear() to be
464 : : * used with g_auto(). */
465 : 17 : if (rinfo->ref_count == 0)
466 : 5 : return;
467 : :
468 : 12 : g_return_if_fail (GI_IS_BASE_INFO (rinfo));
469 : :
470 : 12 : g_assert (rinfo->ref_count == INVALID_REFCOUNT);
471 : :
472 : 12 : GI_BASE_INFO_GET_CLASS (info)->finalize (rinfo);
473 : :
474 : 12 : g_type_class_unref (rinfo->parent_instance.g_class);
475 : :
476 : 12 : memset (rinfo, 0, sizeof (*rinfo));
477 : : }
478 : :
479 : : GIBaseInfo *
480 : 7 : gi_info_from_entry (GIRepository *repository,
481 : : GITypelib *typelib,
482 : : uint16_t index)
483 : : {
484 : : GIBaseInfo *result;
485 : 7 : DirEntry *entry = gi_typelib_get_dir_entry (typelib, index);
486 : :
487 : 7 : if (entry->local)
488 : 7 : result = gi_info_new_full (gi_typelib_blob_type_to_info_type (entry->blob_type),
489 : : repository, NULL, typelib, entry->offset);
490 : : else
491 : : {
492 : 0 : const char *namespace = gi_typelib_get_string (typelib, entry->offset);
493 : 0 : const char *name = gi_typelib_get_string (typelib, entry->name);
494 : :
495 : 0 : result = gi_repository_find_by_name (repository, namespace, name);
496 : 0 : if (result == NULL)
497 : : {
498 : : GIUnresolvedInfo *unresolved;
499 : :
500 : 0 : unresolved = (GIUnresolvedInfo *) gi_info_new_full (GI_INFO_TYPE_UNRESOLVED,
501 : : repository,
502 : : NULL,
503 : : typelib,
504 : : entry->offset);
505 : :
506 : 0 : unresolved->name = name;
507 : 0 : unresolved->namespace = namespace;
508 : :
509 : 0 : return (GIBaseInfo *)unresolved;
510 : : }
511 : 0 : return (GIBaseInfo *)result;
512 : : }
513 : :
514 : 7 : return (GIBaseInfo *)result;
515 : : }
516 : :
517 : : GITypeInfo *
518 : 13 : gi_type_info_new (GIBaseInfo *container,
519 : : GITypelib *typelib,
520 : : uint32_t offset)
521 : : {
522 : 13 : SimpleTypeBlob *type = (SimpleTypeBlob *)&typelib->data[offset];
523 : :
524 : 13 : return (GITypeInfo *) gi_base_info_new (GI_INFO_TYPE_TYPE, container, typelib,
525 : 13 : (type->flags.reserved == 0 && type->flags.reserved2 == 0) ? offset : type->offset);
526 : : }
527 : :
528 : : /*< private >
529 : : * gi_type_info_init:
530 : : * @info: (out caller-allocates): caller-allocated #GITypeInfo to populate
531 : : * @container: (nullable): info which contains this one
532 : : * @typelib: typelib containing the info
533 : : * @offset: offset of the info within @typelib, in bytes
534 : : *
535 : : * Initialise a stack-allocated #GITypeInfo representing an object of type
536 : : * [type@GIRepository.TypeInfo] from @offset of @typelib.
537 : : *
538 : : * This is a specialised form of [func@GIRepository.info_init] for type
539 : : * information.
540 : : *
541 : : * Since: 2.80
542 : : */
543 : : void
544 : 7 : gi_type_info_init (GITypeInfo *info,
545 : : GIBaseInfo *container,
546 : : GITypelib *typelib,
547 : : uint32_t offset)
548 : : {
549 : 7 : GIRealInfo *rinfo = (GIRealInfo*)container;
550 : 7 : SimpleTypeBlob *type = (SimpleTypeBlob *)&typelib->data[offset];
551 : :
552 : 7 : gi_info_init ((GIRealInfo*)info, GI_TYPE_TYPE_INFO, rinfo->repository, container, typelib,
553 : 7 : (type->flags.reserved == 0 && type->flags.reserved2 == 0) ? offset : type->offset);
554 : 7 : }
555 : :
556 : : /* GIBaseInfo functions */
557 : :
558 : : /**
559 : : * GIBaseInfo:
560 : : *
561 : : * `GIBaseInfo` is the common base struct of all other Info structs
562 : : * accessible through the [class@GIRepository.Repository] API.
563 : : *
564 : : * All info structures can be cast to a `GIBaseInfo`, for instance:
565 : : *
566 : : * ```c
567 : : * GIFunctionInfo *function_info = …;
568 : : * GIBaseInfo *info = (GIBaseInfo *) function_info;
569 : : * ```
570 : : *
571 : : * Most [class@GIRepository.Repository] APIs returning a `GIBaseInfo` are
572 : : * actually creating a new struct; in other words,
573 : : * [method@GIRepository.BaseInfo.unref] has to be called when done accessing the
574 : : * data.
575 : : *
576 : : * `GIBaseInfo` structuress are normally accessed by calling either
577 : : * [method@GIRepository.Repository.find_by_name],
578 : : * [method@GIRepository.Repository.find_by_gtype] or
579 : : * [method@GIRepository.get_info].
580 : : *
581 : : * ```c
582 : : * GIBaseInfo *button_info =
583 : : * gi_repository_find_by_name (NULL, "Gtk", "Button");
584 : : *
585 : : * // use button_info…
586 : : *
587 : : * gi_base_info_unref (button_info);
588 : : * ```
589 : : *
590 : : * Since: 2.80
591 : : */
592 : :
593 : : /**
594 : : * gi_base_info_ref:
595 : : * @info: (type GIRepository.BaseInfo): a #GIBaseInfo
596 : : *
597 : : * Increases the reference count of @info.
598 : : *
599 : : * Returns: (transfer full): the same @info.
600 : : * Since: 2.80
601 : : */
602 : : GIBaseInfo *
603 : 1020 : gi_base_info_ref (void *info)
604 : : {
605 : 1020 : GIRealInfo *rinfo = (GIRealInfo*)info;
606 : :
607 : 1020 : g_return_val_if_fail (GI_IS_BASE_INFO (info), NULL);
608 : :
609 : 1020 : g_assert (rinfo->ref_count != INVALID_REFCOUNT);
610 : 1020 : g_atomic_ref_count_inc (&rinfo->ref_count);
611 : :
612 : 1020 : return info;
613 : : }
614 : :
615 : : /**
616 : : * gi_base_info_unref:
617 : : * @info: (type GIRepository.BaseInfo) (transfer full): a #GIBaseInfo
618 : : *
619 : : * Decreases the reference count of @info. When its reference count
620 : : * drops to 0, the info is freed.
621 : : *
622 : : * This must not be called on stack-allocated [type@GIRepository.BaseInfo]s —
623 : : * use [method@GIRepository.BaseInfo.clear] for that.
624 : : *
625 : : * Since: 2.80
626 : : */
627 : : void
628 : 4053 : gi_base_info_unref (void *info)
629 : : {
630 : 4053 : GIRealInfo *rinfo = (GIRealInfo*)info;
631 : :
632 : 4053 : g_return_if_fail (GI_IS_BASE_INFO (info));
633 : :
634 : 4053 : g_assert (rinfo->ref_count > 0 && rinfo->ref_count != INVALID_REFCOUNT);
635 : :
636 : 4053 : if (g_atomic_ref_count_dec (&rinfo->ref_count))
637 : : {
638 : 3033 : GI_BASE_INFO_GET_CLASS (info)->finalize (info);
639 : 3033 : g_type_free_instance ((GTypeInstance *) info);
640 : : }
641 : : }
642 : :
643 : : /**
644 : : * gi_base_info_get_info_type:
645 : : * @info: a #GIBaseInfo
646 : : *
647 : : * Obtain the info type of the `GIBaseInfo`.
648 : : *
649 : : * Returns: the info type of @info
650 : : * Since: 2.80
651 : : */
652 : : GIInfoType
653 : 138 : gi_base_info_get_info_type (GIBaseInfo *info)
654 : : {
655 : 138 : return GI_BASE_INFO_GET_CLASS (info)->info_type;
656 : : }
657 : :
658 : : /**
659 : : * gi_base_info_get_name:
660 : : * @info: a #GIBaseInfo
661 : : *
662 : : * Obtain the name of the @info.
663 : : *
664 : : * What the name represents depends on the type of the
665 : : * @info. For instance for [class@GIRepository.FunctionInfo] it is the name of
666 : : * the function.
667 : : *
668 : : * Returns: (nullable): the name of @info or `NULL` if it lacks a name.
669 : : * Since: 2.80
670 : : */
671 : : const char *
672 : 57 : gi_base_info_get_name (GIBaseInfo *info)
673 : : {
674 : 57 : GIRealInfo *rinfo = (GIRealInfo*)info;
675 : 57 : g_assert (rinfo->ref_count > 0);
676 : 57 : switch (gi_base_info_get_info_type ((GIBaseInfo *) info))
677 : : {
678 : 20 : case GI_INFO_TYPE_FUNCTION:
679 : : case GI_INFO_TYPE_CALLBACK:
680 : : case GI_INFO_TYPE_STRUCT:
681 : : case GI_INFO_TYPE_ENUM:
682 : : case GI_INFO_TYPE_FLAGS:
683 : : case GI_INFO_TYPE_OBJECT:
684 : : case GI_INFO_TYPE_INTERFACE:
685 : : case GI_INFO_TYPE_CONSTANT:
686 : : case GI_INFO_TYPE_UNION:
687 : : {
688 : 20 : CommonBlob *blob = (CommonBlob *)&rinfo->typelib->data[rinfo->offset];
689 : :
690 : 20 : return gi_typelib_get_string (rinfo->typelib, blob->name);
691 : : }
692 : : break;
693 : :
694 : 0 : case GI_INFO_TYPE_VALUE:
695 : : {
696 : 0 : ValueBlob *blob = (ValueBlob *)&rinfo->typelib->data[rinfo->offset];
697 : :
698 : 0 : return gi_typelib_get_string (rinfo->typelib, blob->name);
699 : : }
700 : : break;
701 : :
702 : 3 : case GI_INFO_TYPE_SIGNAL:
703 : : {
704 : 3 : SignalBlob *blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset];
705 : :
706 : 3 : return gi_typelib_get_string (rinfo->typelib, blob->name);
707 : : }
708 : : break;
709 : :
710 : 0 : case GI_INFO_TYPE_PROPERTY:
711 : : {
712 : 0 : PropertyBlob *blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset];
713 : :
714 : 0 : return gi_typelib_get_string (rinfo->typelib, blob->name);
715 : : }
716 : : break;
717 : :
718 : 0 : case GI_INFO_TYPE_VFUNC:
719 : : {
720 : 0 : VFuncBlob *blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset];
721 : :
722 : 0 : return gi_typelib_get_string (rinfo->typelib, blob->name);
723 : : }
724 : : break;
725 : :
726 : 31 : case GI_INFO_TYPE_FIELD:
727 : : {
728 : 31 : FieldBlob *blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset];
729 : :
730 : 31 : return gi_typelib_get_string (rinfo->typelib, blob->name);
731 : : }
732 : : break;
733 : :
734 : 2 : case GI_INFO_TYPE_ARG:
735 : : {
736 : 2 : ArgBlob *blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset];
737 : :
738 : 2 : return gi_typelib_get_string (rinfo->typelib, blob->name);
739 : : }
740 : : break;
741 : 0 : case GI_INFO_TYPE_UNRESOLVED:
742 : : {
743 : 0 : GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info;
744 : :
745 : 0 : return unresolved->name;
746 : : }
747 : : break;
748 : 1 : case GI_INFO_TYPE_TYPE:
749 : 1 : return NULL;
750 : 0 : default: ;
751 : : g_assert_not_reached ();
752 : : /* unnamed */
753 : : }
754 : :
755 : : return NULL;
756 : : }
757 : :
758 : : /**
759 : : * gi_base_info_get_namespace:
760 : : * @info: a #GIBaseInfo
761 : : *
762 : : * Obtain the namespace of @info.
763 : : *
764 : : * Returns: the namespace
765 : : * Since: 2.80
766 : : */
767 : : const char *
768 : 4 : gi_base_info_get_namespace (GIBaseInfo *info)
769 : : {
770 : 4 : GIRealInfo *rinfo = (GIRealInfo*) info;
771 : 4 : Header *header = (Header *)rinfo->typelib->data;
772 : :
773 : 4 : g_assert (rinfo->ref_count > 0);
774 : :
775 : 4 : if (gi_base_info_get_info_type (info) == GI_INFO_TYPE_UNRESOLVED)
776 : : {
777 : 0 : GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info;
778 : :
779 : 0 : return unresolved->namespace;
780 : : }
781 : :
782 : 4 : return gi_typelib_get_string (rinfo->typelib, header->namespace);
783 : : }
784 : :
785 : : /**
786 : : * gi_base_info_is_deprecated:
787 : : * @info: a #GIBaseInfo
788 : : *
789 : : * Obtain whether the @info is represents a metadata which is
790 : : * deprecated.
791 : : *
792 : : * Returns: `TRUE` if deprecated
793 : : * Since: 2.80
794 : : */
795 : : gboolean
796 : 0 : gi_base_info_is_deprecated (GIBaseInfo *info)
797 : : {
798 : 0 : GIRealInfo *rinfo = (GIRealInfo*) info;
799 : 0 : switch (gi_base_info_get_info_type ((GIBaseInfo *) info))
800 : : {
801 : 0 : case GI_INFO_TYPE_FUNCTION:
802 : : case GI_INFO_TYPE_CALLBACK:
803 : : case GI_INFO_TYPE_STRUCT:
804 : : case GI_INFO_TYPE_ENUM:
805 : : case GI_INFO_TYPE_FLAGS:
806 : : case GI_INFO_TYPE_OBJECT:
807 : : case GI_INFO_TYPE_INTERFACE:
808 : : case GI_INFO_TYPE_CONSTANT:
809 : : {
810 : 0 : CommonBlob *blob = (CommonBlob *)&rinfo->typelib->data[rinfo->offset];
811 : :
812 : 0 : return blob->deprecated;
813 : : }
814 : : break;
815 : :
816 : 0 : case GI_INFO_TYPE_VALUE:
817 : : {
818 : 0 : ValueBlob *blob = (ValueBlob *)&rinfo->typelib->data[rinfo->offset];
819 : :
820 : 0 : return blob->deprecated;
821 : : }
822 : : break;
823 : :
824 : 0 : case GI_INFO_TYPE_SIGNAL:
825 : : {
826 : 0 : SignalBlob *blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset];
827 : :
828 : 0 : return blob->deprecated;
829 : : }
830 : : break;
831 : :
832 : 0 : case GI_INFO_TYPE_PROPERTY:
833 : : {
834 : 0 : PropertyBlob *blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset];
835 : :
836 : 0 : return blob->deprecated;
837 : : }
838 : : break;
839 : :
840 : 0 : case GI_INFO_TYPE_VFUNC:
841 : : case GI_INFO_TYPE_FIELD:
842 : : case GI_INFO_TYPE_ARG:
843 : : case GI_INFO_TYPE_TYPE:
844 : : default: ;
845 : : /* no deprecation flag for these */
846 : : }
847 : :
848 : 0 : return FALSE;
849 : : }
850 : :
851 : : /**
852 : : * gi_base_info_get_attribute:
853 : : * @info: a #GIBaseInfo
854 : : * @name: a freeform string naming an attribute
855 : : *
856 : : * Retrieve an arbitrary attribute associated with this node.
857 : : *
858 : : * Returns: (nullable): The value of the attribute, or `NULL` if no such
859 : : * attribute exists
860 : : * Since: 2.80
861 : : */
862 : : const char *
863 : 904 : gi_base_info_get_attribute (GIBaseInfo *info,
864 : : const char *name)
865 : : {
866 : 904 : GIAttributeIter iter = GI_ATTRIBUTE_ITER_INIT;
867 : : const char *curname, *curvalue;
868 : 904 : while (gi_base_info_iterate_attributes (info, &iter, &curname, &curvalue))
869 : : {
870 : 904 : if (strcmp (name, curname) == 0)
871 : 904 : return (const char *) curvalue;
872 : : }
873 : :
874 : 0 : return NULL;
875 : : }
876 : :
877 : : static int
878 : 7819 : cmp_attribute (const void *av,
879 : : const void *bv)
880 : : {
881 : 7819 : const AttributeBlob *a = av;
882 : 7819 : const AttributeBlob *b = bv;
883 : :
884 : 7819 : if (a->offset < b->offset)
885 : 3700 : return -1;
886 : 4119 : else if (a->offset == b->offset)
887 : 904 : return 0;
888 : : else
889 : 3215 : return 1;
890 : : }
891 : :
892 : : /*< private >
893 : : * _attribute_blob_find_first:
894 : : * @GIBaseInfo: A #GIBaseInfo.
895 : : * @blob_offset: The offset for the blob to find the first attribute for.
896 : : *
897 : : * Searches for the first #AttributeBlob for @blob_offset and returns
898 : : * it if found.
899 : : *
900 : : * Returns: (transfer none): A pointer to #AttributeBlob or `NULL` if not found.
901 : : * Since: 2.80
902 : : */
903 : : AttributeBlob *
904 : 906 : _attribute_blob_find_first (GIBaseInfo *info,
905 : : uint32_t blob_offset)
906 : : {
907 : 906 : GIRealInfo *rinfo = (GIRealInfo *) info;
908 : 906 : Header *header = (Header *)rinfo->typelib->data;
909 : : AttributeBlob blob, *first, *res, *previous;
910 : :
911 : 906 : blob.offset = blob_offset;
912 : :
913 : 906 : first = (AttributeBlob *) &rinfo->typelib->data[header->attributes];
914 : :
915 : 906 : res = bsearch (&blob, first, header->n_attributes,
916 : 906 : header->attribute_blob_size, cmp_attribute);
917 : :
918 : 906 : if (res == NULL)
919 : 2 : return NULL;
920 : :
921 : 904 : previous = res - 1;
922 : 904 : while (previous >= first && previous->offset == blob_offset)
923 : : {
924 : 0 : res = previous;
925 : 0 : previous = res - 1;
926 : : }
927 : :
928 : 904 : return res;
929 : : }
930 : :
931 : : /**
932 : : * gi_base_info_iterate_attributes:
933 : : * @info: a #GIBaseInfo
934 : : * @iterator: (inout): a [type@GIRepository.AttributeIter] structure, must be
935 : : * initialized; see below
936 : : * @name: (out) (transfer none): Returned name, must not be freed
937 : : * @value: (out) (transfer none): Returned name, must not be freed
938 : : *
939 : : * Iterate over all attributes associated with this node.
940 : : *
941 : : * The iterator structure is typically stack allocated, and must have its first
942 : : * member initialized to `NULL`. Attributes are arbitrary namespaced key–value
943 : : * pairs which can be attached to almost any item. They are intended for use
944 : : * by software higher in the toolchain than bindings, and are distinct from
945 : : * normal GIR annotations.
946 : : *
947 : : * Both the @name and @value should be treated as constants
948 : : * and must not be freed.
949 : : *
950 : : * ```c
951 : : * void
952 : : * print_attributes (GIBaseInfo *info)
953 : : * {
954 : : * GIAttributeIter iter = GI_ATTRIBUTE_ITER_INIT;
955 : : * const char *name;
956 : : * const char *value;
957 : : * while (gi_base_info_iterate_attributes (info, &iter, &name, &value))
958 : : * {
959 : : * g_print ("attribute name: %s value: %s", name, value);
960 : : * }
961 : : * }
962 : : * ```
963 : : *
964 : : * Returns: `TRUE` if there are more attributes
965 : : * Since: 2.80
966 : : */
967 : : gboolean
968 : 904 : gi_base_info_iterate_attributes (GIBaseInfo *info,
969 : : GIAttributeIter *iterator,
970 : : const char **name,
971 : : const char **value)
972 : : {
973 : 904 : GIRealInfo *rinfo = (GIRealInfo *)info;
974 : 904 : Header *header = (Header *)rinfo->typelib->data;
975 : : AttributeBlob *next, *after;
976 : :
977 : 904 : after = (AttributeBlob *) &rinfo->typelib->data[header->attributes +
978 : 904 : header->n_attributes * header->attribute_blob_size];
979 : :
980 : 904 : if (iterator->data != NULL)
981 : 0 : next = (AttributeBlob *) iterator->data;
982 : : else
983 : 904 : next = _attribute_blob_find_first (info, rinfo->offset);
984 : :
985 : 904 : if (next == NULL || next->offset != rinfo->offset || next >= after)
986 : 0 : return FALSE;
987 : :
988 : 904 : *name = gi_typelib_get_string (rinfo->typelib, next->name);
989 : 904 : *value = gi_typelib_get_string (rinfo->typelib, next->value);
990 : 904 : iterator->data = next + 1;
991 : :
992 : 904 : return TRUE;
993 : : }
994 : :
995 : : /**
996 : : * gi_base_info_get_container:
997 : : * @info: a #GIBaseInfo
998 : : *
999 : : * Obtain the container of the @info.
1000 : : *
1001 : : * The container is the parent `GIBaseInfo`. For instance, the parent of a
1002 : : * [class@GIRepository.FunctionInfo] is an [class@GIRepository.ObjectInfo] or
1003 : : * [class@GIRepository.InterfaceInfo].
1004 : : *
1005 : : * Returns: (transfer none): the container
1006 : : * Since: 2.80
1007 : : */
1008 : : GIBaseInfo *
1009 : 0 : gi_base_info_get_container (GIBaseInfo *info)
1010 : : {
1011 : 0 : return ((GIRealInfo*)info)->container;
1012 : : }
1013 : :
1014 : : /**
1015 : : * gi_base_info_get_typelib:
1016 : : * @info: a #GIBaseInfo
1017 : : *
1018 : : * Obtain the typelib this @info belongs to
1019 : : *
1020 : : * Returns: (transfer none): the typelib
1021 : : * Since: 2.80
1022 : : */
1023 : : GITypelib *
1024 : 3 : gi_base_info_get_typelib (GIBaseInfo *info)
1025 : : {
1026 : 3 : return ((GIRealInfo*)info)->typelib;
1027 : : }
1028 : :
1029 : : /**
1030 : : * gi_base_info_equal:
1031 : : * @info1: a #GIBaseInfo
1032 : : * @info2: a #GIBaseInfo
1033 : : *
1034 : : * Compare two `GIBaseInfo`s.
1035 : : *
1036 : : * Using pointer comparison is not practical since many functions return
1037 : : * different instances of `GIBaseInfo` that refers to the same part of the
1038 : : * TypeLib; use this function instead to do `GIBaseInfo` comparisons.
1039 : : *
1040 : : * Returns: `TRUE` if and only if @info1 equals @info2.
1041 : : * Since: 2.80
1042 : : */
1043 : : gboolean
1044 : 0 : gi_base_info_equal (GIBaseInfo *info1, GIBaseInfo *info2)
1045 : : {
1046 : : /* Compare the TypeLib pointers, which are mmapped. */
1047 : 0 : GIRealInfo *rinfo1 = (GIRealInfo*)info1;
1048 : 0 : GIRealInfo *rinfo2 = (GIRealInfo*)info2;
1049 : 0 : return rinfo1->typelib->data + rinfo1->offset == rinfo2->typelib->data + rinfo2->offset;
1050 : : }
|