diff options
Diffstat (limited to 'girepository')
-rw-r--r-- | girepository/ginfo.c | 143 | ||||
-rw-r--r-- | girepository/girepository.h | 14 | ||||
-rw-r--r-- | girepository/girmodule.c | 88 | ||||
-rw-r--r-- | girepository/girnode.c | 38 | ||||
-rw-r--r-- | girepository/girnode.h | 7 | ||||
-rw-r--r-- | girepository/girparser.c | 52 | ||||
-rw-r--r-- | girepository/gtypelib.c | 22 | ||||
-rw-r--r-- | girepository/gtypelib.h | 31 |
8 files changed, 324 insertions, 71 deletions
diff --git a/girepository/ginfo.c b/girepository/ginfo.c index 1c34ee2..fcc5f09 100644 --- a/girepository/ginfo.c +++ b/girepository/ginfo.c @@ -1,6 +1,7 @@ /* GObject introspection: Repository implementation * * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -402,65 +403,131 @@ g_base_info_is_deprecated (GIBaseInfo *info) return FALSE; } +/** + * g_base_info_get_attribute: + * @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) +{ + GIAttributeIter iter = { 0, }; + gchar *curname, *curvalue; + while (g_base_info_iterate_attributes (info, &iter, &curname, &curvalue)) + { + if (strcmp (name, curname) == 0) + return (const gchar*) curvalue; + } + + return NULL; +} + static int -cmp_annotation (const void *av, - const void *bv) +cmp_attribute (const void *av, + const void *bv) { - const AnnotationBlob *a = av; - const AnnotationBlob *b = bv; + const AttributeBlob *a = av; + const AttributeBlob *b = bv; - if (b->offset < a->offset) + if (a->offset < b->offset) return -1; - - if (b->offset > a->offset) + else if (a->offset == b->offset) + return 0; + else return 1; - - return 0; } -const gchar * -g_base_info_get_annotation (GIBaseInfo *info, - const gchar *name) +static AttributeBlob * +find_first_attribute (GIBaseInfo *info) { GIBaseInfo *base = (GIBaseInfo *)info; Header *header = (Header *)base->typelib->data; - AnnotationBlob blob, *first, *after, *res, *next; - const gchar *rname; + AttributeBlob blob, *first, *res, *previous; blob.offset = base->offset; - first = (AnnotationBlob *) &base->typelib->data[header->annotations]; - after = (AnnotationBlob *) &base->typelib->data[header->annotations + - header->n_annotations * header->annotation_blob_size]; + first = (AttributeBlob *) &base->typelib->data[header->attributes]; + + res = bsearch (&blob, first, header->n_attributes, + header->attribute_blob_size, cmp_attribute); - res = bsearch (&blob, first, header->n_annotations, - header->annotation_blob_size, cmp_annotation); - if (res == NULL) return NULL; - next = res; - do + previous = res - 1; + while (previous >= first && previous->offset == base->offset) { - res = next; - next = res -= header->annotation_blob_size; + res = previous; + previous = res - 1; } - while (next >= first && next->offset == base->offset); - - next = res; - do - { - res = next; - - rname = g_typelib_get_string (base->typelib, res->name); - if (strcmp (name, rname) == 0) - return g_typelib_get_string (base->typelib, res->value); - next = res += header->annotation_blob_size; - } - while (next < after && next->offset == base->offset); + return res; +} - return NULL; +/** + * 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) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + Header *header = (Header *)base->typelib->data; + AttributeBlob *next, *after; + + after = (AttributeBlob *) &base->typelib->data[header->attributes + + header->n_attributes * header->attribute_blob_size]; + + if (iter->data != NULL) + next = (AttributeBlob *) iter->data; + else + next = find_first_attribute (info); + + 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 * diff --git a/girepository/girepository.h b/girepository/girepository.h index 61a9116..4059adc 100644 --- a/girepository/girepository.h +++ b/girepository/girepository.h @@ -1,6 +1,7 @@ /* GObject introspection: Repository * * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -179,14 +180,25 @@ typedef enum /* GIBaseInfo */ +typedef struct { + gpointer data; + gpointer data2; + gpointer data3; + gpointer data4; +} GIAttributeIter; + 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 * g_base_info_get_attribute (GIBaseInfo *info, 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); GTypelib * g_base_info_get_typelib (GIBaseInfo *info); diff --git a/girepository/girmodule.c b/girepository/girmodule.c index 5abd31f..96ee9ce 100644 --- a/girepository/girmodule.c +++ b/girepository/girmodule.c @@ -109,6 +109,53 @@ g_ir_module_add_include_module (GIrModule *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 * g_ir_module_build_typelib (GIrModule *module, GList *modules) @@ -126,6 +173,7 @@ g_ir_module_build_typelib (GIrModule *module, guint32 size, offset, offset2, old_offset; GHashTable *strings; GHashTable *types; + GList *offset_ordered_nodes; char *dependencies; guchar *data; @@ -158,6 +206,7 @@ g_ir_module_build_typelib (GIrModule *module, _g_irnode_init_stats (); strings = 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); 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; 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 */ @@ -195,8 +248,8 @@ g_ir_module_build_typelib (GIrModule *module, header->reserved = 0; header->n_entries = n_entries; header->n_local_entries = n_local_entries; - header->n_annotations = 0; - header->annotations = 0; /* filled in later */ + header->n_attributes = 0; + header->attributes = 0; /* filled in later */ if (dependencies != NULL) header->dependencies = write_string (dependencies, strings, data, &header_size); else @@ -219,7 +272,7 @@ g_ir_module_build_typelib (GIrModule *module, header->value_blob_size = sizeof (ValueBlob); header->constant_blob_size = sizeof (ConstantBlob); 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->enum_blob_size = sizeof (EnumBlob); 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 */ if (i == n_entries) { + GList *link; g_message ("Found implicit cross references, starting over"); g_hash_table_destroy (strings); 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; g_free (data); @@ -282,9 +342,14 @@ g_ir_module_build_typelib (GIrModule *module, build.modules = modules; build.strings = strings; build.types = types; + build.offset_ordered_nodes = offset_ordered_nodes; + build.n_attributes = header->n_attributes; build.data = data; 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)) 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++; } + 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 (); - 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); @@ -305,6 +384,7 @@ g_ir_module_build_typelib (GIrModule *module, g_hash_table_destroy (strings); g_hash_table_destroy (types); + g_list_free (offset_ordered_nodes); return typelib; } diff --git a/girepository/girnode.c b/girepository/girnode.c index fb96d8d..22c0aee 100644 --- a/girepository/girnode.c +++ b/girepository/girnode.c @@ -1,6 +1,7 @@ /* GObject introspection: Typelib creation * * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * 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->offset = 0; + node->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); return node; } @@ -400,6 +404,8 @@ g_ir_node_free (GIrNode *node) break; } + g_hash_table_destroy (node->attributes); + g_free (node); } @@ -540,6 +546,18 @@ g_ir_node_get_size (GIrNode *node) 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 */ static guint32 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); } +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 g_ir_node_cmp (GIrNode *node, GIrNode *other) @@ -1364,6 +1390,15 @@ g_ir_node_build_typelib (GIrNode *node, 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) { case G_IR_NODE_TYPE: @@ -2232,7 +2267,8 @@ g_ir_node_build_typelib (GIrNode *node, old_offset, *offset, old_offset2, *offset2); 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 diff --git a/girepository/girnode.h b/girepository/girnode.h index 45c2bb0..2a1f6b2 100644 --- a/girepository/girnode.h +++ b/girepository/girnode.h @@ -51,6 +51,8 @@ struct _GIrTypelibBuild { GList *modules; GHashTable *strings; GHashTable *types; + GList *offset_ordered_nodes; + guint32 n_attributes; guchar *data; }; @@ -82,6 +84,10 @@ struct _GIrNode { GIrNodeTypeId type; gchar *name; + + guint32 offset; /* Assigned as we build the typelib */ + + GHashTable *attributes; }; struct _GIrNodeXRef @@ -349,6 +355,7 @@ GIrNode * g_ir_node_new (GIrNodeTypeId type); void g_ir_node_free (GIrNode *node); guint32 g_ir_node_get_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, GIrNode *parent, GIrTypelibBuild *build, diff --git a/girepository/girparser.c b/girepository/girparser.c index e08b3fc..006ed3b 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -68,6 +68,7 @@ typedef enum STATE_INTERFACE_CONSTANT, STATE_ALIAS, STATE_TYPE, + STATE_ATTRIBUTE, STATE_UNKNOWN } ParseState; @@ -1865,6 +1866,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 start_return_value (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, @@ -2383,6 +2422,10 @@ start_element_handler (GMarkupParseContext *context, attribute_names, attribute_values, ctx, error)) goto out; + else if (start_attribute (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; break; case 'b': if (start_enum (context, element_name, @@ -2662,7 +2705,7 @@ start_element_handler (GMarkupParseContext *context, ctx->unknown_depth += 1; } - out: ; + out: if (*error) { g_markup_parse_context_get_position (context, &line_number, &char_number); @@ -3027,6 +3070,13 @@ end_element_handler (GMarkupParseContext *context, end_type (ctx); break; } + case STATE_ATTRIBUTE: + if (strcmp ("attribute", element_name) == 0) + { + state_switch (ctx, ctx->prev_state); + } + break; + case STATE_UNKNOWN: ctx->unknown_depth -= 1; if (ctx->unknown_depth == 0) diff --git a/girepository/gtypelib.c b/girepository/gtypelib.c index 6ff00bf..a578c67 100644 --- a/girepository/gtypelib.c +++ b/girepository/gtypelib.c @@ -185,7 +185,7 @@ g_typelib_check_sanity (void) CHECK_SIZE (ObjectBlob, 44); CHECK_SIZE (InterfaceBlob, 40); CHECK_SIZE (ConstantBlob, 24); - CHECK_SIZE (AnnotationBlob, 12); + CHECK_SIZE (AttributeBlob, 12); CHECK_SIZE (UnionBlob, 40); #undef CHECK_SIZE @@ -334,7 +334,7 @@ validate_header (ValidateContext *ctx, header->value_blob_size != sizeof (ValueBlob) || header->constant_blob_size != sizeof (ConstantBlob) || 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->enum_blob_size != sizeof (EnumBlob) || header->struct_blob_size != sizeof (StructBlob) || @@ -358,21 +358,21 @@ validate_header (ValidateContext *ctx, return FALSE; } - if (!is_aligned (header->annotations)) + if (!is_aligned (header->attributes)) { g_set_error (error, G_TYPELIB_ERROR, G_TYPELIB_ERROR_INVALID_HEADER, - "Misaligned annotations"); + "Misaligned attributes"); return FALSE; } - if (header->annotations == 0 && header->n_annotations > 0) + if (header->attributes == 0 && header->n_attributes > 0) { g_set_error (error, G_TYPELIB_ERROR, G_TYPELIB_ERROR_INVALID_HEADER, - "Wrong number of annotations"); + "Wrong number of attributes"); return FALSE; } @@ -1860,13 +1860,13 @@ validate_directory (ValidateContext *ctx, } static gboolean -validate_annotations (ValidateContext *ctx, - GError **error) +validate_attributes (ValidateContext *ctx, + GError **error) { GTypelib *typelib = ctx->typelib; 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_TYPELIB_ERROR, @@ -1926,9 +1926,9 @@ g_typelib_validate (GTypelib *typelib, 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; } diff --git a/girepository/gtypelib.h b/girepository/gtypelib.h index 7a2838f..db5fe11 100644 --- a/girepository/gtypelib.h +++ b/girepository/gtypelib.h @@ -52,14 +52,15 @@ G_BEGIN_DECLS * * The typelib has the following general format. * - * typelib ::= header, directory, blobs, annotations + * typelib ::= header, directory, blobs, attributes, attributedata * * directory ::= list of entries * * entry ::= blob type, name, namespace, offset * blob ::= function|callback|struct|boxed|enum|flags|object|interface|constant|errordomain|union - * annotations ::= list of annotations, sorted by offset - * annotation ::= offset, key, value + * attributes ::= list of attributes, sorted by offset + * attribute ::= offset, key, value + * attributedata ::= string data for attributes * * Details * @@ -189,8 +190,8 @@ typedef enum { * @n_local_entries: The number of entries referring to blobs in this typelib. The * local entries must occur before the unresolved entries. * @directory: Offset of the directory in the typelib. - * @n_annotations: Number of annotation blocks - * @annotations: Offset of the list of annotations in the typelib. + * @n_attributes: Number of attribute blocks + * @attributes: Offset of the list of attributes in the typelib. * @dependencies: Offset of a single string, which is the list of * dependencies, separated by the '|' character. The * dependencies are required in order to avoid having programs @@ -212,7 +213,7 @@ typedef enum { * @property_blob_size: See above. * @field_blob_size: See above. * @value_blob_size: See above. - * @annotation_blob_size: See above. + * @attribute_blob_size: See above. * @constant_blob_size: See above. * @object_blob_size: See above. * @union_blob_size: See above. @@ -237,8 +238,8 @@ typedef struct { guint16 n_entries; guint16 n_local_entries; guint32 directory; - guint32 n_annotations; - guint32 annotations; + guint32 n_attributes; + guint32 attributes; guint32 dependencies; @@ -256,7 +257,7 @@ typedef struct { guint16 property_blob_size; guint16 field_blob_size; guint16 value_blob_size; - guint16 annotation_blob_size; + guint16 attribute_blob_size; guint16 constant_blob_size; guint16 error_domain_blob_size; @@ -1000,18 +1001,18 @@ typedef struct { } ConstantBlob; /** - * AnnotationBlob: - * @offset: The offset of the typelib entry to which this annotation refers. - * Annotations are kept sorted by offset, so that the annotations + * AttributeBlob: + * @offset: The offset of the typelib entry to which this attribute refers. + * Attributes are kept sorted by offset, so that the attributes * of an entry can be found by a binary search. - * @name: The name of the annotation, a string. - * @value: The value of the annotation (also a string) + * @name: The name of the attribute, a string. + * @value: The value of the attribute (also a string) */ typedef struct { guint32 offset; guint32 name; guint32 value; -} AnnotationBlob; +} AttributeBlob; struct _GTypelib { guchar *data; |