Update spec.

2005-03-15  Anders Carlsson  <andersca@imendio.com>

	* docs/iconcache.txt:
	Update spec.

	* gtk/gtkiconcache.c: (find_image_offset),
	(_gtk_icon_cache_get_icon_flags), (_gtk_icon_cache_add_icons),
	(_gtk_icon_cache_get_icon), (_gtk_icon_cache_get_icon_data):
	* gtk/gtkiconcache.h:
	Update to be able to fetch pixbuf data and icon metadata.

	* gtk/gtkicontheme.c: (theme_lookup_icon), (gtk_icon_info_free),
	(icon_info_ensure_scale_and_pixbuf):
	Use new cache functions.

	* gtk/updateiconcache.c: (foreach_remove_func), (load_icon_data),
	(maybe_cache_image_data), (scan_directory), (write_pixdata),
	(get_image_meta_data_size), (get_image_pixel_data_size),
	(get_image_data_size), (get_single_node_size), (get_bucket_size),
	(write_bucket), (main):
	Update to write pixbuf data as well as information from .icon
	files.
This commit is contained in:
Anders Carlsson 2005-03-15 13:18:25 +00:00 committed by Anders Carlsson
parent 7c12edeb93
commit 3fc42d7ab9
8 changed files with 723 additions and 52 deletions

View File

@ -1,3 +1,26 @@
2005-03-15 Anders Carlsson <andersca@imendio.com>
* docs/iconcache.txt:
Update spec.
* gtk/gtkiconcache.c: (find_image_offset),
(_gtk_icon_cache_get_icon_flags), (_gtk_icon_cache_add_icons),
(_gtk_icon_cache_get_icon), (_gtk_icon_cache_get_icon_data):
* gtk/gtkiconcache.h:
Update to be able to fetch pixbuf data and icon metadata.
* gtk/gtkicontheme.c: (theme_lookup_icon), (gtk_icon_info_free),
(icon_info_ensure_scale_and_pixbuf):
Use new cache functions.
* gtk/updateiconcache.c: (foreach_remove_func), (load_icon_data),
(maybe_cache_image_data), (scan_directory), (write_pixdata),
(get_image_meta_data_size), (get_image_pixel_data_size),
(get_image_data_size), (get_single_node_size), (get_bucket_size),
(write_bucket), (main):
Update to write pixbuf data as well as information from .icon
files.
2005-03-15 Tor Lillqvist <tml@novell.com> 2005-03-15 Tor Lillqvist <tml@novell.com>
* gdk/win32/gdkmain-win32.c (_gdk_win32_key_to_string): New * gdk/win32/gdkmain-win32.c (_gdk_win32_key_to_string): New

View File

@ -1,3 +1,26 @@
2005-03-15 Anders Carlsson <andersca@imendio.com>
* docs/iconcache.txt:
Update spec.
* gtk/gtkiconcache.c: (find_image_offset),
(_gtk_icon_cache_get_icon_flags), (_gtk_icon_cache_add_icons),
(_gtk_icon_cache_get_icon), (_gtk_icon_cache_get_icon_data):
* gtk/gtkiconcache.h:
Update to be able to fetch pixbuf data and icon metadata.
* gtk/gtkicontheme.c: (theme_lookup_icon), (gtk_icon_info_free),
(icon_info_ensure_scale_and_pixbuf):
Use new cache functions.
* gtk/updateiconcache.c: (foreach_remove_func), (load_icon_data),
(maybe_cache_image_data), (scan_directory), (write_pixdata),
(get_image_meta_data_size), (get_image_pixel_data_size),
(get_image_data_size), (get_single_node_size), (get_bucket_size),
(write_bucket), (main):
Update to write pixbuf data as well as information from .icon
files.
2005-03-15 Tor Lillqvist <tml@novell.com> 2005-03-15 Tor Lillqvist <tml@novell.com>
* gdk/win32/gdkmain-win32.c (_gdk_win32_key_to_string): New * gdk/win32/gdkmain-win32.c (_gdk_win32_key_to_string): New

View File

