X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkiconcache.c;h=7d8b3fc7395815f5020726ab1f4a46035f87e535;hb=a41b73fbc71f613e4ca90ae8b9dd3bd317d026d6;hp=4e4e7b655fd523710603e242ff5ab85fac4b530f;hpb=f45a35921aec248e0b8494a2145b907684a21fe5;p=~andy%2Fgtk diff --git a/gtk/gtkiconcache.c b/gtk/gtkiconcache.c index 4e4e7b655..7d8b3fc73 100644 --- a/gtk/gtkiconcache.c +++ b/gtk/gtkiconcache.c @@ -12,16 +12,14 @@ * 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 "gtkalias.h" +#include "gtkiconcachevalidator.h" #include #include @@ -48,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; } @@ -73,7 +74,7 @@ _gtk_icon_cache_unref (GtkIconCache *cache) g_print ("unmapping icon cache\n")); if (cache->map) - g_mapped_file_free (cache->map); + g_mapped_file_unref (cache->map); g_free (cache); } } @@ -86,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); @@ -104,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; @@ -121,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); @@ -185,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 @@ -208,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); @@ -230,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); @@ -260,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; @@ -411,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; @@ -419,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) @@ -433,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, @@ -472,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;