]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkiconcache.c
bin: initialize out variables to zero for get_preferred_ functions.
[~andy/gtk] / gtk / gtkiconcache.c
index 55559aac12ada77ee3fb454cdc73d7a215556359..7d8b3fc7395815f5020726ab1f4a46035f87e535 100644 (file)
  * 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 <http://www.gnu.org/licenses/>.
  */
 
-#include <config.h>
+#include "config.h"
 
 #include "gtkdebug.h"
 #include "gtkiconcache.h"
+#include "gtkiconcachevalidator.h"
+
 #include <glib/gstdio.h>
 #include <gdk-pixbuf/gdk-pixdata.h>
 
 #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;
 }
 
@@ -71,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);
     }
 }
@@ -84,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);
@@ -102,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;
 
@@ -119,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);  
@@ -183,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
@@ -206,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);
@@ -228,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);
   
@@ -258,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;
@@ -409,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;
@@ -417,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)
@@ -431,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,
@@ -470,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;