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