#else
#include <utime.h>
#endif
+#include <libgen.h>
#include <glib.h>
#include <glib/gstdio.h>
return cache_stat.st_mtime >= path_stat.st_mtime;
}
+typedef struct
+{
+ gboolean has_pixdata;
+ GdkPixdata pixdata;
+ guint32 offset;
+ guint pixel_data_size;
+} ImageData;
+
+static GHashTable *image_data_hash = NULL;
+
typedef struct
{
int flags;
int dir_index;
- gboolean has_pixdata;
- GdkPixdata pixdata;
+ ImageData *image_data;
+ guint pixel_data_size;
int has_embedded_rect;
int x0, y0, x1, y1;
g_key_file_free (icon_file);
}
+/*
+ * This function was copied from gtkfilesystemunix.c, it should
+ * probably go to GLib
+ */
static void
-maybe_cache_image_data (Image *image, const gchar *path)
+canonicalize_filename (gchar *filename)
{
- if (CAN_CACHE_IMAGE_DATA(image->flags) && !image->has_pixdata)
+ gchar *p, *q;
+ gboolean last_was_slash = FALSE;
+
+ p = filename;
+ q = filename;
+
+ while (*p)
{
- GdkPixbuf *pixbuf;
+ if (*p == G_DIR_SEPARATOR)
+ {
+ if (!last_was_slash)
+ *q++ = G_DIR_SEPARATOR;
+
+ last_was_slash = TRUE;
+ }
+ else
+ {
+ if (last_was_slash && *p == '.')
+ {
+ if (*(p + 1) == G_DIR_SEPARATOR ||
+ *(p + 1) == '\0')
+ {
+ if (*(p + 1) == '\0')
+ break;
+
+ p += 1;
+ }
+ else if (*(p + 1) == '.' &&
+ (*(p + 2) == G_DIR_SEPARATOR ||
+ *(p + 2) == '\0'))
+ {
+ if (q > filename + 1)
+ {
+ q--;
+ while (q > filename + 1 &&
+ *(q - 1) != G_DIR_SEPARATOR)
+ q--;
+ }
+
+ if (*(p + 2) == '\0')
+ break;
+
+ p += 2;
+ }
+ else
+ {
+ *q++ = *p;
+ last_was_slash = FALSE;
+ }
+ }
+ else
+ {
+ *q++ = *p;
+ last_was_slash = FALSE;
+ }
+ }
+
+ p++;
+ }
+
+ if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
+ q--;
+
+ *q = '\0';
+}
+
+static gchar *
+follow_links (const gchar *path)
+{
+ gchar *target;
+ gchar *d, *s;
+ gchar *path2 = NULL;
+
+ path2 = g_strdup (path);
+ while (g_file_test (path2, G_FILE_TEST_IS_SYMLINK))
+ {
+ target = g_file_read_link (path2, NULL);
- pixbuf = gdk_pixbuf_new_from_file (path, NULL);
+ if (target)
+ {
+ if (target[0] == '/')
+ path2 = target;
+ else
+ {
+ d = dirname (path2);
+ s = g_build_path ("/", d, target, NULL);
+ g_free (target);
+ g_free (path2);
+ path2 = s;
+ }
+ }
+ else
+ break;
+ }
+
+ if (strcmp (path, path2) == 0)
+ {
+ g_free (path2);
+ path2 = NULL;
+ }
+
+ return path2;
+}
+
+static void
+maybe_cache_image_data (Image *image,
+ const gchar *path)
+{
+ if (CAN_CACHE_IMAGE_DATA(image->flags) && !image->image_data)
+ {
+ GdkPixbuf *pixbuf;
+ ImageData *idata;
+ gchar *path2;
+
+ idata = g_hash_table_lookup (image_data_hash, path);
+
+ path2 = follow_links (path);
+
+ if (path2)
+ {
+ ImageData *idata2;
+
+ canonicalize_filename (path2);
+
+ idata2 = g_hash_table_lookup (image_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 (image_data_hash, g_strdup (path2), idata);
+
+ if (!idata && idata2)
+ {
+ g_hash_table_insert (image_data_hash, g_strdup (path), idata2);
+ idata = idata2;
+ }
+ }
- if (pixbuf)
+ if (!idata)
+ {
+ idata = g_new0 (ImageData, 1);
+ g_hash_table_insert (image_data_hash, g_strdup (path), idata);
+ if (path2)
+ g_hash_table_insert (image_data_hash, g_strdup (path2), idata);
+ }
+
+ if (!idata->has_pixdata)
{
- image->has_pixdata = TRUE;
- gdk_pixdata_from_pixbuf (&image->pixdata, pixbuf, FALSE);
+ pixbuf = gdk_pixbuf_new_from_file (path, NULL);
+
+ if (pixbuf)
+ {
+ gdk_pixdata_from_pixbuf (&idata->pixdata, pixbuf, FALSE);
+ idata->pixel_data_size = idata->pixdata.length + 8;
+ idata->has_pixdata = TRUE;
+ }
}
+
+ image->image_data = idata;
+
+ if (path2)
+ g_free (path2);
}
}
}
retval = g_file_test (path, G_FILE_TEST_IS_REGULAR);
-
if (retval)
{
if (g_str_has_suffix (name, ".png"))
}
g_free (path);
-
}
g_dir_close (dir);
write_pixdata (FILE *cache, GdkPixdata *pixdata)
{
guint8 *s;
- int len;
- int i;
-
+ guint len;
+ gint i;
/* Type 0 is GdkPixdata */
if (!write_card32 (cache, 0))
guint
get_image_pixel_data_size (Image *image)
{
- if (image->has_pixdata)
- return image->pixdata.length + 8;
+ 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;
+ }
+ }
- return 0;
+ return image->pixel_data_size;
}
guint
len += get_image_pixel_data_size (image);
len += get_image_meta_data_size (image);
- if (len > 0)
+ if (len > 0 || (image->image_data && image->image_data->has_pixdata))
len += 8;
return len;
for (list = node->image_list; list; list = list->next)
{
Image *image = list->data;
-
+
len += get_image_data_size (image);
}
get_bucket_size (HashNode *node)
{
int len = 0;
-
while (node)
{
len += get_single_node_size (node, TRUE);
{
Image *image = list->data;
int image_data_size = get_image_data_size (image);
-
+
/* Directory index */
if (!write_card16 (cache, image->dir_index))
return FALSE;
return FALSE;
data_offset += image_data_size;
}
- else
+ else
{
if (!write_card32 (cache, 0))
return FALSE;
int pixel_data_size = get_image_pixel_data_size (image);
int meta_data_size = get_image_meta_data_size (image);
- if (meta_data_size + pixel_data_size == 0)
+ if (get_image_data_size (image) == 0)
continue;
/* Pixel data */
{
if (!write_card32 (cache, image_data_offset + 8))
return FALSE;
+
+ image->image_data->offset = image_data_offset + 8;
}
else
{
- if (!write_card32 (cache, 0))
+ if (!write_card32 (cache, image->image_data->offset))
return FALSE;
}
if (pixel_data_size > 0)
{
- if (!write_pixdata (cache, &image->pixdata))
+ if (!write_pixdata (cache, &image->image_data->pixdata))
return FALSE;
}
}
files = g_hash_table_new (g_str_hash, g_str_equal);
+ image_data_hash = g_hash_table_new (g_str_hash, g_str_equal);
directories = scan_directory (path, NULL, files, NULL, 0);
g_type_init ();
build_cache (path);
-
+
return 0;
}