Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : * GObject introspection: Typelib creation
3 : : *
4 : : * Copyright (C) 2005 Matthias Clasen
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Lesser General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Lesser General Public
19 : : * License along with this library; if not, write to the
20 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 : : * Boston, MA 02111-1307, USA.
22 : : */
23 : :
24 : : #include "config.h"
25 : :
26 : : #include "girmodule-private.h"
27 : :
28 : : #include "girnode-private.h"
29 : : #include "gitypelib-internal.h"
30 : :
31 : : #include <stdio.h>
32 : : #include <string.h>
33 : : #include <stdlib.h>
34 : :
35 : : #define ALIGN_VALUE(this, boundary) \
36 : : (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
37 : :
38 : : #define NUM_SECTIONS 2
39 : :
40 : : /*< private >
41 : : * gi_ir_module_new:
42 : : * @name:
43 : : * @version:
44 : : * @shared_library: (nullable):
45 : : * @c_prefix:
46 : : *
47 : : * Since: 2.80
48 : : */
49 : : GIIrModule *
50 : 21 : gi_ir_module_new (const char *name,
51 : : const char *version,
52 : : const char *shared_library,
53 : : const char *c_prefix)
54 : : {
55 : : GIIrModule *module;
56 : :
57 : 21 : module = g_slice_new0 (GIIrModule);
58 : :
59 : 21 : module->name = g_strdup (name);
60 : 21 : module->version = g_strdup (version);
61 : 21 : module->shared_library = g_strdup (shared_library);
62 : 21 : module->c_prefix = g_strdup (c_prefix);
63 : 21 : module->dependencies = NULL;
64 : 21 : module->entries = NULL;
65 : :
66 : 21 : module->include_modules = NULL;
67 : 21 : module->aliases = NULL;
68 : :
69 : 21 : return module;
70 : : }
71 : :
72 : : void
73 : 21 : gi_ir_module_free (GIIrModule *module)
74 : : {
75 : : GList *e;
76 : :
77 : 21 : g_free (module->name);
78 : 21 : g_free (module->version);
79 : 21 : g_free (module->shared_library);
80 : 21 : g_free (module->c_prefix);
81 : :
82 : 10726 : for (e = module->entries; e; e = e->next)
83 : 10705 : gi_ir_node_free ((GIIrNode *)e->data);
84 : :
85 : 21 : g_list_free (module->entries);
86 : 21 : g_clear_pointer (&module->dependencies, g_ptr_array_unref);
87 : :
88 : 21 : g_list_free (module->include_modules);
89 : :
90 : 21 : g_hash_table_destroy (module->aliases);
91 : 21 : g_hash_table_destroy (module->pointer_structures);
92 : 21 : g_hash_table_destroy (module->disguised_structures);
93 : :
94 : 21 : g_slice_free (GIIrModule, module);
95 : 21 : }
96 : :
97 : : /**
98 : : * gi_ir_module_fatal:
99 : : * @build: Current build
100 : : * @line: Origin line number, or 0 if unknown
101 : : * @msg: printf-format string
102 : : * @args: Remaining arguments
103 : : *
104 : : * Report a fatal error, then exit.
105 : : *
106 : : * Since: 2.80
107 : : */
108 : : void
109 : 0 : gi_ir_module_fatal (GIIrTypelibBuild *build,
110 : : unsigned int line,
111 : : const char *msg,
112 : : ...)
113 : : {
114 : : GString *context;
115 : : char *formatted;
116 : : GList *link;
117 : :
118 : : va_list args;
119 : :
120 : 0 : va_start (args, msg);
121 : :
122 : 0 : formatted = g_strdup_vprintf (msg, args);
123 : :
124 : 0 : context = g_string_new ("");
125 : 0 : if (line > 0)
126 : 0 : g_string_append_printf (context, "%u: ", line);
127 : 0 : if (build->stack)
128 : 0 : g_string_append (context, "In ");
129 : 0 : for (link = g_list_last (build->stack); link; link = link->prev)
130 : : {
131 : 0 : GIIrNode *node = link->data;
132 : 0 : const char *name = node->name;
133 : 0 : if (name)
134 : : g_string_append (context, name);
135 : 0 : if (link->prev)
136 : 0 : g_string_append (context, ".");
137 : : }
138 : 0 : if (build->stack)
139 : 0 : g_string_append (context, ": ");
140 : :
141 : 0 : g_printerr ("%s-%s.gir:%serror: %s\n", build->module->name,
142 : 0 : build->module->version,
143 : : context->str, formatted);
144 : 0 : g_string_free (context, TRUE);
145 : :
146 : 0 : exit (1);
147 : :
148 : : va_end (args);
149 : : }
150 : :
151 : : static void
152 : 359 : add_alias_foreach (gpointer key,
153 : : gpointer value,
154 : : gpointer data)
155 : : {
156 : 359 : GIIrModule *module = data;
157 : :
158 : 359 : g_hash_table_replace (module->aliases, g_strdup (key), g_strdup (value));
159 : 359 : }
160 : :
161 : : static void
162 : 26 : add_pointer_structure_foreach (gpointer key,
163 : : gpointer value,
164 : : gpointer data)
165 : : {
166 : 26 : GIIrModule *module = data;
167 : :
168 : 26 : g_hash_table_replace (module->pointer_structures, g_strdup (key), value);
169 : 26 : }
170 : :
171 : : static void
172 : 590 : add_disguised_structure_foreach (gpointer key,
173 : : gpointer value,
174 : : gpointer data)
175 : : {
176 : 590 : GIIrModule *module = data;
177 : :
178 : 590 : g_hash_table_replace (module->disguised_structures, g_strdup (key), value);
179 : 590 : }
180 : :
181 : : void
182 : 26 : gi_ir_module_add_include_module (GIIrModule *module,
183 : : GIIrModule *include_module)
184 : : {
185 : 26 : module->include_modules = g_list_prepend (module->include_modules,
186 : : include_module);
187 : :
188 : 26 : g_hash_table_foreach (include_module->aliases,
189 : : add_alias_foreach,
190 : : module);
191 : :
192 : 26 : g_hash_table_foreach (include_module->pointer_structures,
193 : : add_pointer_structure_foreach,
194 : : module);
195 : 26 : g_hash_table_foreach (include_module->disguised_structures,
196 : : add_disguised_structure_foreach,
197 : : module);
198 : 26 : }
199 : :
200 : : struct AttributeWriteData
201 : : {
202 : : unsigned int count;
203 : : uint8_t *databuf;
204 : : GIIrNode *node;
205 : : GHashTable *strings;
206 : : uint32_t *offset;
207 : : uint32_t *offset2;
208 : : };
209 : :
210 : : static void
211 : 1297 : write_attribute (gpointer key, gpointer value, gpointer datap)
212 : : {
213 : 1297 : struct AttributeWriteData *data = datap;
214 : 1297 : uint32_t old_offset = *(data->offset);
215 : 1297 : AttributeBlob *blob = (AttributeBlob*)&(data->databuf[old_offset]);
216 : :
217 : 1297 : *(data->offset) += sizeof (AttributeBlob);
218 : :
219 : 1297 : blob->offset = data->node->offset;
220 : 1297 : blob->name = gi_ir_write_string ((const char*) key, data->strings, data->databuf, data->offset2);
221 : 1297 : blob->value = gi_ir_write_string ((const char*) value, data->strings, data->databuf, data->offset2);
222 : :
223 : 1297 : data->count++;
224 : 1297 : }
225 : :
226 : : static unsigned
227 : 39578 : write_attributes (GIIrModule *module,
228 : : GIIrNode *node,
229 : : GHashTable *strings,
230 : : uint8_t *data,
231 : : uint32_t *offset,
232 : : uint32_t *offset2)
233 : : {
234 : : struct AttributeWriteData wdata;
235 : 39578 : wdata.count = 0;
236 : 39578 : wdata.databuf = data;
237 : 39578 : wdata.node = node;
238 : 39578 : wdata.offset = offset;
239 : 39578 : wdata.offset2 = offset2;
240 : 39578 : wdata.strings = strings;
241 : :
242 : 39578 : g_hash_table_foreach (node->attributes, write_attribute, &wdata);
243 : :
244 : 39578 : return wdata.count;
245 : : }
246 : :
247 : : static int
248 : 295592 : node_cmp_offset_func (const void *a,
249 : : const void *b)
250 : : {
251 : 295592 : const GIIrNode *na = a;
252 : 295592 : const GIIrNode *nb = b;
253 : 295592 : return na->offset - nb->offset;
254 : : }
255 : :
256 : : static void
257 : 7 : alloc_section (uint8_t *data, SectionType section_id, uint32_t offset)
258 : : {
259 : : int i;
260 : 7 : Header *header = (Header*)data;
261 : 7 : Section *section_data = (Section*)&data[header->sections];
262 : :
263 : 7 : g_assert (section_id != GI_SECTION_END);
264 : :
265 : 7 : for (i = 0; i < NUM_SECTIONS; i++)
266 : : {
267 : 7 : if (section_data->id == GI_SECTION_END)
268 : : {
269 : 7 : section_data->id = section_id;
270 : 7 : section_data->offset = offset;
271 : 7 : return;
272 : : }
273 : 0 : section_data++;
274 : : }
275 : : g_assert_not_reached ();
276 : : }
277 : :
278 : : static uint8_t *
279 : 7 : add_directory_index_section (uint8_t *data, GIIrModule *module, uint32_t *offset2)
280 : : {
281 : : DirEntry *entry;
282 : 7 : Header *header = (Header*)data;
283 : : GITypelibHashBuilder *dirindex_builder;
284 : : uint16_t n_interfaces;
285 : : uint16_t required_size;
286 : : uint32_t new_offset;
287 : :
288 : 7 : dirindex_builder = gi_typelib_hash_builder_new ();
289 : :
290 : 7 : n_interfaces = ((Header *)data)->n_local_entries;
291 : :
292 : 2230 : for (uint16_t i = 0; i < n_interfaces; i++)
293 : : {
294 : : const char *str;
295 : 2223 : entry = (DirEntry *)&data[header->directory + (i * header->entry_blob_size)];
296 : 2223 : str = (const char *) (&data[entry->name]);
297 : 2223 : gi_typelib_hash_builder_add_string (dirindex_builder, str, i);
298 : : }
299 : :
300 : 7 : if (!gi_typelib_hash_builder_prepare (dirindex_builder))
301 : : {
302 : : /* This happens if CMPH couldn't create a perfect hash. So
303 : : * we just punt and leave no directory index section.
304 : : */
305 : 0 : gi_typelib_hash_builder_destroy (dirindex_builder);
306 : 0 : return data;
307 : : }
308 : :
309 : 7 : alloc_section (data, GI_SECTION_DIRECTORY_INDEX, *offset2);
310 : :
311 : 7 : required_size = gi_typelib_hash_builder_get_buffer_size (dirindex_builder);
312 : 7 : required_size = ALIGN_VALUE (required_size, 4);
313 : :
314 : 7 : new_offset = *offset2 + required_size;
315 : :
316 : 7 : data = g_realloc (data, new_offset);
317 : :
318 : 7 : gi_typelib_hash_builder_pack (dirindex_builder, ((uint8_t*)data) + *offset2, required_size);
319 : :
320 : 7 : *offset2 = new_offset;
321 : :
322 : 7 : gi_typelib_hash_builder_destroy (dirindex_builder);
323 : 7 : return data;
324 : : }
325 : :
326 : : GITypelib *
327 : 7 : gi_ir_module_build_typelib (GIIrModule *module)
328 : : {
329 : 7 : GError *error = NULL;
330 : 7 : GBytes *bytes = NULL;
331 : : GITypelib *typelib;
332 : : size_t length;
333 : : size_t i;
334 : : GList *e;
335 : : Header *header;
336 : : DirEntry *entry;
337 : : uint32_t header_size;
338 : : uint32_t dir_size;
339 : : uint32_t n_entries;
340 : : uint32_t n_local_entries;
341 : : uint32_t size, offset, offset2, old_offset;
342 : : GHashTable *strings;
343 : : GHashTable *types;
344 : : GList *nodes_with_attributes;
345 : : char *dependencies;
346 : : uint8_t *data;
347 : : Section *section;
348 : :
349 : 7 : header_size = ALIGN_VALUE (sizeof (Header), 4);
350 : 7 : n_local_entries = g_list_length (module->entries);
351 : :
352 : : /* Serialize dependencies into one string; this is convenient
353 : : * and not a major change to the typelib format. */
354 : 7 : if (module->dependencies->len)
355 : : {
356 : 6 : GString *dependencies_str = g_string_new (NULL);
357 : 20 : for (guint i = module->dependencies->len; i > 0; --i)
358 : : {
359 : 14 : const char *dependency = g_ptr_array_index (module->dependencies, i-1);
360 : 14 : if (!strcmp (dependency, module->name))
361 : 0 : continue;
362 : : g_string_append (dependencies_str, dependency);
363 : 14 : if (i > 1)
364 : : g_string_append_c (dependencies_str, '|');
365 : : }
366 : 6 : dependencies = g_string_free (dependencies_str, FALSE);
367 : 6 : if (dependencies && !dependencies[0])
368 : : {
369 : 0 : g_free (dependencies);
370 : 0 : dependencies = NULL;
371 : : }
372 : : }
373 : : else
374 : : {
375 : 1 : dependencies = NULL;
376 : : }
377 : :
378 : 7 : restart:
379 : 12 : gi_ir_node_init_stats ();
380 : 12 : strings = g_hash_table_new (g_str_hash, g_str_equal);
381 : 12 : types = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
382 : 12 : nodes_with_attributes = NULL;
383 : 12 : n_entries = g_list_length (module->entries);
384 : :
385 : 12 : g_message ("%d entries (%d local), %u dependencies", n_entries, n_local_entries,
386 : : module->dependencies ? module->dependencies->len : 0);
387 : :
388 : 12 : dir_size = n_entries * sizeof (DirEntry);
389 : 12 : size = header_size + dir_size;
390 : :
391 : 12 : size += ALIGN_VALUE (strlen (module->name) + 1, 4);
392 : :
393 : 3556 : for (e = module->entries; e; e = e->next)
394 : : {
395 : 3544 : GIIrNode *node = e->data;
396 : :
397 : 3544 : size += gi_ir_node_get_full_size (node);
398 : :
399 : : /* Also reset the offset here */
400 : 3544 : node->offset = 0;
401 : : }
402 : :
403 : : /* Adjust size for strings allocated in header below specially */
404 : 12 : size += ALIGN_VALUE (strlen (module->name) + 1, 4);
405 : 12 : if (module->shared_library)
406 : 12 : size += ALIGN_VALUE (strlen (module->shared_library) + 1, 4);
407 : 12 : if (dependencies != NULL)
408 : 11 : size += ALIGN_VALUE (strlen (dependencies) + 1, 4);
409 : 12 : if (module->c_prefix != NULL)
410 : 12 : size += ALIGN_VALUE (strlen (module->c_prefix) + 1, 4);
411 : :
412 : 12 : size += sizeof (Section) * NUM_SECTIONS;
413 : :
414 : 12 : g_message ("allocating %d bytes (%d header, %d directory, %d entries)",
415 : : size, header_size, dir_size, size - header_size - dir_size);
416 : :
417 : 12 : data = g_malloc0 (size);
418 : :
419 : : /* fill in header */
420 : 12 : header = (Header *)data;
421 : 12 : memcpy (header, GI_IR_MAGIC, 16);
422 : 12 : header->major_version = 4;
423 : 12 : header->minor_version = 0;
424 : 12 : header->reserved = 0;
425 : 12 : header->n_entries = n_entries;
426 : 12 : header->n_local_entries = n_local_entries;
427 : 12 : header->n_attributes = 0;
428 : 12 : header->attributes = 0; /* filled in later */
429 : : /* NOTE: When writing strings to the typelib here, you should also update
430 : : * the size calculations above.
431 : : */
432 : 12 : if (dependencies != NULL)
433 : 11 : header->dependencies = gi_ir_write_string (dependencies, strings, data, &header_size);
434 : : else
435 : 1 : header->dependencies = 0;
436 : 12 : header->size = 0; /* filled in later */
437 : 12 : header->namespace = gi_ir_write_string (module->name, strings, data, &header_size);
438 : 12 : header->nsversion = gi_ir_write_string (module->version, strings, data, &header_size);
439 : 24 : header->shared_library = (module->shared_library?
440 : 12 : gi_ir_write_string (module->shared_library, strings, data, &header_size)
441 : 12 : : 0);
442 : 12 : if (module->c_prefix != NULL)
443 : 12 : header->c_prefix = gi_ir_write_string (module->c_prefix, strings, data, &header_size);
444 : : else
445 : 0 : header->c_prefix = 0;
446 : 12 : header->entry_blob_size = sizeof (DirEntry);
447 : 12 : header->function_blob_size = sizeof (FunctionBlob);
448 : 12 : header->callback_blob_size = sizeof (CallbackBlob);
449 : 12 : header->signal_blob_size = sizeof (SignalBlob);
450 : 12 : header->vfunc_blob_size = sizeof (VFuncBlob);
451 : 12 : header->arg_blob_size = sizeof (ArgBlob);
452 : 12 : header->property_blob_size = sizeof (PropertyBlob);
453 : 12 : header->field_blob_size = sizeof (FieldBlob);
454 : 12 : header->value_blob_size = sizeof (ValueBlob);
455 : 12 : header->constant_blob_size = sizeof (ConstantBlob);
456 : 12 : header->error_domain_blob_size = 16; /* No longer used */
457 : 12 : header->attribute_blob_size = sizeof (AttributeBlob);
458 : 12 : header->signature_blob_size = sizeof (SignatureBlob);
459 : 12 : header->enum_blob_size = sizeof (EnumBlob);
460 : 12 : header->struct_blob_size = sizeof (StructBlob);
461 : 12 : header->object_blob_size = sizeof(ObjectBlob);
462 : 12 : header->interface_blob_size = sizeof (InterfaceBlob);
463 : 12 : header->union_blob_size = sizeof (UnionBlob);
464 : :
465 : 12 : offset2 = ALIGN_VALUE (header_size, 4);
466 : 12 : header->sections = offset2;
467 : :
468 : : /* Initialize all the sections to _END/0; we fill them in later using
469 : : * alloc_section(). (Right now there's just the directory index
470 : : * though, note)
471 : : */
472 : 36 : for (i = 0; i < NUM_SECTIONS; i++)
473 : : {
474 : 24 : section = (Section*) &data[offset2];
475 : 24 : section->id = GI_SECTION_END;
476 : 24 : section->offset = 0;
477 : 24 : offset2 += sizeof(Section);
478 : : }
479 : 12 : header->directory = offset2;
480 : :
481 : : /* fill in directory and content */
482 : 12 : entry = (DirEntry *)&data[header->directory];
483 : :
484 : 12 : offset2 += dir_size;
485 : :
486 : 3556 : for (e = module->entries, i = 0; e; e = e->next, i++)
487 : : {
488 : 3549 : GIIrNode *node = e->data;
489 : :
490 : 3549 : if (strchr (node->name, '.'))
491 : : {
492 : 0 : g_error ("Names may not contain '.'");
493 : : }
494 : :
495 : : /* we picked up implicit xref nodes, start over */
496 : 3549 : if (i == n_entries)
497 : : {
498 : : GList *link;
499 : 5 : g_message ("Found implicit cross references, starting over");
500 : :
501 : 5 : g_hash_table_destroy (strings);
502 : 5 : g_hash_table_destroy (types);
503 : :
504 : : /* Reset the cached offsets */
505 : 27800 : for (link = nodes_with_attributes; link; link = link->next)
506 : 27795 : ((GIIrNode *) link->data)->offset = 0;
507 : :
508 : 5 : g_list_free (nodes_with_attributes);
509 : 5 : strings = NULL;
510 : :
511 : 5 : g_free (data);
512 : 5 : data = NULL;
513 : :
514 : 5 : goto restart;
515 : : }
516 : :
517 : 3544 : offset = offset2;
518 : :
519 : 3544 : if (node->type == GI_IR_NODE_XREF)
520 : : {
521 : 87 : const char *namespace = ((GIIrNodeXRef*)node)->namespace;
522 : :
523 : 87 : entry->blob_type = 0;
524 : 87 : entry->local = FALSE;
525 : 87 : entry->offset = gi_ir_write_string (namespace, strings, data, &offset2);
526 : 87 : entry->name = gi_ir_write_string (node->name, strings, data, &offset2);
527 : : }
528 : : else
529 : : {
530 : 3457 : GIIrTypelibBuild build = {0};
531 : 3457 : old_offset = offset;
532 : 3457 : offset2 = offset + gi_ir_node_get_size (node);
533 : :
534 : 3457 : entry->blob_type = node->type;
535 : 3457 : entry->local = TRUE;
536 : 3457 : entry->offset = offset;
537 : 3457 : entry->name = gi_ir_write_string (node->name, strings, data, &offset2);
538 : :
539 : 3457 : build.module = module;
540 : 3457 : build.strings = strings;
541 : 3457 : build.types = types;
542 : 3457 : build.nodes_with_attributes = nodes_with_attributes;
543 : 3457 : build.n_attributes = header->n_attributes;
544 : 3457 : build.data = data;
545 : 3457 : gi_ir_node_build_typelib (node, NULL, &build, &offset, &offset2, NULL);
546 : 3457 : g_clear_list (&build.stack, NULL);
547 : :
548 : 3457 : nodes_with_attributes = build.nodes_with_attributes;
549 : 3457 : header->n_attributes = build.n_attributes;
550 : :
551 : 3457 : if (offset2 > old_offset + gi_ir_node_get_full_size (node))
552 : 0 : g_error ("left a hole of %d bytes", offset2 - old_offset - gi_ir_node_get_full_size (node));
553 : : }
554 : :
555 : 3544 : entry++;
556 : : }
557 : :
558 : : /* GIBaseInfo expects the AttributeBlob array to be sorted on the field (offset) */
559 : 7 : nodes_with_attributes = g_list_sort (nodes_with_attributes, node_cmp_offset_func);
560 : :
561 : 7 : g_message ("header: %d entries, %d attributes", header->n_entries, header->n_attributes);
562 : :
563 : 7 : gi_ir_node_dump_stats ();
564 : :
565 : : /* Write attributes after the blobs */
566 : 7 : offset = offset2;
567 : 7 : header->attributes = offset;
568 : 7 : offset2 = offset + header->n_attributes * header->attribute_blob_size;
569 : :
570 : 39585 : for (e = nodes_with_attributes; e; e = e->next)
571 : : {
572 : 39578 : GIIrNode *node = e->data;
573 : 39578 : write_attributes (module, node, strings, data, &offset, &offset2);
574 : : }
575 : :
576 : 7 : g_message ("reallocating to %d bytes", offset2);
577 : :
578 : 7 : data = g_realloc (data, offset2);
579 : 7 : header = (Header*) data;
580 : :
581 : 7 : data = add_directory_index_section (data, module, &offset2);
582 : 7 : header = (Header *)data;
583 : :
584 : 7 : length = header->size = offset2;
585 : :
586 : 7 : bytes = g_bytes_new_take (g_steal_pointer (&data), length);
587 : 7 : typelib = gi_typelib_new_from_bytes (bytes, &error);
588 : 7 : g_bytes_unref (bytes);
589 : :
590 : 7 : if (!typelib)
591 : : {
592 : 0 : g_error ("error building typelib: %s",
593 : : error->message);
594 : : }
595 : :
596 : 7 : g_hash_table_destroy (strings);
597 : 7 : g_hash_table_destroy (types);
598 : 7 : g_list_free (nodes_with_attributes);
599 : 7 : g_free (dependencies);
600 : :
601 : 7 : return typelib;
602 : : }
603 : :
|