Blame gtk/gtkiconcachevalidator.c

Packit Service fb6fa5
/* gtkiconcachevalidator.c
Packit Service fb6fa5
 * Copyright (C) 2007 Red Hat, Inc
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This library is free software; you can redistribute it and/or
Packit Service fb6fa5
 * modify it under the terms of the GNU Library General Public
Packit Service fb6fa5
 * License as published by the Free Software Foundation; either
Packit Service fb6fa5
 * version 2 of the License, or (at your option) any later version.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This library is distributed in the hope that it will be useful,
Packit Service fb6fa5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fb6fa5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service fb6fa5
 * Library General Public License for more details.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * You should have received a copy of the GNU Library General Public
Packit Service fb6fa5
 * License along with this library; if not, write to the
Packit Service fb6fa5
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit Service fb6fa5
 * Boston, MA 02111-1307, USA.
Packit Service fb6fa5
 */
Packit Service fb6fa5
#include "config.h"
Packit Service fb6fa5
#include "gtkiconcachevalidator.h"
Packit Service fb6fa5
Packit Service fb6fa5
#include <glib.h>
Packit Service fb6fa5
Packit Service fb6fa5
#undef GDK_PIXBUF_DISABLE_DEPRECATED
Packit Service fb6fa5
#include <gdk-pixbuf/gdk-pixdata.h>
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
#define VERBOSE(x) 
Packit Service fb6fa5
Packit Service fb6fa5
#define check(name,condition) \
Packit Service fb6fa5
  if (!(condition)) \
Packit Service fb6fa5
    { \
Packit Service fb6fa5
      VERBOSE(g_print ("bad %s\n", (name))); \
Packit Service fb6fa5
      return FALSE; \
Packit Service fb6fa5
    } 
Packit Service fb6fa5
Packit Service fb6fa5
static inline gboolean 
Packit Service fb6fa5
get_uint16 (CacheInfo *info, 
Packit Service fb6fa5
            guint32    offset, 
Packit Service fb6fa5
            guint16   *value)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (offset < info->cache_size) 
