commit ac69c8f5a458e79c98d05a65843baeec40f975e7 Author: Rob Taylor Date: Fri Feb 8 15:31:03 2008 +0000 Added: Added: Renamed to tools/Makefile.am: Renamed to tools/compiler.c: 2008-02-08 Rob Taylor * Makefile.am: * configure.ac: * gidl/Makefile.am: Added: * girepository/Makefile.am: Added: * src/Makefile.am: Renamed to tools/Makefile.am: * src/compiler.c: Renamed to tools/compiler.c: * src/g-idl-offsets.pl: Renamed to tools/g-idl-offsets.pl: * src/generate.c: Renamed to tools/generate.c: * src/gidlmodule.c: Renamed to tools/gidlmodule.c: * src/gidlmodule.h: Renamed to tools/gidlmodule.h: * src/gidlnode.c: Renamed to tools/gidlnode.c: * src/gidlnode.h: Renamed to tools/gidlnode.h: * src/gidlparser.c: Renamed to tools/gidlparser.c: * src/gidlparser.h: Renamed to tools/gidlparser.h: * src/gidlwriter.c: Renamed to tools/gidlwriter.c: * src/gidlwriter.h: Renamed to tools/gidlwriter.h: * src/ginfo.c: Renamed to girepository/ginfo.c: * src/ginvoke.c: Renamed to girepository/ginvoke.c: * src/girepository.c: Renamed to girepository/girepository.c: * src/girepository.h: Renamed to girepository/girepository.h: * src/gmetadata.c: Renamed to girepository/gmetadata.c: * src/gmetadata.h: Renamed to girepository/gmetadata.h: * src/scanner.c: Renamed to tools/scanner.c: * src/scanner.h: Renamed to tools/scanner.h: * src/scannerlexer.l: Renamed to tools/scannerlexer.l: * src/scannerparser.y: Renamed to tools/scannerparser.y: * tests/invoke/Makefile.am: Split src/ into girepository/ and tools/ * Makefile.am: * configure.ac: * girepository/Makefile.am: * tests/Makefile.am: * tests/invoke/Makefile.am: * tests/parser/Makefile.am: * tests/roundtrips.sh: * tools/Makefile.am: Make distcheck work. svn path=/trunk/; revision=104 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..480e95f6a --- /dev/null +++ b/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = -DGIREPO_DEFAULT_SEARCH_PATH="\"$(libdir)\"" + +lib_LTLIBRARIES = libgirepository.la + +libgirepository_la_SOURCES = \ + girepository.c \ + gmetadata.h \ + gmetadata.c \ + ginfo.c \ + ginvoke.c +libgirepository_la_CFLAGS = $(GIREPO_CFLAGS) + +girepodir = $(includedir)/glib-2.0/gobject-introspection +girepo_HEADERS = girepository.h diff --git a/ginfo.c b/ginfo.c new file mode 100644 index 000000000..6d66de21b --- /dev/null +++ b/ginfo.c @@ -0,0 +1,1806 @@ +/* GObject introspection: Repository implementation + * + * Copyright (C) 2005 Matthias Clasen + * + * 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 + +#include +#include + +#include "girepository.h" +#include "gmetadata.h" + +struct _GIBaseInfo +{ + gint type; + gint ref_count; + GIBaseInfo *container; + + GMetadata *metadata; + guint32 offset; +}; + +struct _GIUnresolvedInfo +{ + gint type; + gint ref_count; + GIBaseInfo *container; + + const gchar *name; + const gchar *namespace; +}; + +struct _GICallableInfo +{ + GIBaseInfo base; +}; + +struct _GIFunctionInfo +{ + GICallableInfo callable; +}; + +struct _GICallbackInfo +{ + GICallableInfo callable; +}; + +struct _GIRegisteredTypeInfo +{ + GIBaseInfo base; +}; + +struct _GIStructInfo +{ + GIRegisteredTypeInfo registered; +}; + +struct _GIEnumInfo +{ + GIRegisteredTypeInfo registered; +}; + +struct _GIObjectInfo +{ + GIRegisteredTypeInfo registered; +}; + +struct _GIInterfaceInfo +{ + GIRegisteredTypeInfo registered; +}; + +struct _GIConstantInfo +{ + GIBaseInfo base; +}; + +struct _GIValueInfo +{ + GIBaseInfo base; +}; + +struct _GISignalInfo +{ + GICallableInfo callable; +}; + +struct _GIVFuncInfo +{ + GICallableInfo callable; +}; + +struct _GIPropertyInfo +{ + GIBaseInfo base; +}; + +struct _GIFieldInfo +{ + GIBaseInfo base; +}; + +struct _GIArgInfo +{ + GIBaseInfo base; +}; + +struct _GITypeInfo +{ + GIBaseInfo base; +}; + +struct _GIUnionInfo +{ + GIRegisteredTypeInfo registered; +}; + + +/* info creation */ +GIBaseInfo * +g_info_new (GIInfoType type, + GIBaseInfo *container, + GMetadata *metadata, + guint32 offset) +{ + GIBaseInfo *info; + + info = g_new0 (GIBaseInfo, 1); + + info->ref_count = 1; + info->type = type; + + info->metadata = metadata; + info->offset = offset; + + if (container) + info->container = g_base_info_ref (container); + + return info; +} + +static GIBaseInfo * +g_info_from_entry (GMetadata *metadata, + guint16 index) +{ + GIBaseInfo *result; + DirEntry *entry = g_metadata_get_dir_entry (metadata, index); + + if (entry->local) + result = g_info_new (entry->blob_type, NULL, metadata, entry->offset); + else + { + const gchar *namespace = g_metadata_get_string (metadata, entry->offset); + const gchar *name = g_metadata_get_string (metadata, entry->name); + + GIRepository *repository = g_irepository_get_default (); + + result = g_irepository_find_by_name (repository, namespace, name); + if (result == NULL) + { + GIUnresolvedInfo *unresolved; + + unresolved = g_new0 (GIUnresolvedInfo, 1); + + unresolved->type = GI_INFO_TYPE_UNRESOLVED; + unresolved->ref_count = 1; + unresolved->container = NULL; + unresolved->name = name; + unresolved->namespace = namespace; + + result = (GIBaseInfo*)unresolved; + } + } + + return result; +} + +/* GIBaseInfo functions */ +GIBaseInfo * +g_base_info_ref (GIBaseInfo *info) +{ + info->ref_count++; + + return info; +} + +void +g_base_info_unref (GIBaseInfo *info) +{ + info->ref_count--; + + if (!info->ref_count) + { + if (info->container) + g_base_info_unref (info->container); + + g_free (info); + } +} + +GIInfoType +g_base_info_get_type (GIBaseInfo *info) +{ + + return info->type; +} + +const gchar * +g_base_info_get_name (GIBaseInfo *info) +{ + switch (info->type) + { + 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_ERROR_DOMAIN: + case GI_INFO_TYPE_UNION: + { + CommonBlob *blob = (CommonBlob *)&info->metadata->data[info->offset]; + + return g_metadata_get_string (info->metadata, blob->name); + } + break; + + case GI_INFO_TYPE_VALUE: + { + ValueBlob *blob = (ValueBlob *)&info->metadata->data[info->offset]; + + return g_metadata_get_string (info->metadata, blob->name); + } + break; + + case GI_INFO_TYPE_SIGNAL: + { + SignalBlob *blob = (SignalBlob *)&info->metadata->data[info->offset]; + + return g_metadata_get_string (info->metadata, blob->name); + } + break; + + case GI_INFO_TYPE_PROPERTY: + { + PropertyBlob *blob = (PropertyBlob *)&info->metadata->data[info->offset]; + + return g_metadata_get_string (info->metadata, blob->name); + } + break; + + case GI_INFO_TYPE_VFUNC: + { + VFuncBlob *blob = (VFuncBlob *)&info->metadata->data[info->offset]; + + return g_metadata_get_string (info->metadata, blob->name); + } + break; + + case GI_INFO_TYPE_FIELD: + { + FieldBlob *blob = (FieldBlob *)&info->metadata->data[info->offset]; + + return g_metadata_get_string (info->metadata, blob->name); + } + break; + + case GI_INFO_TYPE_ARG: + { + ArgBlob *blob = (ArgBlob *)&info->metadata->data[info->offset]; + + return g_metadata_get_string (info->metadata, blob->name); + } + break; + + case GI_INFO_TYPE_UNRESOLVED: + { + GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info; + + return unresolved->name; + } + break; + + case GI_INFO_TYPE_TYPE: + default: ; + /* unnamed */ + } + + return NULL; +} + +const gchar * +g_base_info_get_namespace (GIBaseInfo *info) +{ + Header *header = (Header *)info->metadata->data; + + if (info->type == GI_INFO_TYPE_UNRESOLVED) + { + GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info; + + return unresolved->namespace; + } + + return g_metadata_get_string (info->metadata, header->namespace); +} + +gboolean +g_base_info_is_deprecated (GIBaseInfo *info) +{ + switch (info->type) + { + 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_ERROR_DOMAIN: + { + CommonBlob *blob = (CommonBlob *)&info->metadata->data[info->offset]; + + return blob->deprecated; + } + break; + + case GI_INFO_TYPE_VALUE: + { + ValueBlob *blob = (ValueBlob *)&info->metadata->data[info->offset]; + + return blob->deprecated; + } + break; + + case GI_INFO_TYPE_SIGNAL: + { + SignalBlob *blob = (SignalBlob *)&info->metadata->data[info->offset]; + + return blob->deprecated; + } + break; + + case GI_INFO_TYPE_PROPERTY: + { + PropertyBlob *blob = (PropertyBlob *)&info->metadata->data[info->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; +} + +static int +cmp_annotation (const void *av, + const void *bv) +{ + const AnnotationBlob *a = av; + const AnnotationBlob *b = bv; + + if (b->offset < a->offset) + return -1; + + if (b->offset > a->offset) + return 1; + + return 0; +} + +const gchar * +g_base_info_get_annotation (GIBaseInfo *info, + const gchar *name) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + AnnotationBlob blob, *first, *after, *res, *next; + const gchar *rname; + + blob.offset = base->offset; + + first = (AnnotationBlob *) &base->metadata->data[header->annotations]; + after = (AnnotationBlob *) &base->metadata->data[header->annotations + + header->n_annotations * header->annotation_blob_size]; + + res = bsearch (&blob, first, header->n_annotations, + header->annotation_blob_size, cmp_annotation); + + if (res == NULL) + return NULL; + + next = res; + do + { + res = next; + next = res -= header->annotation_blob_size; + } + while (next >= first && next->offset == base->offset); + + next = res; + do + { + res = next; + + rname = g_metadata_get_string (base->metadata, res->name); + if (strcmp (name, rname) == 0) + return g_metadata_get_string (base->metadata, res->value); + + next = res += header->annotation_blob_size; + } + while (next < after && next->offset == base->offset); + + return NULL; +} + +GIBaseInfo * +g_base_info_get_container (GIBaseInfo *info) +{ + return info->container; +} + +GMetadata * +g_base_info_get_metadata (GIBaseInfo *info) +{ + return info->metadata; +} + +/* GIFunctionInfo functions */ +const gchar * +g_function_info_get_symbol (GIFunctionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + FunctionBlob *blob = (FunctionBlob *)&base->metadata->data[base->offset]; + + return g_metadata_get_string (base->metadata, blob->symbol); +} + +GIFunctionInfoFlags +g_function_info_get_flags (GIFunctionInfo *info) +{ + GIFunctionInfoFlags flags; + GIBaseInfo *base = (GIBaseInfo *)info; + FunctionBlob *blob = (FunctionBlob *)&base->metadata->data[base->offset]; + + flags = 0; + + if (base->container != NULL) + flags = flags | GI_FUNCTION_IS_METHOD; + + if (blob->constructor) + flags = flags | GI_FUNCTION_IS_CONSTRUCTOR; + + if (blob->getter) + flags = flags | GI_FUNCTION_IS_GETTER; + + if (blob->setter) + flags = flags | GI_FUNCTION_IS_SETTER; + + if (blob->wraps_vfunc) + flags = flags | GI_FUNCTION_WRAPS_VFUNC; + + return flags; +} + +GIPropertyInfo * +g_function_info_get_property (GIFunctionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + FunctionBlob *blob = (FunctionBlob *)&base->metadata->data[base->offset]; + GIInterfaceInfo *container = (GIInterfaceInfo *)base->container; + + return g_interface_info_get_property (container, blob->index); +} + +GIVFuncInfo * +g_function_info_get_vfunc (GIFunctionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + FunctionBlob *blob = (FunctionBlob *)&base->metadata->data[base->offset]; + GIInterfaceInfo *container = (GIInterfaceInfo *)base->container; + + return g_interface_info_get_vfunc (container, blob->index); +} + + +/* GICallableInfo functions */ +static guint32 +signature_offset (GICallableInfo *info) +{ + switch (info->base.type) + { + case GI_INFO_TYPE_FUNCTION: + case GI_INFO_TYPE_VFUNC: + return *(guint32 *)&info->base.metadata->data[info->base.offset + 12]; + case GI_INFO_TYPE_CALLBACK: + case GI_INFO_TYPE_SIGNAL: + return *(guint32 *)&info->base.metadata->data[info->base.offset + 8]; + } + + return 0; +} + +GITypeInfo * +g_type_info_new (GIBaseInfo *container, + GMetadata *metadata, + guint32 offset) +{ + SimpleTypeBlob *type = (SimpleTypeBlob *)&metadata->data[offset]; + + return (GITypeInfo *) g_info_new (GI_INFO_TYPE_TYPE, container, metadata, + type->reserved == 0 ? offset : type->offset); +} + +/** + * g_callable_info_get_return_type: + * @info: a #GICallableInfo + * + * Get the return type of a callable item as + * a #GITypeInfo + * + * Returns: a #GITypeInfo idexing the TypeBlob for the + * return type of #info + */ +GITypeInfo * +g_callable_info_get_return_type (GICallableInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + guint32 offset; + + offset = signature_offset (info); + + return g_type_info_new (base, base->metadata, offset); +} + +/** + * g_callable_info_may_return_null: + * @info: a #GICallableInfo + * + * See if a callable could return NULL. + * + * Returns: TRUE if callable could return NULL + */ +gboolean +g_callable_info_may_return_null (GICallableInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SignatureBlob *blob = (SignatureBlob *)&base->metadata->data[signature_offset (info)]; + + return blob->may_return_null; +} + +/** + * g_callable_info_get_caller_owns: + * @info: a #GICallableInfo + * + * See whether the caller owns the return value + * of this callable. + * + * Returns: TRUE if the caller owns the return value, FALSE otherwise. + */ +GITransfer +g_callable_info_get_caller_owns (GICallableInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SignatureBlob *blob = (SignatureBlob *)&base->metadata->data[signature_offset (info)]; + + if (blob->caller_owns_return_value) + return GI_TRANSFER_EVERYTHING; + else if (blob->caller_owns_return_container) + return GI_TRANSFER_CONTAINER; + else + return GI_TRANSFER_NOTHING; +} + +/** + * g_callable_info_get_n_args: + * @info: a #GICallableInfo + * + * Get the number of arguments (both IN and OUT) for this callable. + * + * Returns: The number of arguments this callable expects. + */ +gint +g_callable_info_get_n_args (GICallableInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + gint offset; + SignatureBlob *blob; + + offset = signature_offset (info); + blob = (SignatureBlob *)&base->metadata->data[offset]; + + return blob->n_arguments; +} + +/** + * g_callable_info_get_arg: + * @info: a #GICallableInfo + * + * Get information about a particular argument of this callable. + * + * Returns: A #GIArgInfo indexing the metadata on the given argument. + */ +GIArgInfo * +g_callable_info_get_arg (GICallableInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + gint offset; + + offset = signature_offset (info); + + return (GIArgInfo *) g_info_new (GI_INFO_TYPE_ARG, base, base->metadata, + offset + header->signature_blob_size + n * header->arg_blob_size); +} + +/* GIArgInfo function */ +GIDirection +g_arg_info_get_direction (GIArgInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ArgBlob *blob = (ArgBlob *)&base->metadata->data[base->offset]; + + if (blob->in && blob->out) + return GI_DIRECTION_INOUT; + else if (blob->out) + return GI_DIRECTION_OUT; + else + return GI_DIRECTION_IN; +} + +gboolean +g_arg_info_is_return_value (GIArgInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ArgBlob *blob = (ArgBlob *)&base->metadata->data[base->offset]; + + return blob->return_value; +} + +gboolean +g_arg_info_is_dipper (GIArgInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ArgBlob *blob = (ArgBlob *)&base->metadata->data[base->offset]; + + return blob->dipper; +} + +gboolean +g_arg_info_is_optional (GIArgInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ArgBlob *blob = (ArgBlob *)&base->metadata->data[base->offset]; + + return blob->optional; +} + +gboolean +g_arg_info_may_be_null (GIArgInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ArgBlob *blob = (ArgBlob *)&base->metadata->data[base->offset]; + + return blob->null_ok; +} + +GITransfer +g_arg_info_get_ownership_transfer (GIArgInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ArgBlob *blob = (ArgBlob *)&base->metadata->data[base->offset]; + + if (blob->transfer_ownership) + return GI_TRANSFER_EVERYTHING; + else if (blob->transfer_container_ownership) + return GI_TRANSFER_CONTAINER; + else + return GI_TRANSFER_NOTHING; +} + +GITypeInfo * +g_arg_info_get_type (GIArgInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + + return g_type_info_new (base, base->metadata, base->offset + 8); +} + +/* GITypeInfo functions */ +gboolean +g_type_info_is_pointer (GITypeInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata->data[base->offset]; + + if (type->reserved == 0) + return type->pointer; + else + { + InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&base->metadata->data[base->offset]; + + return iface->pointer; + } +} + +GITypeTag +g_type_info_get_tag (GITypeInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata->data[base->offset]; + + if (type->reserved == 0) + return type->tag; + else + { + InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&base->metadata->data[base->offset]; + + return iface->tag; + } +} + +GITypeInfo * +g_type_info_get_param_type (GITypeInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata->data[base->offset]; + + if (type->reserved != 0) + { + ParamTypeBlob *param = (ParamTypeBlob *)&base->metadata->data[base->offset]; + + switch (param->tag) + { + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + return g_type_info_new (base, base->metadata, base->offset + 4 + 4 * n); + break; + + default: ; + } + } + + return NULL; +} + +GIBaseInfo * +g_type_info_get_interface (GITypeInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata->data[base->offset]; + + if (type->reserved != 0) + { + InterfaceTypeBlob *blob = (InterfaceTypeBlob *)&base->metadata->data[base->offset]; + + if (blob->tag == GI_TYPE_TAG_INTERFACE) + return g_info_from_entry (base->metadata, blob->interface); + } + + return NULL; +} + +gint +g_type_info_get_array_length (GITypeInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata->data[base->offset]; + + if (type->reserved != 0) + { + ArrayTypeBlob *blob = (ArrayTypeBlob *)&base->metadata->data[base->offset]; + + if (blob->tag == GI_TYPE_TAG_ARRAY) + { + if (blob->has_length) + return blob->length; + } + } + + return -1; +} + +gboolean +g_type_info_is_zero_terminated (GITypeInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata->data[base->offset]; + + if (type->reserved != 0) + { + ArrayTypeBlob *blob = (ArrayTypeBlob *)&base->metadata->data[base->offset]; + + if (blob->tag == GI_TYPE_TAG_ARRAY) + return blob->zero_terminated; + } + + return FALSE; +} + +gint +g_type_info_get_n_error_domains (GITypeInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata->data[base->offset]; + + if (type->reserved != 0) + { + ErrorTypeBlob *blob = (ErrorTypeBlob *)&base->metadata->data[base->offset]; + + if (blob->tag == GI_TYPE_TAG_ERROR) + return blob->n_domains; + } + + return 0; +} + +GIErrorDomainInfo * +g_type_info_get_error_domain (GITypeInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata->data[base->offset]; + + if (type->reserved != 0) + { + ErrorTypeBlob *blob = (ErrorTypeBlob *)&base->metadata->data[base->offset]; + + if (blob->tag == GI_TYPE_TAG_ERROR) + return (GIErrorDomainInfo *) g_info_from_entry (base->metadata, + blob->domains[n]); + } + + return NULL; +} + + +/* GIErrorDomainInfo functions */ +const gchar * +g_error_domain_info_get_quark (GIErrorDomainInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ErrorDomainBlob *blob = (ErrorDomainBlob *)&base->metadata->data[base->offset]; + + return g_metadata_get_string (base->metadata, blob->get_quark); +} + +GIInterfaceInfo * +g_error_domain_info_get_codes (GIErrorDomainInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ErrorDomainBlob *blob = (ErrorDomainBlob *)&base->metadata->data[base->offset]; + + return (GIInterfaceInfo *) g_info_from_entry (base->metadata, blob->error_codes); +} + + +/* GIValueInfo functions */ +glong +g_value_info_get_value (GIValueInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ValueBlob *blob = (ValueBlob *)&base->metadata->data[base->offset]; + + return (glong)blob->value; +} + +/* GIFieldInfo functions */ +GIFieldInfoFlags +g_field_info_get_flags (GIFieldInfo *info) +{ + GIFieldInfoFlags flags; + + GIBaseInfo *base = (GIBaseInfo *)info; + FieldBlob *blob = (FieldBlob *)&base->metadata->data[base->offset]; + + flags = 0; + + if (blob->readable) + flags = flags | GI_FIELD_IS_READABLE; + + if (blob->writable) + flags = flags | GI_FIELD_IS_WRITABLE; + + return flags; +} + +gint +g_field_info_get_size (GIFieldInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + FieldBlob *blob = (FieldBlob *)&base->metadata->data[base->offset]; + + return blob->bits; +} + +gint +g_field_info_get_offset (GIFieldInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + FieldBlob *blob = (FieldBlob *)&base->metadata->data[base->offset]; + + return blob->struct_offset; +} + +GITypeInfo * +g_field_info_get_type (GIFieldInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + + return g_type_info_new (base, base->metadata, base->offset + 8); +} + +/* GIRegisteredTypeInfo functions */ +const gchar * +g_registered_type_info_get_type_name (GIRegisteredTypeInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + RegisteredTypeBlob *blob = (RegisteredTypeBlob *)&base->metadata->data[base->offset]; + + if (blob->gtype_name) + return g_metadata_get_string (base->metadata, blob->gtype_name); + + return NULL; +} + +const gchar * +g_registered_type_info_get_type_init (GIRegisteredTypeInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + RegisteredTypeBlob *blob = (RegisteredTypeBlob *)&base->metadata->data[base->offset]; + + if (blob->gtype_init) + return g_metadata_get_string (base->metadata, blob->gtype_init); + + return NULL; +} + + +/* GIStructInfo functions */ +gint +g_struct_info_get_n_fields (GIStructInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + StructBlob *blob = (StructBlob *)&base->metadata->data[base->offset]; + + return blob->n_fields; +} + +GIFieldInfo * +g_struct_info_get_field (GIStructInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + + return (GIFieldInfo *) g_info_new (GI_INFO_TYPE_FIELD, base, base->metadata, + base->offset + header->struct_blob_size + + n * header->field_blob_size); +} + +gint +g_struct_info_get_n_methods (GIStructInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + StructBlob *blob = (StructBlob *)&base->metadata->data[base->offset]; + + return blob->n_methods; +} + +GIFunctionInfo * +g_struct_info_get_method (GIStructInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + StructBlob *blob = (StructBlob *)&base->metadata->data[base->offset]; + Header *header = (Header *)base->metadata->data; + gint offset; + + offset = base->offset + header->struct_blob_size + + blob->n_fields * header->field_blob_size + + n * header->function_blob_size; + return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, + base->metadata, offset); +} + +static GIFunctionInfo * +find_method (GIBaseInfo *base, + guint32 offset, + gint n_methods, + const gchar *name) +{ + /* FIXME hash */ + Header *header = (Header *)base->metadata->data; + gint i; + + for (i = 0; i < n_methods; i++) + { + FunctionBlob *fblob = (FunctionBlob *)&base->metadata->data[offset]; + const gchar *fname = (const gchar *)&base->metadata->data[fblob->name]; + + if (strcmp (name, fname) == 0) + return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, + base->metadata, offset); + + offset += header->function_blob_size; + } + + return NULL; +} + +GIFunctionInfo * +g_struct_info_find_method (GIStructInfo *info, + const gchar *name) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + StructBlob *blob = (StructBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->struct_blob_size + + blob->n_fields * header->field_blob_size; + + return find_method (base, offset, blob->n_methods, name); +} + +gint +g_enum_info_get_n_values (GIEnumInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + EnumBlob *blob = (EnumBlob *)&base->metadata->data[base->offset]; + + return blob->n_values; +} + +GIValueInfo * +g_enum_info_get_value (GIEnumInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + gint offset; + + offset = base->offset + header->enum_blob_size + + n * header->value_blob_size; + return (GIValueInfo *) g_info_new (GI_INFO_TYPE_VALUE, base, base->metadata, offset); +} + +/* GIObjectInfo functions */ +GIObjectInfo * +g_object_info_get_parent (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + if (blob->parent) + return (GIObjectInfo *) g_info_from_entry (base->metadata, blob->parent); + else + return NULL; +} + +const gchar * +g_object_info_get_type_name (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return g_metadata_get_string (base->metadata, blob->gtype_name); +} + +const gchar * +g_object_info_get_type_init (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return g_metadata_get_string (base->metadata, blob->gtype_init); +} + +gint +g_object_info_get_n_interfaces (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return blob->n_interfaces; +} + +GIInterfaceInfo * +g_object_info_get_interface (GIObjectInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return (GIInterfaceInfo *) g_info_from_entry (base->metadata, blob->interfaces[n]); +} + +gint +g_object_info_get_n_fields (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return blob->n_fields; +} + +GIFieldInfo * +g_object_info_get_field (GIObjectInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + n * header->field_blob_size; + + return (GIFieldInfo *) g_info_new (GI_INFO_TYPE_FIELD, base, base->metadata, offset); +} + +gint +g_object_info_get_n_properties (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return blob->n_properties; +} + +GIPropertyInfo * +g_object_info_get_property (GIObjectInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + n * header->property_blob_size; + + return (GIPropertyInfo *) g_info_new (GI_INFO_TYPE_PROPERTY, base, + base->metadata, offset); +} + +gint +g_object_info_get_n_methods (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return blob->n_methods; +} + +GIFunctionInfo * +g_object_info_get_method (GIObjectInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_properties * header->property_blob_size + + n * header->function_blob_size; + + return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, + base->metadata, offset); +} + +GIFunctionInfo * +g_object_info_find_method (GIObjectInfo *info, + const gchar *name) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + + blob->n_properties * header->property_blob_size; + + return find_method (base, offset, blob->n_methods, name); +} + +gint +g_object_info_get_n_signals (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return blob->n_signals; +} + +GISignalInfo * +g_object_info_get_signal (GIObjectInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + n * header->signal_blob_size; + + return (GISignalInfo *) g_info_new (GI_INFO_TYPE_SIGNAL, base, + base->metadata, offset); +} + +gint +g_object_info_get_n_vfuncs (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return blob->n_vfuncs; +} + +GIVFuncInfo * +g_object_info_get_vfunc (GIObjectInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size + + n * header->vfunc_blob_size; + + return (GIVFuncInfo *) g_info_new (GI_INFO_TYPE_VFUNC, base, + base->metadata, offset); +} + +gint +g_object_info_get_n_constants (GIObjectInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + return blob->n_constants; +} + +GIConstantInfo * +g_object_info_get_constant (GIObjectInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + ObjectBlob *blob = (ObjectBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size + + blob->n_vfuncs * header->vfunc_blob_size + + n * header->constant_blob_size; + + return (GIConstantInfo *) g_info_new (GI_INFO_TYPE_CONSTANT, base, + base->metadata, offset); +} + + +/* GIInterfaceInfo functions */ +gint +g_interface_info_get_n_prerequisites (GIInterfaceInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + return blob->n_prerequisites; +} + +GIBaseInfo * +g_interface_info_get_prerequisite (GIInterfaceInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + return g_info_from_entry (base->metadata, blob->prerequisites[n]); +} + + +gint +g_interface_info_get_n_properties (GIInterfaceInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + return blob->n_properties; +} + +GIPropertyInfo * +g_interface_info_get_property (GIInterfaceInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + n * header->property_blob_size; + + return (GIPropertyInfo *) g_info_new (GI_INFO_TYPE_PROPERTY, base, + base->metadata, offset); +} + +gint +g_interface_info_get_n_methods (GIInterfaceInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + return blob->n_methods; +} + +GIFunctionInfo * +g_interface_info_get_method (GIInterfaceInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size + + n * header->function_blob_size; + + return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, + base->metadata, offset); +} + +GIFunctionInfo * +g_interface_info_find_method (GIInterfaceInfo *info, + const gchar *name) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->object_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size; + + return find_method (base, offset, blob->n_methods, name); +} + +gint +g_interface_info_get_n_signals (GIInterfaceInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + return blob->n_signals; +} + +GISignalInfo * +g_interface_info_get_signal (GIInterfaceInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + n * header->signal_blob_size; + + return (GISignalInfo *) g_info_new (GI_INFO_TYPE_SIGNAL, base, + base->metadata, offset); +} + +gint +g_interface_info_get_n_vfuncs (GIInterfaceInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + return blob->n_vfuncs; +} + +GIVFuncInfo * +g_interface_info_get_vfunc (GIInterfaceInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size + + n * header->vfunc_blob_size; + + return (GIVFuncInfo *) g_info_new (GI_INFO_TYPE_VFUNC, base, + base->metadata, offset); +} + +gint +g_interface_info_get_n_constants (GIInterfaceInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + return blob->n_constants; +} + +GIConstantInfo * +g_interface_info_get_constant (GIInterfaceInfo *info, + gint n) +{ + gint offset; + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + InterfaceBlob *blob = (InterfaceBlob *)&base->metadata->data[base->offset]; + + offset = base->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size + + blob->n_vfuncs * header->vfunc_blob_size + + n * header->constant_blob_size; + + return (GIConstantInfo *) g_info_new (GI_INFO_TYPE_CONSTANT, base, + base->metadata, offset); +} + + + + +/* GIPropertyInfo functions */ +GParamFlags +g_property_info_get_flags (GIPropertyInfo *info) +{ + GParamFlags flags; + GIBaseInfo *base = (GIBaseInfo *)info; + PropertyBlob *blob = (PropertyBlob *)&base->metadata->data[base->offset]; + + flags = 0; + + if (blob->readable) + flags = flags | G_PARAM_READABLE; + + if (blob->writable) + flags = flags | G_PARAM_WRITABLE; + + if (blob->construct) + flags = flags | G_PARAM_CONSTRUCT; + + if (blob->construct_only) + flags = flags | G_PARAM_CONSTRUCT_ONLY; + + return flags; +} + +GITypeInfo * +g_property_info_get_type (GIPropertyInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + + return g_type_info_new (base, base->metadata, base->offset + 8); +} + + +/* GISignalInfo functions */ +GSignalFlags +g_signal_info_get_flags (GISignalInfo *info) +{ + GSignalFlags flags; + + GIBaseInfo *base = (GIBaseInfo *)info; + SignalBlob *blob = (SignalBlob *)&base->metadata->data[base->offset]; + + flags = 0; + + if (blob->run_first) + flags = flags | G_SIGNAL_RUN_FIRST; + + if (blob->run_last) + flags = flags | G_SIGNAL_RUN_LAST; + + if (blob->run_cleanup) + flags = flags | G_SIGNAL_RUN_CLEANUP; + + if (blob->no_recurse) + flags = flags | G_SIGNAL_NO_RECURSE; + + if (blob->detailed) + flags = flags | G_SIGNAL_DETAILED; + + if (blob->action) + flags = flags | G_SIGNAL_ACTION; + + if (blob->no_hooks) + flags = flags | G_SIGNAL_NO_HOOKS; + + return flags; +} + +GIVFuncInfo * +g_signal_info_get_class_closure (GISignalInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SignalBlob *blob = (SignalBlob *)&base->metadata->data[base->offset]; + + if (blob->has_class_closure) + return g_interface_info_get_vfunc ((GIInterfaceInfo *)base->container, blob->class_closure); + + return NULL; +} + +gboolean +g_signal_info_true_stops_emit (GISignalInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + SignalBlob *blob = (SignalBlob *)&base->metadata->data[base->offset]; + + return blob->true_stops_emit; +} + +/* GIVFuncInfo functions */ +GIVFuncInfoFlags +g_vfunc_info_get_flags (GIVFuncInfo *info) +{ + GIVFuncInfoFlags flags; + + GIBaseInfo *base = (GIBaseInfo *)info; + VFuncBlob *blob = (VFuncBlob *)&base->metadata->data[base->offset]; + + flags = 0; + + if (blob->must_chain_up) + flags = flags | GI_VFUNC_MUST_CHAIN_UP; + + if (blob->must_be_implemented) + flags = flags | GI_VFUNC_MUST_OVERRIDE; + + if (blob->must_not_be_implemented) + flags = flags | GI_VFUNC_MUST_NOT_OVERRIDE; + + return flags; +} + +gint +g_vfunc_info_get_offset (GIVFuncInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + VFuncBlob *blob = (VFuncBlob *)&base->metadata->data[base->offset]; + + return blob->struct_offset; +} + +GISignalInfo * +g_vfunc_info_get_signal (GIVFuncInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + VFuncBlob *blob = (VFuncBlob *)&base->metadata->data[base->offset]; + + if (blob->class_closure) + return g_interface_info_get_signal ((GIInterfaceInfo *)base->container, blob->signal); + + return NULL; +} + + +/* GIConstantInfo functions */ +GITypeInfo * +g_constant_info_get_type (GIConstantInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + + return g_type_info_new (base, base->metadata, base->offset + 8); +} + +gint +g_constant_info_get_value (GIConstantInfo *info, + GArgument *value) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + ConstantBlob *blob = (ConstantBlob *)&base->metadata->data[base->offset]; + + /* FIXME non-basic types ? */ + if (blob->type.reserved == 0) + { + if (blob->type.pointer) + value->v_pointer = g_memdup (&base->metadata->data[blob->offset], blob->size); + else + { + switch (blob->type.tag) + { + case GI_TYPE_TAG_BOOLEAN: + value->v_boolean = *(gboolean*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_INT8: + value->v_int8 = *(gint8*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_UINT8: + value->v_uint8 = *(guint8*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_INT16: + value->v_int16 = *(gint16*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_UINT16: + value->v_uint16 = *(guint16*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_INT32: + value->v_int32 = *(gint32*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_UINT32: + value->v_uint32 = *(guint32*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_INT64: + value->v_int64 = *(gint64*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_UINT64: + value->v_uint64 = *(guint64*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_FLOAT: + value->v_float = *(gfloat*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_DOUBLE: + value->v_double = *(gdouble*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_INT: + value->v_int = *(gint*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_UINT: + value->v_uint = *(guint*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_LONG: + value->v_long = *(glong*)&base->metadata->data[blob->offset]; + break; + case GI_TYPE_TAG_ULONG: + value->v_ulong = *(gulong*)&base->metadata->data[blob->offset]; + break; + } + } + } + + return blob->size; +} + +/* GIUnionInfo functions */ +gint +g_union_info_get_n_fields (GIUnionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + UnionBlob *blob = (UnionBlob *)&base->metadata->data[base->offset]; + + return blob->n_fields; +} + +GIFieldInfo * +g_union_info_get_field (GIUnionInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->metadata->data; + + return (GIFieldInfo *) g_info_new (GI_INFO_TYPE_FIELD, base, base->metadata, + base->offset + header->union_blob_size + + n * header->field_blob_size); +} + +gint +g_union_info_get_n_methods (GIUnionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + UnionBlob *blob = (UnionBlob *)&base->metadata->data[base->offset]; + + return blob->n_functions; +} + +GIFunctionInfo * +g_union_info_get_method (GIUnionInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + UnionBlob *blob = (UnionBlob *)&base->metadata->data[base->offset]; + Header *header = (Header *)base->metadata->data; + gint offset; + + offset = base->offset + header->union_blob_size + + blob->n_fields * header->field_blob_size + + n * header->function_blob_size; + return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, + base->metadata, offset); +} + +gboolean +g_union_info_is_discriminated (GIUnionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + UnionBlob *blob = (UnionBlob *)&base->metadata->data[base->offset]; + + return blob->discriminated; +} + +gint +g_union_info_get_discriminator_offset (GIUnionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + UnionBlob *blob = (UnionBlob *)&base->metadata->data[base->offset]; + + return blob->discriminator_offset; +} + +GITypeInfo * +g_union_info_get_discriminator_type (GIUnionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + + return g_type_info_new (base, base->metadata, base->offset + 24); +} + +GIConstantInfo * +g_union_info_get_discriminator (GIUnionInfo *info, + gint n) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + UnionBlob *blob = (UnionBlob *)&base->metadata->data[base->offset]; + + if (blob->discriminated) + { + Header *header = (Header *)base->metadata->data; + gint offset; + + offset = base->offset + header->union_blob_size + + blob->n_fields * header->field_blob_size + + blob->n_functions * header->function_blob_size + + n * header->constant_blob_size; + + return (GIConstantInfo *) g_info_new (GI_INFO_TYPE_CONSTANT, base, + base->metadata, offset); + } + + return NULL; +} diff --git a/ginvoke.c b/ginvoke.c new file mode 100644 index 000000000..986ca7850 --- /dev/null +++ b/ginvoke.c @@ -0,0 +1,284 @@ +/* GObject introspection: Invoke functionality + * + * Copyright (C) 2005 Matthias Clasen + * + * 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 + +#include +#include + +#include "girepository.h" +#include "gmetadata.h" +#include "config.h" + +GQuark +g_invoke_error_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("g-invoke-error-quark"); + return quark; +} + +#include "ffi.h" + +static ffi_type * +get_ffi_type (GITypeInfo *info) +{ + ffi_type *rettype; + + if (g_type_info_is_pointer (info)) + rettype = &ffi_type_pointer; + else + switch (g_type_info_get_tag (info)) + { + case GI_TYPE_TAG_VOID: + rettype = &ffi_type_void; + break; + case GI_TYPE_TAG_BOOLEAN: + rettype = &ffi_type_uint; + break; + case GI_TYPE_TAG_INT8: + rettype = &ffi_type_sint8; + break; + case GI_TYPE_TAG_UINT8: + rettype = &ffi_type_uint8; + break; + case GI_TYPE_TAG_INT16: + rettype = &ffi_type_sint16; + break; + case GI_TYPE_TAG_UINT16: + rettype = &ffi_type_uint16; + break; + case GI_TYPE_TAG_INT32: + rettype = &ffi_type_sint32; + break; + case GI_TYPE_TAG_UINT32: + rettype = &ffi_type_uint32; + break; + case GI_TYPE_TAG_INT64: + rettype = &ffi_type_sint64; + break; + case GI_TYPE_TAG_UINT64: + rettype = &ffi_type_uint64; + break; + case GI_TYPE_TAG_INT: + rettype = &ffi_type_sint; + break; + case GI_TYPE_TAG_UINT: + rettype = &ffi_type_uint; + break; + case GI_TYPE_TAG_SSIZE: /* FIXME */ + case GI_TYPE_TAG_LONG: + rettype = &ffi_type_slong; + break; + case GI_TYPE_TAG_SIZE: /* FIXME */ + case GI_TYPE_TAG_ULONG: + rettype = &ffi_type_ulong; + break; + case GI_TYPE_TAG_FLOAT: + rettype = &ffi_type_float; + break; + case GI_TYPE_TAG_DOUBLE: + rettype = &ffi_type_double; + break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_INTERFACE: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + case GI_TYPE_TAG_ERROR: + rettype = &ffi_type_pointer; + break; + default: + g_assert_not_reached (); + } + + return rettype; +} + +/** + * g_function_info_invoke: + * @info: a #GIFunctionInfo describing the function to invoke + * @in_args: an array of #GArguments, one for each in + * parameter of @info. If there are no in parameter, @in_args + * can be %NULL + * @n_in_args: the length of the @in_args array + * @out_args: an array of #GArguments, one for each out + * parameter of @info. If there are no out parameters, @out_args + * may be %NULL + * @n_out_args: the length of the @out_args array + * @return_value: return location for the return value of the + * function. If the function returns void, @return_value may be + * %NULL + * @error: return location for detailed error information, or %NULL + * + * Invokes the function described in @info with the given + * arguments. Note that inout parameters must appear in both + * argument lists. This function uses dlsym() to obtain a pointer + * to the function, so the library or shared object containing the + * described function must either be linked to the caller, or must + * have been dlopen()ed before calling this function. + * + * Returns: %TRUE if the function has been invoked, %FALSE if an + * error occurred. + */ +gboolean +g_function_info_invoke (GIFunctionInfo *info, + const GArgument *in_args, + int n_in_args, + const GArgument *out_args, + int n_out_args, + GArgument *return_value, + GError **error) +{ + ffi_cif cif; + ffi_type *rtype; + ffi_type **atypes; + const gchar *symbol; + gpointer func; + GITypeInfo *tinfo; + GIArgInfo *ainfo; + gint n_args, in_pos, out_pos, i; + gpointer *args; + gboolean success = FALSE; + + symbol = g_function_info_get_symbol (info); + + if (!g_module_symbol (g_base_info_get_metadata((GIBaseInfo *) info)->module, + symbol, &func)) + { + g_set_error (error, + G_INVOKE_ERROR, + G_INVOKE_ERROR_SYMBOL_NOT_FOUND, + "Could not locate %s: %s", symbol, g_module_error ()); + + return FALSE; + } + + tinfo = g_callable_info_get_return_type ((GICallableInfo *)info); + rtype = get_ffi_type (tinfo); + g_base_info_unref ((GIBaseInfo *)tinfo); + + n_args = g_callable_info_get_n_args ((GICallableInfo *)info); + atypes = g_new (ffi_type*, n_args); + args = g_new (gpointer, n_args); + + in_pos = 0; + out_pos = 0; + for (i = 0; i < n_args; i++) + { + ainfo = g_callable_info_get_arg ((GICallableInfo *)info, i); + switch (g_arg_info_get_direction (ainfo)) + { + case GI_DIRECTION_IN: + tinfo = g_arg_info_get_type (ainfo); + atypes[i] = get_ffi_type (tinfo); + g_base_info_unref ((GIBaseInfo *)tinfo); + + if (in_pos >= n_in_args) + { + g_set_error (error, + G_INVOKE_ERROR, + G_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too few \"in\" arguments"); + goto out; + } + + args[i] = (gpointer)&in_args[in_pos]; + in_pos++; + + break; + case GI_DIRECTION_OUT: + atypes[i] = &ffi_type_pointer; + + if (out_pos >= n_out_args) + { + g_set_error (error, + G_INVOKE_ERROR, + G_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too few \"out\" arguments"); + goto out; + } + + args[i] = (gpointer)&out_args[out_pos]; + out_pos++; + break; + case GI_DIRECTION_INOUT: + atypes[i] = &ffi_type_pointer; + + if (in_pos >= n_in_args) + { + g_set_error (error, + G_INVOKE_ERROR, + G_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too few \"in\" arguments"); + goto out; + } + + if (out_pos >= n_out_args) + { + g_set_error (error, + G_INVOKE_ERROR, + G_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too few \"in\" arguments"); + goto out; + } + + args[i] = (gpointer)&in_args[in_pos]; + in_pos++; + out_pos++; + break; + default: + g_assert_not_reached (); + } + g_base_info_unref ((GIBaseInfo *)ainfo); + } + if (in_pos < n_in_args) + { + g_set_error (error, + G_INVOKE_ERROR, + G_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too many \"in\" arguments"); + goto out; + } + if (out_pos < n_out_args) + { + g_set_error (error, + G_INVOKE_ERROR, + G_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too many \"out\" arguments"); + goto out; + } + + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK) + goto out; + + ffi_call (&cif, func, return_value, args); + + success = TRUE; + + out: + g_free (atypes); + g_free (args); + + return success; +} diff --git a/girepository.c b/girepository.c new file mode 100644 index 000000000..c9b3b683c --- /dev/null +++ b/girepository.c @@ -0,0 +1,499 @@ +/* -*- Mode: C; c-file-style: "gnu"; -*- */ +/* GObject introspection: Repository implementation + * + * Copyright (C) 2005 Matthias Clasen + * + * 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 +#include + +#include +#include +#include +#include "girepository.h" +#include "gmetadata.h" + +static GIRepository *default_repository = NULL; +static GHashTable *default_metadata = NULL; +static GSList *search_path = NULL; + +struct _GIRepositoryPrivate +{ + GHashTable *metadata; /* (string) namespace -> GMetadata */ +}; + +G_DEFINE_TYPE (GIRepository, g_irepository, G_TYPE_OBJECT); + +static void +g_irepository_init (GIRepository *repository) +{ + repository->priv = G_TYPE_INSTANCE_GET_PRIVATE (repository, G_TYPE_IREPOSITORY, + GIRepositoryPrivate); +} + +static void +g_irepository_finalize (GObject *object) +{ + GIRepository *repository = G_IREPOSITORY (object); + + g_hash_table_destroy (repository->priv->metadata); + + (* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository)); +} + +static void +g_irepository_class_init (GIRepositoryClass *class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (class); + + gobject_class->finalize = g_irepository_finalize; + + g_type_class_add_private (class, sizeof (GIRepositoryPrivate)); +} + +const gchar * +g_irepository_register (GIRepository *repository, + GMetadata *metadata) +{ + Header *header; + const gchar *name; + GHashTable *table; + GError *error = NULL; + + g_return_val_if_fail (metadata != NULL, NULL); + + header = (Header *)metadata->data; + + g_return_val_if_fail (header != NULL, NULL); + + if (repository != NULL) + { + if (repository->priv->metadata == NULL) + repository->priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) g_metadata_free); + table = repository->priv->metadata; + } + else + { + if (default_metadata == NULL) + default_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) g_metadata_free); + table = default_metadata; + } + + name = g_metadata_get_string (metadata, header->namespace); + + if (g_hash_table_lookup (table, name)) + { + g_printerr ("metadata (%p) for '%s' already registered\n", + metadata, name); + + return NULL; + } + g_hash_table_insert (table, g_strdup(name), (void *)metadata); + + if (metadata->module == NULL) + metadata->module = g_module_open (NULL, 0); + + return name; +} + + +void +g_irepository_unregister (GIRepository *repository, + const gchar *namespace) +{ + GHashTable *table; + + if (repository != NULL) + table = repository->priv->metadata; + else + table = default_metadata; + + if (!g_hash_table_remove (table, namespace)) + { + g_printerr ("namespace '%s' not registered\n", namespace); + } +} + +gboolean +g_irepository_is_registered (GIRepository *repository, + const gchar *namespace) +{ + GHashTable *table; + + if (repository != NULL) + table = repository->priv->metadata; + else + table = default_metadata; + + return g_hash_table_lookup (table, namespace) != NULL; +} + +GIRepository * +g_irepository_get_default (void) +{ + if (default_repository == NULL) + { + default_repository = g_object_new (G_TYPE_IREPOSITORY, NULL); + if (default_metadata == NULL) + default_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) g_metadata_free); + default_repository->priv->metadata = default_metadata; + } + + return default_repository; +} + +static void +count_interfaces (gpointer key, + gpointer value, + gpointer data) +{ + guchar *metadata = ((GMetadata *) value)->data; + gint *n_interfaces = (gint *)data; + + *n_interfaces += ((Header *)metadata)->n_local_entries; +} + +gint +g_irepository_get_n_infos (GIRepository *repository, + const gchar *namespace) +{ + gint n_interfaces = 0; + + if (namespace) + { + GMetadata *metadata; + + metadata = g_hash_table_lookup (repository->priv->metadata, namespace); + + if (metadata) + n_interfaces = ((Header *)metadata->data)->n_local_entries; + } + else + { + g_hash_table_foreach (repository->priv->metadata, + count_interfaces, &n_interfaces); + } + + return n_interfaces; +} + +typedef struct +{ + gint index; + const gchar *name; + const gchar *type; + GIBaseInfo *iface; +} IfaceData; + +static void +find_interface (gpointer key, + gpointer value, + gpointer data) +{ + gint i; + GMetadata *metadata = (GMetadata *)value; + IfaceData *iface_data = (IfaceData *)data; + gint index; + gint n_entries; + guint32 offset; + const gchar *name; + const gchar *type; + DirEntry *entry; + + index = 0; + n_entries = ((Header *)metadata->data)->n_local_entries; + + if (iface_data->name) + { + for (i = 1; i <= n_entries; i++) + { + entry = g_metadata_get_dir_entry (metadata, i); + name = g_metadata_get_string (metadata, entry->name); + if (strcmp (name, iface_data->name) == 0) + { + index = i; + break; + } + } + } + else if (iface_data->type) + { + for (i = 1; i <= n_entries; i++) + { + entry = g_metadata_get_dir_entry (metadata, i); + if (entry->blob_type < 4) + continue; + + offset = *(guint32*)&metadata->data[entry->offset + 8]; + type = g_metadata_get_string (metadata, offset); + if (strcmp (type, iface_data->type) == 0) + { + index = i; + break; + } + } + } + else if (iface_data->index > n_entries) + iface_data->index -= n_entries; + else if (iface_data->index > 0) + { + index = iface_data->index; + iface_data->index = 0; + } + + if (index != 0) + { + entry = g_metadata_get_dir_entry (metadata, index); + iface_data->iface = g_info_new (entry->blob_type, NULL, + metadata, entry->offset); + } +} + +GIBaseInfo * +g_irepository_get_info (GIRepository *repository, + const gchar *namespace, + gint index) +{ + IfaceData data; + + data.name = NULL; + data.type = NULL; + data.index = index + 1; + data.iface = NULL; + + if (namespace) + { + GMetadata *metadata; + + metadata = g_hash_table_lookup (repository->priv->metadata, namespace); + + if (metadata) + find_interface ((void *)namespace, metadata, &data); + } + else + g_hash_table_foreach (repository->priv->metadata, find_interface, &data); + + return data.iface; +} + +GIBaseInfo * +g_irepository_find_by_gtype (GIRepository *repository, + GType type) +{ + IfaceData data; + + data.name = NULL; + data.type = g_type_name (type); + data.index = -1; + data.iface = NULL; + + g_hash_table_foreach (repository->priv->metadata, find_interface, &data); + + return data.iface; +} + +GIBaseInfo * +g_irepository_find_by_name (GIRepository *repository, + const gchar *namespace, + const gchar *name) +{ + IfaceData data; + + data.name = name; + data.type = NULL; + data.index = -1; + data.iface = NULL; + + if (namespace) + { + GMetadata *metadata; + + metadata = g_hash_table_lookup (repository->priv->metadata, namespace); + + if (metadata) + find_interface ((void *)namespace, metadata, &data); + } + else + g_hash_table_foreach (repository->priv->metadata, find_interface, &data); + + return data.iface; +} + +static void +collect_namespaces (gpointer key, + gpointer value, + gpointer data) +{ + GList **list = data; + + *list = g_list_append (*list, key); +} + +gchar ** +g_irepository_get_namespaces (GIRepository *repository) +{ + GList *l, *list = NULL; + gchar **names; + gint i; + + g_hash_table_foreach (repository->priv->metadata, collect_namespaces, &list); + + names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1)); + i = 0; + for (l = list; l; l = l->next) + names[i++] = g_strdup (l->data); + g_list_free (list); + + return names; +} + +const gchar * +g_irepository_get_shared_library (GIRepository *repository, + const gchar *namespace) +{ + GMetadata *metadata; + Header *header; + + metadata = g_hash_table_lookup (repository->priv->metadata, namespace); + if (!metadata) + return NULL; + header = (Header *) metadata->data; + if (header->shared_library) + return g_metadata_get_string (metadata, header->shared_library); + else + return NULL; +} + +static inline void +g_irepository_build_search_path (void) +{ + gchar **dir; + gchar **tokens; + + if (g_getenv ("GIREPOPATH")) { + gchar *path; + path = g_strconcat (g_getenv ("GIREPOPATH"), ":", GIREPO_DEFAULT_SEARCH_PATH, NULL); + tokens = g_strsplit (path, ":", 0); + g_free (path); + } else + tokens = g_strsplit (GIREPO_DEFAULT_SEARCH_PATH, ":", 0); + + search_path = g_slist_prepend (search_path, "."); + for (dir = tokens; *dir; ++dir) + search_path = g_slist_prepend (search_path, *dir); + search_path = g_slist_reverse (search_path); + g_free (tokens); +} + +const gchar * +g_irepository_register_file (GIRepository *repository, + const gchar *namespace, + GError **error) +{ + GSList *ldir; + const char *dir; + gchar *fname, *full_path; + GMappedFile *mfile; + GError *error1 = NULL; + GMetadata *metadata = NULL; + const gchar *metadata_namespace, *shlib_fname; + GModule *module; + guint32 shlib; + GHashTable *table; + + if (repository != NULL) + table = repository->priv->metadata; + else + table = default_metadata; + + /* don't bother loading a namespace if already registered */ + if (g_hash_table_lookup (table, namespace)) + return NULL; + + if (search_path == NULL) + g_irepository_build_search_path (); + + fname = g_strconcat (namespace, ".repo", NULL); + + for (ldir = search_path; ldir; ldir = ldir->next) { + dir = ldir->data; + full_path = g_build_filename (dir, fname, NULL); + mfile = g_mapped_file_new (full_path, FALSE, &error1); + if (error1) { + g_debug ("Failed to mmap \"%s\"", full_path); + g_clear_error (&error1); + g_free (full_path); + continue; + } + g_free (full_path); + metadata = g_metadata_new_from_mapped_file (mfile); + metadata_namespace = g_metadata_get_string (metadata, ((Header *) metadata->data)->namespace); + if (strcmp (metadata_namespace, namespace) != 0) { + g_set_error (error, G_IREPOSITORY_ERROR, + G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH, + "Metadata file %s for namespace '%s' contains namespace '%s'" + " which doesn't match the file name", + full_path, namespace, metadata_namespace); + return NULL; + } + break; + } + g_free (fname); + if (metadata == NULL) { + g_set_error (error, G_IREPOSITORY_ERROR, + G_IREPOSITORY_ERROR_METADATA_NOT_FOUND, + "Metadata file for namespace '%s' was not found in search" + " path or could not be openened", namespace); + return NULL; + } + /* optionally load shared library and attach it to the metadata */ + shlib = ((Header *) metadata->data)->shared_library; + if (shlib) { + shlib_fname = g_metadata_get_string (metadata, shlib); + module = g_module_open (shlib_fname, G_MODULE_BIND_LAZY|G_MODULE_BIND_LOCAL); + if (module == NULL) { + g_set_error (error, G_IREPOSITORY_ERROR, + G_IREPOSITORY_ERROR_METADATA_NOT_FOUND, + "Metadata for namespace '%s' references shared library %s," + " but it could not be openened (%s)", + namespace, shlib_fname, g_module_error ()); + return NULL; + } + } + + g_hash_table_remove (table, namespace); + return g_irepository_register (repository, metadata); +} + + +GQuark +g_irepository_error_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("g-irepository-error-quark"); + return quark; +} diff --git a/girepository.h b/girepository.h new file mode 100644 index 000000000..7ad1067a1 --- /dev/null +++ b/girepository.h @@ -0,0 +1,452 @@ +/* GObject introspection: Repository + * + * Copyright (C) 2005 Matthias Clasen + * + * 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. + */ + +#ifndef __G_IREPOSITORY_H__ +#define __G_IREPOSITORY_H__ + +#include +#include + +G_BEGIN_DECLS + +#define G_TYPE_IREPOSITORY (g_irepository_get_type ()) +#define G_IREPOSITORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_IREPOSITORY, GIRepository)) + +typedef struct _GIRepository GIRepository; +typedef struct _GIRepositoryClass GIRepositoryClass; +typedef struct _GIRepositoryPrivate GIRepositoryPrivate; +typedef struct _GIBaseInfo GIBaseInfo; +typedef struct _GICallableInfo GICallableInfo; +typedef struct _GIFunctionInfo GIFunctionInfo; +typedef struct _GICallbackInfo GICallbackInfo; +typedef struct _GIRegisteredTypeInfo GIRegisteredTypeInfo; +typedef struct _GIStructInfo GIStructInfo; +typedef struct _GIUnionInfo GIUnionInfo; +typedef struct _GIEnumInfo GIEnumInfo; +typedef struct _GIObjectInfo GIObjectInfo; +typedef struct _GIInterfaceInfo GIInterfaceInfo; +typedef struct _GIConstantInfo GIConstantInfo; +typedef struct _GIValueInfo GIValueInfo; +typedef struct _GISignalInfo GISignalInfo; +typedef struct _GIVFuncInfo GIVFuncInfo; +typedef struct _GIPropertyInfo GIPropertyInfo; +typedef struct _GIFieldInfo GIFieldInfo; +typedef struct _GIArgInfo GIArgInfo; +typedef struct _GITypeInfo GITypeInfo; +typedef struct _GIErrorDomainInfo GIErrorDomainInfo; +typedef struct _GIUnresolvedInfo GIUnresolvedInfo; +typedef struct _GMetadata GMetadata; + +struct _GIRepository +{ + GObject parent; + + /*< private >*/ + GIRepositoryPrivate *priv; +}; + +struct _GIRepositoryClass +{ + GObjectClass parent; +}; + + +/* Repository */ + +GType g_irepository_get_type (void) G_GNUC_CONST; +GIRepository *g_irepository_get_default (void); +const gchar * g_irepository_register (GIRepository *repository, + GMetadata *metadata); +void g_irepository_unregister (GIRepository *repository, + const gchar *namespace); +const gchar * g_irepository_register_file (GIRepository *repository, + const gchar *filename, + GError **error); +gboolean g_irepository_is_registered (GIRepository *repository, + const gchar *namespace); +GIBaseInfo * g_irepository_find_by_name (GIRepository *repository, + const gchar *namespace, + const gchar *name); +gchar ** g_irepository_get_namespaces (GIRepository *repository); +GIBaseInfo * g_irepository_find_by_gtype (GIRepository *repository, + GType gtype); +gint g_irepository_get_n_infos (GIRepository *repository, + const gchar *namespace); +GIBaseInfo * g_irepository_get_info (GIRepository *repository, + const gchar *namespace, + gint index); +const gchar * g_irepository_get_shared_library (GIRepository *repository, + const gchar *namespace); +/* Metadata */ + +GMetadata * g_metadata_new_from_memory (guchar *memory, + gsize len); +GMetadata * g_metadata_new_from_const_memory (const guchar *memory, + gsize len); +GMetadata * g_metadata_new_from_mapped_file (GMappedFile *mfile); +void g_metadata_free (GMetadata *metadata); +void g_metadata_set_module (GMetadata *metadata, + GModule *module); +const gchar * g_metadata_get_namespace (GMetadata *metadata); + +typedef enum +{ + G_IREPOSITORY_ERROR_METADATA_NOT_FOUND, + G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH, + G_IREPOSITORY_ERROR_LIBRARY_NOT_FOUND +} GIRepositoryError; + +#define G_IREPOSITORY_ERROR (g_irepository_error_quark ()) + +GQuark g_irepository_error_quark (void); + + +/* Types of objects registered in the repository */ + +typedef enum +{ + GI_INFO_TYPE_INVALID, + GI_INFO_TYPE_FUNCTION, + GI_INFO_TYPE_CALLBACK, + GI_INFO_TYPE_STRUCT, + GI_INFO_TYPE_BOXED, + GI_INFO_TYPE_ENUM, + GI_INFO_TYPE_FLAGS, + GI_INFO_TYPE_OBJECT, + GI_INFO_TYPE_INTERFACE, + GI_INFO_TYPE_CONSTANT, + GI_INFO_TYPE_ERROR_DOMAIN, + GI_INFO_TYPE_UNION, + GI_INFO_TYPE_VALUE, + GI_INFO_TYPE_SIGNAL, + GI_INFO_TYPE_VFUNC, + GI_INFO_TYPE_PROPERTY, + GI_INFO_TYPE_FIELD, + GI_INFO_TYPE_ARG, + GI_INFO_TYPE_TYPE, + GI_INFO_TYPE_UNRESOLVED +} GIInfoType; + + +/* GIBaseInfo */ + +GIBaseInfo * g_base_info_ref (GIBaseInfo *info); +void g_base_info_unref (GIBaseInfo *info); +GIInfoType g_base_info_get_type (GIBaseInfo *info); +const gchar * g_base_info_get_name (GIBaseInfo *info); +const gchar * g_base_info_get_namespace (GIBaseInfo *info); +gboolean g_base_info_is_deprecated (GIBaseInfo *info); +const gchar * g_base_info_get_annotation (GIBaseInfo *info, + const gchar *name); +GIBaseInfo * g_base_info_get_container (GIBaseInfo *info); +GMetadata * g_base_info_get_metadata (GIBaseInfo *info); + +GIBaseInfo * g_info_new (GIInfoType type, + GIBaseInfo *container, + GMetadata *metadata, + guint32 offset); + + +/* GIFunctionInfo */ + +typedef enum +{ + GI_FUNCTION_IS_METHOD = 1 << 0, + GI_FUNCTION_IS_CONSTRUCTOR = 1 << 1, + GI_FUNCTION_IS_GETTER = 1 << 2, + GI_FUNCTION_IS_SETTER = 1 << 3, + GI_FUNCTION_WRAPS_VFUNC = 1 << 4 +} GIFunctionInfoFlags; + +const gchar * g_function_info_get_symbol (GIFunctionInfo *info); +GIFunctionInfoFlags g_function_info_get_flags (GIFunctionInfo *info); +GIPropertyInfo * g_function_info_get_property (GIFunctionInfo *info); +GIVFuncInfo * g_function_info_get_vfunc (GIFunctionInfo *info); + +typedef union +{ + gboolean v_boolean; + gint8 v_int8; + guint8 v_uint8; + gint16 v_int16; + guint16 v_uint16; + gint32 v_int32; + guint32 v_uint32; + gint64 v_int64; + guint64 v_uint64; + gfloat v_float; + gdouble v_double; + gint v_int; + guint v_uint; + glong v_long; + gulong v_ulong; + gssize v_ssize; + gsize v_size; + gchar * v_string; + gpointer v_pointer; +} GArgument; + +#define G_INVOKE_ERROR (g_invoke_error_quark ()) +GQuark g_invoke_error_quark (void); + +typedef enum +{ + G_INVOKE_ERROR_FAILED, + G_INVOKE_ERROR_SYMBOL_NOT_FOUND, + G_INVOKE_ERROR_ARGUMENT_MISMATCH +} GInvokeError; + +gboolean g_function_info_invoke (GIFunctionInfo *info, + const GArgument *in_args, + int n_in_args, + const GArgument *out_args, + int n_out_args, + GArgument *return_value, + GError **error); + + +/* GICallableInfo */ + +typedef enum { + GI_TRANSFER_NOTHING, + GI_TRANSFER_CONTAINER, + GI_TRANSFER_EVERYTHING +} GITransfer; + +GITypeInfo * g_callable_info_get_return_type (GICallableInfo *info); +GITransfer g_callable_info_get_caller_owns (GICallableInfo *info); +gboolean g_callable_info_may_return_null (GICallableInfo *info); +gint g_callable_info_get_n_args (GICallableInfo *info); +GIArgInfo * g_callable_info_get_arg (GICallableInfo *info, + gint n); + +/* GIArgInfo */ + +typedef enum { + GI_DIRECTION_IN, + GI_DIRECTION_OUT, + GI_DIRECTION_INOUT +} GIDirection; + +GIDirection g_arg_info_get_direction (GIArgInfo *info); +gboolean g_arg_info_is_dipper (GIArgInfo *info); +gboolean g_arg_info_is_return_value (GIArgInfo *info); +gboolean g_arg_info_is_optional (GIArgInfo *info); +gboolean g_arg_info_may_be_null (GIArgInfo *info); +GITransfer g_arg_info_get_ownership_transfer (GIArgInfo *info); +GITypeInfo * g_arg_info_get_type (GIArgInfo *info); + + +/* GITypeInfo */ + +typedef enum { + GI_TYPE_TAG_VOID = 0, + GI_TYPE_TAG_BOOLEAN = 1, + GI_TYPE_TAG_INT8 = 2, + GI_TYPE_TAG_UINT8 = 3, + GI_TYPE_TAG_INT16 = 4, + GI_TYPE_TAG_UINT16 = 5, + GI_TYPE_TAG_INT32 = 6, + GI_TYPE_TAG_UINT32 = 7, + GI_TYPE_TAG_INT64 = 8, + GI_TYPE_TAG_UINT64 = 9, + GI_TYPE_TAG_INT = 10, + GI_TYPE_TAG_UINT = 11, + GI_TYPE_TAG_LONG = 12, + GI_TYPE_TAG_ULONG = 13, + GI_TYPE_TAG_SSIZE = 14, + GI_TYPE_TAG_SIZE = 15, + GI_TYPE_TAG_FLOAT = 16, + GI_TYPE_TAG_DOUBLE = 17, + GI_TYPE_TAG_UTF8 = 18, + GI_TYPE_TAG_FILENAME = 19, + GI_TYPE_TAG_ARRAY = 20, + GI_TYPE_TAG_INTERFACE = 21, + GI_TYPE_TAG_GLIST = 22, + GI_TYPE_TAG_GSLIST = 23, + GI_TYPE_TAG_GHASH = 24, + GI_TYPE_TAG_ERROR = 25 +} GITypeTag; + +gboolean g_type_info_is_pointer (GITypeInfo *info); +GITypeTag g_type_info_get_tag (GITypeInfo *info); +GITypeInfo * g_type_info_get_param_type (GITypeInfo *info, + gint n); +GIBaseInfo * g_type_info_get_interface (GITypeInfo *info); +gint g_type_info_get_array_length (GITypeInfo *info); +gboolean g_type_info_is_zero_terminated (GITypeInfo *info); + +gint g_type_info_get_n_error_domains (GITypeInfo *info); +GIErrorDomainInfo *g_type_info_get_error_domain (GITypeInfo *info, + gint n); + +/* GIErrorDomainInfo */ + +const gchar * g_error_domain_info_get_quark (GIErrorDomainInfo *info); +GIInterfaceInfo * g_error_domain_info_get_codes (GIErrorDomainInfo *info); + + +/* GIValueInfo */ + +glong g_value_info_get_value (GIValueInfo *info); + + +/* GIFieldInfo */ + +typedef enum +{ + GI_FIELD_IS_READABLE = 1 << 0, + GI_FIELD_IS_WRITABLE = 1 << 1 +} GIFieldInfoFlags; + +GIFieldInfoFlags g_field_info_get_flags (GIFieldInfo *info); +gint g_field_info_get_size (GIFieldInfo *info); +gint g_field_info_get_offset (GIFieldInfo *info); +GITypeInfo * g_field_info_get_type (GIFieldInfo *info); + + +/* GIUnionInfo */ +gint g_union_info_get_n_fields (GIUnionInfo *info); +GIFieldInfo * g_union_info_get_field (GIUnionInfo *info, + gint n); +gint g_union_info_get_n_methods (GIUnionInfo *info); +GIFunctionInfo * g_union_info_get_method (GIUnionInfo *info, + gint n); +gboolean g_union_info_is_discriminated (GIUnionInfo *info); +gint g_union_info_get_discriminator_offset (GIUnionInfo *info); +GITypeInfo * g_union_info_get_discriminator_type (GIUnionInfo *info); +GIConstantInfo * g_union_info_get_discriminator (GIUnionInfo *info, + gint n); + + +/* GIStructInfo */ +gint g_struct_info_get_n_fields (GIStructInfo *info); +GIFieldInfo * g_struct_info_get_field (GIStructInfo *info, + gint n); +gint g_struct_info_get_n_methods (GIStructInfo *info); +GIFunctionInfo * g_struct_info_get_method (GIStructInfo *info, + gint n); +GIFunctionInfo * g_struct_info_find_method (GIStructInfo *info, + const gchar *name); + +/* GIRegisteredTypeInfo */ + +const gchar * g_registered_type_info_get_type_name (GIRegisteredTypeInfo *info); +const gchar * g_registered_type_info_get_type_init (GIRegisteredTypeInfo *info); + + +/* GIEnumInfo */ + +gint g_enum_info_get_n_values (GIEnumInfo *info); +GIValueInfo * g_enum_info_get_value (GIEnumInfo *info, + gint n); + +/* GIObjectInfo */ + +const gchar * g_object_info_get_type_name (GIObjectInfo *info); +const gchar * g_object_info_get_type_init (GIObjectInfo *info); +GIObjectInfo * g_object_info_get_parent (GIObjectInfo *info); +gint g_object_info_get_n_interfaces (GIObjectInfo *info); +GIInterfaceInfo * g_object_info_get_interface (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_fields (GIObjectInfo *info); +GIFieldInfo * g_object_info_get_field (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_properties (GIObjectInfo *info); +GIPropertyInfo * g_object_info_get_property (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_methods (GIObjectInfo *info); +GIFunctionInfo * g_object_info_get_method (GIObjectInfo *info, + gint n); +GIFunctionInfo * g_object_info_find_method (GIObjectInfo *info, + const gchar *name); +gint g_object_info_get_n_signals (GIObjectInfo *info); +GISignalInfo * g_object_info_get_signal (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_vfuncs (GIObjectInfo *info); +GIVFuncInfo * g_object_info_get_vfunc (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_constants (GIObjectInfo *info); +GIConstantInfo * g_object_info_get_constant (GIObjectInfo *info, + gint n); + + +/* GIInterfaceInfo */ + +gint g_interface_info_get_n_prerequisites (GIInterfaceInfo *info); +GIBaseInfo * g_interface_info_get_prerequisite (GIInterfaceInfo *info, + gint n); +gint g_interface_info_get_n_properties (GIInterfaceInfo *info); +GIPropertyInfo * g_interface_info_get_property (GIInterfaceInfo *info, + gint n); +gint g_interface_info_get_n_methods (GIInterfaceInfo *info); +GIFunctionInfo * g_interface_info_get_method (GIInterfaceInfo *info, + gint n); +GIFunctionInfo * g_interface_info_find_method (GIInterfaceInfo *info, + const gchar *name); +gint g_interface_info_get_n_signals (GIInterfaceInfo *info); +GISignalInfo * g_interface_info_get_signal (GIInterfaceInfo *info, + gint n); +gint g_interface_info_get_n_vfuncs (GIInterfaceInfo *info); +GIVFuncInfo * g_interface_info_get_vfunc (GIInterfaceInfo *info, + gint n); +gint g_interface_info_get_n_constants (GIInterfaceInfo *info); +GIConstantInfo * g_interface_info_get_constant (GIInterfaceInfo *info, + gint n); + + +/* GIPropertyInfo */ + +GParamFlags g_property_info_get_flags (GIPropertyInfo *info); +GITypeInfo * g_property_info_get_type (GIPropertyInfo *info); + + +/* GISignalInfo */ + +GSignalFlags g_signal_info_get_flags (GISignalInfo *info); +GIVFuncInfo * g_signal_info_get_class_closure (GISignalInfo *info); +gboolean g_signal_info_true_stops_emit (GISignalInfo *info); + + +/* GIVFuncInfo */ + +typedef enum +{ + GI_VFUNC_MUST_CHAIN_UP = 1 << 0, + GI_VFUNC_MUST_OVERRIDE = 1 << 1, + GI_VFUNC_MUST_NOT_OVERRIDE = 1 << 2 +} GIVFuncInfoFlags; + +GIVFuncInfoFlags g_vfunc_info_get_flags (GIVFuncInfo *info); +gint g_vfunc_info_get_offset (GIVFuncInfo *info); +GISignalInfo * g_vfunc_info_get_signal (GIVFuncInfo *info); + + +/* GIConstantInfo */ + +GITypeInfo * g_constant_info_get_type (GIConstantInfo *info); +gint g_constant_info_get_value (GIConstantInfo *info, + GArgument *value); + + +G_END_DECLS + +#endif /* __G_IREPOSITORY_H__ */ + diff --git a/gmetadata.c b/gmetadata.c new file mode 100644 index 000000000..b68039043 --- /dev/null +++ b/gmetadata.c @@ -0,0 +1,1876 @@ +/* GObject introspection: metadata validation, auxiliary functions + * related to the binary metadata format + * + * Copyright (C) 2005 Matthias Clasen + * + * 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 +#include + +#include + +#include "gmetadata.h" + + +#define ALIGN_VALUE(this, boundary) \ + (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) + + +DirEntry * +g_metadata_get_dir_entry (GMetadata *metadata, + guint16 index) +{ + Header *header = (Header *)metadata->data; + + return (DirEntry *)&metadata->data[header->directory + (index - 1) * header->entry_blob_size]; +} + +void +g_metadata_check_sanity (void) +{ + /* Check that struct layout is as we expect */ + g_assert (sizeof (Header) == 100); + g_assert (sizeof (DirEntry) == 12); + g_assert (sizeof (SimpleTypeBlob) == 4); + g_assert (sizeof (ArgBlob) == 12); + g_assert (sizeof (SignatureBlob) == 8); + g_assert (sizeof (CommonBlob) == 8); + g_assert (sizeof (FunctionBlob) == 16); + g_assert (sizeof (InterfaceTypeBlob) == 4); + g_assert (sizeof (ArrayTypeBlob) == 8); + g_assert (sizeof (ParamTypeBlob) == 4); + g_assert (sizeof (ErrorTypeBlob) == 4); + g_assert (sizeof (ErrorDomainBlob) == 16); + g_assert (sizeof (ValueBlob) == 12); + g_assert (sizeof (FieldBlob) == 12); + g_assert (sizeof (RegisteredTypeBlob) == 16); + g_assert (sizeof (StructBlob) == 20); + g_assert (sizeof (EnumBlob) == 20); + g_assert (sizeof (PropertyBlob) == 12); + g_assert (sizeof (SignalBlob) == 12); + g_assert (sizeof (VFuncBlob) == 16); + g_assert (sizeof (ObjectBlob) == 32); + g_assert (sizeof (InterfaceBlob) == 28); + g_assert (sizeof (ConstantBlob) == 20); + g_assert (sizeof (AnnotationBlob) == 12); + g_assert (sizeof (UnionBlob) == 28); +} + + +static gboolean +is_aligned (guint32 offset) +{ + return offset == ALIGN_VALUE (offset, 4); +} + +#define MAX_NAME_LEN 200 + +static gboolean +is_name (const guchar *data, guint32 offset) +{ + gchar *name; + + name = (gchar*)&data[offset]; + + if (!memchr (name, '\0', MAX_NAME_LEN)) + return FALSE; + + if (strspn (name, G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_") < strlen (name)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_header (GMetadata *metadata, + GError **error) +{ + Header *header; + + if (metadata->len < sizeof (Header)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + header = (Header *)metadata->data; + + if (strncmp (header->magic, G_IDL_MAGIC, 16) != 0) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Magic string not found"); + return FALSE; + + } + + if (header->major_version != 1 || header->minor_version != 0) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Version mismatch"); + return FALSE; + + } + + if (header->n_entries < header->n_local_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Inconsistent entry counts"); + return FALSE; + } + + if (header->size != metadata->len) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Metadata size mismatch"); + return FALSE; + } + + if (header->entry_blob_size != 12 || + header->function_blob_size != 16 || + header->callback_blob_size != 12 || + header->signal_blob_size != 12 || + header->vfunc_blob_size != 16 || + header->arg_blob_size != 12 || + header->property_blob_size != 12 || + header->field_blob_size != 12 || + header->value_blob_size != 12 || + header->constant_blob_size != 20 || + header->error_domain_blob_size != 16 || + header->annotation_blob_size != 12 || + header->signature_blob_size != 8 || + header->enum_blob_size != 20 || + header->struct_blob_size != 20 || + header->object_blob_size != 32 || + header->interface_blob_size != 28 || + header->union_blob_size != 28) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Blob size mismatch"); + return FALSE; + } + + if (!is_aligned (header->directory)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Misaligned directory"); + return FALSE; + } + + if (!is_aligned (header->annotations)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Misaligned annotations"); + return FALSE; + } + + if (header->annotations == 0 && header->n_annotations > 0) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Wrong number of annotations"); + return FALSE; + } + + if (!is_name (metadata->data, header->namespace)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Invalid namespace name"); + return FALSE; + } + + return TRUE; +} + +static gboolean validate_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error); + +static gboolean +validate_array_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + ArrayTypeBlob *blob; + + blob = (ArrayTypeBlob*)&metadata->data[offset]; + + if (!blob->pointer) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", blob->tag); + return FALSE; + } + + /* FIXME validate length */ + + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (ArrayTypeBlob, type), + 0, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_iface_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + InterfaceTypeBlob *blob; + Header *header; + + header = (Header *)metadata->data; + + blob = (InterfaceTypeBlob*)&metadata->data[offset]; + + if (blob->interface == 0 || blob->interface > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid directory index %d", blob->interface); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_param_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + gint n_params, + GError **error) +{ + ParamTypeBlob *blob; + gint i; + + blob = (ParamTypeBlob*)&metadata->data[offset]; + + if (!blob->pointer) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", blob->tag); + return FALSE; + } + + if (blob->n_types != n_params) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Parameter type number mismatch"); + return FALSE; + } + + for (i = 0; i < n_params; i++) + { + if (!validate_type_blob (metadata, + offset + sizeof (ParamTypeBlob) + + i * sizeof (SimpleTypeBlob), + 0, FALSE, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_error_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + ErrorTypeBlob *blob; + Header *header; + gint i; + DirEntry *entry; + + blob = (ErrorTypeBlob*)&metadata->data[offset]; + + header = (Header *)metadata->data; + + if (!blob->pointer) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", blob->tag); + return FALSE; + } + + for (i = 0; i < blob->n_domains; i++) + { + if (blob->domains[i] == 0 || blob->domains[i] > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid directory index %d", blob->domains[i]); + return FALSE; + } + + entry = g_metadata_get_dir_entry (metadata, blob->domains[i]); + + if (entry->blob_type != BLOB_TYPE_ERROR_DOMAIN && + (entry->local || entry->blob_type != BLOB_TYPE_INVALID)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +validate_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + SimpleTypeBlob *simple; + InterfaceTypeBlob *iface; + + simple = (SimpleTypeBlob *)&metadata->data[offset]; + + if (simple->reserved == 0 && + simple->reserved2 == 0) + { + if (simple->tag >= TYPE_TAG_ARRAY) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong tag in simple type"); + return FALSE; + } + + if (simple->tag >= TYPE_TAG_UTF8 && + !simple->pointer) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", simple->tag); + return FALSE; + } + + return TRUE; + } + + iface = (InterfaceTypeBlob*)&metadata->data[simple->offset]; + + switch (iface->tag) + { + case TYPE_TAG_ARRAY: + if (!validate_array_type_blob (metadata, simple->offset, + signature_offset, return_type, error)) + return FALSE; + break; + case TYPE_TAG_INTERFACE: + if (!validate_iface_type_blob (metadata, simple->offset, + signature_offset, return_type, error)) + return FALSE; + break; + case TYPE_TAG_LIST: + case TYPE_TAG_SLIST: + if (!validate_param_type_blob (metadata, simple->offset, + signature_offset, return_type, 1, error)) + return FALSE; + break; + case TYPE_TAG_HASH: + if (!validate_param_type_blob (metadata, simple->offset, + signature_offset, return_type, 2, error)) + return FALSE; + break; + case TYPE_TAG_ERROR: + if (!validate_error_type_blob (metadata, simple->offset, + signature_offset, return_type, error)) + return FALSE; + break; + default: + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong tag in complex type"); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_arg_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + GError **error) +{ + ArgBlob *blob; + + if (metadata->len < offset + sizeof (ArgBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ArgBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid argument name"); + return FALSE; + } + + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (ArgBlob, arg_type), + signature_offset, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_signature_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + SignatureBlob *blob; + gint i; + + if (metadata->len < offset + sizeof (SignatureBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (SignatureBlob*) &metadata->data[offset]; + + if (blob->return_type.offset != 0) + { + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (SignatureBlob, return_type), + offset, TRUE, error)) + return FALSE; + } + + for (i = 0; i < blob->n_arguments; i++) + { + if (!validate_arg_blob (metadata, + offset + sizeof (SignatureBlob) + + i * sizeof (ArgBlob), + offset, + error)) + return FALSE; + } + + /* FIXME check constraints on return_value */ + /* FIXME check array-length pairs */ + return TRUE; +} + +static gboolean +validate_function_blob (GMetadata *metadata, + guint32 offset, + guint16 container_type, + GError **error) +{ + FunctionBlob *blob; + + if (metadata->len < offset + sizeof (FunctionBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (FunctionBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_FUNCTION) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid function name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->symbol)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid function symbol"); + return FALSE; + } + + if (blob->constructor) + { + switch (container_type) + { + case BLOB_TYPE_BOXED: + case BLOB_TYPE_OBJECT: + case BLOB_TYPE_INTERFACE: + break; + default: + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Constructor not allowed"); + return FALSE; + } + } + + if (blob->setter || blob->getter || blob->wraps_vfunc) + { + switch (container_type) + { + case BLOB_TYPE_OBJECT: + case BLOB_TYPE_INTERFACE: + break; + default: + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Setter, getter or wrapper not allowed"); + return FALSE; + } + } + + if (blob->index) + { + if (!(blob->setter || blob->getter || blob->wraps_vfunc)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Must be setter, getter or wrapper"); + return FALSE; + } + } + + /* FIXME: validate index range */ + /* FIXME: validate "this" argument for methods */ + /* FIXME: validate return type for constructors */ + + if (!validate_signature_blob (metadata, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_callback_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + CallbackBlob *blob; + + if (metadata->len < offset + sizeof (CallbackBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (CallbackBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_CALLBACK) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid callback name"); + return FALSE; + } + + if (!validate_signature_blob (metadata, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_constant_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + gint value_size[] = { + 0, 4, 1, 1, 2, 2, 4, 4, 8, 8, + sizeof (gint), sizeof (guint), + sizeof (glong), sizeof (gulong), + sizeof (gssize), sizeof (gsize), + sizeof (gfloat), sizeof (gdouble), + 0, 0 + }; + ConstantBlob *blob; + SimpleTypeBlob *type; + + if (metadata->len < offset + sizeof (ConstantBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ConstantBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_CONSTANT) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid constant name"); + return FALSE; + } + + if (!validate_type_blob (metadata, offset + G_STRUCT_OFFSET (ConstantBlob, type), + 0, FALSE, error)) + return FALSE; + + if (!is_aligned (blob->offset)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Misaligned constant value"); + return FALSE; + } + + type = (SimpleTypeBlob *)&metadata->data[offset + G_STRUCT_OFFSET (ConstantBlob, type)]; + if (type->reserved == 0) + { + if (type->tag == 0) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Constant value type void"); + return FALSE; + } + + if (value_size[type->tag] != 0 && + blob->size != value_size[type->tag]) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Constant value size mismatch"); + return FALSE; + } + /* FIXME check string values */ + } + + return TRUE; +} + +static gboolean +validate_value_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + ValueBlob *blob; + + if (metadata->len < offset + sizeof (ValueBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ValueBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid value name"); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_field_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + FieldBlob *blob; + + if (metadata->len < offset + sizeof (FieldBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (FieldBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid field name"); + return FALSE; + } + + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (FieldBlob, type), + 0, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_property_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + PropertyBlob *blob; + + if (metadata->len < offset + sizeof (PropertyBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (PropertyBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid property name"); + return FALSE; + } + + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (PropertyBlob, type), + 0, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_signal_blob (GMetadata *metadata, + guint32 offset, + guint32 container_offset, + GError **error) +{ + SignalBlob *blob; + gint n_signals; + + if (metadata->len < offset + sizeof (SignalBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (SignalBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid signal name"); + return FALSE; + } + + if ((blob->run_first != 0) + + (blob->run_last != 0) + + (blob->run_cleanup != 0) != 1) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid signal run flags"); + return FALSE; + } + + if (blob->has_class_closure) + { + if (((CommonBlob*)&metadata->data[container_offset])->blob_type == BLOB_TYPE_OBJECT) + { + ObjectBlob *object; + + object = (ObjectBlob*)&metadata->data[container_offset]; + + n_signals = object->n_signals; + } + else + { + InterfaceBlob *iface; + + iface = (InterfaceBlob*)&metadata->data[container_offset]; + + n_signals = iface->n_signals; + } + + if (blob->class_closure >= n_signals) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid class closure index"); + return FALSE; + } + } + + if (!validate_signature_blob (metadata, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_vfunc_blob (GMetadata *metadata, + guint32 offset, + guint32 container_offset, + GError **error) +{ + VFuncBlob *blob; + gint n_vfuncs; + + if (metadata->len < offset + sizeof (VFuncBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (VFuncBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid vfunc name"); + return FALSE; + } + + if (blob->class_closure) + { + if (((CommonBlob*)&metadata->data[container_offset])->blob_type == BLOB_TYPE_OBJECT) + { + ObjectBlob *object; + + object = (ObjectBlob*)&metadata->data[container_offset]; + + n_vfuncs = object->n_vfuncs; + } + else + { + InterfaceBlob *iface; + + iface = (InterfaceBlob*)&metadata->data[container_offset]; + + n_vfuncs = iface->n_vfuncs; + } + + if (blob->class_closure >= n_vfuncs) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid class closure index"); + return FALSE; + } + } + + if (!validate_signature_blob (metadata, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_struct_blob (GMetadata *metadata, + guint32 offset, + guint16 blob_type, + GError **error) +{ + StructBlob *blob; + gint i; + + if (metadata->len < offset + sizeof (StructBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (StructBlob*) &metadata->data[offset]; + + if (blob->blob_type != blob_type) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if ((blob->blob_type == BLOB_TYPE_BOXED && blob->unregistered) || + (blob->blob_type == BLOB_TYPE_STRUCT && !blob->unregistered)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Registration/blob type mismatch"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid struct name"); + return FALSE; + } + + if (blob_type == BLOB_TYPE_BOXED) + { + if (!is_name (metadata->data, blob->gtype_name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid boxed type name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_init)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid boxed type init"); + return FALSE; + } + } + else + { + if (blob->gtype_name || blob->gtype_init) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Gtype data in struct"); + return FALSE; + } + } + + if (metadata->len < offset + sizeof (StructBlob) + + blob->n_fields * sizeof (FieldBlob) + + blob->n_methods * sizeof (FunctionBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + for (i = 0; i < blob->n_fields; i++) + { + if (!validate_field_blob (metadata, + offset + sizeof (StructBlob) + + i * sizeof (FieldBlob), + error)) + return FALSE; + } + + for (i = 0; i < blob->n_methods; i++) + { + if (!validate_function_blob (metadata, + offset + sizeof (StructBlob) + + blob->n_fields * sizeof (FieldBlob) + + i * sizeof (FunctionBlob), + blob_type, + error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_enum_blob (GMetadata *metadata, + guint32 offset, + guint16 blob_type, + GError **error) +{ + EnumBlob *blob; + ValueBlob *v1, *v2; + gint i, j; + + if (metadata->len < offset + sizeof (EnumBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (EnumBlob*) &metadata->data[offset]; + + if (blob->blob_type != blob_type) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!blob->unregistered) + { + if (!is_name (metadata->data, blob->gtype_name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid enum type name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_init)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid enum type init"); + return FALSE; + } + } + else + { + if (blob->gtype_name || blob->gtype_init) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Gtype data in unregistered enum"); + return FALSE; + } + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid enum name"); + return FALSE; + } + + if (metadata->len < offset + sizeof (EnumBlob) + + blob->n_values * sizeof (ValueBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + for (i = 0; i < blob->n_values; i++) + { + if (!validate_value_blob (metadata, + offset + sizeof (EnumBlob) + + i * sizeof (ValueBlob), + error)) + return FALSE; + + v1 = (ValueBlob *)&metadata->data[offset + sizeof (EnumBlob) + + i * sizeof (ValueBlob)]; + for (j = 0; j < i; j++) + { + v2 = (ValueBlob *)&metadata->data[offset + sizeof (EnumBlob) + + j * sizeof (ValueBlob)]; + + if (v1->value == v2->value) + { + /* FIXME should this be an error ? */ + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Duplicate enum value"); + return FALSE; + } + } + } + + return TRUE; +} + +static gboolean +validate_object_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + Header *header; + ObjectBlob *blob; + gint i; + guint32 offset2; + + header = (Header *)metadata->data; + + if (metadata->len < offset + sizeof (ObjectBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ObjectBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_OBJECT) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid object type name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_init)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid object type init"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid object name"); + return FALSE; + } + + if (blob->parent > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid parent index"); + return FALSE; + } + + if (blob->parent != 0) + { + DirEntry *entry; + + entry = g_metadata_get_dir_entry (metadata, blob->parent); + if (entry->blob_type != BLOB_TYPE_OBJECT && + (entry->local || entry->blob_type != 0)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Parent not object"); + return FALSE; + } + } + + if (metadata->len < offset + sizeof (ObjectBlob) + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * sizeof (FieldBlob) + + blob->n_properties * sizeof (PropertyBlob) + + blob->n_methods * sizeof (FunctionBlob) + + blob->n_signals * sizeof (SignalBlob) + + blob->n_vfuncs * sizeof (VFuncBlob) + + blob->n_constants * sizeof (ConstantBlob)) + + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + offset2 = offset + sizeof (ObjectBlob); + + for (i = 0; i < blob->n_interfaces; i++, offset2 += 2) + { + guint16 iface; + DirEntry *entry; + + iface = *(guint16*)&metadata->data[offset2]; + if (iface == 0 || iface > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid interface index"); + return FALSE; + } + + entry = g_metadata_get_dir_entry (metadata, iface); + + if (entry->blob_type != BLOB_TYPE_INTERFACE && + (entry->local || entry->blob_type != 0)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Not an interface"); + return FALSE; + } + } + + offset2 += 2 * (blob->n_interfaces %2); + + for (i = 0; i < blob->n_fields; i++, offset2 += sizeof (FieldBlob)) + { + if (!validate_field_blob (metadata, offset2, error)) + return FALSE; + } + + for (i = 0; i < blob->n_properties; i++, offset2 += sizeof (PropertyBlob)) + { + if (!validate_property_blob (metadata, offset2, error)) + return FALSE; + } + + for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob)) + { + if (!validate_function_blob (metadata, offset2, BLOB_TYPE_OBJECT, error)) + return FALSE; + } + + for (i = 0; i < blob->n_signals; i++, offset2 += sizeof (SignalBlob)) + { + if (!validate_signal_blob (metadata, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_vfuncs; i++, offset2 += sizeof (VFuncBlob)) + { + if (!validate_vfunc_blob (metadata, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_constants; i++, offset2 += sizeof (ConstantBlob)) + { + if (!validate_constant_blob (metadata, offset2, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_interface_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + Header *header; + InterfaceBlob *blob; + gint i; + guint32 offset2; + + header = (Header *)metadata->data; + + if (metadata->len < offset + sizeof (InterfaceBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (InterfaceBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_INTERFACE) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid interface type name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_init)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid interface type init"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid interface name"); + return FALSE; + } + + if (metadata->len < offset + sizeof (InterfaceBlob) + + (blob->n_prerequisites + blob->n_prerequisites % 2) * 2 + + blob->n_properties * sizeof (PropertyBlob) + + blob->n_methods * sizeof (FunctionBlob) + + blob->n_signals * sizeof (SignalBlob) + + blob->n_vfuncs * sizeof (VFuncBlob) + + blob->n_constants * sizeof (ConstantBlob)) + + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + offset2 = offset + sizeof (InterfaceBlob); + + for (i = 0; i < blob->n_prerequisites; i++, offset2 += 2) + { + DirEntry *entry; + guint16 req; + + req = *(guint16*)&metadata->data[offset2]; + if (req == 0 || req > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid prerequisite index"); + return FALSE; + } + + entry = g_metadata_get_dir_entry (metadata, req); + if (entry->blob_type != BLOB_TYPE_INTERFACE && + entry->blob_type != BLOB_TYPE_OBJECT && + (entry->local || entry->blob_type != 0)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Not an interface or object"); + return FALSE; + } + } + + offset2 += 2 * (blob->n_prerequisites % 2); + + for (i = 0; i < blob->n_properties; i++, offset2 += sizeof (PropertyBlob)) + { + if (!validate_property_blob (metadata, offset2, error)) + return FALSE; + } + + for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob)) + { + if (!validate_function_blob (metadata, offset2, BLOB_TYPE_INTERFACE, error)) + return FALSE; + } + + for (i = 0; i < blob->n_signals; i++, offset2 += sizeof (SignalBlob)) + { + if (!validate_signal_blob (metadata, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_vfuncs; i++, offset2 += sizeof (VFuncBlob)) + { + if (!validate_vfunc_blob (metadata, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_constants; i++, offset2 += sizeof (ConstantBlob)) + { + if (!validate_constant_blob (metadata, offset2, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_errordomain_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + return TRUE; +} + +static gboolean +validate_union_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + return TRUE; +} + +static gboolean +validate_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + CommonBlob *common; + + if (metadata->len < offset + sizeof (CommonBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + common = (CommonBlob*)&metadata->data[offset]; + + switch (common->blob_type) + { + case BLOB_TYPE_FUNCTION: + if (!validate_function_blob (metadata, offset, 0, error)) + return FALSE; + break; + case BLOB_TYPE_CALLBACK: + if (!validate_callback_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_STRUCT: + case BLOB_TYPE_BOXED: + if (!validate_struct_blob (metadata, offset, common->blob_type, error)) + return FALSE; + break; + case BLOB_TYPE_ENUM: + case BLOB_TYPE_FLAGS: + if (!validate_enum_blob (metadata, offset, common->blob_type, error)) + return FALSE; + break; + case BLOB_TYPE_OBJECT: + if (!validate_object_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_INTERFACE: + if (!validate_interface_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_CONSTANT: + if (!validate_constant_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_ERROR_DOMAIN: + if (!validate_errordomain_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_UNION: + if (!validate_union_blob (metadata, offset, error)) + return FALSE; + break; + default: + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_ENTRY, + "Invalid blob type"); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_directory (GMetadata *metadata, + GError **error) +{ + Header *header = (Header *)metadata->data; + DirEntry *entry; + gint i; + + if (metadata->len < header->directory + header->n_entries * sizeof (DirEntry)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + for (i = 0; i < header->n_entries; i++) + { + entry = g_metadata_get_dir_entry (metadata, i + 1); + + if (!is_name (metadata->data, entry->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Invalid entry name"); + return FALSE; + } + + if ((entry->local && entry->blob_type == BLOB_TYPE_INVALID) || + entry->blob_type > BLOB_TYPE_UNION) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Invalid entry type"); + return FALSE; + } + + if (i < header->n_local_entries) + { + if (!entry->local) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Too few local directory entries"); + return FALSE; + } + + if (!is_aligned (entry->offset)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Misaligned entry"); + return FALSE; + } + + if (!validate_blob (metadata, entry->offset, error)) + return FALSE; + } + else + { + if (entry->local) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Too many local directory entries"); + return FALSE; + } + + if (!is_name (metadata->data, entry->offset)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Invalid namespace name"); + return FALSE; + } + } + } + + return TRUE; +} + +static gboolean +validate_annotations (GMetadata *metadata, + GError **error) +{ + Header *header = (Header *)metadata->data; + + if (header->size < header->annotations + header->n_annotations * sizeof (AnnotationBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + return TRUE; +} + +gboolean +g_metadata_validate (GMetadata *metadata, + GError **error) +{ + if (!validate_header (metadata, error)) + return FALSE; + + if (!validate_directory (metadata, error)) + return FALSE; + + if (!validate_annotations (metadata, error)) + return FALSE; + + return TRUE; +} + +GQuark +g_metadata_error_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("g-metadata-error-quark"); + return quark; +} + + +static inline void +_g_metadata_init (GMetadata *metadata) +{ + Header *header; + + header = (Header *) metadata->data; + if (header->shared_library) + { + const gchar *shlib; + shlib = g_metadata_get_string (metadata, header->shared_library); + metadata->module = g_module_open (shlib, G_MODULE_BIND_LAZY|G_MODULE_BIND_LOCAL); + if (metadata->module == NULL) + g_warning ("Failed to load shared library referenced by the metadata: %s", + g_module_error ()); + } +} + +/** + * g_metadata_new_from_memory: + * @memory: address of memory chunk containing the metadata + * @len: length of memory chunk containing the metadata + * + * Creates a new #GMetadata from a memory location. The memory block + * pointed to by @metadata will be automatically g_free()d when the + * repository is destroyed. + * + * Return value: the new #GMetadata + **/ +GMetadata * +g_metadata_new_from_memory (guchar *memory, gsize len) +{ + GMetadata *meta; + + meta = g_new0 (GMetadata, 1); + meta->data = memory; + meta->len = len; + meta->owns_memory = TRUE; + _g_metadata_init (meta); + return meta; +} + +/** + * g_metadata_new_from_const_memory: + * @memory: address of memory chunk containing the metadata + * @len: length of memory chunk containing the metadata + * + * Creates a new #GMetadata from a memory location. + * + * Return value: the new #GMetadata + **/ +GMetadata * +g_metadata_new_from_const_memory (const guchar *memory, gsize len) +{ + GMetadata *meta; + + meta = g_new0 (GMetadata, 1); + meta->data = (guchar *) memory; + meta->len = len; + meta->owns_memory = FALSE; + _g_metadata_init (meta); + return meta; +} + +/** + * g_metadata_new_from_mapped_file: + * @mfile: a #GMappedFile, that will be free'd when the repository is destroyed + * + * Creates a new #GMetadata from a #GMappedFile. + * + * Return value: the new #GMetadata + **/ +GMetadata * +g_metadata_new_from_mapped_file (GMappedFile *mfile) +{ + GMetadata *meta; + + meta = g_new0 (GMetadata, 1); + meta->mfile = mfile; + meta->owns_memory = FALSE; + meta->data = (guchar *) g_mapped_file_get_contents (mfile); + meta->len = g_mapped_file_get_length (mfile); + _g_metadata_init (meta); + return meta; +} + +/** + * g_metadata_free: + * @metadata: a #GMetadata + * + * Free a #GMetadata. + **/ +void +g_metadata_free (GMetadata *metadata) +{ + if (metadata->mfile) + g_mapped_file_free (metadata->mfile); + else + if (metadata->owns_memory) + g_free (metadata->data); + if (metadata->module) + g_module_close (metadata->module); + g_free (metadata); +} + +/** + * g_metadata_set_module: + * @metadata: a #GMetadata instance + * @module: a #GModule; takes ownership of this module + * + * Sets the target module for all symbols referenced by the metadata. + **/ +void +g_metadata_set_module (GMetadata *metadata, GModule *module) +{ + if (metadata->module) + g_module_close (metadata->module); + metadata->module = module; +} + +const gchar * +g_metadata_get_namespace(GMetadata *metadata) +{ + return g_metadata_get_string (metadata, ((Header *) metadata->data)->namespace); +} diff --git a/gmetadata.h b/gmetadata.h new file mode 100644 index 000000000..a22ee235e --- /dev/null +++ b/gmetadata.h @@ -0,0 +1,549 @@ +/* GObject introspection: struct definitions for the binary + * metadata format, validation + * + * Copyright (C) 2005 Matthias Clasen + * + * 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. + */ + +#ifndef __G_METADATA_H__ +#define __G_METADATA_H__ + +#include +#include "girepository.h" + +G_BEGIN_DECLS + +#define G_IDL_MAGIC "GOBJ\nMETADATA\r\n\032" + +enum +{ + BLOB_TYPE_INVALID, + BLOB_TYPE_FUNCTION, + BLOB_TYPE_CALLBACK, + BLOB_TYPE_STRUCT, + BLOB_TYPE_BOXED, + BLOB_TYPE_ENUM, + BLOB_TYPE_FLAGS, + BLOB_TYPE_OBJECT, + BLOB_TYPE_INTERFACE, + BLOB_TYPE_CONSTANT, + BLOB_TYPE_ERROR_DOMAIN, + BLOB_TYPE_UNION +}; + +typedef struct +{ + gchar magic[16]; + guint8 major_version; + guint8 minor_version; + guint16 reserved; + guint16 n_entries; + guint16 n_local_entries; + guint32 directory; + guint32 n_annotations; + guint32 annotations; + + guint32 size; + guint32 namespace; + guint32 shared_library; + + guint16 entry_blob_size; + guint16 function_blob_size; + guint16 callback_blob_size; + guint16 signal_blob_size; + guint16 vfunc_blob_size; + guint16 arg_blob_size; + guint16 property_blob_size; + guint16 field_blob_size; + guint16 value_blob_size; + guint16 annotation_blob_size; + guint16 constant_blob_size; + guint16 error_domain_blob_size; + + guint16 signature_blob_size; + guint16 enum_blob_size; + guint16 struct_blob_size; + guint16 object_blob_size; + guint16 interface_blob_size; + guint16 union_blob_size; + + guint16 padding[7]; +} Header; + +typedef struct +{ + guint16 blob_type; + + guint local : 1; + guint reserved :15; + + guint32 name; + guint32 offset; +} DirEntry; + + +#define TYPE_POINTER_MASK 1 << 7 +#define TYPE_TAG_MASK 63 + +typedef enum +{ + TYPE_TAG_VOID = 0, + TYPE_TAG_BOOLEAN = 1, + TYPE_TAG_INT8 = 2, + TYPE_TAG_UINT8 = 3, + TYPE_TAG_INT16 = 4, + TYPE_TAG_UINT16 = 5, + TYPE_TAG_INT32 = 6, + TYPE_TAG_UINT32 = 7, + TYPE_TAG_INT64 = 8, + TYPE_TAG_UINT64 = 9, + TYPE_TAG_INT = 10, + TYPE_TAG_UINT = 11, + TYPE_TAG_LONG = 12, + TYPE_TAG_ULONG = 13, + TYPE_TAG_SSIZE = 14, + TYPE_TAG_SIZE = 15, + TYPE_TAG_FLOAT = 16, + TYPE_TAG_DOUBLE = 17, + TYPE_TAG_UTF8 = 18, + TYPE_TAG_FILENAME = 19, + TYPE_TAG_ARRAY = 20, + TYPE_TAG_INTERFACE = 21, + TYPE_TAG_LIST = 22, + TYPE_TAG_SLIST = 23, + TYPE_TAG_HASH = 24, + TYPE_TAG_ERROR = 25 +} TypeTag; + +typedef union +{ + struct + { + guint reserved : 8; + guint reserved2 :16; + guint pointer : 1; + guint reserved3 : 2; + guint tag : 5; + }; + guint32 offset; +} SimpleTypeBlob; + + +typedef struct +{ + guint32 name; + + guint in : 1; + guint out : 1; + guint dipper : 1; + guint null_ok : 1; + guint optional : 1; + guint transfer_ownership : 1; + guint transfer_container_ownership : 1; + guint return_value : 1; + guint reserved :24; + + SimpleTypeBlob arg_type; +} ArgBlob; + +typedef struct +{ + SimpleTypeBlob return_type; + + guint may_return_null : 1; + guint caller_owns_return_value : 1; + guint caller_owns_return_container : 1; + guint reserved :13; + + guint16 n_arguments; + + ArgBlob arguments[]; +} SignatureBlob; + +typedef struct +{ + guint16 blob_type; /* 1 */ + + guint deprecated : 1; + guint reserved :15; + + guint32 name; +} CommonBlob; + +typedef struct +{ + guint16 blob_type; /* 1 */ + + guint deprecated : 1; + guint setter : 1; + guint getter : 1; + guint constructor : 1; + guint wraps_vfunc : 1; + guint reserved : 1; + guint index :10; + + guint32 name; + guint32 symbol; + guint32 signature; +} FunctionBlob; + +typedef struct +{ + guint16 blob_type; /* 2 */ + + guint deprecated : 1; + guint reserved :15; + + guint32 name; + guint32 signature; +} CallbackBlob; + +typedef struct +{ + guint pointer :1; + guint reserved :2; + guint tag :5; + guint8 reserved2; + guint16 interface; +} InterfaceTypeBlob; + +typedef struct +{ + guint pointer :1; + guint reserved :2; + guint tag :5; + + guint zero_terminated :1; + guint has_length :1; + guint reserved2 :6; + + guint16 length; + + SimpleTypeBlob type; +} ArrayTypeBlob; + +typedef struct +{ + guint pointer :1; + guint reserved :2; + guint tag :5; + + guint8 reserved2; + guint16 n_types; + + SimpleTypeBlob type[]; +} ParamTypeBlob; + +typedef struct +{ + guint pointer :1; + guint reserved :2; + guint tag :5; + + guint8 reserved2; + guint16 n_domains; + + guint16 domains[]; +} ErrorTypeBlob; + +typedef struct +{ + guint16 blob_type; /* 10 */ + + guint deprecated : 1; + guint reserved :15; + + guint32 name; + + guint32 get_quark; + guint16 error_codes; + guint16 reserved2; +} ErrorDomainBlob; + +typedef struct +{ + guint deprecated : 1; + guint reserved :31; + guint32 name; + guint32 value; +} ValueBlob; + +typedef struct +{ + guint32 name; + + guint readable : 1; + guint writable : 1; + guint reserved : 6; + guint8 bits; + + guint16 struct_offset; + + SimpleTypeBlob type; +} FieldBlob; + +typedef struct +{ + guint16 blob_type; + guint deprecated : 1; + guint unregistered :15; + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; +} RegisteredTypeBlob; + +typedef struct +{ + guint16 blob_type; + + guint deprecated : 1; + guint unregistered : 1; + guint reserved :14; + + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + + guint16 n_fields; + guint16 n_methods; + +#if 0 + /* variable-length parts of the blob */ + FieldBlob fields[]; + FunctionBlob methods[]; +#endif +} StructBlob; + +typedef struct +{ + guint16 blob_type; + guint deprecated : 1; + guint unregistered : 1; + guint discriminated : 1; + guint reserved :13; + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + + guint16 n_fields; + guint16 n_functions; + + gint32 discriminator_offset; + SimpleTypeBlob discriminator_type; + +#if 0 + FieldBlob fields[]; + FunctionBlob functions[]; + ConstantBlob discriminator_values[] +#endif +} UnionBlob; + +typedef struct +{ + guint16 blob_type; + + guint deprecated : 1; + guint unregistered : 1; + guint reserved :14; + + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + + guint16 n_values; + guint16 reserved2; + + ValueBlob values[]; +} EnumBlob; + +typedef struct +{ + guint32 name; + + guint deprecated : 1; + guint readable : 1; + guint writable : 1; + guint construct : 1; + guint construct_only : 1; + guint reserved :27; + + SimpleTypeBlob type; + +} PropertyBlob; + +typedef struct +{ + guint deprecated : 1; + guint run_first : 1; + guint run_last : 1; + guint run_cleanup : 1; + guint no_recurse : 1; + guint detailed : 1; + guint action : 1; + guint no_hooks : 1; + guint has_class_closure : 1; + guint true_stops_emit : 1; + guint reserved : 6; + + guint16 class_closure; + + guint32 name; + + guint32 signature; +} SignalBlob; + +typedef struct +{ + guint32 name; + + guint must_chain_up : 1; + guint must_be_implemented : 1; + guint must_not_be_implemented : 1; + guint class_closure : 1; + guint reserved :12; + guint16 signal; + + guint16 struct_offset; + guint16 reserved2; + guint32 signature; +} VFuncBlob; + +typedef struct +{ + guint16 blob_type; /* 7 */ + guint deprecated : 1; + guint reserved :15; + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + + guint16 parent; + + guint16 n_interfaces; + guint16 n_fields; + guint16 n_properties; + guint16 n_methods; + guint16 n_signals; + guint16 n_vfuncs; + guint16 n_constants; + + guint16 interfaces[]; + +#if 0 + /* variable-length parts of the blob */ + FieldBlob fields[]; + PropertyBlob properties[]; + FunctionBlob methods[]; + SignalBlob signals[]; + VFuncBlob vfuncs[]; + ConstantBlob constants[]; +#endif +} ObjectBlob; + +typedef struct +{ + guint16 blob_type; + guint deprecated : 1; + guint reserved :15; + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + + guint16 n_prerequisites; + guint16 n_properties; + guint16 n_methods; + guint16 n_signals; + guint16 n_vfuncs; + guint16 n_constants; + + guint16 prerequisites[]; + +#if 0 + /* variable-length parts of the blob */ + PropertyBlob properties[]; + FunctionBlob methods[]; + SignalBlob signals[]; + VFuncBlob vfuncs[]; + ConstantBlob constants[]; +#endif +} InterfaceBlob; + + +typedef struct +{ + guint16 blob_type; + guint deprecated : 1; + guint reserved :15; + guint32 name; + + SimpleTypeBlob type; + + guint32 size; + guint32 offset; +} ConstantBlob; + +typedef struct +{ + guint32 offset; + guint32 name; + guint32 value; +} AnnotationBlob; + + +struct _GMetadata { + guchar *data; + gsize len; + gboolean owns_memory; + GMappedFile *mfile; + GModule *module; +}; + +DirEntry *g_metadata_get_dir_entry (GMetadata *metadata, + guint16 index); + +void g_metadata_check_sanity (void); + +#define g_metadata_get_string(metadata,offset) ((const gchar*)&(metadata->data)[(offset)]) + + +typedef enum +{ + G_METADATA_ERROR_INVALID, + G_METADATA_ERROR_INVALID_HEADER, + G_METADATA_ERROR_INVALID_DIRECTORY, + G_METADATA_ERROR_INVALID_ENTRY, + G_METADATA_ERROR_INVALID_BLOB +} GMetadataError; + +#define G_METADATA_ERROR (g_metadata_error_quark ()) + +GQuark g_metadata_error_quark (void); + +gboolean g_metadata_validate (GMetadata *metadata, + GError **error); + + +G_END_DECLS + +#endif /* __G_METADATA_H__ */ +