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