mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-27 07:56:14 +01:00
Bug 571548 - Generic attributes
We now support an extensible mechanism where arbitrary key-value pairs may be associated with almost all items, including objects, methods, and properties. These attributes appear in both the .gir and the .typelib.
This commit is contained in:
parent
86587133cd
commit
cd845500a5
143
ginfo.c
143
ginfo.c
@ -1,6 +1,7 @@
|
|||||||
/* GObject introspection: Repository implementation
|
/* GObject introspection: Repository implementation
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005 Matthias Clasen
|
* Copyright (C) 2005 Matthias Clasen
|
||||||
|
* Copyright (C) 2008,2009 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -402,65 +403,131 @@ g_base_info_is_deprecated (GIBaseInfo *info)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/**
|
||||||
cmp_annotation (const void *av,
|
* g_base_info_get_attribute:
|
||||||
const void *bv)
|
* @info: A #GIBaseInfo
|
||||||
|
* @name: A freeform string naming an attribute
|
||||||
|
*
|
||||||
|
* Retrieve an arbitrary attribute associated with this node.
|
||||||
|
*
|
||||||
|
* Return value: The value of the attribute, or %NULL if no such attribute exists
|
||||||
|
*/
|
||||||
|
const gchar *
|
||||||
|
g_base_info_get_attribute (GIBaseInfo *info,
|
||||||
|
const gchar *name)
|
||||||
{
|
{
|
||||||
const AnnotationBlob *a = av;
|
GIAttributeIter iter = { 0, };
|
||||||
const AnnotationBlob *b = bv;
|
gchar *curname, *curvalue;
|
||||||
|
while (g_base_info_iterate_attributes (info, &iter, &curname, &curvalue))
|
||||||
if (b->offset < a->offset)
|
{
|
||||||
return -1;
|
if (strcmp (name, curname) == 0)
|
||||||
|
return (const gchar*) curvalue;
|
||||||
if (b->offset > a->offset)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const gchar *
|
return NULL;
|
||||||
g_base_info_get_annotation (GIBaseInfo *info,
|
}
|
||||||
const gchar *name)
|
|
||||||
|
static int
|
||||||
|
cmp_attribute (const void *av,
|
||||||
|
const void *bv)
|
||||||
|
{
|
||||||
|
const AttributeBlob *a = av;
|
||||||
|
const AttributeBlob *b = bv;
|
||||||
|
|
||||||
|
if (a->offset < b->offset)
|
||||||
|
return -1;
|
||||||
|
else if (a->offset == b->offset)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AttributeBlob *
|
||||||
|
find_first_attribute (GIBaseInfo *info)
|
||||||
{
|
{
|
||||||
GIBaseInfo *base = (GIBaseInfo *)info;
|
GIBaseInfo *base = (GIBaseInfo *)info;
|
||||||
Header *header = (Header *)base->typelib->data;
|
Header *header = (Header *)base->typelib->data;
|
||||||
AnnotationBlob blob, *first, *after, *res, *next;
|
AttributeBlob blob, *first, *res, *previous;
|
||||||
const gchar *rname;
|
|
||||||
|
|
||||||
blob.offset = base->offset;
|
blob.offset = base->offset;
|
||||||
|
|
||||||
first = (AnnotationBlob *) &base->typelib->data[header->annotations];
|
first = (AttributeBlob *) &base->typelib->data[header->attributes];
|
||||||
after = (AnnotationBlob *) &base->typelib->data[header->annotations +
|
|
||||||
header->n_annotations * header->annotation_blob_size];
|
|
||||||
|
|
||||||
res = bsearch (&blob, first, header->n_annotations,
|
res = bsearch (&blob, first, header->n_attributes,
|
||||||
header->annotation_blob_size, cmp_annotation);
|
header->attribute_blob_size, cmp_attribute);
|
||||||
|
|
||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
next = res;
|
previous = res - 1;
|
||||||
do
|
while (previous >= first && previous->offset == base->offset)
|
||||||
{
|
{
|
||||||
res = next;
|
res = previous;
|
||||||
next = res -= header->annotation_blob_size;
|
previous = res - 1;
|
||||||
}
|
}
|
||||||
while (next >= first && next->offset == base->offset);
|
|
||||||
|
|
||||||
next = res;
|
return res;
|
||||||
do
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_base_info_iterate_attributes:
|
||||||
|
* @info: A #GIBaseInfo
|
||||||
|
* @iter: A #GIAttributeIter structure, must be initialized; see below
|
||||||
|
* @name: (out) (transfer none): Returned name, must not be freed
|
||||||
|
* @value: (out) (transfer none): Returned name, must not be freed
|
||||||
|
*
|
||||||
|
* Iterate over all attributes associated with this node. The iterator
|
||||||
|
* structure is typically stack allocated, and must have its first
|
||||||
|
* member initialized to %NULL.
|
||||||
|
*
|
||||||
|
* Both the @name and @value should be treated as constants
|
||||||
|
* and must not be freed.
|
||||||
|
*
|
||||||
|
* <example>
|
||||||
|
* <title>Iterating over attributes</title>
|
||||||
|
* <programlisting>
|
||||||
|
* void
|
||||||
|
* print_attributes (GIBaseInfo *info)
|
||||||
|
* {
|
||||||
|
* GIAttributeIter iter = { 0, };
|
||||||
|
* char *name;
|
||||||
|
* char *value;
|
||||||
|
* while (g_base_info_iterate_attributes (info, &iter, &name, &value))
|
||||||
|
* {
|
||||||
|
* g_print ("attribute name: %s value: %s", name, value);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </programlisting>
|
||||||
|
* </example>
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if there are more attributes, %FALSE otherwise
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
g_base_info_iterate_attributes (GIBaseInfo *info,
|
||||||
|
GIAttributeIter *iter,
|
||||||
|
gchar **name,
|
||||||
|
gchar **value)
|
||||||
{
|
{
|
||||||
res = next;
|
GIBaseInfo *base = (GIBaseInfo *)info;
|
||||||
|
Header *header = (Header *)base->typelib->data;
|
||||||
|
AttributeBlob *next, *after;
|
||||||
|
|
||||||
rname = g_typelib_get_string (base->typelib, res->name);
|
after = (AttributeBlob *) &base->typelib->data[header->attributes +
|
||||||
if (strcmp (name, rname) == 0)
|
header->n_attributes * header->attribute_blob_size];
|
||||||
return g_typelib_get_string (base->typelib, res->value);
|
|
||||||
|
|
||||||
next = res += header->annotation_blob_size;
|
if (iter->data != NULL)
|
||||||
}
|
next = (AttributeBlob *) iter->data;
|
||||||
while (next < after && next->offset == base->offset);
|
else
|
||||||
|
next = find_first_attribute (info);
|
||||||
|
|
||||||
return NULL;
|
if (next == NULL || next->offset != base->offset || next >= after)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
*name = (gchar*) g_typelib_get_string (base->typelib, next->name);
|
||||||
|
*value = (gchar*) g_typelib_get_string (base->typelib, next->value);
|
||||||
|
iter->data = next + 1;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
GIBaseInfo *
|
GIBaseInfo *
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* GObject introspection: Repository
|
/* GObject introspection: Repository
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005 Matthias Clasen
|
* Copyright (C) 2005 Matthias Clasen
|
||||||
|
* Copyright (C) 2008,2009 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -179,14 +180,25 @@ typedef enum
|
|||||||
|
|
||||||
/* GIBaseInfo */
|
/* GIBaseInfo */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gpointer data;
|
||||||
|
gpointer data2;
|
||||||
|
gpointer data3;
|
||||||
|
gpointer data4;
|
||||||
|
} GIAttributeIter;
|
||||||
|
|
||||||
GIBaseInfo * g_base_info_ref (GIBaseInfo *info);
|
GIBaseInfo * g_base_info_ref (GIBaseInfo *info);
|
||||||
void g_base_info_unref (GIBaseInfo *info);
|
void g_base_info_unref (GIBaseInfo *info);
|
||||||
GIInfoType g_base_info_get_type (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_name (GIBaseInfo *info);
|
||||||
const gchar * g_base_info_get_namespace (GIBaseInfo *info);
|
const gchar * g_base_info_get_namespace (GIBaseInfo *info);
|
||||||
gboolean g_base_info_is_deprecated (GIBaseInfo *info);
|
gboolean g_base_info_is_deprecated (GIBaseInfo *info);
|
||||||
const gchar * g_base_info_get_annotation (GIBaseInfo *info,
|
const gchar * g_base_info_get_attribute (GIBaseInfo *info,
|
||||||
const gchar *name);
|
const gchar *name);
|
||||||
|
gboolean g_base_info_iterate_attributes (GIBaseInfo *info,
|
||||||
|
GIAttributeIter *iterator,
|
||||||
|
char **name,
|
||||||
|
char **value);
|
||||||
GIBaseInfo * g_base_info_get_container (GIBaseInfo *info);
|
GIBaseInfo * g_base_info_get_container (GIBaseInfo *info);
|
||||||
GTypelib * g_base_info_get_typelib (GIBaseInfo *info);
|
GTypelib * g_base_info_get_typelib (GIBaseInfo *info);
|
||||||
|
|
||||||
|
88
girmodule.c
88
girmodule.c
@ -109,6 +109,53 @@ g_ir_module_add_include_module (GIrModule *module,
|
|||||||
module);
|
module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AttributeWriteData
|
||||||
|
{
|
||||||
|
guint count;
|
||||||
|
guchar *databuf;
|
||||||
|
GIrNode *node;
|
||||||
|
GHashTable *strings;
|
||||||
|
guint32 *offset;
|
||||||
|
guint32 *offset2;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_attribute (gpointer key, gpointer value, gpointer datap)
|
||||||
|
{
|
||||||
|
struct AttributeWriteData *data = datap;
|
||||||
|
guint32 old_offset = *(data->offset);
|
||||||
|
AttributeBlob *blob = (AttributeBlob*)&(data->databuf[old_offset]);
|
||||||
|
|
||||||
|
*(data->offset) += sizeof (AttributeBlob);
|
||||||
|
|
||||||
|
blob->offset = data->node->offset;
|
||||||
|
blob->name = write_string ((const char*) key, data->strings, data->databuf, data->offset2);
|
||||||
|
blob->value = write_string ((const char*) value, data->strings, data->databuf, data->offset2);
|
||||||
|
|
||||||
|
data->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
write_attributes (GIrModule *module,
|
||||||
|
GIrNode *node,
|
||||||
|
GHashTable *strings,
|
||||||
|
guchar *data,
|
||||||
|
guint32 *offset,
|
||||||
|
guint32 *offset2)
|
||||||
|
{
|
||||||
|
struct AttributeWriteData wdata;
|
||||||
|
wdata.count = 0;
|
||||||
|
wdata.databuf = data;
|
||||||
|
wdata.node = node;
|
||||||
|
wdata.offset = offset;
|
||||||
|
wdata.offset2 = offset2;
|
||||||
|
wdata.strings = strings;
|
||||||
|
|
||||||
|
g_hash_table_foreach (node->attributes, write_attribute, &wdata);
|
||||||
|
|
||||||
|
return wdata.count;
|
||||||
|
}
|
||||||
|
|
||||||
GTypelib *
|
GTypelib *
|
||||||
g_ir_module_build_typelib (GIrModule *module,
|
g_ir_module_build_typelib (GIrModule *module,
|
||||||
GList *modules)
|
GList *modules)
|
||||||
@ -126,6 +173,7 @@ g_ir_module_build_typelib (GIrModule *module,
|
|||||||
guint32 size, offset, offset2, old_offset;
|
guint32 size, offset, offset2, old_offset;
|
||||||
GHashTable *strings;
|
GHashTable *strings;
|
||||||
GHashTable *types;
|
GHashTable *types;
|
||||||
|
GList *offset_ordered_nodes;
|
||||||
char *dependencies;
|
char *dependencies;
|
||||||
guchar *data;
|
guchar *data;
|
||||||
|
|
||||||
@ -158,6 +206,7 @@ g_ir_module_build_typelib (GIrModule *module,
|
|||||||
_g_irnode_init_stats ();
|
_g_irnode_init_stats ();
|
||||||
strings = g_hash_table_new (g_str_hash, g_str_equal);
|
strings = g_hash_table_new (g_str_hash, g_str_equal);
|
||||||
types = g_hash_table_new (g_str_hash, g_str_equal);
|
types = g_hash_table_new (g_str_hash, g_str_equal);
|
||||||
|
offset_ordered_nodes = NULL;
|
||||||
n_entries = g_list_length (module->entries);
|
n_entries = g_list_length (module->entries);
|
||||||
|
|
||||||
g_message ("%d entries (%d local), %d dependencies\n", n_entries, n_local_entries,
|
g_message ("%d entries (%d local), %d dependencies\n", n_entries, n_local_entries,
|
||||||
@ -173,6 +222,10 @@ g_ir_module_build_typelib (GIrModule *module,
|
|||||||
GIrNode *node = e->data;
|
GIrNode *node = e->data;
|
||||||
|
|
||||||
size += g_ir_node_get_full_size (node);
|
size += g_ir_node_get_full_size (node);
|
||||||
|
size += g_ir_node_get_attribute_size (node);
|
||||||
|
|
||||||
|
/* Also reset the offset here */
|
||||||
|
node->offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust size for strings allocated in header below specially */
|
/* Adjust size for strings allocated in header below specially */
|
||||||
@ -195,8 +248,8 @@ g_ir_module_build_typelib (GIrModule *module,
|
|||||||
header->reserved = 0;
|
header->reserved = 0;
|
||||||
header->n_entries = n_entries;
|
header->n_entries = n_entries;
|
||||||
header->n_local_entries = n_local_entries;
|
header->n_local_entries = n_local_entries;
|
||||||
header->n_annotations = 0;
|
header->n_attributes = 0;
|
||||||
header->annotations = 0; /* filled in later */
|
header->attributes = 0; /* filled in later */
|
||||||
if (dependencies != NULL)
|
if (dependencies != NULL)
|
||||||
header->dependencies = write_string (dependencies, strings, data, &header_size);
|
header->dependencies = write_string (dependencies, strings, data, &header_size);
|
||||||
else
|
else
|
||||||
@ -219,7 +272,7 @@ g_ir_module_build_typelib (GIrModule *module,
|
|||||||
header->value_blob_size = sizeof (ValueBlob);
|
header->value_blob_size = sizeof (ValueBlob);
|
||||||
header->constant_blob_size = sizeof (ConstantBlob);
|
header->constant_blob_size = sizeof (ConstantBlob);
|
||||||
header->error_domain_blob_size = sizeof (ErrorDomainBlob);
|
header->error_domain_blob_size = sizeof (ErrorDomainBlob);
|
||||||
header->annotation_blob_size = sizeof (AnnotationBlob);
|
header->attribute_blob_size = sizeof (AttributeBlob);
|
||||||
header->signature_blob_size = sizeof (SignatureBlob);
|
header->signature_blob_size = sizeof (SignatureBlob);
|
||||||
header->enum_blob_size = sizeof (EnumBlob);
|
header->enum_blob_size = sizeof (EnumBlob);
|
||||||
header->struct_blob_size = sizeof (StructBlob);
|
header->struct_blob_size = sizeof (StructBlob);
|
||||||
@ -245,10 +298,17 @@ g_ir_module_build_typelib (GIrModule *module,
|
|||||||
/* we picked up implicit xref nodes, start over */
|
/* we picked up implicit xref nodes, start over */
|
||||||
if (i == n_entries)
|
if (i == n_entries)
|
||||||
{
|
{
|
||||||
|
GList *link;
|
||||||
g_message ("Found implicit cross references, starting over");
|
g_message ("Found implicit cross references, starting over");
|
||||||
|
|
||||||
g_hash_table_destroy (strings);
|
g_hash_table_destroy (strings);
|
||||||
g_hash_table_destroy (types);
|
g_hash_table_destroy (types);
|
||||||
|
|
||||||
|
/* Reset the cached offsets */
|
||||||
|
for (link = offset_ordered_nodes; link; link = link->next)
|
||||||
|
((GIrNode *) link->data)->offset = 0;
|
||||||
|
|
||||||
|
g_list_free (offset_ordered_nodes);
|
||||||
strings = NULL;
|
strings = NULL;
|
||||||
|
|
||||||
g_free (data);
|
g_free (data);
|
||||||
@ -282,9 +342,14 @@ g_ir_module_build_typelib (GIrModule *module,
|
|||||||
build.modules = modules;
|
build.modules = modules;
|
||||||
build.strings = strings;
|
build.strings = strings;
|
||||||
build.types = types;
|
build.types = types;
|
||||||
|
build.offset_ordered_nodes = offset_ordered_nodes;
|
||||||
|
build.n_attributes = header->n_attributes;
|
||||||
build.data = data;
|
build.data = data;
|
||||||
g_ir_node_build_typelib (node, NULL, &build, &offset, &offset2);
|
g_ir_node_build_typelib (node, NULL, &build, &offset, &offset2);
|
||||||
|
|
||||||
|
offset_ordered_nodes = build.offset_ordered_nodes;
|
||||||
|
header->n_attributes = build.n_attributes;
|
||||||
|
|
||||||
if (offset2 > old_offset + g_ir_node_get_full_size (node))
|
if (offset2 > old_offset + g_ir_node_get_full_size (node))
|
||||||
g_error ("left a hole of %d bytes\n", offset2 - old_offset - g_ir_node_get_full_size (node));
|
g_error ("left a hole of %d bytes\n", offset2 - old_offset - g_ir_node_get_full_size (node));
|
||||||
}
|
}
|
||||||
@ -292,9 +357,23 @@ g_ir_module_build_typelib (GIrModule *module,
|
|||||||
entry++;
|
entry++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offset_ordered_nodes = g_list_reverse (offset_ordered_nodes);
|
||||||
|
|
||||||
|
g_message ("header: %d entries, %d attributes", header->n_entries, header->n_attributes);
|
||||||
|
|
||||||
_g_irnode_dump_stats ();
|
_g_irnode_dump_stats ();
|
||||||
|
|
||||||
header->annotations = offset2;
|
/* Write attributes after the blobs */
|
||||||
|
offset = offset2;
|
||||||
|
header->attributes = offset;
|
||||||
|
offset2 = offset + header->n_attributes * header->attribute_blob_size;
|
||||||
|
|
||||||
|
for (e = offset_ordered_nodes; e; e = e->next)
|
||||||
|
{
|
||||||
|
GIrNode *node = e->data;
|
||||||
|
|
||||||
|
write_attributes (module, node, strings, data, &offset, &offset2);
|
||||||
|
}
|
||||||
|
|
||||||
g_message ("reallocating to %d bytes", offset2);
|
g_message ("reallocating to %d bytes", offset2);
|
||||||
|
|
||||||
@ -305,6 +384,7 @@ g_ir_module_build_typelib (GIrModule *module,
|
|||||||
|
|
||||||
g_hash_table_destroy (strings);
|
g_hash_table_destroy (strings);
|
||||||
g_hash_table_destroy (types);
|
g_hash_table_destroy (types);
|
||||||
|
g_list_free (offset_ordered_nodes);
|
||||||
|
|
||||||
return typelib;
|
return typelib;
|
||||||
}
|
}
|
||||||
|
38
girnode.c
38
girnode.c
@ -1,6 +1,7 @@
|
|||||||
/* GObject introspection: Typelib creation
|
/* GObject introspection: Typelib creation
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005 Matthias Clasen
|
* Copyright (C) 2005 Matthias Clasen
|
||||||
|
* Copyright (C) 2008,2009 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -184,6 +185,9 @@ g_ir_node_new (GIrNodeTypeId type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
node->type = type;
|
node->type = type;
|
||||||
|
node->offset = 0;
|
||||||
|
node->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
|
g_free, g_free);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -400,6 +404,8 @@ g_ir_node_free (GIrNode *node)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_hash_table_destroy (node->attributes);
|
||||||
|
|
||||||
g_free (node);
|
g_free (node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,6 +546,18 @@ g_ir_node_get_size (GIrNode *node)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_attribute_size (gpointer key, gpointer value, gpointer data)
|
||||||
|
{
|
||||||
|
const gchar *key_str = key;
|
||||||
|
const gchar *value_str = value;
|
||||||
|
gint *size_p = data;
|
||||||
|
|
||||||
|
*size_p += sizeof (AttributeBlob);
|
||||||
|
*size_p += ALIGN_VALUE (strlen (key_str) + 1, 4);
|
||||||
|
*size_p += ALIGN_VALUE (strlen (value_str) + 1, 4);
|
||||||
|
}
|
||||||
|
|
||||||
/* returns the full size of the blob including variable-size parts */
|
/* returns the full size of the blob including variable-size parts */
|
||||||
static guint32
|
static guint32
|
||||||
g_ir_node_get_full_size_internal (GIrNode *parent,
|
g_ir_node_get_full_size_internal (GIrNode *parent,
|
||||||
@ -851,6 +869,14 @@ g_ir_node_get_full_size (GIrNode *node)
|
|||||||
return g_ir_node_get_full_size_internal (NULL, node);
|
return g_ir_node_get_full_size_internal (NULL, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guint32
|
||||||
|
g_ir_node_get_attribute_size (GIrNode *node)
|
||||||
|
{
|
||||||
|
guint32 size = 0;
|
||||||
|
g_hash_table_foreach (node->attributes, add_attribute_size, &size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
g_ir_node_cmp (GIrNode *node,
|
g_ir_node_cmp (GIrNode *node,
|
||||||
GIrNode *other)
|
GIrNode *other)
|
||||||
@ -1364,6 +1390,15 @@ g_ir_node_build_typelib (GIrNode *node,
|
|||||||
|
|
||||||
g_ir_node_compute_offsets (node, module, modules);
|
g_ir_node_compute_offsets (node, module, modules);
|
||||||
|
|
||||||
|
/* We should only be building each node once. If we do a typelib expansion, we also
|
||||||
|
* reset the offset in girmodule.c.
|
||||||
|
*/
|
||||||
|
g_assert (node->offset == 0);
|
||||||
|
node->offset = *offset;
|
||||||
|
build->offset_ordered_nodes = g_list_prepend (build->offset_ordered_nodes, node);
|
||||||
|
|
||||||
|
build->n_attributes += g_hash_table_size (node->attributes);
|
||||||
|
|
||||||
switch (node->type)
|
switch (node->type)
|
||||||
{
|
{
|
||||||
case G_IR_NODE_TYPE:
|
case G_IR_NODE_TYPE:
|
||||||
@ -2232,7 +2267,8 @@ g_ir_node_build_typelib (GIrNode *node,
|
|||||||
old_offset, *offset, old_offset2, *offset2);
|
old_offset, *offset, old_offset2, *offset2);
|
||||||
|
|
||||||
if (*offset2 - old_offset2 + *offset - old_offset > g_ir_node_get_full_size (node))
|
if (*offset2 - old_offset2 + *offset - old_offset > g_ir_node_get_full_size (node))
|
||||||
g_error ("exceeding space reservation !!");
|
g_error ("exceeding space reservation; offset: %d (prev %d) offset2: %d (prev %d) nodesize: %d",
|
||||||
|
*offset, old_offset, *offset2, old_offset2, g_ir_node_get_full_size (node));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if str is already in the pool, return previous location, otherwise write str
|
/* if str is already in the pool, return previous location, otherwise write str
|
||||||
|
@ -51,6 +51,8 @@ struct _GIrTypelibBuild {
|
|||||||
GList *modules;
|
GList *modules;
|
||||||
GHashTable *strings;
|
GHashTable *strings;
|
||||||
GHashTable *types;
|
GHashTable *types;
|
||||||
|
GList *offset_ordered_nodes;
|
||||||
|
guint32 n_attributes;
|
||||||
guchar *data;
|
guchar *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -82,6 +84,10 @@ struct _GIrNode
|
|||||||
{
|
{
|
||||||
GIrNodeTypeId type;
|
GIrNodeTypeId type;
|
||||||
gchar *name;
|
gchar *name;
|
||||||
|
|
||||||
|
guint32 offset; /* Assigned as we build the typelib */
|
||||||
|
|
||||||
|
GHashTable *attributes;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GIrNodeXRef
|
struct _GIrNodeXRef
|
||||||
@ -349,6 +355,7 @@ GIrNode * g_ir_node_new (GIrNodeTypeId type);
|
|||||||
void g_ir_node_free (GIrNode *node);
|
void g_ir_node_free (GIrNode *node);
|
||||||
guint32 g_ir_node_get_size (GIrNode *node);
|
guint32 g_ir_node_get_size (GIrNode *node);
|
||||||
guint32 g_ir_node_get_full_size (GIrNode *node);
|
guint32 g_ir_node_get_full_size (GIrNode *node);
|
||||||
|
guint32 g_ir_node_get_attribute_size (GIrNode *node);
|
||||||
void g_ir_node_build_typelib (GIrNode *node,
|
void g_ir_node_build_typelib (GIrNode *node,
|
||||||
GIrNode *parent,
|
GIrNode *parent,
|
||||||
GIrTypelibBuild *build,
|
GIrTypelibBuild *build,
|
||||||
|
52
girparser.c
52
girparser.c
@ -68,6 +68,7 @@ typedef enum
|
|||||||
STATE_INTERFACE_CONSTANT,
|
STATE_INTERFACE_CONSTANT,
|
||||||
STATE_ALIAS,
|
STATE_ALIAS,
|
||||||
STATE_TYPE,
|
STATE_TYPE,
|
||||||
|
STATE_ATTRIBUTE,
|
||||||
STATE_UNKNOWN
|
STATE_UNKNOWN
|
||||||
} ParseState;
|
} ParseState;
|
||||||
|
|
||||||
@ -1864,6 +1865,44 @@ end_type (ParseContext *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
start_attribute (GMarkupParseContext *context,
|
||||||
|
const gchar *element_name,
|
||||||
|
const gchar **attribute_names,
|
||||||
|
const gchar **attribute_values,
|
||||||
|
ParseContext *ctx,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
const gchar *name;
|
||||||
|
const gchar *value;
|
||||||
|
GIrNode *curnode;
|
||||||
|
|
||||||
|
if (strcmp (element_name, "attribute") != 0 || ctx->node_stack == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
name = find_attribute ("name", attribute_names, attribute_values);
|
||||||
|
value = find_attribute ("value", attribute_names, attribute_values);
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
{
|
||||||
|
MISSING_ATTRIBUTE (context, error, element_name, "name");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (value == NULL)
|
||||||
|
{
|
||||||
|
MISSING_ATTRIBUTE (context, error, element_name, "value");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
state_switch (ctx, STATE_ATTRIBUTE);
|
||||||
|
|
||||||
|
curnode = CURRENT_NODE (ctx);
|
||||||
|
|
||||||
|
g_hash_table_insert (curnode->attributes, g_strdup (name), g_strdup (value));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
start_return_value (GMarkupParseContext *context,
|
start_return_value (GMarkupParseContext *context,
|
||||||
const gchar *element_name,
|
const gchar *element_name,
|
||||||
@ -2383,6 +2422,10 @@ start_element_handler (GMarkupParseContext *context,
|
|||||||
attribute_names, attribute_values,
|
attribute_names, attribute_values,
|
||||||
ctx, error))
|
ctx, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
else if (start_attribute (context, element_name,
|
||||||
|
attribute_names, attribute_values,
|
||||||
|
ctx, error))
|
||||||
|
goto out;
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
if (start_enum (context, element_name,
|
if (start_enum (context, element_name,
|
||||||
@ -2662,7 +2705,7 @@ start_element_handler (GMarkupParseContext *context,
|
|||||||
ctx->unknown_depth += 1;
|
ctx->unknown_depth += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out: ;
|
out:
|
||||||
if (*error)
|
if (*error)
|
||||||
{
|
{
|
||||||
g_markup_parse_context_get_position (context, &line_number, &char_number);
|
g_markup_parse_context_get_position (context, &line_number, &char_number);
|
||||||
@ -3027,6 +3070,13 @@ end_element_handler (GMarkupParseContext *context,
|
|||||||
end_type (ctx);
|
end_type (ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case STATE_ATTRIBUTE:
|
||||||
|
if (strcmp ("attribute", element_name) == 0)
|
||||||
|
{
|
||||||
|
state_switch (ctx, ctx->prev_state);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case STATE_UNKNOWN:
|
case STATE_UNKNOWN:
|
||||||
ctx->unknown_depth -= 1;
|
ctx->unknown_depth -= 1;
|
||||||
if (ctx->unknown_depth == 0)
|
if (ctx->unknown_depth == 0)
|
||||||
|
20
gtypelib.c
20
gtypelib.c
@ -185,7 +185,7 @@ g_typelib_check_sanity (void)
|
|||||||
CHECK_SIZE (ObjectBlob, 44);
|
CHECK_SIZE (ObjectBlob, 44);
|
||||||
CHECK_SIZE (InterfaceBlob, 40);
|
CHECK_SIZE (InterfaceBlob, 40);
|
||||||
CHECK_SIZE (ConstantBlob, 24);
|
CHECK_SIZE (ConstantBlob, 24);
|
||||||
CHECK_SIZE (AnnotationBlob, 12);
|
CHECK_SIZE (AttributeBlob, 12);
|
||||||
CHECK_SIZE (UnionBlob, 40);
|
CHECK_SIZE (UnionBlob, 40);
|
||||||
#undef CHECK_SIZE
|
#undef CHECK_SIZE
|
||||||
|
|
||||||
@ -334,7 +334,7 @@ validate_header (ValidateContext *ctx,
|
|||||||
header->value_blob_size != sizeof (ValueBlob) ||
|
header->value_blob_size != sizeof (ValueBlob) ||
|
||||||
header->constant_blob_size != sizeof (ConstantBlob) ||
|
header->constant_blob_size != sizeof (ConstantBlob) ||
|
||||||
header->error_domain_blob_size != sizeof (ErrorDomainBlob) ||
|
header->error_domain_blob_size != sizeof (ErrorDomainBlob) ||
|
||||||
header->annotation_blob_size != sizeof (AnnotationBlob) ||
|
header->attribute_blob_size != sizeof (AttributeBlob) ||
|
||||||
header->signature_blob_size != sizeof (SignatureBlob) ||
|
header->signature_blob_size != sizeof (SignatureBlob) ||
|
||||||
header->enum_blob_size != sizeof (EnumBlob) ||
|
header->enum_blob_size != sizeof (EnumBlob) ||
|
||||||
header->struct_blob_size != sizeof (StructBlob) ||
|
header->struct_blob_size != sizeof (StructBlob) ||
|
||||||
@ -358,21 +358,21 @@ validate_header (ValidateContext *ctx,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_aligned (header->annotations))
|
if (!is_aligned (header->attributes))
|
||||||
{
|
{
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_TYPELIB_ERROR,
|
G_TYPELIB_ERROR,
|
||||||
G_TYPELIB_ERROR_INVALID_HEADER,
|
G_TYPELIB_ERROR_INVALID_HEADER,
|
||||||
"Misaligned annotations");
|
"Misaligned attributes");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header->annotations == 0 && header->n_annotations > 0)
|
if (header->attributes == 0 && header->n_attributes > 0)
|
||||||
{
|
{
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_TYPELIB_ERROR,
|
G_TYPELIB_ERROR,
|
||||||
G_TYPELIB_ERROR_INVALID_HEADER,
|
G_TYPELIB_ERROR_INVALID_HEADER,
|
||||||
"Wrong number of annotations");
|
"Wrong number of attributes");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1860,13 +1860,13 @@ validate_directory (ValidateContext *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
validate_annotations (ValidateContext *ctx,
|
validate_attributes (ValidateContext *ctx,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GTypelib *typelib = ctx->typelib;
|
GTypelib *typelib = ctx->typelib;
|
||||||
Header *header = (Header *)typelib->data;
|
Header *header = (Header *)typelib->data;
|
||||||
|
|
||||||
if (header->size < header->annotations + header->n_annotations * sizeof (AnnotationBlob))
|
if (header->size < header->attributes + header->n_attributes * sizeof (AttributeBlob))
|
||||||
{
|
{
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_TYPELIB_ERROR,
|
G_TYPELIB_ERROR,
|
||||||
@ -1926,9 +1926,9 @@ g_typelib_validate (GTypelib *typelib,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validate_annotations (&ctx, error))
|
if (!validate_attributes (&ctx, error))
|
||||||
{
|
{
|
||||||
prefix_with_context (error, "annotations", &ctx);
|
prefix_with_context (error, "attributes", &ctx);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
31
gtypelib.h
31
gtypelib.h
@ -52,14 +52,15 @@ G_BEGIN_DECLS
|
|||||||
*
|
*
|
||||||
* The typelib has the following general format.
|
* The typelib has the following general format.
|
||||||
*
|
*
|
||||||
* typelib ::= header, directory, blobs, annotations
|
* typelib ::= header, directory, blobs, attributes, attributedata
|
||||||
*
|
*
|
||||||
* directory ::= list of entries
|
* directory ::= list of entries
|
||||||
*
|
*
|
||||||
* entry ::= blob type, name, namespace, offset
|
* entry ::= blob type, name, namespace, offset
|
||||||
* blob ::= function|callback|struct|boxed|enum|flags|object|interface|constant|errordomain|union
|
* blob ::= function|callback|struct|boxed|enum|flags|object|interface|constant|errordomain|union
|
||||||
* annotations ::= list of annotations, sorted by offset
|
* attributes ::= list of attributes, sorted by offset
|
||||||
* annotation ::= offset, key, value
|
* attribute ::= offset, key, value
|
||||||
|
* attributedata ::= string data for attributes
|
||||||
*
|
*
|
||||||
* Details
|
* Details
|
||||||
*
|
*
|
||||||
@ -189,8 +190,8 @@ typedef enum {
|
|||||||
* @n_local_entries: The number of entries referring to blobs in this typelib. The
|
* @n_local_entries: The number of entries referring to blobs in this typelib. The
|
||||||
* local entries must occur before the unresolved entries.
|
* local entries must occur before the unresolved entries.
|
||||||
* @directory: Offset of the directory in the typelib.
|
* @directory: Offset of the directory in the typelib.
|
||||||
* @n_annotations: Number of annotation blocks
|
* @n_attributes: Number of attribute blocks
|
||||||
* @annotations: Offset of the list of annotations in the typelib.
|
* @attributes: Offset of the list of attributes in the typelib.
|
||||||
* @dependencies: Offset of a single string, which is the list of
|
* @dependencies: Offset of a single string, which is the list of
|
||||||
* dependencies, separated by the '|' character. The
|
* dependencies, separated by the '|' character. The
|
||||||
* dependencies are required in order to avoid having programs
|
* dependencies are required in order to avoid having programs
|
||||||
@ -212,7 +213,7 @@ typedef enum {
|
|||||||
* @property_blob_size: See above.
|
* @property_blob_size: See above.
|
||||||
* @field_blob_size: See above.
|
* @field_blob_size: See above.
|
||||||
* @value_blob_size: See above.
|
* @value_blob_size: See above.
|
||||||
* @annotation_blob_size: See above.
|
* @attribute_blob_size: See above.
|
||||||
* @constant_blob_size: See above.
|
* @constant_blob_size: See above.
|
||||||
* @object_blob_size: See above.
|
* @object_blob_size: See above.
|
||||||
* @union_blob_size: See above.
|
* @union_blob_size: See above.
|
||||||
@ -237,8 +238,8 @@ typedef struct {
|
|||||||
guint16 n_entries;
|
guint16 n_entries;
|
||||||
guint16 n_local_entries;
|
guint16 n_local_entries;
|
||||||
guint32 directory;
|
guint32 directory;
|
||||||
guint32 n_annotations;
|
guint32 n_attributes;
|
||||||
guint32 annotations;
|
guint32 attributes;
|
||||||
|
|
||||||
guint32 dependencies;
|
guint32 dependencies;
|
||||||
|
|
||||||
@ -256,7 +257,7 @@ typedef struct {
|
|||||||
guint16 property_blob_size;
|
guint16 property_blob_size;
|
||||||
guint16 field_blob_size;
|
guint16 field_blob_size;
|
||||||
guint16 value_blob_size;
|
guint16 value_blob_size;
|
||||||
guint16 annotation_blob_size;
|
guint16 attribute_blob_size;
|
||||||
guint16 constant_blob_size;
|
guint16 constant_blob_size;
|
||||||
guint16 error_domain_blob_size;
|
guint16 error_domain_blob_size;
|
||||||
|
|
||||||
@ -1000,18 +1001,18 @@ typedef struct {
|
|||||||
} ConstantBlob;
|
} ConstantBlob;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AnnotationBlob:
|
* AttributeBlob:
|
||||||
* @offset: The offset of the typelib entry to which this annotation refers.
|
* @offset: The offset of the typelib entry to which this attribute refers.
|
||||||
* Annotations are kept sorted by offset, so that the annotations
|
* Attributes are kept sorted by offset, so that the attributes
|
||||||
* of an entry can be found by a binary search.
|
* of an entry can be found by a binary search.
|
||||||
* @name: The name of the annotation, a string.
|
* @name: The name of the attribute, a string.
|
||||||
* @value: The value of the annotation (also a string)
|
* @value: The value of the attribute (also a string)
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
guint32 offset;
|
guint32 offset;
|
||||||
guint32 name;
|
guint32 name;
|
||||||
guint32 value;
|
guint32 value;
|
||||||
} AnnotationBlob;
|
} AttributeBlob;
|
||||||
|
|
||||||
struct _GTypelib {
|
struct _GTypelib {
|
||||||
guchar *data;
|
guchar *data;
|
||||||
|
Loading…
Reference in New Issue
Block a user