diff options
author | Matthias Clasen <mclasen@redhat.com> | 2007-02-15 16:56:11 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2007-02-15 16:56:11 +0000 |
commit | d775d73c83156419452bc2993b345e3a5a3fc072 (patch) | |
tree | fc69ce583ddd51435ac7dc181b0b8018bcdba7ee /gtk/updateiconcache.c | |
parent | eab53a01e17a18257ced7e40ab684d4b51a2627f (diff) | |
download | gdk-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.c | 681 |
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) |