From e7bdd4b88d50445e30d97c3f03e35a14cc5ac90a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 15 May 2005 04:30:43 +0000 Subject: [PATCH] Add union.test. 2005-05-15 Matthias Clasen * tests/roundtrips.sh (SIMPLE_TESTS): Add union.test. * tests/union.test: Add a union test. * src/generate.c: Handle unions. * src/girepository.h: * src/ginfo.c: Add GIUnionInfo and functions to access it. * src/gidlnode.c: Handle GIdlNodeUnion nodes. * src/gidlparser.c (start_union): Parse elements. * src/gidlnode.h: Add a GIdlNodeUnion. * gidl.dtd: Add a element. * src/gmetadata.c (g_metadata_check_sanity): Check union_blob_size. * src/gmetadata.h: Add union_blob_size to Header, add a UnionBlob. * metadata-format.txt: Add a UnionBlob. --- ChangeLog | 27 ++++++++ TODO | 3 +- gidl.dtd | 20 ++++-- metadata-format.txt | 53 +++++++++++++++- src/generate.c | 174 ++++++++++++++++++++++++++++++++++++++++------------ src/gidlmodule.c | 1 + src/gidlnode.c | 125 +++++++++++++++++++++++++++++++++++++ src/gidlnode.h | 19 ++++++ src/gidlparser.c | 145 ++++++++++++++++++++++++++++++++++++++++++- src/ginfo.c | 104 ++++++++++++++++++++++++++++++- src/girepository.h | 16 +++++ src/gmetadata.c | 3 +- src/gmetadata.h | 31 +++++++++- tests/roundtrips.sh | 2 +- tests/union.test | 14 +++++ 15 files changed, 683 insertions(+), 54 deletions(-) create mode 100644 tests/union.test diff --git a/ChangeLog b/ChangeLog index 48188f4..900468c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2005-05-15 Matthias Clasen + + * tests/roundtrips.sh (SIMPLE_TESTS): Add union.test. + + * tests/union.test: Add a union test. + + * src/generate.c: Handle unions. + + * src/girepository.h: + * src/ginfo.c: Add GIUnionInfo and functions to access it. + + * src/gidlnode.c: Handle GIdlNodeUnion nodes. + + * src/gidlparser.c (start_union): Parse elements. + + * src/gidlnode.h: Add a GIdlNodeUnion. + + * gidl.dtd: Add a element. + + * src/gmetadata.c (g_metadata_check_sanity): Check + union_blob_size. + + * src/gmetadata.h: Add union_blob_size to Header, + add a UnionBlob. + + * metadata-format.txt: Add a UnionBlob. + 2005-05-13 Matthias Clasen * tests/*: Update testcases. diff --git a/TODO b/TODO index 325db9d..34375af 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,6 @@ XML format Binary format ------------- - Add hashes to lookup interfaces and functions in interfaces -- Do we need (at least limited) handling of unions ? E.g. GdkEvent - Write a validator - Handle parent being 0 @@ -25,6 +24,8 @@ Repository - Add thorough error checking - Use hashes - Maybe allow populating repositories at runtime +- Think about a system-wide repository mapping namespace ids to + libraries/metadata files General ------- diff --git a/gidl.dtd b/gidl.dtd index f19b037..d134fc1 100644 --- a/gidl.dtd +++ b/gidl.dtd @@ -2,7 +2,7 @@ - + @@ -15,7 +15,6 @@ null-ok (0|1) #IMPLIED transfer (full|shallow|none) #IMPLIED > - - + + + + + + + \n"); + g_fprintf (file, "\""); + + if (branch) + { + g_fprintf (file, " branch=\""); + type = g_constant_info_get_type (branch); + g_constant_info_get_value (branch, &value); + write_constant_value (namespace, type, &value, file); + g_fprintf (file, "\""); + } + + g_fprintf (file," />\n"); } static void @@ -383,7 +402,7 @@ write_struct_info (const gchar *namespace, for (i = 0; i < g_struct_info_get_n_fields (info); i++) { GIFieldInfo *field = g_struct_info_get_field (info, i); - write_field_info (namespace, field, file); + write_field_info (namespace, field, NULL, file); g_base_info_unref ((GIBaseInfo *)field); } @@ -423,77 +442,86 @@ write_value_info (const gchar *namespace, } static void -write_constant_info (const gchar *namespace, - GIConstantInfo *info, - FILE *file, - gint indent) +write_constant_value (const gchar *namespace, + GITypeInfo *type, + GArgument *value, + FILE *file) { - GITypeInfo *type; - const gchar *name; - gboolean deprecated; - GArgument value; - - name = g_base_info_get_name ((GIBaseInfo *)info); - deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); - - g_fprintf (file, "%*sv_boolean); break; case GI_TYPE_TAG_INT8: - g_fprintf (file, "%d", value.v_int8); + g_fprintf (file, "%d", value->v_int8); break; case GI_TYPE_TAG_UINT8: - g_fprintf (file, "%d", value.v_uint8); + g_fprintf (file, "%d", value->v_uint8); break; case GI_TYPE_TAG_INT16: - g_fprintf (file, "%" G_GINT16_FORMAT, value.v_int16); + g_fprintf (file, "%" G_GINT16_FORMAT, value->v_int16); break; case GI_TYPE_TAG_UINT16: - g_fprintf (file, "%" G_GUINT16_FORMAT, value.v_uint16); + g_fprintf (file, "%" G_GUINT16_FORMAT, value->v_uint16); break; case GI_TYPE_TAG_INT32: - g_fprintf (file, "%" G_GINT32_FORMAT, value.v_int32); + g_fprintf (file, "%" G_GINT32_FORMAT, value->v_int32); break; case GI_TYPE_TAG_UINT32: - g_fprintf (file, "%" G_GUINT32_FORMAT, value.v_uint32); + g_fprintf (file, "%" G_GUINT32_FORMAT, value->v_uint32); break; case GI_TYPE_TAG_INT64: - g_fprintf (file, "%" G_GINT64_FORMAT, value.v_int64); + g_fprintf (file, "%" G_GINT64_FORMAT, value->v_int64); break; case GI_TYPE_TAG_UINT64: - g_fprintf (file, "%" G_GUINT64_FORMAT, value.v_uint64); + g_fprintf (file, "%" G_GUINT64_FORMAT, value->v_uint64); break; case GI_TYPE_TAG_FLOAT: - g_fprintf (file, "%f", value.v_float); + g_fprintf (file, "%f", value->v_float); break; case GI_TYPE_TAG_DOUBLE: - g_fprintf (file, "%Lf", value.v_double); + g_fprintf (file, "%Lf", value->v_double); break; case GI_TYPE_TAG_STRING: - g_fprintf (file, "%s", value.v_string); + g_fprintf (file, "%s", value->v_string); break; case GI_TYPE_TAG_INT: - g_fprintf (file, "%d", value.v_int); + g_fprintf (file, "%d", value->v_int); break; case GI_TYPE_TAG_UINT: - g_fprintf (file, "%d", value.v_uint); + g_fprintf (file, "%d", value->v_uint); break; case GI_TYPE_TAG_LONG: - g_fprintf (file, "%ld", value.v_long); + g_fprintf (file, "%ld", value->v_long); break; case GI_TYPE_TAG_ULONG: - g_fprintf (file, "%ld", value.v_ulong); + g_fprintf (file, "%ld", value->v_ulong); break; } +} + +static void +write_constant_info (const gchar *namespace, + GIConstantInfo *info, + FILE *file, + gint indent) +{ + GITypeInfo *type; + const gchar *name; + gboolean deprecated; + GArgument value; + + name = g_base_info_get_name ((GIBaseInfo *)info); + deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); + + g_fprintf (file, "%*s\n"); g_base_info_unref ((GIBaseInfo *)type); @@ -714,7 +742,7 @@ write_object_info (const gchar *namespace, for (i = 0; i < g_object_info_get_n_fields (info); i++) { GIFieldInfo *field = g_object_info_get_field (info, i); - write_field_info (namespace, field, file); + write_field_info (namespace, field, NULL, file); g_base_info_unref ((GIBaseInfo *)field); } @@ -856,6 +884,67 @@ write_error_domain_info (const gchar *namespace, } static void +write_union_info (const gchar *namespace, + GIUnionInfo *info, + FILE *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + gboolean deprecated; + gint i; + + name = g_base_info_get_name ((GIBaseInfo *)info); + deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); + + type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info); + type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info); + + g_fprintf (file, " \n"); + + if (g_union_info_is_discriminated (info)) + { + gint offset; + GITypeInfo *type; + + offset = g_union_info_get_discriminator_offset (info); + type = g_union_info_get_discriminator_type (info); + + g_fprintf (file, " \n"); + g_base_info_unref ((GIBaseInfo *)type); + } + + for (i = 0; i < g_union_info_get_n_fields (info); i++) + { + GIFieldInfo *field = g_union_info_get_field (info, i); + GIConstantInfo *constant = g_union_info_get_discriminator (info, i); + write_field_info (namespace, field, constant, file); + g_base_info_unref ((GIBaseInfo *)field); + if (constant) + g_base_info_unref ((GIBaseInfo *)constant); + } + + for (i = 0; i < g_union_info_get_n_methods (info); i++) + { + GIFunctionInfo *function = g_union_info_get_method (info, i); + write_function_info (namespace, function, file, 6); + g_base_info_unref ((GIBaseInfo *)function); + } + + g_fprintf (file, " \n"); +} + +static void write_repository (GIRepository *repository, gboolean needs_prefix) { @@ -915,7 +1004,11 @@ write_repository (GIRepository *repository, case GI_INFO_TYPE_BOXED: write_struct_info (ns, (GIStructInfo *)info, file); break; - + + case GI_INFO_TYPE_UNION: + write_union_info (ns, (GIUnionInfo *)info, file); + break; + case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: write_enum_info (ns, (GIEnumInfo *)info, file); @@ -936,6 +1029,9 @@ write_repository (GIRepository *repository, case GI_INFO_TYPE_ERROR_DOMAIN: write_error_domain_info (ns, (GIErrorDomainInfo *)info, file); break; + + default: + g_error ("unknown info type %d\n", g_base_info_get_type (info)); } g_base_info_unref (info); diff --git a/src/gidlmodule.c b/src/gidlmodule.c index de155f1..6319e83 100644 --- a/src/gidlmodule.c +++ b/src/gidlmodule.c @@ -133,6 +133,7 @@ g_idl_module_build_metadata (GIdlModule *module, header->struct_blob_size = 20; header->object_blob_size = 32; header->interface_blob_size = 28; + header->union_blob_size = 28; /* fill in directory and content */ entry = (DirEntry *)&data[header->directory]; diff --git a/src/gidlnode.c b/src/gidlnode.c index 2bf501a..f8223c4 100644 --- a/src/gidlnode.c +++ b/src/gidlnode.c @@ -125,6 +125,10 @@ g_idl_node_new (GIdlNodeTypeId type) node = g_malloc0 (sizeof (GIdlNodeXRef)); break; + case G_IDL_NODE_UNION: + node = g_malloc0 (sizeof (GIdlNodeUnion)); + break; + default: g_error ("Unhandled node type %d\n", type); break; @@ -323,6 +327,22 @@ g_idl_node_free (GIdlNode *node) } break; + case G_IDL_NODE_UNION: + { + GIdlNodeUnion *union_ = (GIdlNodeUnion *)node; + + g_free (node->name); + g_free (union_->gtype_name); + g_free (union_->gtype_init); + + g_idl_node_free ((GIdlNode *)union_->discriminator_type); + for (l = union_->members; l; l = l->next) + g_idl_node_free ((GIdlNode *)l->data); + for (l = union_->discriminators; l; l = l->next) + g_idl_node_free ((GIdlNode *)l->data); + } + break; + default: g_error ("Unhandled node type %d\n", node->type); break; @@ -442,6 +462,18 @@ g_idl_node_get_size (GIdlNode *node) size = 0; break; + case G_IDL_NODE_UNION: + { + GIdlNodeUnion *union_ = (GIdlNodeUnion *)node; + + size = 28; + for (l = union_->members; l; l = l->next) + size += g_idl_node_get_size ((GIdlNode *)l->data); + for (l = union_->discriminators; l; l = l->next) + size += g_idl_node_get_size ((GIdlNode *)l->data); + } + break; + default: g_error ("Unhandled node type %d\n", node->type); size = 0; @@ -699,6 +731,19 @@ g_idl_node_get_full_size (GIdlNode *node) } break; + case G_IDL_NODE_UNION: + { + GIdlNodeUnion *union_ = (GIdlNodeUnion *)node; + + size = 28; + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + for (l = union_->members; l; l = l->next) + size += g_idl_node_get_full_size ((GIdlNode *)l->data); + for (l = union_->discriminators; l; l = l->next) + size += g_idl_node_get_full_size ((GIdlNode *)l->data); + } + break; + default: g_error ("Unknown type tag %d\n", node->type); size = 0; @@ -1419,6 +1464,86 @@ g_idl_node_build_metadata (GIdlNode *node, } break; + case G_IDL_NODE_UNION: + { + UnionBlob *blob = (UnionBlob *)&data[*offset]; + GIdlNodeUnion *union_ = (GIdlNodeUnion *)node; + + blob->blob_type = BLOB_TYPE_UNION; + blob->deprecated = union_->deprecated; + blob->reserved = 0; + blob->name = write_string (node->name, strings, data, offset2); + if (union_->gtype_name) + { + blob->unregistered = FALSE; + blob->gtype_name = write_string (union_->gtype_name, strings, data, offset2); + blob->gtype_init = write_string (union_->gtype_init, strings, data, offset2); + } + else + { + blob->unregistered = TRUE; + blob->gtype_name = 0; + blob->gtype_init = 0; + } + + blob->n_fields = 0; + blob->n_functions = 0; + + blob->discriminator_offset = union_->discriminator_offset; + + if (union_->discriminator_type) + { + *offset += 24; + blob->discriminated = TRUE; + g_idl_node_build_metadata ((GIdlNode *)union_->discriminator_type, + module, modules, strings, types, + data, offset, offset2); + } + else + { + *offset += 28; + blob->discriminated = FALSE; + blob->discriminator_type.offset = 0; + } + + + for (l = union_->members; l; l = l->next) + { + GIdlNode *member = (GIdlNode *)l->data; + + if (member->type == G_IDL_NODE_FIELD) + { + blob->n_fields++; + g_idl_node_build_metadata (member, module, modules, strings, + types, data, offset, offset2); + } + } + + for (l = union_->members; l; l = l->next) + { + GIdlNode *member = (GIdlNode *)l->data; + + if (member->type == G_IDL_NODE_FUNCTION) + { + blob->n_functions++; + g_idl_node_build_metadata (member, module, modules, strings, + types, data, offset, offset2); + } + } + + if (union_->discriminator_type) + { + for (l = union_->discriminators; l; l = l->next) + { + GIdlNode *member = (GIdlNode *)l->data; + + g_idl_node_build_metadata (member, module, modules, strings, + types, data, offset, offset2); + } + } + } + break; + case G_IDL_NODE_ENUM: case G_IDL_NODE_FLAGS: { diff --git a/src/gidlnode.h b/src/gidlnode.h index 394d2f4..e81d713 100644 --- a/src/gidlnode.h +++ b/src/gidlnode.h @@ -41,6 +41,7 @@ typedef struct _GIdlNodeStruct GIdlNodeStruct; typedef struct _GIdlNodeConstant GIdlNodeConstant; typedef struct _GIdlNodeErrorDomain GIdlNodeErrorDomain; typedef struct _GIdlNodeXRef GIdlNodeXRef; +typedef struct _GIdlNodeUnion GIdlNodeUnion; typedef enum { @@ -55,6 +56,7 @@ typedef enum G_IDL_NODE_INTERFACE, G_IDL_NODE_CONSTANT, G_IDL_NODE_ERROR_DOMAIN, + G_IDL_NODE_UNION, G_IDL_NODE_PARAM, G_IDL_NODE_TYPE, G_IDL_NODE_PROPERTY, @@ -271,6 +273,23 @@ struct _GIdlNodeStruct GList *members; }; +struct _GIdlNodeUnion +{ + GIdlNode node; + + gboolean deprecated; + + GList *members; + GList *discriminators; + + gchar *gtype_name; + gchar *gtype_init; + + gint discriminator_offset; + GIdlNodeType *discriminator_type; +}; + + struct _GIdlNodeErrorDomain { GIdlNode node; diff --git a/src/gidlparser.c b/src/gidlparser.c index c175aba..8b38ed7 100644 --- a/src/gidlparser.c +++ b/src/gidlparser.c @@ -39,7 +39,8 @@ typedef enum STATE_BOXED, STATE_STRUCT, STATE_SIGNAL, - STATE_ERRORDOMAIN + STATE_ERRORDOMAIN, + STATE_UNION } ParseState; typedef struct _ParseContext ParseContext; @@ -413,7 +414,8 @@ start_function (GMarkupParseContext *context, ((ctx->state == STATE_OBJECT || ctx->state == STATE_INTERFACE || ctx->state == STATE_BOXED || - ctx->state == STATE_STRUCT) && + ctx->state == STATE_STRUCT || + ctx->state == STATE_UNION) && strcmp (element_name, "method") == 0) || ((ctx->state == STATE_OBJECT || ctx->state == STATE_BOXED) && @@ -504,6 +506,14 @@ start_function (GMarkupParseContext *context, struct_ = (GIdlNodeStruct *)ctx->current_node; struct_->members = g_list_append (struct_->members, function); } break; + case G_IDL_NODE_UNION: + { + GIdlNodeUnion *union_; + + union_ = (GIdlNodeUnion *)ctx->current_node; + union_->members = g_list_append (union_->members, function); + } + break; } ctx->current_node = (GIdlNode *)function; @@ -657,19 +667,22 @@ start_field (GMarkupParseContext *context, if (strcmp (element_name, "field") == 0 && (ctx->state == STATE_OBJECT || ctx->state == STATE_BOXED || - ctx->state == STATE_STRUCT)) + ctx->state == STATE_STRUCT || + ctx->state == STATE_UNION)) { const gchar *name; const gchar *type; const gchar *readable; const gchar *writable; const gchar *bits; + const gchar *branch; name = find_attribute ("name", attribute_names, attribute_values); type = find_attribute ("type", attribute_names, attribute_values); readable = find_attribute ("readable", attribute_names, attribute_values); writable = find_attribute ("writable", attribute_names, attribute_values); bits = find_attribute ("bits", attribute_names, attribute_values); + branch = find_attribute ("branch", attribute_names, attribute_values); if (name == NULL) MISSING_ATTRIBUTE (error, element_name, "name"); @@ -724,6 +737,26 @@ start_field (GMarkupParseContext *context, struct_->members = g_list_append (struct_->members, field); } break; + case G_IDL_NODE_UNION: + { + GIdlNodeUnion *union_; + + union_ = (GIdlNodeUnion *)ctx->current_node; + union_->members = g_list_append (union_->members, field); + if (branch) + { + GIdlNodeConstant *constant; + + constant = (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT); + ((GIdlNode *)constant)->name = g_strdup (name); + constant->value = g_strdup (branch); + constant->type = union_->discriminator_type; + constant->deprecated = FALSE; + + union_->discriminators = g_list_append (union_->discriminators, constant); + } + } + break; } } return TRUE; @@ -1424,6 +1457,88 @@ start_struct (GMarkupParseContext *context, return FALSE; } + +static gboolean +start_union (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + if (strcmp (element_name, "union") == 0 && + ctx->state == STATE_NAMESPACE) + { + const gchar *name; + const gchar *deprecated; + const gchar *typename; + const gchar *typeinit; + + name = find_attribute ("name", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + typename = find_attribute ("type-name", attribute_names, attribute_values); + typeinit = find_attribute ("get-type", attribute_names, attribute_values); + + if (name == NULL) + MISSING_ATTRIBUTE (error, element_name, "name"); + else + { + GIdlNodeUnion *union_; + + union_ = (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION); + + ((GIdlNode *)union_)->name = g_strdup (name); + union_->gtype_name = g_strdup (typename); + union_->gtype_init = g_strdup (typeinit); + if (deprecated && strcmp (deprecated, "1") == 0) + union_->deprecated = TRUE; + else + union_->deprecated = FALSE; + + ctx->current_node = (GIdlNode *)union_; + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, union_); + + ctx->state = STATE_UNION; + } + return TRUE; + } + return FALSE; +} + +static gboolean +start_discriminator (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + if (strcmp (element_name, "discriminator") == 0 && + ctx->state == STATE_UNION) + { + const gchar *type; + const gchar *offset; + + type = find_attribute ("type", attribute_names, attribute_values); + offset = find_attribute ("offset", attribute_names, attribute_values); + if (type == NULL) + MISSING_ATTRIBUTE (error, element_name, "type"); + else if (offset == NULL) + MISSING_ATTRIBUTE (error, element_name, "offset"); + { + ((GIdlNodeUnion *)ctx->current_node)->discriminator_type + = parse_type (type); + ((GIdlNodeUnion *)ctx->current_node)->discriminator_offset + = atoi (offset); + } + + return TRUE; + } + + return FALSE; +} + static void start_element_handler (GMarkupParseContext *context, const gchar *element_name, @@ -1477,6 +1592,13 @@ start_element_handler (GMarkupParseContext *context, goto out; break; + case 'd': + if (start_discriminator (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + case 'e': if (start_enum (context, element_name, attribute_names, attribute_values, @@ -1660,6 +1782,13 @@ start_element_handler (GMarkupParseContext *context, break; + case 'u': + if (start_union (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + case 'v': if (start_vfunc (context, element_name, attribute_names, attribute_values, @@ -1725,6 +1854,8 @@ end_element_handler (GMarkupParseContext *context, ctx->state = STATE_BOXED; else if (ctx->current_node->type == G_IDL_NODE_STRUCT) ctx->state = STATE_STRUCT; + else if (ctx->current_node->type == G_IDL_NODE_UNION) + ctx->state = STATE_UNION; } break; @@ -1776,6 +1907,14 @@ end_element_handler (GMarkupParseContext *context, ctx->state = STATE_NAMESPACE; } break; + case STATE_UNION: + if (strcmp (element_name, "union") == 0) + { + ctx->current_node = NULL; + ctx->state = STATE_NAMESPACE; + } + break; + case STATE_IMPLEMENTS: ctx->state = STATE_OBJECT; break; diff --git a/src/ginfo.c b/src/ginfo.c index 4e44043..5423424 100644 --- a/src/ginfo.c +++ b/src/ginfo.c @@ -121,12 +121,16 @@ struct _GIArgInfo GIBaseInfo base; }; - struct _GITypeInfo { GIBaseInfo base; }; +struct _GIUnionInfo +{ + GIRegisteredTypeInfo registered; +}; + /* info creation */ GIBaseInfo * @@ -232,6 +236,7 @@ g_base_info_get_name (GIBaseInfo *info) 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[info->offset]; @@ -1638,3 +1643,100 @@ g_constant_info_get_value (GIConstantInfo *info, return blob->size; } + +/* GIUnionInfo functions */ +gint +g_union_info_get_n_fields (GIUnionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + UnionBlob *blob = (UnionBlob *)&base->metadata[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; + + 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[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[base->offset]; + Header *header = (Header *)base->metadata; + 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[base->offset]; + + return blob->discriminated; +} + +gint +g_union_info_get_discriminator_offset (GIUnionInfo *info) +{ + GIBaseInfo *base = (GIBaseInfo *)info; + UnionBlob *blob = (UnionBlob *)&base->metadata[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[base->offset]; + + if (blob->discriminated) + { + Header *header = (Header *)base->metadata; + 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/src/girepository.h b/src/girepository.h index 6a20cd8..8839d5c 100644 --- a/src/girepository.h +++ b/src/girepository.h @@ -37,6 +37,7 @@ 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; @@ -102,6 +103,7 @@ typedef enum 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, @@ -284,6 +286,20 @@ 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, diff --git a/src/gmetadata.c b/src/gmetadata.c index 40d7d6f..0e613fc 100644 --- a/src/gmetadata.c +++ b/src/gmetadata.c @@ -36,7 +36,7 @@ void g_metadata_check_sanity (void) { /* Check that struct layout is as we expect */ - g_assert (sizeof (Header) == 80); + g_assert (sizeof (Header) == 84); g_assert (sizeof (DirEntry) == 12); g_assert (sizeof (SimpleTypeBlob) == 4); g_assert (sizeof (ArgBlob) == 12); @@ -60,6 +60,7 @@ g_metadata_check_sanity (void) g_assert (sizeof (InterfaceBlob) == 28); g_assert (sizeof (ConstantBlob) == 20); g_assert (sizeof (AnnotationBlob) == 12); + g_assert (sizeof (UnionBlob) == 28); } diff --git a/src/gmetadata.h b/src/gmetadata.h index 39c2cd2..c09a6b1 100644 --- a/src/gmetadata.h +++ b/src/gmetadata.h @@ -38,7 +38,8 @@ enum BLOB_TYPE_OBJECT, BLOB_TYPE_INTERFACE, BLOB_TYPE_CONSTANT, - BLOB_TYPE_ERROR_DOMAIN + BLOB_TYPE_ERROR_DOMAIN, + BLOB_TYPE_UNION }; typedef struct @@ -74,6 +75,9 @@ typedef struct guint16 struct_blob_size; guint16 object_blob_size; guint16 interface_blob_size; + guint16 union_blob_size; + + guint16 padding; } Header; typedef struct @@ -292,6 +296,31 @@ typedef struct #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; diff --git a/tests/roundtrips.sh b/tests/roundtrips.sh index 8ed422a..e5cd0fe 100755 --- a/tests/roundtrips.sh +++ b/tests/roundtrips.sh @@ -1,6 +1,6 @@ #! /bin/sh -SIMPLE_TESTS="array.test boxed.test enum.test errors.test function.test interface.test" +SIMPLE_TESTS="array.test boxed.test enum.test errors.test function.test interface.test union.test" for i in $SIMPLE_TESTS; do echo $i diff --git a/tests/union.test b/tests/union.test new file mode 100644 index 0000000..329512e --- /dev/null +++ b/tests/union.test @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + -- 2.7.4