/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- * GObject introspection: Base struct implementation * * Copyright (C) 2005 Matthias Clasen * Copyright (C) 2008,2009 Red Hat, Inc. * * SPDX-License-Identifier: LGPL-2.1-or-later * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #include "gitypelib-internal.h" #include "girepository-private.h" #include "gibaseinfo.h" #include "gibaseinfo-private.h" #define INVALID_REFCOUNT 0x7FFFFFFF /* Type registration of BaseInfo. */ #define GI_BASE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_TYPE_BASE_INFO, GIBaseInfoClass)) static void value_base_info_init (GValue *value) { value->data[0].v_pointer = NULL; } static void value_base_info_free_value (GValue *value) { if (value->data[0].v_pointer != NULL) gi_base_info_unref (value->data[0].v_pointer); } static void value_base_info_copy_value (const GValue *src, GValue *dst) { if (src->data[0].v_pointer != NULL) dst->data[0].v_pointer = gi_base_info_ref (src->data[0].v_pointer); else dst->data[0].v_pointer = NULL; } static void * value_base_info_peek_pointer (const GValue *value) { return value->data[0].v_pointer; } static char * value_base_info_collect_value (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { GIBaseInfo *info = collect_values[0].v_pointer; if (info == NULL) { value->data[0].v_pointer = NULL; return NULL; } if (info->parent_instance.g_class == NULL) return g_strconcat ("invalid unclassed GIBaseInfo pointer for " "value type '", G_VALUE_TYPE_NAME (value), "'", NULL); value->data[0].v_pointer = gi_base_info_ref (info); return NULL; } static char * value_base_info_lcopy_value (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { GIBaseInfo **node_p = collect_values[0].v_pointer; if (node_p == NULL) return g_strconcat ("value location for '", G_VALUE_TYPE_NAME (value), "' passed as NULL", NULL); if (value->data[0].v_pointer == NULL) *node_p = NULL; else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) *node_p = value->data[0].v_pointer; else *node_p = gi_base_info_ref (value->data[0].v_pointer); return NULL; } static void gi_base_info_finalize (GIBaseInfo *self) { if (self->ref_count != INVALID_REFCOUNT && self->container && self->container->ref_count != INVALID_REFCOUNT) gi_base_info_unref (self->container); } static void gi_base_info_class_init (GIBaseInfoClass *klass) { klass->info_type = GI_INFO_TYPE_INVALID; klass->finalize = gi_base_info_finalize; } static void gi_base_info_init (GIBaseInfo *self) { /* Initialise a dynamically allocated #GIBaseInfo’s members. * * This function *must* be kept in sync with gi_info_init(). */ g_atomic_ref_count_init (&self->ref_count); } GType gi_base_info_get_type (void) { static GType base_info_type = 0; if (g_once_init_enter_pointer (&base_info_type)) { static const GTypeFundamentalInfo finfo = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE), }; static const GTypeValueTable value_table = { value_base_info_init, value_base_info_free_value, value_base_info_copy_value, value_base_info_peek_pointer, "p", value_base_info_collect_value, "p", value_base_info_lcopy_value, }; const GTypeInfo type_info = { /* Class */ sizeof (GIBaseInfoClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gi_base_info_class_init, (GClassFinalizeFunc) NULL, NULL, /* Instance */ sizeof (GIBaseInfo), 0, (GInstanceInitFunc) gi_base_info_init, /* GValue */ &value_table, }; GType _base_info_type = g_type_register_fundamental (g_type_fundamental_next (), g_intern_static_string ("GIBaseInfo"), &type_info, &finfo, G_TYPE_FLAG_ABSTRACT); g_once_init_leave_pointer (&base_info_type, _base_info_type); } return base_info_type; } /*< private > * gi_base_info_type_register_static: * @type_name: the name of the type * @instance_size: size (in bytes) of the type’s instance struct * @class_init: class init function for the type * @parent_type: [type@GObject.Type] for the parent type; this will typically be * `GI_TYPE_BASE_INFO` * @type_flags: flags for the type * * Registers a new [type@GIRepository.BaseInfo] type for the given @type_name * using the type information provided. * * Returns: the newly registered [type@GObject.Type] * Since: 2.80 */ GType gi_base_info_type_register_static (const char *type_name, size_t instance_size, GClassInitFunc class_init, GType parent_type, GTypeFlags type_flags) { GTypeInfo info; info.class_size = sizeof (GIBaseInfoClass); info.base_init = NULL; info.base_finalize = NULL; info.class_init = class_init; info.class_finalize = NULL; info.instance_size = instance_size; info.n_preallocs = 0; info.instance_init = NULL; info.value_table = NULL; return g_type_register_static (parent_type, type_name, &info, type_flags); } static GType gi_base_info_types[GI_INFO_TYPE_N_TYPES]; #define GI_DEFINE_BASE_INFO_TYPE(type_name, TYPE_ENUM_VALUE) \ GType \ type_name ## _get_type (void) \ { \ gi_base_info_init_types (); \ g_assert (gi_base_info_types[TYPE_ENUM_VALUE] != G_TYPE_INVALID); \ return gi_base_info_types[TYPE_ENUM_VALUE]; \ } GI_DEFINE_BASE_INFO_TYPE (gi_callable_info, GI_INFO_TYPE_CALLABLE) GI_DEFINE_BASE_INFO_TYPE (gi_function_info, GI_INFO_TYPE_FUNCTION) GI_DEFINE_BASE_INFO_TYPE (gi_callback_info, GI_INFO_TYPE_CALLBACK) GI_DEFINE_BASE_INFO_TYPE (gi_registered_type_info, GI_INFO_TYPE_REGISTERED_TYPE) GI_DEFINE_BASE_INFO_TYPE (gi_struct_info, GI_INFO_TYPE_STRUCT) GI_DEFINE_BASE_INFO_TYPE (gi_union_info, GI_INFO_TYPE_UNION) GI_DEFINE_BASE_INFO_TYPE (gi_enum_info, GI_INFO_TYPE_ENUM) GI_DEFINE_BASE_INFO_TYPE (gi_flags_info, GI_INFO_TYPE_FLAGS) GI_DEFINE_BASE_INFO_TYPE (gi_object_info, GI_INFO_TYPE_OBJECT) GI_DEFINE_BASE_INFO_TYPE (gi_interface_info, GI_INFO_TYPE_INTERFACE) GI_DEFINE_BASE_INFO_TYPE (gi_boxed_info, GI_INFO_TYPE_BOXED) GI_DEFINE_BASE_INFO_TYPE (gi_constant_info, GI_INFO_TYPE_CONSTANT) GI_DEFINE_BASE_INFO_TYPE (gi_value_info, GI_INFO_TYPE_VALUE) GI_DEFINE_BASE_INFO_TYPE (gi_signal_info, GI_INFO_TYPE_SIGNAL) GI_DEFINE_BASE_INFO_TYPE (gi_vfunc_info, GI_INFO_TYPE_VFUNC) GI_DEFINE_BASE_INFO_TYPE (gi_property_info, GI_INFO_TYPE_PROPERTY) GI_DEFINE_BASE_INFO_TYPE (gi_field_info, GI_INFO_TYPE_FIELD) GI_DEFINE_BASE_INFO_TYPE (gi_arg_info, GI_INFO_TYPE_ARG) GI_DEFINE_BASE_INFO_TYPE (gi_type_info, GI_INFO_TYPE_TYPE) GI_DEFINE_BASE_INFO_TYPE (gi_unresolved_info, GI_INFO_TYPE_UNRESOLVED) void gi_base_info_init_types (void) { static size_t register_types_once = 0; if (g_once_init_enter (®ister_types_once)) { const struct { GIInfoType info_type; const char *type_name; size_t instance_size; GClassInitFunc class_init; GIInfoType parent_info_type; /* 0 for GIBaseInfo */ GTypeFlags type_flags; } types[] = { { GI_INFO_TYPE_CALLABLE, "GICallableInfo", sizeof (GICallableInfo), gi_callable_info_class_init, 0, G_TYPE_FLAG_ABSTRACT }, { GI_INFO_TYPE_FUNCTION, "GIFunctionInfo", sizeof (GIFunctionInfo), gi_function_info_class_init, GI_INFO_TYPE_CALLABLE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_CALLBACK, "GICallbackInfo", sizeof (GICallbackInfo), gi_callback_info_class_init, GI_INFO_TYPE_CALLABLE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_REGISTERED_TYPE, "GIRegisteredTypeInfo", sizeof (GIRegisteredTypeInfo), gi_registered_type_info_class_init, 0, G_TYPE_FLAG_ABSTRACT }, { GI_INFO_TYPE_STRUCT, "GIStructInfo", sizeof (GIStructInfo), gi_struct_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_UNION, "GIUnionInfo", sizeof (GIUnionInfo), gi_union_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_ENUM, "GIEnumInfo", sizeof (GIEnumInfo), gi_enum_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_FLAGS, "GIFlagsInfo", sizeof (GIFlagsInfo), gi_flags_info_class_init, GI_INFO_TYPE_ENUM, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_OBJECT, "GIObjectInfo", sizeof (GIObjectInfo), gi_object_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_INTERFACE, "GIInterfaceInfo", sizeof (GIInterfaceInfo), gi_interface_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_BOXED, "GIBoxedInfo", sizeof (GIBoxedInfo), gi_boxed_info_class_init, GI_INFO_TYPE_REGISTERED_TYPE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_CONSTANT, "GIConstantInfo", sizeof (GIConstantInfo), gi_constant_info_class_init, 0, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_VALUE, "GIValueInfo", sizeof (GIValueInfo), gi_value_info_class_init, 0, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_SIGNAL, "GISignalInfo", sizeof (GISignalInfo), gi_signal_info_class_init, GI_INFO_TYPE_CALLABLE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_VFUNC, "GIVFuncInfo", sizeof (GIVFuncInfo), gi_vfunc_info_class_init, GI_INFO_TYPE_CALLABLE, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_PROPERTY, "GIPropertyInfo", sizeof (GIPropertyInfo), gi_property_info_class_init, 0, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_FIELD, "GIFieldInfo", sizeof (GIFieldInfo), gi_field_info_class_init, 0, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_ARG, "GIArgInfo", sizeof (GIArgInfo), gi_arg_info_class_init, 0, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_TYPE, "GITypeInfo", sizeof (GITypeInfo), gi_type_info_class_init, 0, G_TYPE_FLAG_NONE }, { GI_INFO_TYPE_UNRESOLVED, "GIUnresolvedInfo", sizeof (GIUnresolvedInfo), gi_unresolved_info_class_init, 0, G_TYPE_FLAG_NONE }, }; for (size_t i = 0; i < G_N_ELEMENTS (types); i++) { GType registered_type, parent_type; parent_type = (types[i].parent_info_type == 0) ? GI_TYPE_BASE_INFO : gi_base_info_types[types[i].parent_info_type]; g_assert (parent_type != G_TYPE_INVALID); registered_type = gi_base_info_type_register_static (g_intern_static_string (types[i].type_name), types[i].instance_size, types[i].class_init, parent_type, types[i].type_flags); gi_base_info_types[types[i].info_type] = registered_type; } g_once_init_leave (®ister_types_once, 1); } } /* info creation */ GIBaseInfo * gi_info_new_full (GIInfoType type, GIRepository *repository, GIBaseInfo *container, GITypelib *typelib, uint32_t offset) { GIRealInfo *info; g_return_val_if_fail (container != NULL || repository != NULL, NULL); g_return_val_if_fail (GI_IS_REPOSITORY (repository), NULL); g_return_val_if_fail (offset <= G_MAXUINT32, NULL); gi_base_info_init_types (); g_assert (gi_base_info_types[type] != G_TYPE_INVALID); info = (GIRealInfo *) g_type_create_instance (gi_base_info_types[type]); info->typelib = typelib; info->offset = offset; if (container) info->container = container; if (container && container->ref_count != INVALID_REFCOUNT) gi_base_info_ref (info->container); /* Don’t keep a strong ref, since the repository keeps a cache of #GIBaseInfos * and holds refs on them. If we kept a ref here, there’d be a cycle. * Don’t keep a weak ref either, as that would make creating/destroying a * #GIBaseInfo noticeably more expensive, and infos are performance critical * for bindings. * As stated in the documentation, the mitigation here is to require the user * to keep the #GIRepository alive longer than any of its #GIBaseInfos. */ info->repository = repository; return (GIBaseInfo*)info; } /** * gi_base_info_new: * @type: type of the info to create * @container: (nullable): info which contains this one * @typelib: typelib containing the info * @offset: offset of the info within @typelib, in bytes * * Create a new #GIBaseInfo representing an object of the given @type from * @offset of @typelib. * * Returns: (transfer full): The new #GIBaseInfo, unref with * [method@GIRepository.BaseInfo.unref] * Since: 2.80 */ GIBaseInfo * gi_base_info_new (GIInfoType type, GIBaseInfo *container, GITypelib *typelib, size_t offset) { return gi_info_new_full (type, ((GIRealInfo*)container)->repository, container, typelib, offset); } /*< private > * gi_info_init: * @info: (out caller-allocates): caller-allocated #GIRealInfo to populate * @type: type of the info to create * @repository: repository the info is in * @container: (nullable): info which contains this one * @typelib: typelib containing the info * @offset: offset of the info within @typelib, in bytes * * Initialise a stack-allocated #GIBaseInfo representing an object of the given * @type from @offset of @typelib. * * Since: 2.80 */ void gi_info_init (GIRealInfo *info, GType type, GIRepository *repository, GIBaseInfo *container, GITypelib *typelib, uint32_t offset) { memset (info, 0, sizeof (GIRealInfo)); /* Evil setup of a stack allocated #GTypeInstance. This is not something it’s * really designed to do. * * This function *must* be kept in sync with gi_base_info_init(), which is * the equivalent function for dynamically allocated types. */ info->parent_instance.g_class = g_type_class_ref (type); /* g_type_create_instance() calls the #GInstanceInitFunc for each of the * parent types, down to (and including) @type. We don’t need to do that, as * #GIBaseInfo is fundamental so doesn’t have a parent type, the instance init * function for #GIBaseInfo is gi_base_info_init() (which only sets the * refcount, which we already do here), and subtypes of #GIBaseInfo don’t have * instance init functions (see gi_base_info_type_register_static()). */ /* Invalid refcount used to flag stack-allocated infos */ info->ref_count = INVALID_REFCOUNT; info->typelib = typelib; info->offset = offset; if (container) info->container = container; g_assert (GI_IS_REPOSITORY (repository)); info->repository = repository; } /** * gi_base_info_clear: * @info: (type GIRepository.BaseInfo): a #GIBaseInfo * * Clears memory allocated internally by a stack-allocated * [type@GIRepository.BaseInfo]. * * This does not deallocate the [type@GIRepository.BaseInfo] struct itself. * * This must only be called on stack-allocated [type@GIRepository.BaseInfo]s. * Use [method@GIRepository.BaseInfo.unref] for heap-allocated ones. * * Since: 2.80 */ void gi_base_info_clear (void *info) { GIBaseInfo *rinfo = (GIBaseInfo *) info; g_return_if_fail (GI_IS_BASE_INFO (rinfo)); g_assert (rinfo->ref_count == INVALID_REFCOUNT); GI_BASE_INFO_GET_CLASS (info)->finalize (rinfo); g_type_class_unref (rinfo->parent_instance.g_class); } GIBaseInfo * gi_info_from_entry (GIRepository *repository, GITypelib *typelib, uint16_t index) { GIBaseInfo *result; DirEntry *entry = gi_typelib_get_dir_entry (typelib, index); if (entry->local) result = gi_info_new_full (entry->blob_type, repository, NULL, typelib, entry->offset); else { const char *namespace = gi_typelib_get_string (typelib, entry->offset); const char *name = gi_typelib_get_string (typelib, entry->name); result = gi_repository_find_by_name (repository, namespace, name); if (result == NULL) { GIUnresolvedInfo *unresolved; unresolved = (GIUnresolvedInfo *) gi_info_new_full (GI_INFO_TYPE_UNRESOLVED, repository, NULL, typelib, entry->offset); unresolved->name = name; unresolved->namespace = namespace; return (GIBaseInfo *)unresolved; } return (GIBaseInfo *)result; } return (GIBaseInfo *)result; } GITypeInfo * gi_type_info_new (GIBaseInfo *container, GITypelib *typelib, uint32_t offset) { SimpleTypeBlob *type = (SimpleTypeBlob *)&typelib->data[offset]; return (GITypeInfo *) gi_base_info_new (GI_INFO_TYPE_TYPE, container, typelib, (type->flags.reserved == 0 && type->flags.reserved2 == 0) ? offset : type->offset); } /*< private > * gi_type_info_init: * @info: (out caller-allocates): caller-allocated #GITypeInfo to populate * @container: (nullable): info which contains this one * @typelib: typelib containing the info * @offset: offset of the info within @typelib, in bytes * * Initialise a stack-allocated #GITypeInfo representing an object of type * [type@GIRepository.TypeInfo] from @offset of @typelib. * * This is a specialised form of [func@GIRepository.info_init] for type * information. * * Since: 2.80 */ void gi_type_info_init (GITypeInfo *info, GIBaseInfo *container, GITypelib *typelib, uint32_t offset) { GIRealInfo *rinfo = (GIRealInfo*)container; SimpleTypeBlob *type = (SimpleTypeBlob *)&typelib->data[offset]; gi_info_init ((GIRealInfo*)info, GI_TYPE_TYPE_INFO, rinfo->repository, container, typelib, (type->flags.reserved == 0 && type->flags.reserved2 == 0) ? offset : type->offset); } /* GIBaseInfo functions */ /** * GIBaseInfo: * * `GIBaseInfo` is the common base struct of all other Info structs * accessible through the [class@GIRepository.Repository] API. * * All info structures can be cast to a `GIBaseInfo`, for instance: * * ```c * GIFunctionInfo *function_info = …; * GIBaseInfo *info = (GIBaseInfo *) function_info; * ``` * * Most [class@GIRepository.Repository] APIs returning a `GIBaseInfo` are * actually creating a new struct; in other words, * [method@GIRepository.BaseInfo.unref] has to be called when done accessing the * data. * * `GIBaseInfo` structuress are normally accessed by calling either * [method@GIRepository.Repository.find_by_name], * [method@GIRepository.Repository.find_by_gtype] or * [method@GIRepository.get_info]. * * ```c * GIBaseInfo *button_info = * gi_repository_find_by_name (NULL, "Gtk", "Button"); * * // use button_info… * * gi_base_info_unref (button_info); * ``` * * Since: 2.80 */ /** * gi_base_info_ref: * @info: (type GIRepository.BaseInfo): a #GIBaseInfo * * Increases the reference count of @info. * * Returns: (transfer full): the same @info. * Since: 2.80 */ GIBaseInfo * gi_base_info_ref (void *info) { GIRealInfo *rinfo = (GIRealInfo*)info; g_return_val_if_fail (GI_IS_BASE_INFO (info), NULL); g_assert (rinfo->ref_count != INVALID_REFCOUNT); g_atomic_ref_count_inc (&rinfo->ref_count); return info; } /** * gi_base_info_unref: * @info: (type GIRepository.BaseInfo) (transfer full): a #GIBaseInfo * * Decreases the reference count of @info. When its reference count * drops to 0, the info is freed. * * This must not be called on stack-allocated [type@GIRepository.BaseInfo]s — * use [method@GIRepository.BaseInfo.clear] for that. * * Since: 2.80 */ void gi_base_info_unref (void *info) { GIRealInfo *rinfo = (GIRealInfo*)info; g_return_if_fail (GI_IS_BASE_INFO (info)); g_assert (rinfo->ref_count > 0 && rinfo->ref_count != INVALID_REFCOUNT); if (g_atomic_ref_count_dec (&rinfo->ref_count)) { GI_BASE_INFO_GET_CLASS (info)->finalize (info); g_type_free_instance ((GTypeInstance *) info); } } /** * gi_base_info_get_info_type: * @info: a #GIBaseInfo * * Obtain the info type of the `GIBaseInfo`. * * Returns: the info type of @info * Since: 2.80 */ GIInfoType gi_base_info_get_info_type (GIBaseInfo *info) { return GI_BASE_INFO_GET_CLASS (info)->info_type; } /** * gi_base_info_get_name: * @info: a #GIBaseInfo * * Obtain the name of the @info. * * What the name represents depends on the [type@GIRepository.InfoType] of the * @info. For instance for [class@GIRepository.FunctionInfo] it is the name of * the function. * * Returns: (nullable): the name of @info or `NULL` if it lacks a name. * Since: 2.80 */ const char * gi_base_info_get_name (GIBaseInfo *info) { GIRealInfo *rinfo = (GIRealInfo*)info; g_assert (rinfo->ref_count > 0); switch (gi_base_info_get_info_type ((GIBaseInfo *) info)) { case GI_INFO_TYPE_FUNCTION: case GI_INFO_TYPE_CALLBACK: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_CONSTANT: case GI_INFO_TYPE_UNION: { CommonBlob *blob = (CommonBlob *)&rinfo->typelib->data[rinfo->offset]; return gi_typelib_get_string (rinfo->typelib, blob->name); } break; case GI_INFO_TYPE_VALUE: { ValueBlob *blob = (ValueBlob *)&rinfo->typelib->data[rinfo->offset]; return gi_typelib_get_string (rinfo->typelib, blob->name); } break; case GI_INFO_TYPE_SIGNAL: { SignalBlob *blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset]; return gi_typelib_get_string (rinfo->typelib, blob->name); } break; case GI_INFO_TYPE_PROPERTY: { PropertyBlob *blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset]; return gi_typelib_get_string (rinfo->typelib, blob->name); } break; case GI_INFO_TYPE_VFUNC: { VFuncBlob *blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset]; return gi_typelib_get_string (rinfo->typelib, blob->name); } break; case GI_INFO_TYPE_FIELD: { FieldBlob *blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; return gi_typelib_get_string (rinfo->typelib, blob->name); } break; case GI_INFO_TYPE_ARG: { ArgBlob *blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; return gi_typelib_get_string (rinfo->typelib, blob->name); } break; case GI_INFO_TYPE_UNRESOLVED: { GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info; return unresolved->name; } break; case GI_INFO_TYPE_TYPE: return NULL; default: ; g_assert_not_reached (); /* unnamed */ } return NULL; } /** * gi_base_info_get_namespace: * @info: a #GIBaseInfo * * Obtain the namespace of @info. * * Returns: the namespace * Since: 2.80 */ const char * gi_base_info_get_namespace (GIBaseInfo *info) { GIRealInfo *rinfo = (GIRealInfo*) info; Header *header = (Header *)rinfo->typelib->data; g_assert (rinfo->ref_count > 0); if (gi_base_info_get_info_type (info) == GI_INFO_TYPE_UNRESOLVED) { GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info; return unresolved->namespace; } return gi_typelib_get_string (rinfo->typelib, header->namespace); } /** * gi_base_info_is_deprecated: * @info: a #GIBaseInfo * * Obtain whether the @info is represents a metadata which is * deprecated. * * Returns: `TRUE` if deprecated * Since: 2.80 */ gboolean gi_base_info_is_deprecated (GIBaseInfo *info) { GIRealInfo *rinfo = (GIRealInfo*) info; switch (gi_base_info_get_info_type ((GIBaseInfo *) info)) { case GI_INFO_TYPE_FUNCTION: case GI_INFO_TYPE_CALLBACK: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_CONSTANT: { CommonBlob *blob = (CommonBlob *)&rinfo->typelib->data[rinfo->offset]; return blob->deprecated; } break; case GI_INFO_TYPE_VALUE: { ValueBlob *blob = (ValueBlob *)&rinfo->typelib->data[rinfo->offset]; return blob->deprecated; } break; case GI_INFO_TYPE_SIGNAL: { SignalBlob *blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset]; return blob->deprecated; } break; case GI_INFO_TYPE_PROPERTY: { PropertyBlob *blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset]; return blob->deprecated; } break; case GI_INFO_TYPE_VFUNC: case GI_INFO_TYPE_FIELD: case GI_INFO_TYPE_ARG: case GI_INFO_TYPE_TYPE: default: ; /* no deprecation flag for these */ } return FALSE; } /** * gi_base_info_get_attribute: * @info: a #GIBaseInfo * @name: a freeform string naming an attribute * * Retrieve an arbitrary attribute associated with this node. * * Returns: (nullable): The value of the attribute, or `NULL` if no such * attribute exists * Since: 2.80 */ const char * gi_base_info_get_attribute (GIBaseInfo *info, const char *name) { GIAttributeIter iter = GI_ATTRIBUTE_ITER_INIT; const char *curname, *curvalue; while (gi_base_info_iterate_attributes (info, &iter, &curname, &curvalue)) { if (strcmp (name, curname) == 0) return (const char *) curvalue; } return NULL; } static int cmp_attribute (const void *av, const void *bv) { const AttributeBlob *a = av; const AttributeBlob *b = bv; if (a->offset < b->offset) return -1; else if (a->offset == b->offset) return 0; else return 1; } /*< private > * _attribute_blob_find_first: * @GIBaseInfo: A #GIBaseInfo. * @blob_offset: The offset for the blob to find the first attribute for. * * Searches for the first #AttributeBlob for @blob_offset and returns * it if found. * * Returns: (transfer none): A pointer to #AttributeBlob or `NULL` if not found. * Since: 2.80 */ AttributeBlob * _attribute_blob_find_first (GIBaseInfo *info, uint32_t blob_offset) { GIRealInfo *rinfo = (GIRealInfo *) info; Header *header = (Header *)rinfo->typelib->data; AttributeBlob blob, *first, *res, *previous; blob.offset = blob_offset; first = (AttributeBlob *) &rinfo->typelib->data[header->attributes]; res = bsearch (&blob, first, header->n_attributes, header->attribute_blob_size, cmp_attribute); if (res == NULL) return NULL; previous = res - 1; while (previous >= first && previous->offset == blob_offset) { res = previous; previous = res - 1; } return res; } /** * gi_base_info_iterate_attributes: * @info: a #GIBaseInfo * @iterator: (inout): a [type@GIRepository.AttributeIter] structure, must be * initialized; see below * @name: (out) (transfer none): Returned name, must not be freed * @value: (out) (transfer none): Returned name, must not be freed * * Iterate over all attributes associated with this node. * * The iterator structure is typically stack allocated, and must have its first * member initialized to `NULL`. Attributes are arbitrary namespaced key–value * pairs which can be attached to almost any item. They are intended for use * by software higher in the toolchain than bindings, and are distinct from * normal GIR annotations. * * Both the @name and @value should be treated as constants * and must not be freed. * * ```c * void * print_attributes (GIBaseInfo *info) * { * GIAttributeIter iter = GI_ATTRIBUTE_ITER_INIT; * const char *name; * const char *value; * while (gi_base_info_iterate_attributes (info, &iter, &name, &value)) * { * g_print ("attribute name: %s value: %s", name, value); * } * } * ``` * * Returns: `TRUE` if there are more attributes * Since: 2.80 */ gboolean gi_base_info_iterate_attributes (GIBaseInfo *info, GIAttributeIter *iterator, const char **name, const char **value) { GIRealInfo *rinfo = (GIRealInfo *)info; Header *header = (Header *)rinfo->typelib->data; AttributeBlob *next, *after; after = (AttributeBlob *) &rinfo->typelib->data[header->attributes + header->n_attributes * header->attribute_blob_size]; if (iterator->data != NULL) next = (AttributeBlob *) iterator->data; else next = _attribute_blob_find_first (info, rinfo->offset); if (next == NULL || next->offset != rinfo->offset || next >= after) return FALSE; *name = gi_typelib_get_string (rinfo->typelib, next->name); *value = gi_typelib_get_string (rinfo->typelib, next->value); iterator->data = next + 1; return TRUE; } /** * gi_base_info_get_container: * @info: a #GIBaseInfo * * Obtain the container of the @info. * * The container is the parent `GIBaseInfo`. For instance, the parent of a * [class@GIRepository.FunctionInfo] is an [class@GIRepository.ObjectInfo] or * [class@GIRepository.InterfaceInfo]. * * Returns: (transfer none): the container * Since: 2.80 */ GIBaseInfo * gi_base_info_get_container (GIBaseInfo *info) { return ((GIRealInfo*)info)->container; } /** * gi_base_info_get_typelib: * @info: a #GIBaseInfo * * Obtain the typelib this @info belongs to * * Returns: (transfer none): the typelib * Since: 2.80 */ GITypelib * gi_base_info_get_typelib (GIBaseInfo *info) { return ((GIRealInfo*)info)->typelib; } /** * gi_base_info_equal: * @info1: a #GIBaseInfo * @info2: a #GIBaseInfo * * Compare two `GIBaseInfo`s. * * Using pointer comparison is not practical since many functions return * different instances of `GIBaseInfo` that refers to the same part of the * TypeLib; use this function instead to do `GIBaseInfo` comparisons. * * Returns: `TRUE` if and only if @info1 equals @info2. * Since: 2.80 */ gboolean gi_base_info_equal (GIBaseInfo *info1, GIBaseInfo *info2) { /* Compare the TypeLib pointers, which are mmapped. */ GIRealInfo *rinfo1 = (GIRealInfo*)info1; GIRealInfo *rinfo2 = (GIRealInfo*)info2; return rinfo1->typelib->data + rinfo1->offset == rinfo2->typelib->data + rinfo2->offset; }