diff options
author | Matthias Clasen <mclasen@redhat.com> | 2007-05-01 20:00:17 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2007-05-01 20:00:17 +0000 |
commit | 2a80113304da3afab9b9d6930a95427e35a83af6 (patch) | |
tree | 1ec7be2b5a2cda68885043e8dc861b9c5b8c5563 /gtk/gtkiconcachevalidator.c | |
parent | 6bade15e6051bec14c70af1b9568091db4b35730 (diff) | |
download | gtk+-2a80113304da3afab9b9d6930a95427e35a83af6.tar.gz |
Add an icon cache validator.
2007-05-01 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkiconcachvalidator.[hc]: Add an icon cache validator.
* gtk/updateiconcache.c: Validate the generated cache before
moving it in place. Also add a --validate option to validate
an existing icon cache.
* gtk/gtkiconcache.c: Validate icon caches before using them.
* gtk/Makefile.am: Integrate it.
svn path=/trunk/; revision=17753
Diffstat (limited to 'gtk/gtkiconcachevalidator.c')
-rw-r--r-- | gtk/gtkiconcachevalidator.c | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/gtk/gtkiconcachevalidator.c b/gtk/gtkiconcachevalidator.c new file mode 100644 index 0000000000..cb1d964ba7 --- /dev/null +++ b/gtk/gtkiconcachevalidator.c @@ -0,0 +1,376 @@ +/* gtkiconcachevalidator.c + * Copyright (C) 2007 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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. + */ +#include "config.h" +#include "gtkiconcachevalidator.h" + +#include <glib.h> +#include <gdk-pixbuf/gdk-pixdata.h> + + +#define VERBOSE(x) + +#define check(name,condition) \ + if (!(condition)) \ + { \ + VERBOSE(g_print ("bad %s\n", (name))); \ + return FALSE; \ + } + +static inline gboolean +get_uint16 (CacheInfo *info, + guint32 offset, + guint16 *value) +{ + if (offset < info->cache_size) + { + *value = GUINT16_FROM_BE(*(guint16*)(info->cache + offset)); + return TRUE; + } + else + { + *value = 0; + return FALSE; + } +} + +static inline gboolean +get_uint32 (CacheInfo *info, + guint32 offset, + guint32 *value) +{ + if (offset < info->cache_size) + { + *value = GUINT32_FROM_BE(*(guint32*)(info->cache + offset)); + return TRUE; + } + else + { + *value = 0; + return FALSE; + } +} + +static gboolean +check_version (CacheInfo *info) +{ + guint16 major, minor; + + check ("major version", get_uint16 (info, 0, &major) && major == 1); + check ("minor version", get_uint16 (info, 2, &minor) && minor == 0); + + return TRUE; +} + +static gboolean +check_string (CacheInfo *info, + guint32 offset) +{ + check ("string offset", offset < info->cache_size); + + if (info->flags & CHECK_STRINGS) + { + gint i; + gchar c; + + /* assume no string is longer than 1k */ + for (i = 0; i < 1024; i++) + { + check ("string offset", offset + i < info->cache_size) + c = *(info->cache + offset + i); + if (c == '\0') + break; + check ("string content", g_ascii_isgraph (c)); + } + check ("string length", i < 1024); + } + + return TRUE; +} + +static gboolean +check_directory_list (CacheInfo *info, + guint32 offset) +{ + guint32 directory_offset; + gint i; + + check ("offset, directory list", get_uint32 (info, offset, &info->n_directories)); + + for (i = 0; i < info->n_directories; i++) + { + check ("offset, directory", get_uint32 (info, offset + 4 + 4 * i, &directory_offset)); + if (!check_string (info, directory_offset)) + return FALSE; + } + + return TRUE; +} + +static gboolean +check_pixel_data (CacheInfo *info, + guint32 offset) +{ + guint32 type; + guint32 length; + + check ("offset, pixel data type", get_uint32 (info, offset, &type)); + check ("offset, pixel data length", get_uint32 (info, offset + 4, &length)); + + check ("pixel data type", type == 0); + check ("pixel data length", offset + 8 + length < info->cache_size); + + if (info->flags & CHECK_PIXBUFS) + { + GdkPixdata data; + + check ("pixel data", gdk_pixdata_deserialize (&data, length, + info->cache + offset + 8, + NULL)); + } + + return TRUE; +} + +static gboolean +check_embedded_rect (CacheInfo *info, + guint32 offset) +{ + check ("embedded rect", offset + 4 < info->cache_size); + + return TRUE; +} + +static gboolean +check_attach_point_list (CacheInfo *info, + guint32 offset) +{ + guint32 n_attach_points; + + check ("offset, attach point list", get_uint32 (info, offset, &n_attach_points)); + check ("attach points", offset + 4 + 4 * n_attach_points < info->cache_size); + + return TRUE; +} + +static gboolean +check_display_name_list (CacheInfo *info, + guint32 offset) +{ + guint32 n_display_names; + gint i; + + check ("offset, display name list", + get_uint32 (info, offset, &n_display_names)); + for (i = 0; i < n_display_names; i++) + { + if (!check_string (info, offset + 4 + 8 * i)) + return FALSE; + if (!check_string (info, offset + 4 + 8 * i + 4)) + return FALSE; + } + + return TRUE; +} + +static gboolean +check_meta_data (CacheInfo *info, + guint32 offset) +{ + guint32 embedded_rect_offset; + guint32 attach_point_list_offset; + guint32 display_name_list_offset; + + check ("offset, embedded rect", + get_uint32 (info, offset, &embedded_rect_offset)); + check ("offset, attach point list", + get_uint32 (info, offset + 4, &attach_point_list_offset)); + check ("offset, display name list", + get_uint32 (info, offset + 8, &display_name_list_offset)); + + if (embedded_rect_offset != 0) + { + if (!check_embedded_rect (info, embedded_rect_offset)) + return FALSE; + } + + if (attach_point_list_offset != 0) + { + if (!check_attach_point_list (info, attach_point_list_offset)) + return FALSE; + } + + if (display_name_list_offset != 0) + { + if (!check_display_name_list (info, display_name_list_offset)) + return FALSE; + } + + return TRUE; +} + +static gboolean +check_image_data (CacheInfo *info, + guint32 offset) +{ + guint32 pixel_data_offset; + guint32 meta_data_offset; + + check ("offset, pixel data", get_uint32 (info, offset, &pixel_data_offset)); + check ("offset, meta data", get_uint32 (info, offset + 4, &meta_data_offset)); + + if (pixel_data_offset != 0) + { + if (!check_pixel_data (info, pixel_data_offset)) + return FALSE; + } + if (meta_data_offset != 0) + { + if (!check_meta_data (info, meta_data_offset)) + return FALSE; + } + + return TRUE; +} + +static gboolean +check_image (CacheInfo *info, + guint32 offset) +{ + guint16 index; + guint16 flags; + guint32 image_data_offset; + + check ("offset, image index", get_uint16 (info, offset, &index)); + check ("offset, image flags", get_uint16 (info, offset + 2, &flags)); + check ("offset, image data offset", + get_uint32 (info, offset + 4, &image_data_offset)); + + check ("image index", index < info->n_directories); + check ("image flags", flags == 1 || flags == 2 || flags == 4 || + flags == 9 || flags == 10 || flags == 12); + + if (image_data_offset != 0) + { + if (!check_image_data (info, image_data_offset)) + return FALSE; + } + + return TRUE; +} + +static gboolean +check_image_list (CacheInfo *info, + guint32 offset) +{ + guint32 n_images; + gint i; + + check ("offset, image list", get_uint32 (info, offset, &n_images)); + + for (i = 0; i < n_images; i++) + { + if (!check_image (info, offset + 4 + 8 * i)) + return FALSE; + } + + return TRUE; +} + +static gboolean +check_icon (CacheInfo *info, + guint32 offset) +{ + guint32 chain_offset; + guint32 name_offset; + guint32 image_list_offset; + + check ("offset, icon chain", get_uint32 (info, offset, &chain_offset)); + check ("offset, icon name", get_uint32 (info, offset + 4, &name_offset)); + check ("offset, icon image list", get_uint32 (info, offset + 8, + &image_list_offset)); + + if (!check_string (info, name_offset)) + return FALSE; + if (!check_image_list (info, image_list_offset)) + return FALSE; + if (chain_offset != 0xffffffff) + { + if (!check_icon (info, chain_offset)) + return FALSE; + } + + return TRUE; +} + +static gboolean +check_hash (CacheInfo *info, + guint32 offset) +{ + guint32 n_buckets, icon_offset; + gint i; + + check ("offset, hash size", get_uint32 (info, offset, &n_buckets)); + + for (i = 0; i < n_buckets; i++) + { + check ("offset, hash chain", + get_uint32 (info, offset + 4 + 4 * i, &icon_offset)); + if (icon_offset != 0xffffffff) + { + if (!check_icon (info, icon_offset)) + return FALSE; + } + } + + return TRUE; +} + +/** + * _gtk_icon_cache_validate: + * @info: a CacheInfo structure + * + * Validates the icon cache passed in the @cache and + * @cache_size fields of the @info structure. The + * validator checks that offsets specified in the + * cache do not point outside the mapped area, that + * strings look reasonable, and that pixbufs can + * be deserialized. The amount of validation can + * be controlled with the @flags field. + * + * Return value: %TRUE if the cache is valid + */ +gboolean +_gtk_icon_cache_validate (CacheInfo *info) +{ + guint32 hash_offset; + guint32 directory_list_offset; + + if (!check_version (info)) + return FALSE; + check ("header, hash offset", get_uint32 (info, 4, &hash_offset)); + check ("header, directory list offset", get_uint32 (info, 8, &directory_list_offset)); + if (!check_directory_list (info, directory_list_offset)) + return FALSE; + + if (!check_hash (info, hash_offset)) + return FALSE; + + return TRUE; +} + |