Packit Service fb6fa5
    { 
Packit Service fb6fa5
      *value = GUINT16_FROM_BE(*(guint16*)(info->cache + offset)); 
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else 
Packit Service fb6fa5
    { 
Packit Service fb6fa5
      *value = 0;
Packit Service fb6fa5
      return FALSE; 
Packit Service fb6fa5
    } 
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static inline gboolean 
Packit Service fb6fa5
get_uint32 (CacheInfo *info, 
Packit Service fb6fa5
            guint32    offset, 
Packit Service fb6fa5
            guint32   *value)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (offset < info->cache_size) 
Packit Service fb6fa5
    { 
Packit Service fb6fa5
      *value = GUINT32_FROM_BE(*(guint32*)(info->cache + offset)); 
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else 
Packit Service fb6fa5
    { 
Packit Service fb6fa5
      *value = 0;
Packit Service fb6fa5
      return FALSE; 
Packit Service fb6fa5
    } 
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_version (CacheInfo *info)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint16 major, minor;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("major version", get_uint16 (info, 0, &major) && major == 1);
Packit Service fb6fa5
  check ("minor version", get_uint16 (info, 2, &minor) && minor == 0);
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_string (CacheInfo *info, 
Packit Service fb6fa5
              guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  check ("string offset", offset < info->cache_size);
Packit Service fb6fa5
Packit Service fb6fa5
  if (info->flags & CHECK_STRINGS) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gint i;
Packit Service fb6fa5
      gchar c;
Packit Service fb6fa5
Packit Service fb6fa5
      /* assume no string is longer than 1k */
Packit Service fb6fa5
      for (i = 0; i < 1024; i++) 
Packit Service fb6fa5
        { 
Packit Service fb6fa5
          check ("string offset", offset + i < info->cache_size)
Packit Service fb6fa5
          c = *(info->cache + offset + i);
Packit Service fb6fa5
          if (c == '\0')
Packit Service fb6fa5
            break;
Packit Service fb6fa5
          check ("string content", g_ascii_isgraph (c));
Packit Service fb6fa5
        }
Packit Service fb6fa5
      check ("string length", i < 1024);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_string_utf8 (CacheInfo *info, 
Packit Service fb6fa5
                   guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  check ("string offset", offset < info->cache_size);
Packit Service fb6fa5
Packit Service fb6fa5
  if (info->flags & CHECK_STRINGS) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gint i;
Packit Service fb6fa5
      gchar c;
Packit Service fb6fa5
Packit Service fb6fa5
      /* assume no string is longer than 1k */
Packit Service fb6fa5
      for (i = 0; i < 1024; i++) 
Packit Service fb6fa5
        { 
Packit Service fb6fa5
          check ("string offset", offset + i < info->cache_size)
Packit Service fb6fa5
            c = *(info->cache + offset + i);
Packit Service fb6fa5
          if (c == '\0')
Packit Service fb6fa5
            break;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      check ("string length", i < 1024);
Packit Service fb6fa5
      check ("string utf8 data", g_utf8_validate((char *)(info->cache + offset), -1, NULL));
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_directory_list (CacheInfo *info, 
Packit Service fb6fa5
                      guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 directory_offset;
Packit Service fb6fa5
  gint i;
Packit Service fb6fa5
	
Packit Service fb6fa5
  check ("offset, directory list", get_uint32 (info, offset, &info->n_directories));
Packit Service fb6fa5
	
Packit Service fb6fa5
  for (i = 0; i < info->n_directories; i++) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      check ("offset, directory", get_uint32 (info, offset + 4 + 4 * i, &directory_offset));
Packit Service fb6fa5
      if (!check_string (info, directory_offset))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_pixel_data (CacheInfo *info, 
Packit Service fb6fa5
                  guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 type;
Packit Service fb6fa5
  guint32 length;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("offset, pixel data type", get_uint32 (info, offset, &type));
Packit Service fb6fa5
  check ("offset, pixel data length", get_uint32 (info, offset + 4, &length));
Packit Service fb6fa5
Packit Service fb6fa5
  check ("pixel data type", type == 0);
Packit Service fb6fa5
  check ("pixel data length", offset + 8 + length < info->cache_size);
Packit Service fb6fa5
Packit Service fb6fa5
  if (info->flags & CHECK_PIXBUFS) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GdkPixdata data; 
Packit Service fb6fa5
 
Packit Service fb6fa5
      check ("pixel data", gdk_pixdata_deserialize (&data, length,
Packit Service fb6fa5
                                                    (const guint8*)info->cache + offset + 8, 
Packit Service fb6fa5
                                                    NULL));
Packit Service fb6fa5
    }
Packit Service fb6fa5
	
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_embedded_rect (CacheInfo *info, 
Packit Service fb6fa5
                     guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  check ("embedded rect", offset + 4 < info->cache_size);
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_attach_point_list (CacheInfo *info, 
Packit Service fb6fa5
                         guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 n_attach_points;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("offset, attach point list", get_uint32 (info, offset, &n_attach_points));
Packit Service fb6fa5
  check ("attach points", offset + 4 + 4 * n_attach_points < info->cache_size); 
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_display_name_list (CacheInfo *info, 
Packit Service fb6fa5
                         guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 n_display_names, ofs;
Packit Service fb6fa5
  gint i;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("offset, display name list", 
Packit Service fb6fa5
         get_uint32 (info, offset, &n_display_names));
Packit Service fb6fa5
  for (i = 0; i < n_display_names; i++) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      get_uint32(info, offset + 4 + 8 * i, &ofs;;
Packit Service fb6fa5
      if (!check_string (info, ofs))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
      get_uint32(info, offset + 4 + 8 * i + 4, &ofs;;
Packit Service fb6fa5
      if (!check_string_utf8 (info, ofs))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
	
Packit Service fb6fa5
  return TRUE;	
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_meta_data (CacheInfo *info, 
Packit Service fb6fa5
                 guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 embedded_rect_offset;
Packit Service fb6fa5
  guint32 attach_point_list_offset;
Packit Service fb6fa5
  guint32 display_name_list_offset;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("offset, embedded rect", 
Packit Service fb6fa5
         get_uint32 (info, offset, &embedded_rect_offset));
Packit Service fb6fa5
  check ("offset, attach point list", 
Packit Service fb6fa5
         get_uint32 (info, offset + 4, &attach_point_list_offset));
Packit Service fb6fa5
  check ("offset, display name list", 
Packit Service fb6fa5
         get_uint32 (info, offset + 8, &display_name_list_offset));
Packit Service fb6fa5
Packit Service fb6fa5
  if (embedded_rect_offset != 0) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!check_embedded_rect (info, embedded_rect_offset))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (attach_point_list_offset != 0) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!check_attach_point_list (info, attach_point_list_offset))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (display_name_list_offset != 0) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!check_display_name_list (info, display_name_list_offset))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_image_data (CacheInfo *info, 
Packit Service fb6fa5
                  guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 pixel_data_offset;
Packit Service fb6fa5
  guint32 meta_data_offset;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("offset, pixel data", get_uint32 (info, offset, &pixel_data_offset));
Packit Service fb6fa5
  check ("offset, meta data", get_uint32 (info, offset + 4, &meta_data_offset));
Packit Service fb6fa5
Packit Service fb6fa5
  if (pixel_data_offset != 0) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!check_pixel_data (info, pixel_data_offset))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  if (meta_data_offset != 0) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!check_meta_data (info, meta_data_offset))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
	
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_image (CacheInfo *info, 
Packit Service fb6fa5
             guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint16 index;
Packit Service fb6fa5
  guint16 flags;
Packit Service fb6fa5
  guint32 image_data_offset;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("offset, image index", get_uint16 (info, offset, &index));
Packit Service fb6fa5
  check ("offset, image flags", get_uint16 (info, offset + 2, &flags));	
Packit Service fb6fa5
  check ("offset, image data offset", 
Packit Service fb6fa5
         get_uint32 (info, offset + 4, &image_data_offset));
Packit Service fb6fa5
Packit Service fb6fa5
  check ("image index", index < info->n_directories);
Packit Service fb6fa5
  check ("image flags", flags < 16);
Packit Service fb6fa5
Packit Service fb6fa5
  if (image_data_offset != 0) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!check_image_data (info, image_data_offset))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_image_list (CacheInfo *info, 
Packit Service fb6fa5
                  guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 n_images;
Packit Service fb6fa5
  gint i;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("offset, image list", get_uint32 (info, offset, &n_images));
Packit Service fb6fa5
	
Packit Service fb6fa5
  for (i = 0; i < n_images; i++) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!check_image (info, offset + 4 + 8 * i))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_icon (CacheInfo *info, 
Packit Service fb6fa5
            guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 chain_offset;
Packit Service fb6fa5
  guint32 name_offset;
Packit Service fb6fa5
  guint32 image_list_offset;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("offset, icon chain", get_uint32 (info, offset, &chain_offset));
Packit Service fb6fa5
  check ("offset, icon name", get_uint32 (info, offset + 4, &name_offset));
Packit Service fb6fa5
  check ("offset, icon image list", get_uint32 (info, offset + 8, 
Packit Service fb6fa5
         &image_list_offset));
Packit Service fb6fa5
Packit Service fb6fa5
  if (!check_string (info, name_offset))
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
  if (!check_image_list (info, image_list_offset))
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
  if (chain_offset != 0xffffffff) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!check_icon (info, chain_offset))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean 
Packit Service fb6fa5
check_hash (CacheInfo *info, 
Packit Service fb6fa5
            guint32    offset)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 n_buckets, icon_offset;
Packit Service fb6fa5
  gint i;
Packit Service fb6fa5
Packit Service fb6fa5
  check ("offset, hash size", get_uint32 (info, offset, &n_buckets));
Packit Service fb6fa5
Packit Service fb6fa5
  for (i = 0; i < n_buckets; i++) 
Packit Service fb6fa5
    {
Packit Service fb6fa5
      check ("offset, hash chain", 
Packit Service fb6fa5
             get_uint32 (info, offset + 4 + 4 * i, &icon_offset));
Packit Service fb6fa5
      if (icon_offset != 0xffffffff) 
Packit Service fb6fa5
        {
Packit Service fb6fa5
          if (!check_icon (info, icon_offset))
Packit Service fb6fa5
            return FALSE;
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/**
Packit Service fb6fa5
 * _gtk_icon_cache_validate:
Packit Service fb6fa5
 * @info: a CacheInfo structure 
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * Validates the icon cache passed in the @cache and
Packit Service fb6fa5
 * @cache_size fields of the @info structure. The
Packit Service fb6fa5
 * validator checks that offsets specified in the
Packit Service fb6fa5
 * cache do not point outside the mapped area, that
Packit Service fb6fa5
 * strings look reasonable, and that pixbufs can
Packit Service fb6fa5
 * be deserialized. The amount of validation can
Packit Service fb6fa5
 * be controlled with the @flags field.  
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * Return value: %TRUE if the cache is valid
Packit Service fb6fa5
 */
Packit Service fb6fa5
gboolean 
Packit Service fb6fa5
_gtk_icon_cache_validate (CacheInfo *info)
Packit Service fb6fa5
{
Packit Service fb6fa5
  guint32 hash_offset;
Packit Service fb6fa5
  guint32 directory_list_offset;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!check_version (info))
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
  check ("header, hash offset", get_uint32 (info, 4, &hash_offset));
Packit Service fb6fa5
  check ("header, directory list offset", get_uint32 (info, 8, &directory_list_offset));
Packit Service fb6fa5
  if (!check_directory_list (info, directory_list_offset))
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!check_hash (info, hash_offset))
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5