X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkiconcache.c;h=7d8b3fc7395815f5020726ab1f4a46035f87e535;hb=bbf915118bd3ff3a871a8c8014514352037f6d10;hp=d6f685065b0e9dfd916da203aaca7cd160c8085b;hpb=97ef14b22496d5a024341e4dc5735b26231d25b1;p=~andy%2Fgtk diff --git a/gtk/gtkiconcache.c b/gtk/gtkiconcache.c index d6f685065..7d8b3fc73 100644 --- a/gtk/gtkiconcache.c +++ b/gtk/gtkiconcache.c @@ -12,15 +12,15 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ -#include +#include "config.h" #include "gtkdebug.h" #include "gtkiconcache.h" +#include "gtkiconcachevalidator.h" + #include #include @@ -46,17 +46,20 @@ #define GET_UINT16(cache, offset) (GUINT16_FROM_BE (*(guint16 *)((cache) + (offset)))) #define GET_UINT32(cache, offset) (GUINT32_FROM_BE (*(guint32 *)((cache) + (offset)))) + struct _GtkIconCache { gint ref_count; GMappedFile *map; gchar *buffer; + + guint32 last_chain_offset; }; GtkIconCache * _gtk_icon_cache_ref (GtkIconCache *cache) { - cache->ref_count ++; + cache->ref_count++; return cache; } @@ -70,7 +73,8 @@ _gtk_icon_cache_unref (GtkIconCache *cache) GTK_NOTE (ICONTHEME, g_print ("unmapping icon cache\n")); - g_mapped_file_free (cache->map); + if (cache->map) + g_mapped_file_unref (cache->map); g_free (cache); } } @@ -83,9 +87,8 @@ _gtk_icon_cache_new_for_path (const gchar *path) gchar *cache_filename; gint fd = -1; - struct stat st; - struct stat path_st; - gchar *buffer = NULL; + GStatBuf st; + GStatBuf path_st; /* Check if we have a cache file */ cache_filename = g_build_filename (path, "icon-theme.cache", NULL); @@ -101,7 +104,18 @@ _gtk_icon_cache_new_for_path (const gchar *path) if (fd < 0) goto done; - + +#ifdef G_OS_WIN32 + +/* Bug 660730: _fstat32 is only defined in msvcrt80.dll+/VS 2005+ */ +/* or possibly in the msvcrt.dll linked to by the Windows DDK */ +/* (will need to check on the Windows DDK part later) */ +#if (_MSC_VER >= 1400 || __MSVCRT_VERSION__ >= 0x0800) +#undef fstat /* Just in case */ +#define fstat _fstat32 +#endif +#endif + if (fstat (fd, &st) < 0 || st.st_size < 4) goto done; @@ -118,25 +132,32 @@ _gtk_icon_cache_new_for_path (const gchar *path) if (!map) goto done; - /* Verify version */ - buffer = g_mapped_file_get_contents (map); - if (GET_UINT16 (buffer, 0) != MAJOR_VERSION || - GET_UINT16 (buffer, 2) != MINOR_VERSION) +#ifdef G_ENABLE_DEBUG + if (gtk_get_debug_flags () & GTK_DEBUG_ICONTHEME) { - g_mapped_file_free (map); + CacheInfo info; - GTK_NOTE (ICONTHEME, - g_print ("wrong cache version\n")); - goto done; + info.cache = g_mapped_file_get_contents (map); + info.cache_size = g_mapped_file_get_length (map); + info.n_directories = 0; + info.flags = CHECK_OFFSETS|CHECK_STRINGS; + + if (!_gtk_icon_cache_validate (&info)) + { + g_mapped_file_unref (map); + g_warning ("Icon cache '%s' is invalid\n", cache_filename); + + goto done; + } } - - GTK_NOTE (ICONTHEME, - g_print ("found cache for %s\n", path)); +#endif + + GTK_NOTE (ICONTHEME, g_print ("found cache for %s\n", path)); cache = g_new0 (GtkIconCache, 1); cache->ref_count = 1; cache->map = map; - cache->buffer = buffer; + cache->buffer = g_mapped_file_get_contents (map); done: g_free (cache_filename); @@ -146,13 +167,26 @@ _gtk_icon_cache_new_for_path (const gchar *path) return cache; } -static int +GtkIconCache * +_gtk_icon_cache_new (const gchar *data) +{ + GtkIconCache *cache; + + cache = g_new0 (GtkIconCache, 1); + cache->ref_count = 1; + cache->map = NULL; + cache->buffer = (gchar *)data; + + return cache; +} + +static gint get_directory_index (GtkIconCache *cache, const gchar *directory) { guint32 dir_list_offset; - int n_dirs; - int i; + gint n_dirs; + gint i; dir_list_offset = GET_UINT32 (cache->buffer, 8); @@ -169,11 +203,11 @@ get_directory_index (GtkIconCache *cache, return -1; } -gboolean -_gtk_icon_cache_has_directory (GtkIconCache *cache, - const gchar *directory) +gint +_gtk_icon_cache_get_directory_index (GtkIconCache *cache, + const gchar *directory) { - return get_directory_index (cache, directory) != -1; + return get_directory_index (cache, directory); } static guint @@ -192,19 +226,27 @@ icon_name_hash (gconstpointer key) static gint find_image_offset (GtkIconCache *cache, const gchar *icon_name, - const gchar *directory) + gint directory_index) { guint32 hash_offset; guint32 n_buckets; guint32 chain_offset; - int hash, directory_index; + int hash; guint32 image_list_offset, n_images; - gboolean found = FALSE; int i; - + + chain_offset = cache->last_chain_offset; + if (chain_offset) + { + guint32 name_offset = GET_UINT32 (cache->buffer, chain_offset + 4); + gchar *name = cache->buffer + name_offset; + + if (strcmp (name, icon_name) == 0) + goto find_dir; + } + hash_offset = GET_UINT32 (cache->buffer, 4); n_buckets = GET_UINT32 (cache->buffer, hash_offset); - hash = icon_name_hash (icon_name) % n_buckets; chain_offset = GET_UINT32 (cache->buffer, hash_offset + 4 + 4 * hash); @@ -214,20 +256,19 @@ find_image_offset (GtkIconCache *cache, gchar *name = cache->buffer + name_offset; if (strcmp (name, icon_name) == 0) - { - found = TRUE; - break; + { + cache->last_chain_offset = chain_offset; + goto find_dir; } - + chain_offset = GET_UINT32 (cache->buffer, chain_offset); } - if (!found) { - return 0; - } + cache->last_chain_offset = 0; + return 0; +find_dir: /* We've found an icon list, now check if we have the right icon in it */ - directory_index = get_directory_index (cache, directory); image_list_offset = GET_UINT32 (cache->buffer, chain_offset + 8); n_images = GET_UINT32 (cache->buffer, image_list_offset); @@ -244,11 +285,11 @@ find_image_offset (GtkIconCache *cache, gint _gtk_icon_cache_get_icon_flags (GtkIconCache *cache, const gchar *icon_name, - const gchar *directory) + gint directory_index) { guint32 image_offset; - image_offset = find_image_offset (cache, icon_name, directory); + image_offset = find_image_offset (cache, icon_name, directory_index); if (!image_offset) return 0; @@ -327,6 +368,62 @@ _gtk_icon_cache_has_icon (GtkIconCache *cache, return FALSE; } +gboolean +_gtk_icon_cache_has_icon_in_directory (GtkIconCache *cache, + const gchar *icon_name, + const gchar *directory) +{ + guint32 hash_offset; + guint32 n_buckets; + guint32 chain_offset; + gint hash; + gboolean found_icon = FALSE; + gint directory_index; + + directory_index = get_directory_index (cache, directory); + + if (directory_index == -1) + return FALSE; + + hash_offset = GET_UINT32 (cache->buffer, 4); + n_buckets = GET_UINT32 (cache->buffer, hash_offset); + + hash = icon_name_hash (icon_name) % n_buckets; + + chain_offset = GET_UINT32 (cache->buffer, hash_offset + 4 + 4 * hash); + while (chain_offset != 0xffffffff) + { + guint32 name_offset = GET_UINT32 (cache->buffer, chain_offset + 4); + gchar *name = cache->buffer + name_offset; + + if (strcmp (name, icon_name) == 0) + { + found_icon = TRUE; + break; + } + + chain_offset = GET_UINT32 (cache->buffer, chain_offset); + } + + if (found_icon) + { + guint32 image_list_offset = GET_UINT32 (cache->buffer, chain_offset + 8); + guint32 n_images = GET_UINT32 (cache->buffer, image_list_offset); + guint32 image_offset = image_list_offset + 4; + gint i; + for (i = 0; i < n_images; i++) + { + guint16 index = GET_UINT16 (cache->buffer, image_offset); + + if (index == directory_index) + return TRUE; + image_offset += 8; + } + } + + return FALSE; +} + static void pixbuf_destroy_cb (guchar *pixels, gpointer data) @@ -339,7 +436,7 @@ pixbuf_destroy_cb (guchar *pixels, GdkPixbuf * _gtk_icon_cache_get_icon (GtkIconCache *cache, const gchar *icon_name, - const gchar *directory) + gint directory_index) { guint32 offset, image_data_offset, pixel_data_offset; guint32 length, type; @@ -347,8 +444,11 @@ _gtk_icon_cache_get_icon (GtkIconCache *cache, GdkPixdata pixdata; GError *error = NULL; - offset = find_image_offset (cache, icon_name, directory); + offset = find_image_offset (cache, icon_name, directory_index); + if (!offset) + return NULL; + image_data_offset = GET_UINT32 (cache->buffer, offset + 4); if (!image_data_offset) @@ -361,14 +461,14 @@ _gtk_icon_cache_get_icon (GtkIconCache *cache, if (type != 0) { GTK_NOTE (ICONTHEME, - g_print ("invalid pixel data type %d\n", type)); + g_print ("invalid pixel data type %u\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, + (guchar *)(cache->buffer + pixel_data_offset + 8), &error)) { GTK_NOTE (ICONTHEME, @@ -400,13 +500,13 @@ _gtk_icon_cache_get_icon (GtkIconCache *cache, GtkIconData * _gtk_icon_cache_get_icon_data (GtkIconCache *cache, const gchar *icon_name, - const gchar *directory) + gint directory_index) { guint32 offset, image_data_offset, meta_data_offset; GtkIconData *data; int i; - offset = find_image_offset (cache, icon_name, directory); + offset = find_image_offset (cache, icon_name, directory_index); if (!offset) return NULL; @@ -419,7 +519,7 @@ _gtk_icon_cache_get_icon_data (GtkIconCache *cache, if (!meta_data_offset) return NULL; - data = g_new0 (GtkIconData, 1); + data = g_slice_new0 (GtkIconData); offset = GET_UINT32 (cache->buffer, meta_data_offset); if (offset)