/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- * GObject introspection: Field 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 "gibaseinfo-private.h" #include "girepository-private.h" #include "gitypelib-internal.h" #include "config.h" #include "gifieldinfo.h" /** * GIFieldInfo: * * A `GIFieldInfo` struct represents a field of a struct, union, or object. * * The `GIFieldInfo` is fetched by calling * [method@GIRepository.StructInfo.get_field], * [method@GIRepository.UnionInfo.get_field] or * [method@GIRepository.ObjectInfo.get_field]. * * A field has a size, type and a struct offset associated and a set of flags, * which are currently `GI_FIELD_IS_READABLE` or `GI_FIELD_IS_WRITABLE`. * * See also: [type@GIRepository.StructInfo], [type@GIRepository.UnionInfo], * [type@GIRepository.ObjectInfo] * * Since: 2.80 */ /** * gi_field_info_get_flags: * @info: a #GIFieldInfo * * Obtain the flags for this `GIFieldInfo`. See * [flags@GIRepository.FieldInfoFlags] for possible flag values. * * Returns: the flags * Since: 2.80 */ GIFieldInfoFlags gi_field_info_get_flags (GIFieldInfo *info) { GIFieldInfoFlags flags; GIRealInfo *rinfo = (GIRealInfo *)info; FieldBlob *blob; g_return_val_if_fail (info != NULL, 0); g_return_val_if_fail (GI_IS_FIELD_INFO (info), 0); blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; flags = 0; if (blob->readable) flags = flags | GI_FIELD_IS_READABLE; if (blob->writable) flags = flags | GI_FIELD_IS_WRITABLE; return flags; } /** * gi_field_info_get_size: * @info: a #GIFieldInfo * * Obtain the size of the field member, in bits. This is how * much space you need to allocate to store the field. * * Returns: the field size, in bits * Since: 2.80 */ gsize gi_field_info_get_size (GIFieldInfo *info) { GIRealInfo *rinfo = (GIRealInfo *)info; FieldBlob *blob; g_return_val_if_fail (info != NULL, 0); g_return_val_if_fail (GI_IS_FIELD_INFO (info), 0); blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; return blob->bits; } /** * gi_field_info_get_offset: * @info: a #GIFieldInfo * * Obtain the offset of the field member, in bytes. This is relative * to the beginning of the struct or union. * * Returns: the field offset, in bytes * Since: 2.80 */ gsize gi_field_info_get_offset (GIFieldInfo *info) { GIRealInfo *rinfo = (GIRealInfo *)info; FieldBlob *blob; g_return_val_if_fail (info != NULL, 0); g_return_val_if_fail (GI_IS_FIELD_INFO (info), 0); blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; return blob->struct_offset; } /** * gi_field_info_get_type_info: * @info: a #GIFieldInfo * * Obtain the type of a field as a [type@GIRepository.TypeInfo]. * * Returns: (transfer full): the [type@GIRepository.TypeInfo]. Free the struct * by calling [method@GIRepository.BaseInfo.unref] when done. * Since: 2.80 */ GITypeInfo * gi_field_info_get_type_info (GIFieldInfo *info) { GIRealInfo *rinfo = (GIRealInfo *)info; Header *header = (Header *)rinfo->typelib->data; FieldBlob *blob; GIRealInfo *type_info; g_return_val_if_fail (info != NULL, NULL); g_return_val_if_fail (GI_IS_FIELD_INFO (info), NULL); blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; if (blob->has_embedded_type) { type_info = (GIRealInfo *) gi_info_new (GI_INFO_TYPE_TYPE, (GIBaseInfo*)info, rinfo->typelib, rinfo->offset + header->field_blob_size); type_info->type_is_embedded = TRUE; } else return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, rinfo->offset + G_STRUCT_OFFSET (FieldBlob, type)); return (GITypeInfo *) type_info; } /** * gi_field_info_get_field: (skip) * @field_info: a #GIFieldInfo * @mem: pointer to a block of memory representing a C structure or union * @value: a [type@GIRepository.Argument] into which to store the value retrieved * * Reads a field identified by a `GIFieldInfo` from a C structure or * union. * * This only handles fields of simple C types. It will fail for a field of a * composite type like a nested structure or union even if that is actually * readable. * * Returns: `TRUE` if reading the field succeeded, `FALSE` otherwise * Since: 2.80 */ gboolean gi_field_info_get_field (GIFieldInfo *field_info, gpointer mem, GIArgument *value) { int offset; GITypeInfo *type_info; gboolean result = FALSE; g_return_val_if_fail (field_info != NULL, FALSE); g_return_val_if_fail (GI_IS_FIELD_INFO (field_info), FALSE); if ((gi_field_info_get_flags (field_info) & GI_FIELD_IS_READABLE) == 0) return FALSE; offset = gi_field_info_get_offset (field_info); type_info = gi_field_info_get_type_info (field_info); if (gi_type_info_is_pointer (type_info)) { value->v_pointer = G_STRUCT_MEMBER (gpointer, mem, offset); result = TRUE; } else { switch (gi_type_info_get_tag (type_info)) { case GI_TYPE_TAG_VOID: g_warning("Field %s: should not be have void type", gi_base_info_get_name ((GIBaseInfo *)field_info)); break; case GI_TYPE_TAG_BOOLEAN: value->v_boolean = G_STRUCT_MEMBER (gboolean, mem, offset) != FALSE; result = TRUE; break; case GI_TYPE_TAG_INT8: case GI_TYPE_TAG_UINT8: value->v_uint8 = G_STRUCT_MEMBER (guint8, mem, offset); result = TRUE; break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_UINT16: value->v_uint16 = G_STRUCT_MEMBER (guint16, mem, offset); result = TRUE; break; case GI_TYPE_TAG_INT32: case GI_TYPE_TAG_UINT32: case GI_TYPE_TAG_UNICHAR: value->v_uint32 = G_STRUCT_MEMBER (guint32, mem, offset); result = TRUE; break; case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: value->v_uint64 = G_STRUCT_MEMBER (guint64, mem, offset); result = TRUE; break; case GI_TYPE_TAG_GTYPE: value->v_size = G_STRUCT_MEMBER (gsize, mem, offset); result = TRUE; break; case GI_TYPE_TAG_FLOAT: value->v_float = G_STRUCT_MEMBER (gfloat, mem, offset); result = TRUE; break; case GI_TYPE_TAG_DOUBLE: value->v_double = G_STRUCT_MEMBER (gdouble, mem, offset); result = TRUE; break; case GI_TYPE_TAG_ARRAY: /* We don't check the array type and that it is fixed-size, we trust g-ir-compiler to do the right thing */ value->v_pointer = G_STRUCT_MEMBER_P (mem, offset); result = TRUE; break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: case GI_TYPE_TAG_GHASH: g_warning("Field %s: type %s should have is_pointer set", gi_base_info_get_name ((GIBaseInfo *)field_info), gi_type_tag_to_string (gi_type_info_get_tag (type_info))); break; case GI_TYPE_TAG_ERROR: /* Needs to be handled by the language binding directly */ break; case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *interface = gi_type_info_get_interface (type_info); switch (gi_base_info_get_info_type (interface)) { case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: case GI_INFO_TYPE_BOXED: /* Needs to be handled by the language binding directly */ break; case GI_INFO_TYPE_OBJECT: break; case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: { /* FIXME: there's a mismatch here between the value->v_int we use * here and the gint64 result returned from gi_value_info_get_value(). * But to switch this to gint64, we'd have to make gi_function_info_invoke() * translate value->v_int64 to the proper ABI for an enum function * call parameter, which will usually be int, and then fix up language * bindings. */ GITypeTag storage_type = gi_enum_info_get_storage_type ((GIEnumInfo *)interface); switch (storage_type) { case GI_TYPE_TAG_INT8: case GI_TYPE_TAG_UINT8: value->v_int = (gint)G_STRUCT_MEMBER (guint8, mem, offset); result = TRUE; break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_UINT16: value->v_int = (gint)G_STRUCT_MEMBER (guint16, mem, offset); result = TRUE; break; case GI_TYPE_TAG_INT32: case GI_TYPE_TAG_UINT32: value->v_int = (gint)G_STRUCT_MEMBER (guint32, mem, offset); result = TRUE; break; case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: value->v_int = (gint)G_STRUCT_MEMBER (guint64, mem, offset); result = TRUE; break; default: g_warning("Field %s: Unexpected enum storage type %s", gi_base_info_get_name ((GIBaseInfo *)field_info), gi_type_tag_to_string (storage_type)); break; } break; } case GI_INFO_TYPE_VFUNC: case GI_INFO_TYPE_CALLBACK: g_warning("Field %s: Interface type %d should have is_pointer set", gi_base_info_get_name ((GIBaseInfo *)field_info), gi_base_info_get_info_type (interface)); break; case GI_INFO_TYPE_INVALID: case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_FUNCTION: case GI_INFO_TYPE_CONSTANT: case GI_INFO_TYPE_VALUE: case GI_INFO_TYPE_SIGNAL: case GI_INFO_TYPE_PROPERTY: case GI_INFO_TYPE_FIELD: case GI_INFO_TYPE_ARG: case GI_INFO_TYPE_TYPE: case GI_INFO_TYPE_UNRESOLVED: g_warning("Field %s: Interface type %d not expected", gi_base_info_get_name ((GIBaseInfo *)field_info), gi_base_info_get_info_type (interface)); break; default: break; } gi_base_info_unref ((GIBaseInfo *)interface); break; } break; default: break; } } gi_base_info_unref ((GIBaseInfo *)type_info); return result; } /** * gi_field_info_set_field: (skip) * @field_info: a #GIFieldInfo * @mem: pointer to a block of memory representing a C structure or union * @value: a [type@GIRepository.Argument] holding the value to store * * Writes a field identified by a `GIFieldInfo` to a C structure or * union. * * This only handles fields of simple C types. It will fail for a field of a * composite type like a nested structure or union even if that is actually * writable. Note also that that it will refuse to write fields where memory * management would by required. A field with a type such as `char *` must be * set with a setter function. * * Returns: `TRUE` if writing the field succeeded, `FALSE` otherwise * Since: 2.80 */ gboolean gi_field_info_set_field (GIFieldInfo *field_info, gpointer mem, const GIArgument *value) { int offset; GITypeInfo *type_info; gboolean result = FALSE; g_return_val_if_fail (field_info != NULL, FALSE); g_return_val_if_fail (GI_IS_FIELD_INFO (field_info), FALSE); if ((gi_field_info_get_flags (field_info) & GI_FIELD_IS_WRITABLE) == 0) return FALSE; offset = gi_field_info_get_offset (field_info); type_info = gi_field_info_get_type_info (field_info); if (!gi_type_info_is_pointer (type_info)) { switch (gi_type_info_get_tag (type_info)) { case GI_TYPE_TAG_VOID: g_warning("Field %s: should not be have void type", gi_base_info_get_name ((GIBaseInfo *)field_info)); break; case GI_TYPE_TAG_BOOLEAN: G_STRUCT_MEMBER (gboolean, mem, offset) = value->v_boolean != FALSE; result = TRUE; break; case GI_TYPE_TAG_INT8: case GI_TYPE_TAG_UINT8: G_STRUCT_MEMBER (guint8, mem, offset) = value->v_uint8; result = TRUE; break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_UINT16: G_STRUCT_MEMBER (guint16, mem, offset) = value->v_uint16; result = TRUE; break; case GI_TYPE_TAG_INT32: case GI_TYPE_TAG_UINT32: case GI_TYPE_TAG_UNICHAR: G_STRUCT_MEMBER (guint32, mem, offset) = value->v_uint32; result = TRUE; break; case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: G_STRUCT_MEMBER (guint64, mem, offset) = value->v_uint64; result = TRUE; break; case GI_TYPE_TAG_GTYPE: G_STRUCT_MEMBER (gsize, mem, offset) = value->v_size; result = TRUE; break; case GI_TYPE_TAG_FLOAT: G_STRUCT_MEMBER (gfloat, mem, offset) = value->v_float; result = TRUE; break; case GI_TYPE_TAG_DOUBLE: G_STRUCT_MEMBER (gdouble, mem, offset)= value->v_double; result = TRUE; break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_ARRAY: case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: case GI_TYPE_TAG_GHASH: g_warning("Field %s: type %s should have is_pointer set", gi_base_info_get_name ((GIBaseInfo *)field_info), gi_type_tag_to_string (gi_type_info_get_tag (type_info))); break; case GI_TYPE_TAG_ERROR: /* Needs to be handled by the language binding directly */ break; case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *interface = gi_type_info_get_interface (type_info); switch (gi_base_info_get_info_type (interface)) { case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: case GI_INFO_TYPE_BOXED: /* Needs to be handled by the language binding directly */ break; case GI_INFO_TYPE_OBJECT: break; case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: { /* See FIXME above */ GITypeTag storage_type = gi_enum_info_get_storage_type ((GIEnumInfo *)interface); switch (storage_type) { case GI_TYPE_TAG_INT8: case GI_TYPE_TAG_UINT8: G_STRUCT_MEMBER (guint8, mem, offset) = (guint8)value->v_int; result = TRUE; break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_UINT16: G_STRUCT_MEMBER (guint16, mem, offset) = (guint16)value->v_int; result = TRUE; break; case GI_TYPE_TAG_INT32: case GI_TYPE_TAG_UINT32: G_STRUCT_MEMBER (guint32, mem, offset) = (guint32)value->v_int; result = TRUE; break; case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: G_STRUCT_MEMBER (guint64, mem, offset) = (guint64)value->v_int; result = TRUE; break; default: g_warning("Field %s: Unexpected enum storage type %s", gi_base_info_get_name ((GIBaseInfo *)field_info), gi_type_tag_to_string (storage_type)); break; } break; } break; case GI_INFO_TYPE_VFUNC: case GI_INFO_TYPE_CALLBACK: g_warning("Field%s: Interface type %d should have is_pointer set", gi_base_info_get_name ((GIBaseInfo *)field_info), gi_base_info_get_info_type (interface)); break; case GI_INFO_TYPE_INVALID: case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_FUNCTION: case GI_INFO_TYPE_CONSTANT: case GI_INFO_TYPE_VALUE: case GI_INFO_TYPE_SIGNAL: case GI_INFO_TYPE_PROPERTY: case GI_INFO_TYPE_FIELD: case GI_INFO_TYPE_ARG: case GI_INFO_TYPE_TYPE: case GI_INFO_TYPE_UNRESOLVED: g_warning("Field %s: Interface type %d not expected", gi_base_info_get_name ((GIBaseInfo *)field_info), gi_base_info_get_info_type (interface)); break; default: break; } gi_base_info_unref ((GIBaseInfo *)interface); break; } break; default: break; } } else { switch (gi_type_info_get_tag (type_info)) { case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *interface = gi_type_info_get_interface (type_info); switch (gi_base_info_get_info_type (interface)) { case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: G_STRUCT_MEMBER (gpointer, mem, offset) = (gpointer)value->v_pointer; result = TRUE; break; default: break; } gi_base_info_unref ((GIBaseInfo *)interface); } break; default: break; } } gi_base_info_unref ((GIBaseInfo *)type_info); return result; } void gi_field_info_class_init (gpointer g_class, gpointer class_data) { GIBaseInfoClass *info_class = g_class; info_class->info_type = GI_INFO_TYPE_FIELD; }