Initial stab at getting the focus code to work.

Fri Jun  1 18:54:47 2001  Jonathan Blandford  <jrb@redhat.com>

	* gtk/gtktreeview.c: (gtk_tree_view_focus): Initial stab at
	getting the focus code to work.
	(gtk_tree_view_class_init): Add a bunch of keybindings.

	* gtk/gtktreeviewcolumn.c
	(gtk_tree_view_column_set_cell_data_func):
	s/GtkCellDataFunc/GtkTreeCellDataFunc.
	(_gtk_tree_view_column_set_tree_view): Use "notify::model" instead
	of "properties_changed" to help justify the death of the latter
	signal. (-:

	* tests/testtreefocus.c (main): Let some columns be focussable to
	test focus better.
This commit is contained in:
Jonathan Blandford
2001-06-01 23:05:46 +00:00
committed by Havoc Pennington
parent 11043de66f
commit 741c71eb93
9 changed files with 3273 additions and 130 deletions

View File

@@ -495,6 +495,7 @@ This can later be composited together with other
#GtkRcStyle structures to form a #GtkStyle.
</para>
@parent_instance:
@name:
@bg_pixmap_name:
@font_desc:

View File

@@ -1,3 +1,34 @@
2001-06-01 Havoc Pennington <hp@redhat.com>
Apply patch from sandmann@daimi.au.dk, with some tweaks.
Makes things a bit more robust, and adds test-loaders.c
which is good for finding further robustness bugs to fix.
* io-tiff.c: Try to work around libtiff suckiness a bit;
put a giant thread lock on the whole loader,
paranoically check both whether error handlers were called and
also whether functions return false. Handle case where width or
height is 0. Various cleanups.
* io-png.c (gdk_pixbuf__png_image_stop_load): only unref pixbuf
if it existed
(png_error_callback): apparently libpng expects you to longjmp out
of this thing?
* io-gif.c (struct _GifContext): remove unused "pixbuf" field
(lzw_read_byte): change "Mail jrb if this fails" g_warning
to a g_set_error()
(gif_get_lzw): check for out-of-memory
(gif_prepare_lzw): catch/report an error
(new_context): use try_malloc, since GifContext is nearly 70K
(gdk_pixbuf__gif_image_load_increment): set context->buf to NULL
so we don't crash later.
* Makefile.am: Add test-loaders
* gdk-pixbuf-loader.c (gdk_pixbuf_loader_close): handle context ==
NULL due to errors
2001-05-29 Darin Adler <darin@eazel.com>
* gdk-pixbuf.h: Fix prototype to use "(void)" instead of "()".

View File

@@ -160,8 +160,8 @@ builtin_objs = @INCLUDED_LOADER_OBJ@
endif
noinst_PROGRAMS = test-gdk-pixbuf
TESTS = test-gdk-pixbuf
TESTS = test-gdk-pixbuf test-loaders
noinst_PROGRAMS = $(TESTS)
DEPS = libgdk_pixbuf-1.3.la
INCLUDES = -I$(top_srcdir) -I$(top_builddir) \
@@ -170,11 +170,14 @@ INCLUDES = -I$(top_srcdir) -I$(top_builddir) \
@INCLUDED_LOADER_DEFINE@ \
@GTK_DEBUG_FLAGS@ \
@GDK_PIXBUF_DEP_CFLAGS@
AM_CPPFLAGS = "-DPIXBUF_LIBDIR=\"$(loaderdir)\""
AM_CPPFLAGS = "-DPIXBUF_LIBDIR=\"$(loaderdir)\"" "-DBUILT_MODULES_DIR=\"$(srcdir)/.libs\""
LDADDS = libgdk_pixbuf-1.3.la
test_gdk_pixbuf_LDADD = $(LDADDS)
test_loaders_LDADD = $(LDADDS)
test_loaders_SOURCES = test-loaders.c test-images.h
bin_PROGRAMS=make-inline-pixbuf
@@ -182,6 +185,8 @@ make_inline_pixbuf_SOURCES=make-inline-pixbuf.c
make_inline_pixbuf_LDADD = $(LDADDS)
#
# The GdkPixBuf library
#

View File

@@ -345,7 +345,7 @@ gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
g_return_val_if_fail (count >= 0, FALSE);
priv = loader->priv;
/* we expect it's not to be closed */
g_return_val_if_fail (priv->closed == FALSE, FALSE);
@@ -532,7 +532,7 @@ gdk_pixbuf_loader_close (GdkPixbufLoader *loader,
if (priv->image_module == NULL)
gdk_pixbuf_loader_load_module (loader, NULL, NULL);
if (priv->image_module && priv->image_module->stop_load)
if (priv->image_module && priv->image_module->stop_load && priv->context)
retval = priv->image_module->stop_load (priv->context, error);
priv->closed = TRUE;

View File

@@ -123,7 +123,6 @@ struct _GifContext
unsigned int frame_bit_pixel;
unsigned int aspect_ratio;
GdkPixbuf *pixbuf;
GdkPixbufGifAnim *animation;
GdkPixbufFrame *frame;
Gif89 gif89;
@@ -198,10 +197,10 @@ static int count = 0;
/* Returns TRUE if read is OK,
* FALSE if more memory is needed. */
static int
static gboolean
gif_read (GifContext *context, guchar *buffer, size_t len)
{
gint retval;
gboolean retval;
#ifdef IO_GIFDEBUG
gint i;
#endif
@@ -586,9 +585,13 @@ lzw_read_byte (GifContext *context)
int count;
unsigned char buf[260];
/*g_error (" DID WE EVER EVER GET HERE\n");*/
g_warning ("Unhandled Case. If you have an image that causes this, let me <jrb@redhat.com> know.\n");
/* FIXME - we should handle this case */
g_set_error (context->error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_FAILED,
_("GIF image loader can't understand this image."));
return -2;
if (ZeroDataBlock) {
return -2;
}
@@ -735,7 +738,15 @@ gif_get_lzw (GifContext *context)
8,
context->frame_len,
context->frame_height);
if (!context->frame->pixbuf) {
g_free (context->frame);
g_set_error (context->error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load GIF file"));
return -2;
}
context->frame->x_offset = context->x_offset;
context->frame->y_offset = context->y_offset;
context->frame->need_recomposite = TRUE;
@@ -962,6 +973,14 @@ gif_prepare_lzw (GifContext *context)
/*g_message (_("GIF: EOF / read error on image data\n"));*/
return -1;
}
if (context->lzw_set_code_size > MAX_LZW_BITS) {
g_set_error (context->error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("GIF image is corrupt (incorrect LZW compression)"));
return -2;
}
context->lzw_code_size = context->lzw_set_code_size + 1;
context->lzw_clear_code = 1 << context->lzw_set_code_size;
@@ -974,6 +993,9 @@ gif_prepare_lzw (GifContext *context)
context->code_last_byte = 0;
context->code_done = FALSE;
g_assert (context->lzw_clear_code <=
G_N_ELEMENTS (context->lzw_table[0]));
for (i = 0; i < context->lzw_clear_code; ++i) {
context->lzw_table[0][i] = 0;
context->lzw_table[1][i] = i;
@@ -1188,7 +1210,7 @@ gif_get_next_step (GifContext *context)
}
#define LOG(x)
#define LOG(x) /* g_print ("%d: %s\n", __LINE__, x); */
static gint
gif_main_loop (GifContext *context)
@@ -1269,8 +1291,12 @@ new_context (void)
{
GifContext *context;
context = g_new0 (GifContext, 1);
context = g_try_malloc (sizeof (GifContext));
if (context == NULL)
return NULL;
memset (context, 0, sizeof (GifContext));
context->animation = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM, NULL);
context->frame = NULL;
context->file = NULL;
@@ -1297,6 +1323,15 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
g_return_val_if_fail (file != NULL, NULL);
context = new_context ();
if (context == NULL) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load GIF file"));
return NULL;
}
context->file = file;
context->error = error;
@@ -1333,6 +1368,15 @@ gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
count = 0;
#endif
context = new_context ();
if (context == NULL) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load GIF file"));
return NULL;
}
context->error = error;
context->prepare_func = prepare_func;
context->update_func = update_func;
@@ -1401,8 +1445,10 @@ gdk_pixbuf__gif_image_load_increment (gpointer data,
retval = gif_main_loop (context);
if (retval == -2)
if (retval == -2) {
context->buf = NULL;
return FALSE;
}
if (retval == -1) {
/* we didn't have enough memory */
/* prepare for the next image_load_increment */
@@ -1437,6 +1483,14 @@ gdk_pixbuf__gif_image_load_animation (FILE *file,
context = new_context ();
if (context == NULL) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load GIF file"));
return NULL;
}
context->error = error;
context->file = file;

View File

@@ -1,3 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - PNG image loader
*
* Copyright (C) 1999 Mark Crichton
@@ -403,7 +404,8 @@ gdk_pixbuf__png_image_stop_load (gpointer context, GError **error)
* we have unused image data
*/
gdk_pixbuf_unref(lc->pixbuf);
if (lc->pixbuf)
gdk_pixbuf_unref (lc->pixbuf);
png_destroy_read_struct(&lc->png_read_ptr, NULL, NULL);
g_free(lc);
@@ -606,6 +608,8 @@ png_error_callback(png_structp png_read_ptr,
_("Fatal error reading PNG image file: %s"),
error_msg);
}
longjmp (png_read_ptr->jmpbuf, 1);
}
static void
@@ -639,7 +643,8 @@ gdk_pixbuf__png_image_save (FILE *f,
guchar *ptr;
guchar *pixels;
int x, y, j;
png_bytep row_ptr, data = NULL;
png_bytep row_ptr;
png_bytep data;
png_color_8 sig_bit;
int w, h, rowstride;
int has_alpha;
@@ -661,6 +666,7 @@ gdk_pixbuf__png_image_save (FILE *f,
}
#endif
}
data = NULL;
bpc = gdk_pixbuf_get_bits_per_sample (pixbuf);
w = gdk_pixbuf_get_width (pixbuf);

