summaryrefslogtreecommitdiff
path: root/gtk/updateiconcache.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2007-02-15 16:56:11 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2007-02-15 16:56:11 +0000
commitd775d73c83156419452bc2993b345e3a5a3fc072 (patch)
treefc69ce583ddd51435ac7dc181b0b8018bcdba7ee /gtk/updateiconcache.c
parenteab53a01e17a18257ced7e40ab684d4b51a2627f (diff)
downloadgdk-pixbuf-d775d73c83156419452bc2993b345e3a5a3fc072.tar.gz
Handle symlinked .icon files intelligently; also avoid storing duplicate
2007-02-15 Matthias Clasen <mclasen@redhat.com> * gtk/updateiconcache.c: Handle symlinked .icon files intelligently; also avoid storing duplicate strings. svn path=/trunk/; revision=17298
Diffstat (limited to 'gtk/updateiconcache.c')
-rw-r--r--gtk/updateiconcache.c681
1 files changed, 446 insertions, 235 deletions
diff --git a/gtk/updateiconcache.c b/gtk/updateiconcache.c
index a9c4cb734..ad1bb71f0 100644
--- a/gtk/updateiconcache.c
+++ b/gtk/updateiconcache.c
@@ -53,8 +53,6 @@ static gchar *var_name = "-";
#define HAS_SUFFIX_PNG (1 << 2)
#define HAS_ICON_FILE (1 << 3)
-#define CAN_CACHE_IMAGE_DATA(flags) (!index_only && (((flags) & HAS_SUFFIX_PNG) || ((flags) & HAS_SUFFIX_XPM)))
-
#define MAJOR_VERSION 1
#define MINOR_VERSION 0
#define HASH_OFFSET 12
@@ -158,13 +156,29 @@ has_theme_index (const gchar *path)
typedef struct
{
- gboolean has_pixdata;
GdkPixdata pixdata;
+ gboolean has_pixdata;
guint32 offset;
- guint pixel_data_size;
+ guint size;
} ImageData;
+typedef struct
+{
+ int has_embedded_rect;
+ int x0, y0, x1, y1;
+
+ int n_attach_points;
+ int *attach_points;
+
+ int n_display_names;
+ char **display_names;
+
+ guint32 offset;
+ gint size;
+} IconData;
+
static GHashTable *image_data_hash = NULL;
+static GHashTable *icon_data_hash = NULL;
typedef struct
{
@@ -174,16 +188,18 @@ typedef struct
ImageData *image_data;
guint pixel_data_size;
- int has_embedded_rect;
- int x0, y0, x1, y1;
-
- int n_attach_points;
- int *attach_points;
-
- int n_display_names;
- char **display_names;
+ IconData *icon_data;
+ guint icon_data_size;
} Image;
+static void
+free_icon_data (IconData *icon_data)
+{
+ g_free (icon_data->attach_points);
+ g_strfreev (icon_data->display_names);
+ g_free (icon_data);
+}
+
static gboolean
foreach_remove_func (gpointer key, gpointer value, gpointer user_data)
{
@@ -194,9 +210,9 @@ foreach_remove_func (gpointer key, gpointer value, gpointer user_data)
if (image->flags == HAS_ICON_FILE)
{
+ /* just a .icon file, throw away */
g_free (key);
- g_free (image->attach_points);
- g_strfreev (image->display_names);
+ free_icon_data (image->icon_data);
g_free (image);
return TRUE;
@@ -215,8 +231,8 @@ foreach_remove_func (gpointer key, gpointer value, gpointer user_data)
return TRUE;
}
-static void
-load_icon_data (Image *image, const char *path)
+static IconData *
+load_icon_data (const char *path)
{
GKeyFile *icon_file;
char **split;
@@ -228,6 +244,7 @@ load_icon_data (Image *image, const char *path)
GError *error = NULL;
gchar **keys;
gsize n_keys;
+ IconData *data;
icon_file = g_key_file_new ();
g_key_file_set_list_separator (icon_file, ',');
@@ -235,9 +252,13 @@ load_icon_data (Image *image, const char *path)
if (error)
{
g_error_free (error);
- return;
+ g_key_file_free (icon_file);
+
+ return NULL;
}
+ data = g_new0 (IconData, 1);
+
ivalues = g_key_file_get_integer_list (icon_file,
"Icon Data", "EmbeddedTextRectangle",
&length, NULL);
@@ -245,11 +266,11 @@ load_icon_data (Image *image, const char *path)
{
if (length == 4)
{
- image->has_embedded_rect = TRUE;
- image->x0 = ivalues[0];
- image->y0 = ivalues[1];
- image->x1 = ivalues[2];
- image->y1 = ivalues[3];
+ data->has_embedded_rect = TRUE;
+ data->x0 = ivalues[0];
+ data->y0 = ivalues[1];
+ data->x1 = ivalues[2];
+ data->y1 = ivalues[3];
}
g_free (ivalues);
@@ -260,19 +281,19 @@ load_icon_data (Image *image, const char *path)
{
split = g_strsplit (str, "|", -1);
- image->n_attach_points = g_strv_length (split);
- image->attach_points = g_new (int, 2 * image->n_attach_points);
+ data->n_attach_points = g_strv_length (split);
+ data->attach_points = g_new (int, 2 * data->n_attach_points);
i = 0;
- while (split[i] != NULL && i < image->n_attach_points)
+ while (split[i] != NULL && i < data->n_attach_points)
{
split_point = strchr (split[i], ',');
if (split_point)
{
*split_point = 0;
split_point++;
- image->attach_points[2 * i] = atoi (split[i]);
- image->attach_points[2 * i + 1] = atoi (split_point);
+ data->attach_points[2 * i] = atoi (split[i]);
+ data->attach_points[2 * i + 1] = atoi (split_point);
}
i++;
}
@@ -282,8 +303,8 @@ load_icon_data (Image *image, const char *path)
}
keys = g_key_file_get_keys (icon_file, "Icon Data", &n_keys, &error);
- image->display_names = g_new0 (gchar *, 2 * n_keys + 1);
- image->n_display_names = 0;
+ data->display_names = g_new0 (gchar *, 2 * n_keys + 1);
+ data->n_display_names = 0;
for (i = 0; i < n_keys; i++)
{
@@ -313,15 +334,23 @@ load_icon_data (Image *image, const char *path)
NULL);
}
- image->display_names[2 * image->n_display_names] = lang;
- image->display_names[2 * image->n_display_names + 1] = name;
- image->n_display_names++;
+ data->display_names[2 * data->n_display_names] = lang;
+ data->display_names[2 * data->n_display_names + 1] = name;
+ data->n_display_names++;
}
}
g_strfreev (keys);
g_key_file_free (icon_file);
+
+ /* -1 means not computed yet, the real value depends
+ * on string pool state, and will be computed
+ * later
+ */
+ data->size = -1;
+
+ return data;
}
/*
@@ -440,14 +469,14 @@ static void
maybe_cache_image_data (Image *image,
const gchar *path)
{
- if (CAN_CACHE_IMAGE_DATA(image->flags) && !image->image_data)
+ if (!index_only && !image->image_data &&
+ (g_str_has_suffix (path, ".png") || g_str_has_suffix (path, ".xpm")))
{
GdkPixbuf *pixbuf;
ImageData *idata;
gchar *path2;
idata = g_hash_table_lookup (image_data_hash, path);
-
path2 = follow_links (path);
if (path2)
@@ -487,7 +516,7 @@ maybe_cache_image_data (Image *image,
if (pixbuf)
{
gdk_pixdata_from_pixbuf (&idata->pixdata, pixbuf, FALSE);
- idata->pixel_data_size = idata->pixdata.length + 8;
+ idata->size = idata->pixdata.length + 8;
idata->has_pixdata = TRUE;
}
}
@@ -499,6 +528,55 @@ maybe_cache_image_data (Image *image,
}
}
+static void
+maybe_cache_icon_data (Image *image,
+ const gchar *path)
+{
+ if (g_str_has_suffix (path, ".icon"))
+ {
+ IconData *idata = NULL;
+ gchar *path2 = NULL;
+
+ idata = g_hash_table_lookup (icon_data_hash, path);
+ path2 = follow_links (path);
+
+ if (path2)
+ {
+ IconData *idata2;
+
+ canonicalize_filename (path2);
+
+ idata2 = g_hash_table_lookup (icon_data_hash, path2);
+
+ if (idata && idata2 && idata != idata2)
+ g_error (_("different idatas found for symlinked '%s' and '%s'\n"),
+ path, path2);
+
+ if (idata && !idata2)
+ g_hash_table_insert (icon_data_hash, g_strdup (path2), idata);
+
+ if (!idata && idata2)
+ {
+ g_hash_table_insert (icon_data_hash, g_strdup (path), idata2);
+ idata = idata2;
+ }
+ }
+
+ if (!idata)
+ {
+ idata = load_icon_data (path);
+ g_hash_table_insert (icon_data_hash, g_strdup (path), idata);
+ if (path2)
+ g_hash_table_insert (icon_data_hash, g_strdup (path2), idata);
+ }
+
+ image->icon_data = idata;
+
+ if (path2)
+ g_free (path2);
+ }
+}
+
static GList *
scan_directory (const gchar *base_path,
const gchar *subdir,
@@ -568,12 +646,7 @@ scan_directory (const gchar *base_path,
*dot = '\0';
image = g_hash_table_lookup (dir_hash, basename);
- if (image)
- {
- image->flags |= flags;
- maybe_cache_image_data (image, path);
- }
- else
+ if (!image)
{
if (!dir_added)
{
@@ -588,16 +661,15 @@ scan_directory (const gchar *base_path,
}
image = g_new0 (Image, 1);
- image->flags = flags;
image->dir_index = dir_index;
- maybe_cache_image_data (image, path);
-
g_hash_table_insert (dir_hash, g_strdup (basename), image);
}
- if (g_str_has_suffix (name, ".icon"))
- load_icon_data (image, path);
-
+ image->flags |= flags;
+
+ maybe_cache_image_data (image, path);
+ maybe_cache_icon_data (image, path);
+
g_free (basename);
}
@@ -621,6 +693,7 @@ struct _HashNode
HashNode *next;
gchar *name;
GList *image_list;
+ gint offset;
};
static guint
@@ -663,6 +736,20 @@ convert_to_hash (gpointer key, gpointer value, gpointer user_data)
return TRUE;
}
+static GHashTable *string_pool = NULL;
+
+static int
+find_string (const gchar *n)
+{
+ return GPOINTER_TO_INT (g_hash_table_lookup (string_pool, n));
+}
+
+static void
+add_string (const gchar *n, int offset)
+{
+ g_hash_table_insert (string_pool, n, GINT_TO_POINTER (offset));
+}
+
static gboolean
write_string (FILE *cache, const gchar *n)
{
@@ -676,6 +763,8 @@ write_string (FILE *cache, const gchar *n)
i = fwrite (s, l, 1, cache);
+ g_free (s);
+
return i == 1;
}
@@ -706,11 +795,12 @@ write_card32 (FILE *cache, guint32 n)
static gboolean
-write_pixdata (FILE *cache, GdkPixdata *pixdata)
+write_image_data (FILE *cache, ImageData *image_data, int offset)
{
guint8 *s;
guint len;
gint i;
+ GdkPixdata *pixdata = &image_data->pixdata;
/* Type 0 is GdkPixdata */
if (!write_card32 (cache, 0))
@@ -732,6 +822,121 @@ write_pixdata (FILE *cache, GdkPixdata *pixdata)
}
static gboolean
+write_icon_data (FILE *cache, IconData *icon_data, int offset)
+{
+ int ofs = offset + 12;
+ int j;
+ int tmp, tmp2;
+
+ if (icon_data->has_embedded_rect)
+ {
+ if (!write_card32 (cache, ofs))
+ return FALSE;
+
+ ofs += 8;
+ }
+ else
+ {
+ if (!write_card32 (cache, 0))
+ return FALSE;
+ }
+
+ if (icon_data->n_attach_points > 0)
+ {
+ if (!write_card32 (cache, ofs))
+ return FALSE;
+
+ ofs += 4 + 4 * icon_data->n_attach_points;
+ }
+ else
+ {
+ if (!write_card32 (cache, 0))
+ return FALSE;
+ }
+
+ if (icon_data->n_display_names > 0)
+ {
+ if (!write_card32 (cache, ofs))
+ return FALSE;
+ }
+ else
+ {
+ if (!write_card32 (cache, 0))
+ return FALSE;
+ }
+
+ if (icon_data->has_embedded_rect)
+ {
+ if (!write_card16 (cache, icon_data->x0) ||
+ !write_card16 (cache, icon_data->y0) ||
+ !write_card16 (cache, icon_data->x1) ||
+ !write_card16 (cache, icon_data->y1))
+ return FALSE;
+ }
+
+ if (icon_data->n_attach_points > 0)
+ {
+ if (!write_card32 (cache, icon_data->n_attach_points))
+ return FALSE;
+
+ for (j = 0; j < 2 * icon_data->n_attach_points; j++)
+ {
+ if (!write_card16 (cache, icon_data->attach_points[j]))
+ return FALSE;
+ }
+ }
+
+ if (icon_data->n_display_names > 0)
+ {
+ if (!write_card32 (cache, icon_data->n_display_names))
+ return FALSE;
+
+ ofs += 4 + 8 * icon_data->n_display_names;
+
+ tmp = ofs;
+ for (j = 0; j < 2 * icon_data->n_display_names; j++)
+ {
+ tmp2 = find_string (icon_data->display_names[j]);
+ if (tmp2 == 0 || tmp2 == -1)
+ {
+ tmp2 = tmp;
+ tmp += ALIGN_VALUE (strlen (icon_data->display_names[j]) + 1, 4);
+ /* We're playing a little game with negative
+ * offsets here to handle duplicate strings in
+ * the array.
+ */
+ add_string (icon_data->display_names[j], -tmp2);
+ }
+ else if (tmp2 < 0)
+ {
+ tmp2 = -tmp2;
+ }
+
+ if (!write_card32 (cache, tmp2))
+ return FALSE;
+
+ }
+
+ g_assert (ofs == ftell (cache));
+ for (j = 0; j < 2 * icon_data->n_display_names; j++)
+ {
+ tmp2 = find_string (icon_data->display_names[j]);
+ g_assert (tmp2 != 0 && tmp2 != -1);
+ if (tmp2 < 0)
+ {
+ tmp2 = -tmp2;
+ g_assert (tmp2 == ftell (cache));
+ add_string (icon_data->display_names[j], tmp2);
+ if (!write_string (cache, icon_data->display_names[j]))
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
write_header (FILE *cache, guint32 dir_list_offset)
{
return (write_card16 (cache, MAJOR_VERSION) &&
@@ -740,105 +945,143 @@ write_header (FILE *cache, guint32 dir_list_offset)
write_card32 (cache, dir_list_offset));
}
-static guint
+static gint
get_image_meta_data_size (Image *image)
{
gint i;
- guint len = 0;
-
- if (image->has_embedded_rect ||
- image->attach_points > 0 ||
- image->n_display_names > 0)
- len += 12;
-
- if (image->has_embedded_rect)
- len += 8;
- if (image->n_attach_points > 0)
- len += 4 + image->n_attach_points * 4;
-
- if (image->n_display_names > 0)
+ /* The complication with storing the size in both
+ * IconData and Image is necessary since we attribute
+ * the size of the IconData only to the first Image
+ * using it (at which time it is written out in the
+ * cache). Later Images just refer to the written out
+ * IconData via the offset.
+ */
+ if (image->icon_data_size == 0)
{
- len += 4 + 8 * image->n_display_names;
-
- for (i = 0; image->display_names[i]; i++)
- len += ALIGN_VALUE (strlen (image->display_names[i]) + 1, 4);
+ if (image->icon_data && image->icon_data->size < 0)
+ {
+ IconData *data = image->icon_data;
+
+ data->size = 0;
+
+ if (data->has_embedded_rect ||
+ data->attach_points > 0 ||
+ data->n_display_names > 0)
+ data->size += 12;
+
+ if (data->has_embedded_rect)
+ data->size += 8;
+
+ if (data->n_attach_points > 0)
+ data->size += 4 + data->n_attach_points * 4;
+
+ if (data->n_display_names > 0)
+ {
+ data->size += 4 + 8 * data->n_display_names;
+
+ for (i = 0; data->display_names[i]; i++)
+ {
+ int poolv;
+ if ((poolv = find_string (data->display_names[i])) == 0)
+ {
+ data->size += ALIGN_VALUE (strlen (data->display_names[i]) + 1, 4);
+ /* Adding the string to the pool with -1
+ * to indicate that it hasn't been written out
+ * to the cache yet. We still need it in the
+ * pool in case the same string occurs twice
+ * during a get_single_node_size() calculation.
+ */
+ //g_print ("adding non-written out string %s\n", data->display_names[i]);
+ add_string (data->display_names[i], -1);
+ }
+ //else
+ //g_print ("found string %s in pool: %d\n", data->display_names[i], poolv);
+ }
+ }
+
+ image->icon_data_size = data->size;
+ data->size = 0;
+ }
}
- return len;
+ g_assert (image->icon_data_size % 4 == 0);
+
+ return image->icon_data_size;
}
-static guint
+static gint
get_image_pixel_data_size (Image *image)
{
+ /* The complication with storing the size in both
+ * ImageData and Image is necessary since we attribute
+ * the size of the ImageData only to the first Image
+ * using it (at which time it is written out in the
+ * cache). Later Images just refer to the written out
+ * ImageData via the offset.
+ */
if (image->pixel_data_size == 0)
{
if (image->image_data &&
image->image_data->has_pixdata)
{
- image->pixel_data_size = image->image_data->pixel_data_size;
- image->image_data->pixel_data_size = 0;
+ image->pixel_data_size = image->image_data->size;
+ image->image_data->size = 0;
}
}
+ g_assert (image->pixel_data_size % 4 == 0);
+
return image->pixel_data_size;
}
-static guint
+static gint
get_image_data_size (Image *image)
{
- guint len;
+ gint len;
len = 0;
len += get_image_pixel_data_size (image);
len += get_image_meta_data_size (image);
-
- if (len > 0 || (image->image_data && image->image_data->has_pixdata))
+
+ /* Even if len is zero, we need to reserve space to
+ * write the ImageData, unless this is an .svg without
+ * .icon, in which case both image_data and icon_data
+ * are NULL.
+ */
+ if (len > 0 || image->image_data || image->icon_data)
len += 8;
return len;
}
-static guint
-get_single_node_size (HashNode *node, gboolean include_image_data)
+static void
+get_single_node_size (HashNode *node, int *node_size, int *image_data_size)
{
- int len = 0;
GList *list;
/* Node pointers */
- len += 12;
+ *node_size = 12;
/* Name */
- len += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ if (find_string (node->name) == 0)
+ {
+ *node_size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ add_string (node->name, -1);
+ }
/* Image list */
- len += 4 + g_list_length (node->image_list) * 8;
+ *node_size += 4 + g_list_length (node->image_list) * 8;
/* Image data */
- if (include_image_data)
- for (list = node->image_list; list; list = list->next)
- {
- Image *image = list->data;
-
- len += get_image_data_size (image);
- }
-
- return len;
-}
-
-static guint
-get_bucket_size (HashNode *node)
-{
- int len = 0;
- while (node)
+ *image_data_size = 0;
+ for (list = node->image_list; list; list = list->next)
{
- len += get_single_node_size (node, TRUE);
+ Image *image = list->data;
- node = node->next;
+ *image_data_size += get_image_data_size (image);
}
-
- return len;
}
static gboolean
@@ -846,13 +1089,25 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
{
while (node != NULL)
{
- int next_offset = *offset + get_single_node_size (node, TRUE);
- int image_data_offset = *offset + get_single_node_size (node, FALSE);
+ int node_size, image_data_size;
+ int next_offset, image_data_offset;
int data_offset;
+ int name_offset;
+ int name_size;
+ int image_list_offset;
int tmp;
- int i, j, len;
+ int i, len;
GList *list;
+
+ g_assert (*offset == ftell (cache));
+
+ node->offset = *offset;
+ get_single_node_size (node, &node_size, &image_data_size);
+ g_assert (node_size % 4 == 0);
+ g_assert (image_data_size % 4 == 0);
+ image_data_offset = *offset + node_size;
+ next_offset = *offset + node_size + image_data_size;
/* Chain offset */
if (node->next != NULL)
{
@@ -865,26 +1120,35 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
return FALSE;
}
- /* Icon name offset */
- if (!write_card32 (cache, *offset + 12))
+ name_size = 0;
+ name_offset = find_string (node->name);
+ if (name_offset <= 0)
+ {
+ name_offset = *offset + 12;
+ name_size = ALIGN_VALUE (strlen (node->name) + 1, 4);
+ add_string (node->name, name_offset);
+ }
+ if (!write_card32 (cache, name_offset))
return FALSE;
- /* Image list offset */
- tmp = *offset + 12 + ALIGN_VALUE (strlen (node->name) + 1, 4);
- if (!write_card32 (cache, tmp))
+ image_list_offset = *offset + 12 + name_size;
+ if (!write_card32 (cache, image_list_offset))
return FALSE;
/* Icon name */
- if (!write_string (cache, node->name))
- return FALSE;
-
+ if (name_size > 0)
+ {
+ if (!write_string (cache, node->name))
+ return FALSE;
+ }
+
/* Image list */
len = g_list_length (node->image_list);
if (!write_card32 (cache, len))
return FALSE;
/* Image data goes right after the image list */
- tmp += 4 + len * 8;
+ tmp = image_list_offset + 4 + len * 8;
list = node->image_list;
data_offset = image_data_offset;
@@ -931,125 +1195,39 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
/* Pixel data */
if (pixel_data_size > 0)
{
- if (!write_card32 (cache, image_data_offset + 8))
- return FALSE;
-
image->image_data->offset = image_data_offset + 8;
+ if (!write_card32 (cache, image->image_data->offset))
+ return FALSE;
}
else
{
- gint offset;
-
- if (image->image_data)
- offset = image->image_data->offset;
- else
- offset = 0;
-
- if (!write_card32 (cache, offset))
+ if (!write_card32 (cache, (guint32) image->image_data ? image->image_data->offset : 0))
return FALSE;
}
if (meta_data_size > 0)
{
- if (!write_card32 (cache, image_data_offset + pixel_data_size + 8))
+ image->icon_data->offset = image_data_offset + pixel_data_size + 8;
+ if (!write_card32 (cache, image->icon_data->offset))
return FALSE;
}
else
{
- if (!write_card32 (cache, 0))
+ if (!write_card32 (cache, image->icon_data ? image->icon_data->offset : 0))
return FALSE;
}
if (pixel_data_size > 0)
{
- if (!write_pixdata (cache, &image->image_data->pixdata))
+ if (!write_image_data (cache, image->image_data, image->image_data->offset))
return FALSE;
}
if (meta_data_size > 0)
{
- int ofs = image_data_offset + pixel_data_size + 20;
-
- if (image->has_embedded_rect)
- {
- if (!write_card32 (cache, ofs))
- return FALSE;
-
- ofs += 8;
- }
- else
- {
- if (!write_card32 (cache, 0))
- return FALSE;
- }
-
- if (image->n_attach_points > 0)
- {
- if (!write_card32 (cache, ofs))
- return FALSE;
-
- ofs += 4 + 4 * image->n_attach_points;
- }
- else
- {
- if (!write_card32 (cache, 0))
- return FALSE;
- }
-
- if (image->n_display_names > 0)
- {
- if (!write_card32 (cache, ofs))
- return FALSE;
- }
- else
- {
- if (!write_card32 (cache, 0))
- return FALSE;
- }
-
- if (image->has_embedded_rect)
- {
- if (!write_card16 (cache, image->x0) ||
- !write_card16 (cache, image->y0) ||
- !write_card16 (cache, image->x1) ||
- !write_card16 (cache, image->y1))
- return FALSE;
- }
-
- if (image->n_attach_points > 0)
- {
- if (!write_card32 (cache, image->n_attach_points))
- return FALSE;
-
- for (j = 0; j < 2 * image->n_attach_points; j++)
- {
- if (!write_card16 (cache, image->attach_points[j]))
- return FALSE;
- }
- }
-
- if (image->n_display_names > 0)
- {
- if (!write_card32 (cache, image->n_display_names))
- return FALSE;
-
- ofs += 4 + 8 * image->n_display_names;
-
- for (j = 0; j < 2 * image->n_display_names; j++)
- {
- if (!write_card32 (cache, ofs))
- return FALSE;
-
- ofs += ALIGN_VALUE (strlen (image->display_names[j]) + 1, 4);
- }
-
- for (j = 0; j < 2 * image->n_display_names; j++)
- {
- if (!write_string (cache, image->display_names[j]))
- return FALSE;
- }
- }
- }
+ if (!write_icon_data (cache, image->icon_data, image->icon_data->offset))
+ return FALSE;
+ }
image_data_offset += pixel_data_size + meta_data_size + 8;
}
@@ -1071,41 +1249,44 @@ write_hash_table (FILE *cache, HashContext *context, int *new_offset)
if (!(write_card32 (cache, context->size)))
return FALSE;
- /* Size int + size * 4 */
- node_offset = offset + 4 + context->size * 4;
-
+ offset += 4;
+ node_offset = offset + context->size * 4;
+ /* Just write zeros here, we will rewrite this later */
for (i = 0; i < context->size; i++)
{
- if (context->nodes[i] != NULL)
- {
- if (!write_card32 (cache, node_offset))
- return FALSE;
-
- node_offset += get_bucket_size (context->nodes[i]);
- }
- else
- {
- if (!write_card32 (cache, 0xffffffff))
- {
- return FALSE;
- }
- }
+ if (!write_card32 (cache, 0))
+ return FALSE;
}
- *new_offset = node_offset;
-
/* Now write the buckets */
- node_offset = offset + 4 + context->size * 4;
-
for (i = 0; i < context->size; i++)
{
if (!context->nodes[i])
continue;
+ g_assert (node_offset % 4 == 0);
if (!write_bucket (cache, context->nodes[i], &node_offset))
return FALSE;
}
+ *new_offset = node_offset;
+
+ /* Now write out the bucket offsets */
+
+ fseek (cache, offset, SEEK_SET);
+
+ for (i = 0; i < context->size; i++)
+ {
+ if (context->nodes[i] != NULL)
+ node_offset = context->nodes[i]->offset;
+ else
+ node_offset = 0xffffffff;
+ if (!write_card32 (cache, node_offset))
+ return FALSE;
+ }
+
+ fseek (cache, 0, SEEK_END);
+
return TRUE;
}
@@ -1115,6 +1296,7 @@ write_dir_index (FILE *cache, int offset, GList *directories)
int n_dirs;
GList *d;
char *dir;
+ int tmp, tmp2;
n_dirs = g_list_length (directories);
@@ -1123,21 +1305,48 @@ write_dir_index (FILE *cache, int offset, GList *directories)
offset += 4 + n_dirs * 4;
+ tmp = offset;
for (d = directories; d; d = d->next)
{
dir = d->data;
- if (!write_card32 (cache, offset))
+
+ tmp2 = find_string (dir);
+
+ if (tmp2 == 0 || tmp2 == -1)
+ {
+ tmp2 = tmp;
+ tmp += ALIGN_VALUE (strlen (dir) + 1, 4);
+ /* We're playing a little game with negative
+ * offsets here to handle duplicate strings in
+ * the array, even though that should not
+ * really happen for the directory index.
+ */
+ add_string (dir, -tmp2);
+ }
+ else if (tmp2 < 0)
+ {
+ tmp2 = -tmp2;
+ }
+
+ if (!write_card32 (cache, tmp2))
return FALSE;
-
- offset += ALIGN_VALUE (strlen (dir) + 1, 4);
}
+ g_assert (offset == ftell (cache));
for (d = directories; d; d = d->next)
{
dir = d->data;
- if (!write_string (cache, dir))
- return FALSE;
+ tmp2 = find_string (dir);
+ g_assert (tmp2 != 0 && tmp2 != -1);
+ if (tmp2 < 0)
+ {
+ tmp2 = -tmp2;
+ g_assert (tmp2 == ftell (cache));
+ add_string (dir, tmp2);
+ if (!write_string (cache, dir))
+ return FALSE;
+ }
}
return TRUE;
@@ -1214,7 +1423,9 @@ build_cache (const gchar *path)
files = g_hash_table_new (g_str_hash, g_str_equal);
image_data_hash = g_hash_table_new (g_str_hash, g_str_equal);
-
+ icon_data_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ string_pool = g_hash_table_new (g_str_hash, g_str_equal);
+
directories = scan_directory (path, NULL, files, NULL, 0);
if (g_hash_table_size (files) == 0)