Commit 24a2b4c1 authored by Colin Walters's avatar Colin Walters
Browse files

Add directory index section

Use the internal perfect hashing API to add an index to the directory.

To support this, add the notion of additional "sections" to the
typelib.  A section index is inserted between the header and the
directory.

https://bugzilla.gnome.org/show_bug.cgi?id=554943
parent 0c7d259b
......@@ -23,11 +23,13 @@
#include <stdlib.h>
#include "girmodule.h"
#include "gitypelib-internal.h"
#include "girnode.h"
#define ALIGN_VALUE(this, boundary) \
(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
#define NUM_SECTIONS 2
GIrModule *
_g_ir_module_new (const gchar *name,
......@@ -220,6 +222,73 @@ node_cmp_offset_func (gconstpointer a,
return na->offset - nb->offset;
}
static void
alloc_section (guint8 *data, SectionType section_id, guint32 offset)
{
int i;
Header *header = (Header*)data;
Section *section_data = (Section*)&data[header->sections];
g_assert (section_id != GI_SECTION_END);
for (i = 0; i < NUM_SECTIONS; i++)
{
if (section_data->id == GI_SECTION_END)
{
section_data->id = section_id;
section_data->offset = offset;
return;
}
section_data++;
}
g_assert_not_reached ();
}
static guint8*
add_directory_index_section (guint8 *data, GIrModule *module, guint32 *offset2)
{
DirEntry *entry;
Header *header = (Header*)data;
GITypelibHashBuilder *dirindex_builder;
guint i, n_interfaces;
guint16 required_size;
guint32 new_offset;
dirindex_builder = _gi_typelib_hash_builder_new ();
n_interfaces = ((Header *)data)->n_local_entries;
for (i = 0; i < n_interfaces; i++)
{
entry = (DirEntry *)&data[header->directory + (i * header->entry_blob_size)];
const char *str = (const char *) (&data[entry->name]);
_gi_typelib_hash_builder_add_string (dirindex_builder, str, i);
}
if (!_gi_typelib_hash_builder_prepare (dirindex_builder))
{
/* This happens if CMPH couldn't create a perfect hash. So
* we just punt and leave no directory index section.
*/
_gi_typelib_hash_builder_destroy (dirindex_builder);
return data;
}
alloc_section (data, GI_SECTION_DIRECTORY_INDEX, *offset2);
required_size = _gi_typelib_hash_builder_get_buffer_size (dirindex_builder);
new_offset = *offset2 + ALIGN_VALUE (required_size, 4);
data = g_realloc (data, new_offset);
_gi_typelib_hash_builder_pack (dirindex_builder, ((guint8*)data) + *offset2, required_size);
*offset2 = new_offset;
_gi_typelib_hash_builder_destroy (dirindex_builder);
return data;
}
GITypelib *
_g_ir_module_build_typelib (GIrModule *module)
......@@ -241,6 +310,7 @@ _g_ir_module_build_typelib (GIrModule *module)
GList *nodes_with_attributes;
char *dependencies;
guchar *data;
Section *section;
header_size = ALIGN_VALUE (sizeof (Header), 4);
n_local_entries = g_list_length (module->entries);
......@@ -301,6 +371,8 @@ _g_ir_module_build_typelib (GIrModule *module)
if (module->c_prefix != NULL)
size += ALIGN_VALUE (strlen (module->c_prefix) + 1, 4);
size += sizeof (Section) * NUM_SECTIONS;
g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n",
size, header_size, dir_size, size - header_size - dir_size);
......@@ -333,7 +405,6 @@ _g_ir_module_build_typelib (GIrModule *module)
header->c_prefix = _g_ir_write_string (module->c_prefix, strings, data, &header_size);
else
header->c_prefix = 0;
header->directory = ALIGN_VALUE (header_size, 4);
header->entry_blob_size = sizeof (DirEntry);
header->function_blob_size = sizeof (FunctionBlob);
header->callback_blob_size = sizeof (CallbackBlob);
......@@ -353,10 +424,26 @@ _g_ir_module_build_typelib (GIrModule *module)
header->interface_blob_size = sizeof (InterfaceBlob);
header->union_blob_size = sizeof (UnionBlob);
offset2 = ALIGN_VALUE (header_size, 4);
header->sections = offset2;
/* Initialize all the sections to _END/0; we fill them in later using
* alloc_section(). (Right now there's just the directory index
* though, note)
*/
for (i = 0; i < NUM_SECTIONS; i++)
{
section = (Section*) &data[offset2];
section->id = GI_SECTION_END;
section->offset = 0;
offset2 += sizeof(Section);
}
header->directory = offset2;
/* fill in directory and content */
entry = (DirEntry *)&data[header->directory];
offset2 = header->directory + dir_size;
offset2 += dir_size;
for (e = module->entries, i = 0; e; e = e->next, i++)
{
......@@ -452,6 +539,10 @@ _g_ir_module_build_typelib (GIrModule *module)
data = g_realloc (data, offset2);
header = (Header*) data;
data = add_directory_index_section (data, module, &offset2);
header = (Header *)data;
length = header->size = offset2;
typelib = g_typelib_new_from_memory (data, length, &error);
if (!typelib)
......
......@@ -52,7 +52,7 @@ G_BEGIN_DECLS
*
* The typelib has the following general format.
*
* typelib ::= header, directory, blobs, attributes, attributedata
* typelib ::= header, section-index, directory, blobs, attributes, attributedata
*
* directory ::= list of entries
*
......@@ -233,6 +233,7 @@ typedef enum {
* write parser which continue to work if the format is extended by
* adding new fields before the first flexible array member in
* variable-size blobs.
* @sections: Offset of section blob array
*
* The header structure appears exactly once at the beginning of a typelib. It is a
* collection of meta-information, such as the number of entries and dependencies.
......@@ -278,10 +279,34 @@ typedef struct {
guint16 interface_blob_size;
guint16 union_blob_size;
guint32 sections;
/* <private> */
guint16 padding[7];
guint16 padding[5];
} Header;
typedef enum {
GI_SECTION_END = 0,
GI_SECTION_DIRECTORY_INDEX = 1
} SectionType;
/**
* Section:
* @id: A #SectionType
* @offset: Integer offset for this section
*
* A section is a blob of data that's (at least theoretically) optional,
* and may or may not be present in the typelib. Presently, just used
* for the directory index. This allows a form of dynamic extensibility
* with different tradeoffs from the format minor version.
*
*/
typedef struct {
guint32 id;
guint32 offset;
} Section;
/**
* DirEntry:
* @blob_type: A #GTypelibBlobType
......
......@@ -139,25 +139,61 @@ g_typelib_get_dir_entry (GITypelib *typelib,
return (DirEntry *)&typelib->data[header->directory + (index - 1) * header->entry_blob_size];
}
static Section *
get_section_by_id (GITypelib *typelib,
SectionType section_type)
{
Header *header = (Header *)typelib->data;
Section *section;
if (header->sections == 0)
return NULL;
for (section = (Section*)&typelib->data[header->sections];
section->id != GI_SECTION_END;
section++)
{
if (section->id == section_type)
return section;
}
return NULL;
}
DirEntry *
g_typelib_get_dir_entry_by_name (GITypelib *typelib,
g_typelib_get_dir_entry_by_name (GITypelib *typelib,
const char *name)
{
Header *header = (Header *)typelib->data;
guint n_entries = header->n_local_entries;
Section *dirindex;
gint i;
const char *entry_name;
DirEntry *entry;
guint i;
for (i = 1; i <= n_entries; i++)
dirindex = get_section_by_id (typelib, GI_SECTION_DIRECTORY_INDEX);
if (dirindex == NULL)
{
gint n_entries = ((Header *)typelib->data)->n_local_entries;
for (i = 1; i <= n_entries; i++)
{
entry = g_typelib_get_dir_entry (typelib, i);
entry_name = g_typelib_get_string (typelib, entry->name);
if (strcmp (name, entry_name) == 0)
return entry;
}
return NULL;
}
else
{
const char *entry_name;
guint8 *hash = (guint8*) &typelib->data[dirindex->offset];
guint16 index;
entry = g_typelib_get_dir_entry (typelib, i);
index = _gi_typelib_hash_search (hash, name);
entry = g_typelib_get_dir_entry (typelib, index + 1);
entry_name = g_typelib_get_string (typelib, entry->name);
if (strcmp (name, entry_name) == 0)
return entry;
return NULL;
}
return NULL;
}
DirEntry *
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment