1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 * GObject introspection: Typelib creation
4 * Copyright (C) 2005 Matthias Clasen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
26 #include "girmodule.h"
27 #include "gitypelib-internal.h"
30 #define ALIGN_VALUE(this, boundary) \
31 (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
33 #define NUM_SECTIONS 2
36 _g_ir_module_new (const gchar *name,
38 const gchar *shared_library,
39 const gchar *c_prefix)
43 module = g_slice_new0 (GIrModule);
45 module->name = g_strdup (name);
46 module->version = g_strdup (version);
48 module->shared_library = g_strdup (shared_library);
50 module->shared_library = NULL;
51 module->c_prefix = g_strdup (c_prefix);
52 module->dependencies = NULL;
53 module->entries = NULL;
55 module->include_modules = NULL;
56 module->aliases = NULL;
62 _g_ir_module_free (GIrModule *module)
66 g_free (module->name);
68 for (e = module->entries; e; e = e->next)
69 _g_ir_node_free ((GIrNode *)e->data);
71 g_list_free (module->entries);
72 /* Don't free dependencies, we inherit that from the parser */
74 g_list_free (module->include_modules);
76 g_hash_table_destroy (module->aliases);
77 g_hash_table_destroy (module->disguised_structures);
79 g_slice_free (GIrModule, module);
84 * @build: Current build
85 * @line: Origin line number, or 0 if unknown
86 * @msg: printf-format string
87 * @args: Remaining arguments
89 * Report a fatal error, then exit.
92 _g_ir_module_fatal (GIrTypelibBuild *build,
103 va_start (args, msg);
105 formatted = g_strdup_vprintf (msg, args);
107 context = g_string_new ("");
109 g_string_append_printf (context, "%d: ", line);
111 g_string_append (context, "In ");
112 for (link = g_list_last (build->stack); link; link = link->prev)
114 GIrNode *node = link->data;
115 const char *name = node->name;
117 g_string_append (context, name);
119 g_string_append (context, ".");
122 g_string_append (context, ": ");
124 g_printerr ("%s-%s.gir:%serror: %s\n", build->module->name,
125 build->module->version,
126 context->str, formatted);
127 g_string_free (context, TRUE);
135 add_alias_foreach (gpointer key,
139 GIrModule *module = data;
141 g_hash_table_replace (module->aliases, g_strdup (key), g_strdup (value));
145 add_disguised_structure_foreach (gpointer key,
149 GIrModule *module = data;
151 g_hash_table_replace (module->disguised_structures, g_strdup (key), value);
155 _g_ir_module_add_include_module (GIrModule *module,
156 GIrModule *include_module)
158 module->include_modules = g_list_prepend (module->include_modules,
161 g_hash_table_foreach (include_module->aliases,
165 g_hash_table_foreach (include_module->disguised_structures,
166 add_disguised_structure_foreach,
170 struct AttributeWriteData
181 write_attribute (gpointer key, gpointer value, gpointer datap)
183 struct AttributeWriteData *data = datap;
184 guint32 old_offset = *(data->offset);
185 AttributeBlob *blob = (AttributeBlob*)&(data->databuf[old_offset]);
187 *(data->offset) += sizeof (AttributeBlob);
189 blob->offset = data->node->offset;
190 blob->name = _g_ir_write_string ((const char*) key, data->strings, data->databuf, data->offset2);
191 blob->value = _g_ir_write_string ((const char*) value, data->strings, data->databuf, data->offset2);
197 write_attributes (GIrModule *module,
204 struct AttributeWriteData wdata;
206 wdata.databuf = data;
208 wdata.offset = offset;
209 wdata.offset2 = offset2;
210 wdata.strings = strings;
212 g_hash_table_foreach (node->attributes, write_attribute, &wdata);
218 node_cmp_offset_func (gconstpointer a,
221 const GIrNode *na = a;
222 const GIrNode *nb = b;
223 return na->offset - nb->offset;
227 alloc_section (guint8 *data, SectionType section_id, guint32 offset)
230 Header *header = (Header*)data;
231 Section *section_data = (Section*)&data[header->sections];
233 g_assert (section_id != GI_SECTION_END);
235 for (i = 0; i < NUM_SECTIONS; i++)
237 if (section_data->id == GI_SECTION_END)
239 section_data->id = section_id;
240 section_data->offset = offset;
245 g_assert_not_reached ();
249 add_directory_index_section (guint8 *data, GIrModule *module, guint32 *offset2)
252 Header *header = (Header*)data;
253 GITypelibHashBuilder *dirindex_builder;
254 guint i, n_interfaces;
255 guint16 required_size;
258 dirindex_builder = _gi_typelib_hash_builder_new ();
260 n_interfaces = ((Header *)data)->n_local_entries;
262 for (i = 0; i < n_interfaces; i++)
264 entry = (DirEntry *)&data[header->directory + (i * header->entry_blob_size)];
265 const char *str = (const char *) (&data[entry->name]);
266 _gi_typelib_hash_builder_add_string (dirindex_builder, str, i);
269 if (!_gi_typelib_hash_builder_prepare (dirindex_builder))
271 /* This happens if CMPH couldn't create a perfect hash. So
272 * we just punt and leave no directory index section.
274 _gi_typelib_hash_builder_destroy (dirindex_builder);
278 alloc_section (data, GI_SECTION_DIRECTORY_INDEX, *offset2);
280 required_size = _gi_typelib_hash_builder_get_buffer_size (dirindex_builder);
282 new_offset = *offset2 + ALIGN_VALUE (required_size, 4);
284 data = g_realloc (data, new_offset);
286 _gi_typelib_hash_builder_pack (dirindex_builder, ((guint8*)data) + *offset2, required_size);
288 *offset2 = new_offset;
290 _gi_typelib_hash_builder_destroy (dirindex_builder);
295 _g_ir_module_build_typelib (GIrModule *module)
297 GError *error = NULL;
307 guint32 n_local_entries;
308 guint32 size, offset, offset2, old_offset;
311 GList *nodes_with_attributes;
316 header_size = ALIGN_VALUE (sizeof (Header), 4);
317 n_local_entries = g_list_length (module->entries);
319 /* Serialize dependencies into one string; this is convenient
320 * and not a major change to the typelib format. */
322 GString *dependencies_str = g_string_new ("");
324 for (link = module->dependencies; link; link = link->next)
326 const char *dependency = link->data;
327 if (!strcmp (dependency, module->name))
329 g_string_append (dependencies_str, dependency);
331 g_string_append_c (dependencies_str, '|');
333 dependencies = g_string_free (dependencies_str, FALSE);
334 if (!dependencies[0])
336 g_free (dependencies);
342 _g_irnode_init_stats ();
343 strings = g_hash_table_new (g_str_hash, g_str_equal);
344 types = g_hash_table_new (g_str_hash, g_str_equal);
345 nodes_with_attributes = NULL;
346 n_entries = g_list_length (module->entries);
348 g_message ("%d entries (%d local), %d dependencies\n", n_entries, n_local_entries,
349 g_list_length (module->dependencies));
351 dir_size = n_entries * sizeof (DirEntry);
352 size = header_size + dir_size;
354 size += ALIGN_VALUE (strlen (module->name) + 1, 4);
356 for (e = module->entries; e; e = e->next)
358 GIrNode *node = e->data;
360 size += _g_ir_node_get_full_size (node);
362 /* Also reset the offset here */
366 /* Adjust size for strings allocated in header below specially */
367 size += ALIGN_VALUE (strlen (module->name) + 1, 4);
368 if (module->shared_library)
369 size += ALIGN_VALUE (strlen (module->shared_library) + 1, 4);
370 if (dependencies != NULL)
371 size += ALIGN_VALUE (strlen (dependencies) + 1, 4);
372 if (module->c_prefix != NULL)
373 size += ALIGN_VALUE (strlen (module->c_prefix) + 1, 4);
375 size += sizeof (Section) * NUM_SECTIONS;
377 g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n",
378 size, header_size, dir_size, size - header_size - dir_size);
380 data = g_malloc0 (size);
383 header = (Header *)data;
384 memcpy (header, G_IR_MAGIC, 16);
385 header->major_version = 4;
386 header->minor_version = 0;
387 header->reserved = 0;
388 header->n_entries = n_entries;
389 header->n_local_entries = n_local_entries;
390 header->n_attributes = 0;
391 header->attributes = 0; /* filled in later */
392 /* NOTE: When writing strings to the typelib here, you should also update
393 * the size calculations above.
395 if (dependencies != NULL)
396 header->dependencies = _g_ir_write_string (dependencies, strings, data, &header_size);
398 header->dependencies = 0;
399 header->size = 0; /* filled in later */
400 header->namespace = _g_ir_write_string (module->name, strings, data, &header_size);
401 header->nsversion = _g_ir_write_string (module->version, strings, data, &header_size);
402 header->shared_library = (module->shared_library?
403 _g_ir_write_string (module->shared_library, strings, data, &header_size)
405 if (module->c_prefix != NULL)
406 header->c_prefix = _g_ir_write_string (module->c_prefix, strings, data, &header_size);
408 header->c_prefix = 0;
409 header->entry_blob_size = sizeof (DirEntry);
410 header->function_blob_size = sizeof (FunctionBlob);
411 header->callback_blob_size = sizeof (CallbackBlob);
412 header->signal_blob_size = sizeof (SignalBlob);
413 header->vfunc_blob_size = sizeof (VFuncBlob);
414 header->arg_blob_size = sizeof (ArgBlob);
415 header->property_blob_size = sizeof (PropertyBlob);
416 header->field_blob_size = sizeof (FieldBlob);
417 header->value_blob_size = sizeof (ValueBlob);
418 header->constant_blob_size = sizeof (ConstantBlob);
419 header->error_domain_blob_size = 16; /* No longer used */
420 header->attribute_blob_size = sizeof (AttributeBlob);
421 header->signature_blob_size = sizeof (SignatureBlob);
422 header->enum_blob_size = sizeof (EnumBlob);
423 header->struct_blob_size = sizeof (StructBlob);
424 header->object_blob_size = sizeof(ObjectBlob);
425 header->interface_blob_size = sizeof (InterfaceBlob);
426 header->union_blob_size = sizeof (UnionBlob);
428 offset2 = ALIGN_VALUE (header_size, 4);
429 header->sections = offset2;
431 /* Initialize all the sections to _END/0; we fill them in later using
432 * alloc_section(). (Right now there's just the directory index
435 for (i = 0; i < NUM_SECTIONS; i++)
437 section = (Section*) &data[offset2];
438 section->id = GI_SECTION_END;
440 offset2 += sizeof(Section);
442 header->directory = offset2;
444 /* fill in directory and content */
445 entry = (DirEntry *)&data[header->directory];
449 for (e = module->entries, i = 0; e; e = e->next, i++)
451 GIrTypelibBuild build;
452 GIrNode *node = e->data;
454 if (strchr (node->name, '.'))
456 g_error ("Names may not contain '.'");
459 /* we picked up implicit xref nodes, start over */
463 g_message ("Found implicit cross references, starting over");
465 g_hash_table_destroy (strings);
466 g_hash_table_destroy (types);
468 /* Reset the cached offsets */
469 for (link = nodes_with_attributes; link; link = link->next)
470 ((GIrNode *) link->data)->offset = 0;
472 g_list_free (nodes_with_attributes);
483 if (node->type == G_IR_NODE_XREF)
485 const char *namespace = ((GIrNodeXRef*)node)->namespace;
487 entry->blob_type = 0;
488 entry->local = FALSE;
489 entry->offset = _g_ir_write_string (namespace, strings, data, &offset2);
490 entry->name = _g_ir_write_string (node->name, strings, data, &offset2);
495 offset2 = offset + _g_ir_node_get_size (node);
497 entry->blob_type = node->type;
499 entry->offset = offset;
500 entry->name = _g_ir_write_string (node->name, strings, data, &offset2);
502 memset (&build, 0, sizeof (build));
503 build.module = module;
504 build.strings = strings;
506 build.nodes_with_attributes = nodes_with_attributes;
507 build.n_attributes = header->n_attributes;
509 _g_ir_node_build_typelib (node, NULL, &build, &offset, &offset2);
511 nodes_with_attributes = build.nodes_with_attributes;
512 header->n_attributes = build.n_attributes;
514 if (offset2 > old_offset + _g_ir_node_get_full_size (node))
515 g_error ("left a hole of %d bytes\n", offset2 - old_offset - _g_ir_node_get_full_size (node));
521 /* GIBaseInfo expects the AttributeBlob array to be sorted on the field (offset) */
522 nodes_with_attributes = g_list_sort (nodes_with_attributes, node_cmp_offset_func);
524 g_message ("header: %d entries, %d attributes", header->n_entries, header->n_attributes);
526 _g_irnode_dump_stats ();
528 /* Write attributes after the blobs */
530 header->attributes = offset;
531 offset2 = offset + header->n_attributes * header->attribute_blob_size;
533 for (e = nodes_with_attributes; e; e = e->next)
535 GIrNode *node = e->data;
536 write_attributes (module, node, strings, data, &offset, &offset2);
539 g_message ("reallocating to %d bytes", offset2);
541 data = g_realloc (data, offset2);
542 header = (Header*) data;
544 data = add_directory_index_section (data, module, &offset2);
545 header = (Header *)data;
547 length = header->size = offset2;
548 typelib = g_typelib_new_from_memory (data, length, &error);
551 g_error ("error building typelib: %s",
555 g_hash_table_destroy (strings);
556 g_hash_table_destroy (types);
557 g_list_free (nodes_with_attributes);