View File

@@ -1,3 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - TIFF image loader
*
* Copyright (C) 1999 Mark Crichton
@@ -6,6 +7,7 @@
* Authors: Mark Crichton <crichton@gimp.org>
* Federico Mena-Quintero <federico@gimp.org>
* Jonathan Blandford <jrb@redhat.com>
* Søren Sandmann <sandmann@daimi.au.dk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -42,103 +44,197 @@
#endif
typedef struct _TiffData TiffData;
struct _TiffData
typedef struct _TiffContext TiffContext;
struct _TiffContext
{
ModulePreparedNotifyFunc prepare_func;
ModuleUpdatedNotifyFunc update_func;
gpointer user_data;
gchar *tempname;
FILE *file;
gboolean all_okay;
guchar *buffer;
guint allocated;
guint used;
guint pos;
};
static GdkPixbuf *
gdk_pixbuf__tiff_image_load_real (FILE *f, TiffData *context, GError **error)
/* There's no user data for the error handlers, so we just have to
* put a big-ass lock on the whole TIFF loader
*/
G_LOCK_DEFINE_STATIC (tiff_loader);
static char *global_error = NULL;
static TIFFErrorHandler orig_error_handler = NULL;
static TIFFErrorHandler orig_warning_handler = NULL;
static void
tiff_warning_handler (const char *mod, const char *fmt, va_list ap)
{
/* Don't print anything; we should not be dumping junk to
* stderr, since that may be bad for some apps.
*/
/* libTIFF seems to occasionally warn about things that
* are really errors, so maybe we should just call tiff_error_handler
* here.
*/
}
static void
tiff_error_handler (const char *mod, const char *fmt, va_list ap)
{
if (global_error) {
/* Blah, loader called us twice */
return;
}
global_error = g_strdup_vprintf (fmt, ap);
}
static void
tiff_push_handlers (void)
{
if (global_error)
g_warning ("TIFF loader left crufty global_error around, FIXME");
orig_error_handler = TIFFSetErrorHandler (tiff_error_handler);
orig_warning_handler = TIFFSetWarningHandler (tiff_warning_handler);
}
static void
tiff_pop_handlers (void)
{
if (global_error)
g_warning ("TIFF loader left crufty global_error around, FIXME");
TIFFSetErrorHandler (orig_error_handler);
TIFFSetWarningHandler (orig_warning_handler);
}
static void
tiff_set_error (GError **error,
int error_code,
const char *msg)
{
/* Take the error message from libtiff and merge it with
* some context we provide.
*/
g_set_error (error,
GDK_PIXBUF_ERROR,
error_code,
"%s%s%s",
msg, global_error ? ": " : "", global_error);
if (global_error) {
g_free (global_error);
global_error = NULL;
}
}
static GdkPixbuf *
tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
{
TIFF *tiff;
guchar *pixels = NULL;
guchar *tmppix;
gint w, h, x, y, num_pixs, fd;
uint32 *rast, *tmp_rast;
gint w, h, x, y, num_pixs;
GdkPixbuf *pixbuf;
fd = fileno (f);
tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");
if (!tiff) {
/* We're called with the lock held. */
g_return_val_if_fail (global_error == NULL, NULL);
if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &w) || global_error) {
tiff_set_error (error,
GDK_PIXBUF_ERROR_FAILED,
_("Could not get image width (bad TIFF file)"));
return NULL;
}
if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &h) || global_error) {
tiff_set_error (error,
GDK_PIXBUF_ERROR_FAILED,
_("Could not get image height (bad TIFF file)"));
return NULL;
}
num_pixs = w * h;
if (num_pixs == 0) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Failed to open TIFF image"));
return NULL;
_("Width or height of TIFF image is zero"));
return NULL;
}
TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &h);
num_pixs = w * h;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h);
if (!pixbuf) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Insufficient memory to open TIFF file"));
TIFFClose (tiff);
return NULL;
return NULL;
}
G_UNLOCK (tiff_loader);
if (context)
(* context->prepare_func) (pixbuf, NULL, context->user_data);
G_LOCK (tiff_loader);
/* Yes, it needs to be _TIFFMalloc... */
rast = (uint32 *) _TIFFmalloc (num_pixs * sizeof (uint32));
rast = (uint32 *) _TIFFmalloc (num_pixs * sizeof (uint32));
if (!rast) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Insufficient memory to open TIFF file"));
TIFFClose (tiff);
return NULL;
return NULL;
}
if (!TIFFReadRGBAImage (tiff, w, h, rast, 0) || global_error) {
tiff_set_error (error,
GDK_PIXBUF_ERROR_FAILED,
_("Failed to load RGB data from TIFF file"));
_TIFFfree (rast);
if (TIFFReadRGBAImage (tiff, w, h, rast, 0)) {
pixels = gdk_pixbuf_get_pixels (pixbuf);
return NULL;
}
pixels = gdk_pixbuf_get_pixels (pixbuf);
g_assert (pixels);
tmppix = pixels;
for (y = 0; y < h; y++) {
/* Unexplainable...are tiffs backwards? */
/* Also looking at the GIMP plugin, this
* whole reading thing can be a bit more
* robust.
*/
tmp_rast = rast + ((h - y - 1) * w);
for (x = 0; x < w; x++) {
tmppix[0] = TIFFGetR (*tmp_rast);
tmppix[1] = TIFFGetG (*tmp_rast);
tmppix[2] = TIFFGetB (*tmp_rast);
tmppix[3] = TIFFGetA (*tmp_rast);
tmp_rast++;
tmppix += 4;
}
}
g_assert (pixels);
tmppix = pixels;
_TIFFfree (rast);
for (y = 0; y < h; y++) {
/* Unexplainable...are tiffs backwards? */
/* Also looking at the GIMP plugin, this
* whole reading thing can be a bit more
* robust.
*/
tmp_rast = rast + ((h - y - 1) * w);
for (x = 0; x < w; x++) {
tmppix[0] = TIFFGetR (*tmp_rast);
tmppix[1] = TIFFGetG (*tmp_rast);
tmppix[2] = TIFFGetB (*tmp_rast);
tmppix[3] = TIFFGetA (*tmp_rast);
tmp_rast++;
tmppix += 4;
}
}
}
_TIFFfree (rast);
TIFFClose (tiff);
if (context) {
G_UNLOCK (tiff_loader);
if (context)
(* context->update_func) (pixbuf, 0, 0, w, h, context->user_data);
gdk_pixbuf_unref (pixbuf);
}
return pixbuf;
G_LOCK (tiff_loader);
return pixbuf;
}
@@ -148,17 +244,49 @@ gdk_pixbuf__tiff_image_load_real (FILE *f, TiffData *context, GError **error)
static GdkPixbuf *
gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
{
return gdk_pixbuf__tiff_image_load_real (f, NULL, error);
TIFF *tiff;
int fd;
GdkPixbuf *pixbuf;
g_return_val_if_fail (f != NULL, NULL);
G_LOCK (tiff_loader);
tiff_push_handlers ();
fd = fileno (f);
tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");
if (!tiff) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Failed to open TIFF image"));
tiff_pop_handlers ();
G_UNLOCK (tiff_loader);
return NULL;
}
pixbuf = tiff_image_parse (tiff, NULL, error);
TIFFClose (tiff);
if (global_error) {
tiff_set_error (error,
GDK_PIXBUF_ERROR_FAILED,
_("TIFFClose operation failed"));
}
tiff_pop_handlers ();
G_UNLOCK (tiff_loader);
return pixbuf;
}
/* Progressive loader */
/*
* Tiff loading progressively cannot be done. We write it to a file, then load
* the file when it's done. It's not pretty.
*/
static gpointer
gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func,
@@ -166,54 +294,165 @@ gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func,
gpointer user_data,
GError **error)
{
TiffData *context;
gint fd;
context = g_new (TiffData, 1);
TiffContext *context;
context = g_new0 (TiffContext, 1);
context->prepare_func = prepare_func;
context->update_func = update_func;
context->user_data = user_data;
context->all_okay = TRUE;
fd = g_file_open_tmp ("gdkpixbuf-tif-tmp.XXXXXX", &context->tempname,
NULL);
if (fd < 0) {
g_free (context);
return NULL;
}
context->file = fdopen (fd, "w");
if (context->file == NULL) {
g_free (context->tempname);
g_free (context);
return NULL;
}
context->buffer = NULL;
context->allocated = 0;
context->used = 0;
context->pos = 0;
return context;
}
static tsize_t
tiff_read (thandle_t handle, tdata_t buf, tsize_t size)
{
TiffContext *context = (TiffContext *)handle;
if (context->pos + size > context->used)
return 0;
memcpy (buf, context->buffer + context->pos, size);
context->pos += size;
return size;
}
static tsize_t
tiff_write (thandle_t handle, tdata_t buf, tsize_t size)
{
return -1;
}
static toff_t
tiff_seek (thandle_t handle, toff_t offset, int whence)
{
TiffContext *context = (TiffContext *)handle;
switch (whence) {
case SEEK_SET:
if (offset > context->used || offset < 0)
return -1;
context->pos = offset;
break;
case SEEK_CUR:
if (offset + context->pos >= context->used)
return -1;
context->pos += offset;
break;
case SEEK_END:
if (offset + context->used > context->used)
return -1;
context->pos = context->used + offset;
break;
default:
return -1;
break;
}
return context->pos;
}
static int
tiff_close (thandle_t context)
{
return 0;
}
static toff_t
tiff_size (thandle_t handle)
{
TiffContext *context = (TiffContext *)handle;
return context->used;
}
static int
tiff_map_file (thandle_t handle, tdata_t *buf, toff_t *size)
{
TiffContext *context = (TiffContext *)handle;
*buf = context->buffer;
*size = context->used;
return 0;
}
static void
tiff_unmap_file (thandle_t handle, tdata_t data, toff_t offset)
{
}
static gboolean
gdk_pixbuf__tiff_image_stop_load (gpointer data,
GError **error)
{
TiffData *context = (TiffData*) data;
gboolean retval = FALSE;
TiffContext *context = data;
TIFF *tiff;
gboolean retval;
g_return_val_if_fail (data != NULL, TRUE);
g_return_val_if_fail (data != NULL, FALSE);
fflush (context->file);
rewind (context->file);
if (context->all_okay) {
G_LOCK (tiff_loader);
tiff_push_handlers ();
tiff = TIFFClientOpen ("libtiff-pixbuf", "r", data,
tiff_read, tiff_write,
tiff_seek, tiff_close,
tiff_size,
tiff_map_file, tiff_unmap_file);
if (!tiff) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_FAILED,
_("Failed to load TIFF image"));
retval = FALSE;
} else {
GdkPixbuf *pixbuf;
pixbuf = gdk_pixbuf__tiff_image_load_real (context->file, context, error);
if (pixbuf != NULL)
retval = TRUE;
pixbuf = tiff_image_parse (tiff, context, error);
if (pixbuf)
g_object_unref (G_OBJECT (pixbuf));
retval = pixbuf != NULL;
TIFFClose (tiff);
}
if (global_error)
g_warning ("Error left set in TIFF loader\n");
g_free (context->buffer);
g_free (context);
fclose (context->file);
unlink (context->tempname);
g_free (context->tempname);
g_free ((TiffData *) context);
tiff_pop_handlers ();
G_UNLOCK (tiff_loader);
return retval;
}
static gboolean
make_available_at_least (TiffContext *context, guint needed)
{
guchar *new_buffer = NULL;
guint need_alloc;
need_alloc = context->used + needed;
if (need_alloc > context->allocated) {
guint new_size = 1;
while (new_size < need_alloc)
new_size *= 2;
new_buffer = g_try_realloc (context->buffer, new_size);
if (new_buffer) {
context->buffer = new_buffer;
context->allocated = new_size;
return TRUE;
}
return FALSE;
}
return TRUE;
}
@@ -221,28 +460,28 @@ static gboolean
gdk_pixbuf__tiff_image_load_increment (gpointer data, const guchar *buf,
guint size, GError **error)
{
TiffData *context = (TiffData *) data;
TiffContext *context = (TiffContext *) data;
g_return_val_if_fail (data != NULL, FALSE);
if (fwrite (buf, sizeof (guchar), size, context->file) != size) {
context->all_okay = FALSE;
if (!make_available_at_least (context, size)) {
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
_("Failed to write to temporary file when loading TIFF image"));
return FALSE;
}
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Insufficient memory to open TIFF file"));
return FALSE;
}
memcpy (context->buffer + context->used, buf, size);
context->used += size;
return TRUE;
}
void
gdk_pixbuf__tiff_fill_vtable (GdkPixbufModule *module)
{
module->load = gdk_pixbuf__tiff_image_load;
module->begin_load = gdk_pixbuf__tiff_image_begin_load;
module->stop_load = gdk_pixbuf__tiff_image_stop_load;
module->load_increment = gdk_pixbuf__tiff_image_load_increment;
module->load = gdk_pixbuf__tiff_image_load;
module->begin_load = gdk_pixbuf__tiff_image_begin_load;
module->stop_load = gdk_pixbuf__tiff_image_stop_load;
module->load_increment = gdk_pixbuf__tiff_image_load_increment;
}

