X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkiconcache.c;h=7d8b3fc7395815f5020726ab1f4a46035f87e535;hb=fa4878979e0a72890ca577a210ccd7cf6291dbf0;hp=afe96cecf7690e73466040d2bdd688cf3f7c8018;hpb=d4c43a42ad66a324cc84384e6970305b9742621c;p=~andy%2Fgtk
diff --git a/gtk/gtkiconcache.c b/gtk/gtkiconcache.c
index afe96cecf..7d8b3fc73 100644
--- a/gtk/gtkiconcache.c
+++ b/gtk/gtkiconcache.c
@@ -12,21 +12,24 @@
* 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
#ifdef HAVE_UNISTD_H
#include
#endif
+#ifdef G_OS_WIN32
+#include
+#endif
#include
#include
#include
@@ -43,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;
}
@@ -67,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);
}
}
@@ -80,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);
@@ -98,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;
@@ -115,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);
@@ -143,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);
@@ -166,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
@@ -189,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);
@@ -211,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);
@@ -241,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;
@@ -323,11 +367,76 @@ _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)
+{
+ GtkIconCache *cache = data;
+
+ _gtk_icon_cache_unref (cache);
+}
+
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;
@@ -335,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)
@@ -349,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,
@@ -366,8 +478,11 @@ _gtk_icon_cache_get_icon (GtkIconCache *cache,
return NULL;
}
- pixbuf = gdk_pixbuf_from_pixdata (&pixdata, FALSE, &error);
-
+ pixbuf = gdk_pixbuf_new_from_data (pixdata.pixel_data, GDK_COLORSPACE_RGB,
+ (pixdata.pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA,
+ 8, pixdata.width, pixdata.height, pixdata.rowstride,
+ (GdkPixbufDestroyNotify)pixbuf_destroy_cb,
+ cache);
if (!pixbuf)
{
GTK_NOTE (ICONTHEME,
@@ -377,19 +492,21 @@ _gtk_icon_cache_get_icon (GtkIconCache *cache,
return NULL;
}
+ _gtk_icon_cache_ref (cache);
+
return pixbuf;
}
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;
@@ -402,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)