@ -1,3 +1,26 @@
2005-03-15 Anders Carlsson <andersca@imendio.com>
* docs/iconcache.txt:
Update spec.
* gtk/gtkiconcache.c: (find_image_offset),
(_gtk_icon_cache_get_icon_flags), (_gtk_icon_cache_add_icons),
(_gtk_icon_cache_get_icon), (_gtk_icon_cache_get_icon_data):
* gtk/gtkiconcache.h:
Update to be able to fetch pixbuf data and icon metadata.
* gtk/gtkicontheme.c: (theme_lookup_icon), (gtk_icon_info_free),
(icon_info_ensure_scale_and_pixbuf):
Use new cache functions.
* gtk/updateiconcache.c: (foreach_remove_func), (load_icon_data),
(maybe_cache_image_data), (scan_directory), (write_pixdata),
(get_image_meta_data_size), (get_image_pixel_data_size),
(get_image_data_size), (get_single_node_size), (get_bucket_size),
(write_bucket), (main):
Update to write pixbuf data as well as information from .icon
files.
2005-03-15 Tor Lillqvist <tml@novell.com> 2005-03-15 Tor Lillqvist <tml@novell.com>
* gdk/win32/gdkmain-win32.c (_gdk_win32_key_to_string): New * gdk/win32/gdkmain-win32.c (_gdk_win32_key_to_string): New

View File

@ -74,6 +74,44 @@ HAS_SUFFIX_XPM 2
HAS_SUFFIX_SVG 4 HAS_SUFFIX_SVG 4
HAS_ICON_FILE 8 HAS_ICON_FILE 8
ImageData:
4 CARD32 IMAGE_PIXEL_DATA_OFFSET
4 CARD32 IMAGE_META_DATA_OFFSET
4 CARD32 IMAGE_PIXEL_DATA_TYPE
4 CARD32 IMAGE_PIXEL_DATA_LENGTH
N/A N/A PIXEL_DATA
IMAGE_PIXEL_DATA_TYPE
0 GdkPixdata format
MetaData:
4 CARD32 EMBEDDED_RECT_OFFSET
4 CARD32 ATTACH_POINT_LIST_OFFSET
4 CARD32 DISPLAY_NAME_LIST_OFFSET
EmbeddedRect:
2 CARD16 X0
2 CARD16 Y0
2 CARD16 X1
2 CARD16 Y1
AttachPointList:
4 CARD32 N_ATTACH_POINTS
4*N_ATTACH_POINTS AttachPoint
AttachPoint:
2 CARD16 X
2 CARD16 Y
DisplayNameList:
4 CARD32 N_DISPLAY_NAMES
4*N_DISPLAY_NAMES DisplayName
DisplayName:
4 CARD32 DISPLAY_LANG_OFFSET
4 CARD32 DISPLAY_NAME_OFFSET
Notes: Notes:

View File