2362
gdk-pixbuf/test-images.h Normal file

File diff suppressed because it is too large Load Diff

445
gdk-pixbuf/test-loaders.c Normal file
View File

@@ -0,0 +1,445 @@
/* -*- Mode: C; c-basic-offset: 2; -*- */
/* GdkPixbuf library - test loaders
*
* Copyright (C) 2001 Søren Sandmann (sandmann@daimi.au.dk)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include "gdk-pixbuf.h"
#include <stdio.h>
#include <stdlib.h>
#include "test-images.h"
#include <time.h>
#include <string.h>
#define PRETEND_MEM_SIZE (16 * 1024 * 1024)
#define REMAINING_MEM_SIZE 5000
static int current_allocation = 0;
static int max_allocation = 0;
#define HEADER_SPACE sizeof(void*)
static gpointer
record_bytes (gpointer mem, gsize bytes)
{
if (mem == NULL ||
(current_allocation + bytes) > max_allocation)
{
if (mem)
free (mem);
return NULL;
}
*(void **)mem = GINT_TO_POINTER (bytes);
g_assert (GPOINTER_TO_INT (*(void**)mem) == bytes);
g_assert (current_allocation >= 0);
current_allocation += bytes;
g_assert (current_allocation >= 0);
g_assert ( mem == (void*) ((((char*)mem) + HEADER_SPACE) - HEADER_SPACE) );
return ((char*)mem) + HEADER_SPACE;
}
static gpointer
limited_try_malloc (gsize n_bytes)
{
return record_bytes (malloc (n_bytes + HEADER_SPACE), n_bytes);
}
static gpointer
limited_malloc (gsize n_bytes)
{
return limited_try_malloc (n_bytes);
}
static gpointer
limited_calloc (gsize n_blocks,
gsize n_block_bytes)
{
int bytes = n_blocks * n_block_bytes + HEADER_SPACE;
gpointer mem = malloc (bytes);
memset (mem, 0, bytes);
return record_bytes (mem, n_blocks * n_block_bytes);
}
static void
limited_free (gpointer mem)
{
gpointer real = ((char*)mem) - HEADER_SPACE;
g_assert (current_allocation >= 0);
current_allocation -= GPOINTER_TO_INT (*(void**)real);
g_assert (current_allocation >= 0);
free (real);
}
static gpointer
limited_try_realloc (gpointer mem,
gsize n_bytes)
{
if (mem == NULL)
{
return limited_try_malloc (n_bytes);
}
else
{
gpointer real;
g_assert (mem);
real = ((char*)mem) - HEADER_SPACE;
g_assert (current_allocation >= 0);
current_allocation -= GPOINTER_TO_INT (*(void**)real);
g_assert (current_allocation >= 0);
return record_bytes (realloc (real, n_bytes + HEADER_SPACE), n_bytes);
}
}
static gpointer
limited_realloc (gpointer mem,
gsize n_bytes)
{
return limited_try_realloc (mem, n_bytes);
}
static GMemVTable limited_table = {
limited_malloc,
limited_realloc,
limited_free,
limited_calloc,
limited_try_malloc,
limited_try_realloc
};
static gboolean
test_loader (const guchar *bytes, gsize len, gboolean data_is_ok)
{
GdkPixbufLoader *loader;
GError *err = NULL;
gboolean did_fail = FALSE;
loader = gdk_pixbuf_loader_new ();
gdk_pixbuf_loader_write (loader, bytes, len, &err);
if (err)
{
g_error_free (err);
err = NULL;
did_fail = TRUE;
}
gdk_pixbuf_loader_close (loader, NULL);
if (err)
{
g_error_free (err);
err = NULL;
did_fail = TRUE;
}
g_object_unref (G_OBJECT (loader));
if (data_is_ok == did_fail)
return FALSE;
else
return TRUE;
}
static void
mem_test (const guchar *bytes, gsize len)
{
gboolean did_fail = FALSE;
GError *err = NULL;
GdkPixbufLoader *loader;
GList *loaders = NULL;
GList *i;
do {
loader = gdk_pixbuf_loader_new ();
gdk_pixbuf_loader_write (loader, bytes, len, &err);
if (err)
{
g_error_free (err);
err = NULL;
did_fail = TRUE;
}
gdk_pixbuf_loader_close (loader, NULL);
if (err)
{
g_error_free (err);
err = NULL;
did_fail = TRUE;
}
loaders = g_list_prepend (loaders, loader);
} while (!did_fail);
for (i = loaders; i != NULL; i = i->next)
g_object_unref (G_OBJECT (i->data));
g_list_free (loaders);
}
void
assault (const gchar *header, gsize header_size,
int n_images, gboolean verbose)
{
enum { N_CHARACTERS = 10000 };
int j;
for (j = 0; j < n_images; ++j)
{
GError *err = NULL;
int i;
GdkPixbufLoader *loader;
if (verbose)
g_print ("'img' no: %d\n", j);
loader = gdk_pixbuf_loader_new ();
gdk_pixbuf_loader_write (loader, header, header_size, &err);
if (err)
{
g_error_free (err);
continue;
}
for (i = 0; i < N_CHARACTERS; ++i)
{
int r = g_random_int ();
if (verbose)
{
int j;
for (j = 0; j < sizeof (r); j++)
g_print ("%u, ", ((guchar *)&r)[j]);
}
gdk_pixbuf_loader_write (loader, (guchar *)&r, sizeof (r), &err);
if (err)
{
g_error_free (err);
err = NULL;
break;
}
}
if (verbose)
g_print ("\n");
gdk_pixbuf_loader_close (loader, &err);
if (err)
{
g_error_free (err);
err = NULL;
}
g_object_unref (G_OBJECT (loader));
}
}
static void
randomly_modify (const guchar *image, guint size, gboolean verbose)
{
int i;
guchar *img_copy = g_malloc (size);
for (i = 0; i < size; i++)
img_copy [i] = image[i];
for (i = 0; i < size / 4; i++)
{
int j;
guint index = rand () % size;
guchar byte = rand () % 256;
img_copy[index] = byte;
if (verbose)
g_print ("%d\n", i);
if (verbose)
for (j = 0; j < size; j++)
g_print ("%u, ", img_copy[j]);
test_loader (img_copy, size, FALSE);
}
g_free (img_copy);
}
#define TEST(bytes, data_is_ok) \
do { \
g_print ("%-30s", " " #bytes " "); \
fflush (stdout); \
if (test_loader (bytes, sizeof (bytes), data_is_ok)) \
g_print ("\tpassed\n"); \
else \
g_print ("\tFAILED\n"); \
} while (0)
#define LOWMEMTEST(bytes) \
do { \
g_print ("%-30s", "memory " #bytes " "); \
fflush (stdout); \
mem_test (bytes, sizeof (bytes)); \
g_print ("\tpassed\n"); \
} while (0)
#define TEST_RANDOM(header, n_img, verbose) \
do { \
static guchar h[] = { header }; \
g_print ("%-30s", "random " #header " "); \
fflush (stdout); \
assault (h, sizeof (h), n_img, verbose); \
g_print ("\tpassed\n"); \
} while (0);
#define TEST_RANDOMLY_MODIFIED(image, verbose) \
do { \
g_print ("%-30s", "randomly modified " #image " "); \
fflush (stdout); \
randomly_modify (image, sizeof (image), verbose); \
g_print ("\tpassed\n"); \
} while (0);
static void
almost_exhaust_memory (void)
{
gpointer x = g_malloc (REMAINING_MEM_SIZE);
while (g_try_malloc (REMAINING_MEM_SIZE / 10))
;
g_free (x);
}
static void
write_seed (int seed)
{
FILE *f;
/* write this so you can reproduce failed tests */
f = fopen ("test-loaders-seed", "w");
if (!f)
{
perror ("fopen");
exit (EXIT_FAILURE);
}
if (fprintf (f, "%d\n", seed) < 0)
{
perror ("fprintf");
exit (EXIT_FAILURE);
}
if (fclose (f) < 0)
{
perror ("fclose");
exit (EXIT_FAILURE);
}
g_print ("seed: %d\n", seed);
}
int
main (int argc, char **argv)
{
int seed;
/* Set a malloc which emulates low mem */
max_allocation = G_MAXINT;
g_mem_set_vtable (&limited_table);
if (argc > 1)
seed = atoi (argv[1]);
else
{
seed = time (NULL);
write_seed (seed);
}
g_random_set_seed (seed);
g_type_init (G_TYPE_DEBUG_NONE);
g_log_set_fatal_mask (NULL, G_LOG_LEVEL_WARNING | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
setenv ("GDK_PIXBUF_MODULEDIR", BUILT_MODULES_DIR, TRUE);
TEST (valid_gif_test, TRUE);
TEST (gif_test_1, FALSE);
TEST (gif_test_2, FALSE);
TEST (gif_test_3, FALSE);
TEST (gif_test_4, FALSE);
TEST (valid_png_test, TRUE);
TEST (png_test_1, FALSE);
#if 0
TEST (png_test_2, FALSE);
#endif
TEST (valid_jpeg_test, TRUE);
TEST (valid_tiff1_test, TRUE);
TEST (tiff1_test_1, FALSE);
#if 0
TEST_RANDOMLY_MODIFIED (valid_gif_test, FALSE); // these all break more or
TEST_RANDOMLY_MODIFIED (valid_png_test, FALSE); // less spectacularly, patched or not
TEST_RANDOMLY_MODIFIED (valid_tiff1_test, FALSE);
#endif
TEST_RANDOMLY_MODIFIED (valid_jpeg_test, FALSE); // The jpeg loader does not break
#if 0
TEST_RANDOM (GIF_HEADER, 150, FALSE);
TEST_RANDOM (PNG_HEADER, 10000, FALSE);
TEST_RANDOM (JPEG_HEADER, 8000, FALSE);
TEST_RANDOM (TIFF1_HEADER, 150, FALSE);
TEST_RANDOM (TIFF2_HEADER, 150, FALSE);
#endif
/* memory tests */
/* How do the loaders behave when memory is low?
It depends on the state the above tests left the
memory in.
- Sometimes the png loader tries to report an
"out of memory", but then g_strdup_printf() calls
g_malloc(), which fails.
- There are unchecked realloc()s inside libtiff, which means it
will never work with low memory, unless something drastic is
done, like allocating a lot of memory upfront and release it
before entering libtiff. Also, some TIFFReadRGBAImage calls
returns successfully, even though they have called the error
handler with an 'out of memory' message.
*/
max_allocation = PRETEND_MEM_SIZE;
almost_exhaust_memory ();
g_print ("Allocated %dK of %dK, %dK free during tests\n",
current_allocation / 1024, max_allocation / 1024,
(max_allocation - current_allocation) / 1024);
#if 0
LOWMEMTEST (valid_tiff1_test);
#endif
LOWMEMTEST (valid_gif_test);
LOWMEMTEST (valid_png_test);
LOWMEMTEST (valid_jpeg_test);
return 0;
}