glib/girepository/gibaseinfo.c
Philip Withnall bf4cf2d464 gibaseinfo: Fix use of stack-allocated GIBaseInfos
Most of the code for handling stack-allocated infos was correct, it was
just missing code to initialise the `GTypeInstance` member.

Since `GTypeInstance` isn’t really designed for stack allocation, this
is a little hacky — it requires setting up the member within
`GTypeInstance` manually. It works, though.

The externally visible consequence of this, though, is that
stack-allocated `GIBaseInfo`s now need to be cleared when they’re
finished being used. This allows the `GTypeClass` ref to be dropped.

All users of the stack-allocated APIs in libgirepository will need to
adapt to this change.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Fixes: #3218
2024-01-23 18:07:17 +00:00

1038 lines
31 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -*- 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 <stdlib.h>
#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
#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);
if (self->ref_count != INVALID_REFCOUNT)
g_clear_object (&self->repository);
}
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 #GIBaseInfos 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 types 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 (&register_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 (&register_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);
info->repository = g_object_ref (repository);
return (GIBaseInfo*)info;
}
/**
* gi_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_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 its
* 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 dont need to do that, as
* #GIBaseInfo is fundamental so doesnt 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 dont 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_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 keyvalue
* 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;
}