@ -21,6 +21,7 @@
#include "gtkdebug.h" #include "gtkdebug.h"
#include "gtkiconcache.h" #include "gtkiconcache.h"
#include <glib/gstdio.h> #include <glib/gstdio.h>
#include <gdk-pixbuf/gdk-pixdata.h>
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
#include <sys/mman.h> #include <sys/mman.h>
@ -233,7 +234,7 @@ icon_name_hash (gconstpointer key)
} }
gint gint
_gtk_icon_cache_get_icon_flags (GtkIconCache *cache, find_image_offset (GtkIconCache *cache,
const gchar *icon_name, const gchar *icon_name,
const gchar *directory) const gchar *directory)
{ {
@ -265,8 +266,9 @@ _gtk_icon_cache_get_icon_flags (GtkIconCache *cache,
chain_offset = GET_UINT32 (cache->buffer, chain_offset); chain_offset = GET_UINT32 (cache->buffer, chain_offset);
} }
if (!found) if (!found) {
return 0; return 0;
}
/* We've found an icon list, now check if we have the right icon in it */ /* We've found an icon list, now check if we have the right icon in it */
directory_index = get_directory_index (cache, directory); directory_index = get_directory_index (cache, directory);
@ -277,12 +279,27 @@ _gtk_icon_cache_get_icon_flags (GtkIconCache *cache,
{ {
if (GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * i) == if (GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * i) ==
directory_index) directory_index)
return GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * i + 2); return image_list_offset + 4 + 8 * i;
} }
return 0; return 0;
} }
gint
_gtk_icon_cache_get_icon_flags (GtkIconCache *cache,
const gchar *icon_name,
const gchar *directory)
{
guint32 image_offset;
image_offset = find_image_offset (cache, icon_name, directory);
if (!image_offset)
return 0;
return GET_UINT16 (cache->buffer, image_offset + 2);
}
void void
_gtk_icon_cache_add_icons (GtkIconCache *cache, _gtk_icon_cache_add_icons (GtkIconCache *cache,
const gchar *directory, const gchar *directory,
@ -354,4 +371,140 @@ _gtk_icon_cache_has_icon (GtkIconCache *cache,
return FALSE; return FALSE;
} }
GdkPixbuf *
_gtk_icon_cache_get_icon (GtkIconCache *cache,
const gchar *icon_name,
const gchar *directory)
{
guint32 offset, image_data_offset, pixel_data_offset;
guint32 length, type;
GdkPixbuf *pixbuf;
GdkPixdata pixdata;
GError *error = NULL;
offset = find_image_offset (cache, icon_name, directory);
image_data_offset = GET_UINT32 (cache->buffer, offset + 4);
if (!image_data_offset)
return NULL;
pixel_data_offset = GET_UINT32 (cache->buffer, image_data_offset);
type = GET_UINT32 (cache->buffer, pixel_data_offset);
if (type != 0)
{
GTK_NOTE (ICONTHEME,
g_print ("invalid pixel data type %d\n", type));
return NULL;
}
length = GET_UINT32 (cache->buffer, pixel_data_offset + 4);
if (!gdk_pixdata_deserialize (&pixdata, length,
cache->buffer + pixel_data_offset + 8,
&error))
{
GTK_NOTE (ICONTHEME,
g_print ("could not deserialize data: %s\n", error->message));
g_error_free (error);
return NULL;
}
pixbuf = gdk_pixbuf_from_pixdata (&pixdata, FALSE, &error);
if (!pixbuf)
{
GTK_NOTE (ICONTHEME,
g_print ("could not convert pixdata to pixbuf: %s\n", error->message));
g_error_free (error);
return NULL;
}
return pixbuf;
}
GtkIconData *
_gtk_icon_cache_get_icon_data (GtkIconCache *cache,
const gchar *icon_name,
const gchar *directory)
{
guint32 offset, image_data_offset, meta_data_offset;
GtkIconData *data;
int i;
offset = find_image_offset (cache, icon_name, directory);
if (!offset)
return NULL;
image_data_offset = GET_UINT32 (cache->buffer, offset + 4);
if (!image_data_offset)
return NULL;
meta_data_offset = GET_UINT32 (cache->buffer, image_data_offset + 4);
if (!meta_data_offset)
return NULL;
data = g_new0 (GtkIconData, 1);
offset = GET_UINT32 (cache->buffer, meta_data_offset);
if (offset)
{
data->has_embedded_rect = TRUE;
data->x0 = GET_UINT16 (cache->buffer, offset);
data->y0 = GET_UINT16 (cache->buffer, offset + 2);
data->x1 = GET_UINT16 (cache->buffer, offset + 4);
data->y1 = GET_UINT16 (cache->buffer, offset + 6);
}
offset = GET_UINT32 (cache->buffer, meta_data_offset + 4);
if (offset)
{
data->n_attach_points = GET_UINT32 (cache->buffer, offset);
data->attach_points = g_new (GdkPoint, data->n_attach_points);
for (i = 0; i < data->n_attach_points; i++)
{
data->attach_points[i].x = GET_UINT16 (cache->buffer, offset + 4 + 4 * i);
data->attach_points[i].y = GET_UINT16 (cache->buffer, offset + 4 + 4 * i + 2);
}
}
offset = GET_UINT32 (cache->buffer, meta_data_offset + 8);
if (offset)
{
gint n_names;
gchar *lang, *name;
gchar **langs;
GHashTable *table = g_hash_table_new (g_str_hash, g_str_equal);
n_names = GET_UINT32 (cache->buffer, offset);
for (i = 0; i < n_names; i++)
{
lang = cache->buffer + GET_UINT32 (cache->buffer, offset + 4 + 8 * i);
name = cache->buffer + GET_UINT32 (cache->buffer, offset + 4 + 8 * i + 4);
g_hash_table_insert (table, lang, name);
}
langs = (gchar **)g_get_language_names ();
for (i = 0; langs[i]; i++)
{
name = g_hash_table_lookup (table, langs[i]);
if (name)
{
data->display_name = g_strdup (name);
break;
}
}
g_hash_table_destroy (table);
}
return data;
}

View File

@ -20,8 +20,21 @@
#define __GTK_ICON_CACHE_H__ #define __GTK_ICON_CACHE_H__
#include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdk.h>
typedef struct _GtkIconCache GtkIconCache; typedef struct _GtkIconCache GtkIconCache;
typedef struct _GtkIconData GtkIconData;
struct _GtkIconData
{
gboolean has_embedded_rect;
gint x0, y0, x1, y1;
GdkPoint *attach_points;
gint n_attach_points;
gchar *display_name;
};
GtkIconCache *_gtk_icon_cache_new_for_path (const gchar *path); GtkIconCache *_gtk_icon_cache_new_for_path (const gchar *path);
gboolean _gtk_icon_cache_has_directory (GtkIconCache *cache, gboolean _gtk_icon_cache_has_directory (GtkIconCache *cache,
@ -35,6 +48,12 @@ void _gtk_icon_cache_add_icons (GtkIconCache *cache,
gint _gtk_icon_cache_get_icon_flags (GtkIconCache *cache, gint _gtk_icon_cache_get_icon_flags (GtkIconCache *cache,
const gchar *icon_name, const gchar *icon_name,
const gchar *directory); const gchar *directory);
GdkPixbuf *_gtk_icon_cache_get_icon (GtkIconCache *cache,
const gchar *icon_name,
const gchar *directory);
GtkIconData *_gtk_icon_cache_get_icon_data (GtkIconCache *cache,
const gchar *icon_name,
const gchar *directory);
GtkIconCache *_gtk_icon_cache_ref (GtkIconCache *cache); GtkIconCache *_gtk_icon_cache_ref (GtkIconCache *cache);
void _gtk_icon_cache_unref (GtkIconCache *cache); void _gtk_icon_cache_unref (GtkIconCache *cache);

View File

@ -47,8 +47,6 @@
#define DEFAULT_THEME_NAME "hicolor" #define DEFAULT_THEME_NAME "hicolor"
typedef struct _GtkIconData GtkIconData;
typedef enum typedef enum
{ {
ICON_THEME_DIR_FIXED, ICON_THEME_DIR_FIXED,
@ -113,6 +111,9 @@ struct _GtkIconInfo
#endif #endif
GdkPixbuf *builtin_pixbuf; GdkPixbuf *builtin_pixbuf;
/* Cache pixbuf (if there is any) */
GdkPixbuf *cache_pixbuf;
GtkIconData *data; GtkIconData *data;
/* Information about the directory where /* Information about the directory where
@ -151,17 +152,6 @@ typedef struct
GList *dirs; GList *dirs;
} IconTheme; } IconTheme;
struct _GtkIconData
{
gboolean has_embedded_rect;
gint x0, y0, x1, y1;
GdkPoint *attach_points;
gint n_attach_points;
gchar *display_name;
};
typedef struct typedef struct
{ {
IconThemeDirType type; IconThemeDirType type;
@ -1901,6 +1891,8 @@ theme_lookup_icon (IconTheme *theme,
if (min_dir->icon_data != NULL) if (min_dir->icon_data != NULL)
icon_info->data = g_hash_table_lookup (min_dir->icon_data, icon_name); icon_info->data = g_hash_table_lookup (min_dir->icon_data, icon_name);
else
icon_info->data = _gtk_icon_cache_get_icon_data (min_dir->cache, icon_name, min_dir->subdir);
if (icon_info->data == NULL && if (icon_info->data == NULL &&
min_dir->cache && has_icon_file) min_dir->cache && has_icon_file)
@ -1923,6 +1915,12 @@ theme_lookup_icon (IconTheme *theme,
g_free (icon_file_path); g_free (icon_file_path);
} }
if (min_dir->cache)
{
icon_info->cache_pixbuf = _gtk_icon_cache_get_icon (min_dir->cache, icon_name,
min_dir->subdir);
}
icon_info->dir_type = min_dir->type; icon_info->dir_type = min_dir->type;
icon_info->dir_size = min_dir->size; icon_info->dir_size = min_dir->size;
icon_info->threshold = min_dir->threshold; icon_info->threshold = min_dir->threshold;
@ -2334,6 +2332,8 @@ gtk_icon_info_free (GtkIconInfo *icon_info)
g_object_unref (icon_info->builtin_pixbuf); g_object_unref (icon_info->builtin_pixbuf);
if (icon_info->pixbuf) if (icon_info->pixbuf)
g_object_unref (icon_info->pixbuf); g_object_unref (icon_info->pixbuf);
if (icon_info->cache_pixbuf)
g_object_unref (icon_info->cache_pixbuf);
g_free (icon_info); g_free (icon_info);
} }
@ -2519,8 +2519,11 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info,
*/ */
if (icon_info->builtin_pixbuf) if (icon_info->builtin_pixbuf)
source_pixbuf = g_object_ref (icon_info->builtin_pixbuf); source_pixbuf = g_object_ref (icon_info->builtin_pixbuf);
else if (icon_info->cache_pixbuf)
source_pixbuf = g_object_ref (icon_info->cache_pixbuf);
else else
{ {
source_pixbuf = gdk_pixbuf_new_from_file (icon_info->filename, source_pixbuf = gdk_pixbuf_new_from_file (icon_info->filename,
&icon_info->load_error); &icon_info->load_error);
if (!source_pixbuf) if (!source_pixbuf)

View File

@ -30,6 +30,7 @@
#include <glib.h> #include <glib.h>
#include <glib/gstdio.h> #include <glib/gstdio.h>
#include <gdk-pixbuf/gdk-pixdata.h>
static gboolean force_update = FALSE; static gboolean force_update = FALSE;
static gboolean quiet = FALSE; static gboolean quiet = FALSE;
@ -41,6 +42,8 @@ static gboolean quiet = FALSE;
#define HAS_SUFFIX_PNG (1 << 2) #define HAS_SUFFIX_PNG (1 << 2)
#define HAS_ICON_FILE (1 << 3) #define HAS_ICON_FILE (1 << 3)
#define CAN_CACHE_IMAGE_DATA(flags) (((flags) & HAS_SUFFIX_PNG) || ((flags) & HAS_SUFFIX_XPM))
#define MAJOR_VERSION 1 #define MAJOR_VERSION 1
#define MINOR_VERSION 0 #define MINOR_VERSION 0
#define HASH_OFFSET 12 #define HASH_OFFSET 12
@ -82,6 +85,18 @@ typedef struct
{ {
int flags; int flags;
int dir_index; int dir_index;
gboolean has_pixdata;
GdkPixdata pixdata;
int has_embedded_rect;
int x0, y0, x1, y1;
int n_attach_points;
int *attach_points;
int n_display_names;
char **display_names;
} Image; } Image;
static gboolean static gboolean
@ -96,6 +111,8 @@ foreach_remove_func (gpointer key, gpointer value, gpointer user_data)
{ {
g_free (key); g_free (key);
g_free (image); g_free (image);
g_free (image->attach_points);
g_strfreev (image->display_names);
return TRUE; return TRUE;
} }
@ -113,6 +130,132 @@ foreach_remove_func (gpointer key, gpointer value, gpointer user_data)
return TRUE; return TRUE;
} }
static void
load_icon_data (Image *image, const char *path)
{
GKeyFile *icon_file;
char **split;
gsize length;
char *str;
char *split_point;
int i;
gint *ivalues;
GError *error = NULL;
gchar **keys;
gsize n_keys;
icon_file = g_key_file_new ();
g_key_file_set_list_separator (icon_file, ',');
g_key_file_load_from_file (icon_file, path, G_KEY_FILE_KEEP_TRANSLATIONS, &error);
if (error)
{
g_error_free (error);
return;
}
ivalues = g_key_file_get_integer_list (icon_file,
"Icon Data", "EmbeddedTextRectangle",
&length, NULL);
if (ivalues)
{
if (length == 4)
{
image->has_embedded_rect = TRUE;
image->x0 = ivalues[0];
image->y0 = ivalues[1];
image->x1 = ivalues[2];
image->y1 = ivalues[3];
}
g_free (ivalues);
}
str = g_key_file_get_string (icon_file, "Icon Data", "AttachPoints", NULL);
if (str)
{
split = g_strsplit (str, "|", -1);
image->n_attach_points = g_strv_length (split);
image->attach_points = g_new (int, 2 * image->n_attach_points);
i = 0;
while (split[i] != NULL && i < image->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);
}
i++;
}
g_strfreev (split);
g_free (str);
}
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;
for (i = 0; i < n_keys; i++)
{
gchar *lang, *name;
if (g_str_has_prefix (keys[i], "DisplayName"))
{
gchar *open, *close = NULL;
open = strchr (keys[i], '[');
if (open)
close = strchr (open, ']');
if (open && close)
{
lang = g_strndup (open + 1, close - open - 1);
name = g_key_file_get_locale_string (icon_file,
"Icon Data", "DisplayName",
lang, NULL);
}
else
{
lang = g_strdup ("C");
name = g_key_file_get_string (icon_file,
"Icon Data", "DisplayName",
NULL);
}
image->display_names[2 * image->n_display_names] = lang;
image->display_names[2 * image->n_display_names + 1] = name;
image->n_display_names++;
}
}
g_strfreev (keys);
g_key_file_free (icon_file);
}
static void
maybe_cache_image_data (Image *image, const gchar *path)
{
if (CAN_CACHE_IMAGE_DATA(image->flags) && !image->has_pixdata)
{
GdkPixbuf *pixbuf;
pixbuf = gdk_pixbuf_new_from_file (path, NULL);
if (pixbuf)
{
image->has_pixdata = TRUE;
gdk_pixdata_from_pixbuf (&image->pixdata, pixbuf, FALSE);
}
}
}
GList * GList *
scan_directory (const gchar *base_path, scan_directory (const gchar *base_path,
const gchar *subdir, const gchar *subdir,
@ -163,7 +306,6 @@ scan_directory (const gchar *base_path,
} }
retval = g_file_test (path, G_FILE_TEST_IS_REGULAR); retval = g_file_test (path, G_FILE_TEST_IS_REGULAR);
g_free (path);
if (retval) if (retval)
{ {
@ -185,7 +327,10 @@ scan_directory (const gchar *base_path,
image = g_hash_table_lookup (dir_hash, basename); image = g_hash_table_lookup (dir_hash, basename);
if (image) if (image)
{
image->flags |= flags; image->flags |= flags;
maybe_cache_image_data (image, path);
}
else else
{ {
if (!dir_added) if (!dir_added)
@ -203,12 +348,19 @@ scan_directory (const gchar *base_path,
image = g_new0 (Image, 1); image = g_new0 (Image, 1);
image->flags = flags; image->flags = flags;
image->dir_index = dir_index; image->dir_index = dir_index;
maybe_cache_image_data (image, path);
g_hash_table_insert (dir_hash, g_strdup (basename), image); g_hash_table_insert (dir_hash, g_strdup (basename), image);
} }
if (g_str_has_suffix (name, ".icon"))
load_icon_data (image, path);
g_free (basename); g_free (basename);
} }
g_free (path);
} }
g_dir_close (dir); g_dir_close (dir);
@ -313,6 +465,34 @@ write_card32 (FILE *cache, guint32 n)
return i == 1; return i == 1;
} }
gboolean
write_pixdata (FILE *cache, GdkPixdata *pixdata)
{
guint8 *s;
int len;
int i;
/* Type 0 is GdkPixdata */
if (!write_card32 (cache, 0))
return FALSE;
s = gdk_pixdata_serialize (pixdata, &len);
if (!write_card32 (cache, len))
{
g_free (s);
return FALSE;
}
i = fwrite (s, len, 1, cache);
g_free (s);
return i == 1;
}
static gboolean static gboolean
write_header (FILE *cache, guint32 dir_list_offset) write_header (FILE *cache, guint32 dir_list_offset)
{ {
@ -322,11 +502,64 @@ write_header (FILE *cache, guint32 dir_list_offset)
write_card32 (cache, dir_list_offset)); write_card32 (cache, dir_list_offset));
} }
guint
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)
{
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);
}
return len;
}
guint guint
get_single_node_size (HashNode *node) get_image_pixel_data_size (Image *image)
{
if (image->has_pixdata)
return image->pixdata.length + 8;
return 0;
}
guint
get_image_data_size (Image *image)
{
guint len;
len = 0;
len += get_image_pixel_data_size (image);
len += get_image_meta_data_size (image);
if (len > 0)
len += 8;
return len;
}
guint
get_single_node_size (HashNode *node, gboolean include_image_data)
{ {
int len = 0; int len = 0;
GList *list;
/* Node pointers */ /* Node pointers */
len += 12; len += 12;
@ -337,6 +570,15 @@ get_single_node_size (HashNode *node)
/* Image list */ /* Image list */
len += 4 + g_list_length (node->image_list) * 8; len += 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; return len;
} }
@ -347,7 +589,7 @@ get_bucket_size (HashNode *node)
while (node) while (node)
{ {
len += get_single_node_size (node); len += get_single_node_size (node, TRUE);
node = node->next; node = node->next;
} }
@ -360,8 +602,11 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
{ {
while (node != NULL) while (node != NULL)
{ {
int next_offset = *offset + get_single_node_size (node); int next_offset = *offset + get_single_node_size (node, TRUE);
int i, len; int image_data_offset = *offset + get_single_node_size (node, FALSE);
int data_offset;
int tmp;
int i, j, len;
GList *list; GList *list;
/* Chain offset */ /* Chain offset */
@ -381,7 +626,8 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
return FALSE; return FALSE;
/* Image list offset */ /* Image list offset */
if (!write_card32 (cache, *offset + 12 + ALIGN_VALUE (strlen (node->name) + 1, 4))) tmp = *offset + 12 + ALIGN_VALUE (strlen (node->name) + 1, 4);
if (!write_card32 (cache, tmp))
return FALSE; return FALSE;
/* Icon name */ /* Icon name */
@ -393,10 +639,15 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
if (!write_card32 (cache, len)) if (!write_card32 (cache, len))
return FALSE; return FALSE;
/* Image data goes right after the image list */
tmp += 4 + len * 8;
list = node->image_list; list = node->image_list;
data_offset = image_data_offset;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
{ {
Image *image = list->data; Image *image = list->data;
int image_data_size = get_image_data_size (image);
/* Directory index */ /* Directory index */
if (!write_card16 (cache, image->dir_index)) if (!write_card16 (cache, image->dir_index))
@ -407,12 +658,149 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
return FALSE; return FALSE;
/* Image data offset */ /* Image data offset */
if (image_data_size > 0)
{
if (!write_card32 (cache, data_offset))
return FALSE;
data_offset += image_data_size;
}
else
{
if (!write_card32 (cache, 0)) if (!write_card32 (cache, 0))
return FALSE; return FALSE;
}
list = list->next; list = list->next;
} }
/* Now write the image data */
list = node->image_list;
for (i = 0; i < len; i++, list = list->next)
{
Image *image = list->data;
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)
continue;
/* Pixel data */
if (pixel_data_size > 0)
{
if (!write_card32 (cache, image_data_offset + 8))
return FALSE;
}
else
{
if (!write_card32 (cache, 0))
return FALSE;
}
if (meta_data_size > 0)
{
if (!write_card32 (cache, image_data_offset + pixel_data_size + 8))
return FALSE;
}
else
{
if (!write_card32 (cache, 0))
return FALSE;
}
if (pixel_data_size > 0)
{
if (!write_pixdata (cache, &image->pixdata))
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;
}
}
}
image_data_offset += pixel_data_size + meta_data_size + 8;
}
*offset = next_offset; *offset = next_offset;
node = node->next; node = node->next;
} }
@ -643,6 +1031,7 @@ main (int argc, char **argv)
if (!force_update && is_cache_up_to_date (path)) if (!force_update && is_cache_up_to_date (path))
return 0; return 0;
g_type_init ();
build_cache (path); build_cache (path);
return 0; return 0;