Commit 9fde4eb5 authored by Havoc Pennington's avatar Havoc Pennington Committed by Havoc Pennington

Some updates

2000-10-18  Havoc Pennington  <hp@redhat.com>

	* gtk/gtk-sections.txt: Some updates

	* gdk/gdk-sections.txt: remove GdkPixbufAlphaMode

	* gdk-pixbuf/gdk-pixbuf-sections.txt: Add new API, remove
	GdkPixbufClass/GdkAnimationClass since those are private

	* gdk-pixbuf/Makefile.am (IGNORE_HFILES): ignore more headers

2000-10-18  Havoc Pennington  <hp@redhat.com>

	* gtk/gtktextiter.c (gtk_text_iter_forward_to_newline): Fix a bug
	where any number of empty lines would get skipped

	* gtk/gtktextiter.h: Remove padding from GtkTextIter; live on the
	edge.

	* gtk/gtktextiter.c (gtk_text_iter_make_surreal): enhance the
	warning about invalid iterators (explain more thoroughly)
	(gtk_text_iter_in_region): rename gtk_text_iter_in_range

	* gtk/gtktextview.c (FOCUS_EDGE_WIDTH): Make focus rectangle less
	big

	* demos/*.c: Add error handling

	* gtk/gtktextbuffer.c: don't modify const iterators

	* gtk/gdk-pixbuf-loader.c: Add full error handling here

	* gtk/gtkimage.c (gtk_image_set_from_file): ignore errors
	on file load

	* gtk/gtkiconfactory.c: Update to reflect addition of error
	handling to gdk-pixbuf loaders

2000-10-16  Havoc Pennington  <hp@redhat.com>

	* gdk-pixbuf-io.c (gdk_pixbuf_get_module)
	(gdk_pixbuf_get_named_module) (gdk_pixbuf_load_module):
	add error reporting here also

	* make-inline-pixbuf.c (main): use GError

	* io-xpm.c: include unistd.h

	* gdk-pixbuf-util.c: include string.h

	* io-*.c: add error reporting

	* gdk-pixbuf-animation.c (gdk_pixbuf_animation_new_from_file): add
	error reporting

	* gdk-pixbuf-io.c (gdk_pixbuf_new_from_file): Add error reporting

	* gdk-pixbuf-io.h: Add GError** to load_increment and load
	methods

	* gdk-pixbuf-io.c (gdk_pixbuf_save) (gdk_pixbuf_savev): return
	a G_FILE_ERROR if we fail to write or close the file.

	* gdk-pixbuf.h: remove GDK_PIXBUF_ERROR_IO, instead we'll use
	G_FILE_ERROR_*. Rename enum to GdkPixbufError, properly following
	the GError naming rules. Add GError** to load functions.
parent 03ed8493
......@@ -17,9 +17,11 @@ GDK_PIXBUF_MICRO
<SECTION>
<FILE>gdk-pixbuf</FILE>
GdkPixbufError
GDK_PIXBUF_ERROR
GdkColorspace
GdkPixbufAlphaMode
GdkPixbuf
GdkPixbufClass
gdk_pixbuf_get_colorspace
gdk_pixbuf_get_n_channels
gdk_pixbuf_get_has_alpha
......@@ -33,12 +35,10 @@ gdk_pixbuf_get_rowstride
GDK_PIXBUF
GDK_TYPE_PIXBUF
GDK_IS_PIXBUF
GDK_IS_PIXBUF_CLASS
GDK_PIXBUF_CLASS
GDK_PIXBUF_GET_CLASS
<SUBSECTION Private>
gdk_pixbuf_get_type
gdk_pixbuf_error_quark
</SECTION>
<SECTION>
......@@ -53,11 +53,18 @@ gdk_pixbuf_unref
gdk_pixbuf_new_from_file
</SECTION>
<SECTION>
<FILE>file-saving</FILE>
gdk_pixbuf_savev
gdk_pixbuf_save
</SECTION>
<SECTION>
<FILE>creating</FILE>
gdk_pixbuf_new
gdk_pixbuf_new_from_data
gdk_pixbuf_new_from_xpm_data
gdk_pixbuf_new_from_inline
gdk_pixbuf_copy
</SECTION>
......@@ -65,6 +72,7 @@ gdk_pixbuf_copy
<FILE>util</FILE>
gdk_pixbuf_add_alpha
gdk_pixbuf_copy_area
gdk_pixbuf_saturate_and_pixelate
</SECTION>
<SECTION>
......@@ -72,7 +80,6 @@ gdk_pixbuf_copy_area
GdkPixbufFrameAction
GdkPixbufFrame
GdkPixbufAnimation
GdkPixbufAnimationClass
gdk_pixbuf_animation_new_from_file
gdk_pixbuf_animation_ref
gdk_pixbuf_animation_unref
......@@ -88,10 +95,7 @@ gdk_pixbuf_frame_get_x_offset
<SUBSECTION Standard>
GDK_PIXBUF_ANIMATION
GDK_PIXBUF_ANIMATION_CLASS
GDK_TYPE_PIXBUF_ANIMATION
GDK_PIXBUF_ANIMATION_GET_CLASS
GDK_IS_PIXBUF_ANIMATION_CLASS
GDK_IS_PIXBUF_ANIMATION
<SUBSECTION Private>
......
......@@ -22,6 +22,7 @@
*/
#include <config.h>
#include <errno.h>
#include "gdk-pixbuf-io.h"
#include "gdk-pixbuf-private.h"
......@@ -92,10 +93,12 @@ gdk_pixbuf_animation_finalize (GObject *object)
/**
* gdk_pixbuf_animation_new_from_file:
* @filename: Name of file to load.
* @error: return location for error
*
* Creates a new animation by loading it from a file. The file format is
* detected automatically. If the file's format does not support multi-frame
* images, then an animation with a single frame will be created.
* images, then an animation with a single frame will be created. Possible errors
* are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
*
* Return value: A newly created animation with a reference count of 1, or NULL
* if any of several error conditions ocurred: the file could not be opened,
......@@ -103,7 +106,8 @@ gdk_pixbuf_animation_finalize (GObject *object)
* allocate the image buffer, or the image file contained invalid data.
**/
GdkPixbufAnimation *
gdk_pixbuf_animation_new_from_file (const char *filename)
gdk_pixbuf_animation_new_from_file (const char *filename,
GError **error)
{
GdkPixbufAnimation *animation;
int size;
......@@ -114,25 +118,39 @@ gdk_pixbuf_animation_new_from_file (const char *filename)
g_return_val_if_fail (filename != NULL, NULL);
f = fopen (filename, "rb");
if (!f)
if (!f) {
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
_("Failed to open file '%s': %s"),
filename, g_strerror (errno));
return NULL;
}
size = fread (&buffer, 1, sizeof (buffer), f);
if (size == 0) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image file '%s' contains no data"),
filename);
fclose (f);
return NULL;
}
image_module = gdk_pixbuf_get_module (buffer, size);
image_module = gdk_pixbuf_get_module (buffer, size, filename, error);
if (!image_module) {
g_warning ("Unable to find handler for file: %s", filename);
fclose (f);
return NULL;
}
if (image_module->module == NULL)
gdk_pixbuf_load_module (image_module);
if (!gdk_pixbuf_load_module (image_module, error)) {
fclose (f);
return NULL;
}
if (image_module->load_animation == NULL) {
GdkPixbuf *pixbuf;
......@@ -141,14 +159,35 @@ gdk_pixbuf_animation_new_from_file (const char *filename)
/* Keep this logic in sync with gdk_pixbuf_new_from_file() */
if (image_module->load == NULL) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
_("Don't know how to load the animation in file '%s'"),
filename);
fclose (f);
return NULL;
}
fseek (f, 0, SEEK_SET);
pixbuf = (* image_module->load) (f);
pixbuf = (* image_module->load) (f, error);
fclose (f);
if (pixbuf == NULL && error != NULL && *error == NULL) {
/* I don't trust these crufty longjmp()'ing image libs
* to maintain proper error invariants, and I don't
* want user code to segfault as a result. We need to maintain
* the invariant that error gets set if NULL is returned.
*/
g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.",
image_module->module_name);
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_FAILED,
_("Failed to load image '%s': reason not known, probably a corrupt image file"),
filename);
}
if (pixbuf == NULL)
return NULL;
......@@ -167,7 +206,26 @@ gdk_pixbuf_animation_new_from_file (const char *filename)
animation->height = gdk_pixbuf_get_height (pixbuf);
} else {
fseek (f, 0, SEEK_SET);
animation = (* image_module->load_animation) (f);
animation = (* image_module->load_animation) (f, error);
if (animation == NULL && error != NULL && *error == NULL) {
/* I don't trust these crufty longjmp()'ing
* image libs to maintain proper error
* invariants, and I don't want user code to
* segfault as a result. We need to maintain
* the invariant that error gets set if NULL
* is returned.
*/
g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.",
image_module->module_name);
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_FAILED,
_("Failed to load animation '%s': reason not known, probably a corrupt animation file"),
filename);
}
fclose (f);
}
......
......@@ -23,6 +23,7 @@
#include <config.h>
#include "gdk-pixbuf.h"
#include "gdk-pixbuf-private.h"
#include "gdk-pixbuf-i18n.h"
#include <stdlib.h>
#include <string.h>
......@@ -106,7 +107,10 @@ read_bool (const guchar **p)
}
static GdkPixbuf*
read_raw_inline (const guchar *data, gboolean copy_pixels, int length)
read_raw_inline (const guchar *data,
gboolean copy_pixels,
int length,
GError **error)
{
GdkPixbuf *pixbuf;
const guchar *p = data;
......@@ -116,6 +120,11 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length)
if (length >= 0 && length < 12) {
/* Not enough buffer to hold the width/height/rowstride */
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image data is partially missing"));
return NULL;
}
......@@ -123,9 +132,14 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length)
width = read_int (&p);
height = read_int (&p);
if (rowstride < width)
if (rowstride < width) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image has an incorrect pixel rowstride, perhaps the data was corrupted somehow."));
return NULL; /* bad data from untrusted source. */
}
/* rowstride >= width, so we can trust width */
length -= 12;
......@@ -133,37 +147,71 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length)
/* There's some better way like G_MAXINT/height > rowstride
* but I'm not sure it works, so stick to this for now.
*/
if (((double)height) * ((double)rowstride) > (double)G_MAXINT)
if (((double)height) * ((double)rowstride) > (double)G_MAXINT) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image size is impossibly large, perhaps the data was corrupted somehow"));
return NULL; /* overflow */
}
if (length >= 0 &&
length < (height * rowstride + 13)) {
/* Not enough buffer to hold the remaining header
* information plus the data.
*/
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image data is partially missing, probably it was ocorrupted somehow."));
return NULL;
}
/* Read the remaining 13 bytes of header information */
has_alpha = read_bool (&p) != FALSE;
colorspace = read_int (&p);
n_channels = read_int (&p);
bits_per_sample = read_int (&p);
if (colorspace != GDK_COLORSPACE_RGB)
if (colorspace != GDK_COLORSPACE_RGB) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image has an unknown colorspace code (%d), perhaps the image data was corrupted"),
colorspace);
return NULL;
}
if (bits_per_sample != 8)
if (bits_per_sample != 8) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image has an improper number of bits per sample (%d), perhaps the image data was corrupted"),
bits_per_sample);
return NULL;
if (has_alpha && n_channels != 4)
}
if (has_alpha && n_channels != 4) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image has an improper number of channels (%d), perhaps the image data was corrupted"),
n_channels);
return NULL;
if (!has_alpha && n_channels != 3)
}
if (!has_alpha && n_channels != 3) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image has an improper number of channels (%d), perhaps the image data was corrupted"),
n_channels);
return NULL;
}
if (copy_pixels) {
guchar *pixels;
gint dest_rowstride;
......@@ -172,10 +220,19 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length)
pixbuf = gdk_pixbuf_new (colorspace,
has_alpha, bits_per_sample,
width, height);
if (pixbuf == NULL) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to store a %d by %d image; try exiting some applications to free memory."),
width, height);
return NULL;
}
pixels = gdk_pixbuf_get_pixels (pixbuf);
dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
for (row = 0; row < height; row++) {
memcpy (pixels, p, rowstride);
pixels += dest_rowstride;
......@@ -190,32 +247,42 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length)
rowstride,
NULL, NULL);
}
return pixbuf;
}
/**
* gdk_pixbuf_new_from_inline:
* @data: An inlined GdkPixbuf
* @inline_pixbuf: An inlined GdkPixbuf
* @copy_pixels: whether to copy the pixels out of the inline data, or to use them in-place
* @length: length of the inline data
* @error: return location for error
*
* Create a #GdkPixbuf from a custom format invented to store pixbuf
* data in C program code. This library comes with a program called "make-inline-pixbuf"
* that can write out a variable definition containing an inlined pixbuf.
* This is useful if you want to ship a program with images, but
* don't want to depend on any external files.
* data in C program code. This library comes with a program called
* "make-inline-pixbuf" that can write out a variable definition
* containing an inlined pixbuf. This is useful if you want to ship a
* program with images, but don't want to depend on any external
* files.
*
* The inline data format contains the pixels in #GdkPixbuf's native
* format. Since the inline pixbuf is read-only static data, you
* don't need to copy it unless you intend to write to it.
*
* If you create a pixbuf from const inline data compiled into your
* program, it's probably safe to ignore errors, since things will
* always succeed. For non-const inline data, you could get out of
* memory. For untrusted inline data located at runtime, you could
* have corrupt inline data in addition.
*
* Return value: A newly-created #GdkPixbuf structure with a reference count of
* 1.
* 1, or NULL If error is set.
**/
GdkPixbuf*
gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf,
gboolean copy_pixels,
int length)
int length,
GError **error)
{
const guchar *p;
GdkPixbuf *pixbuf;
......@@ -225,12 +292,20 @@ gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf,
/* not enough bytes to contain even the magic number
* and format code.
*/
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image contained no data."));
return NULL;
}
p = inline_pixbuf;
if (read_int (&p) != GDK_PIXBUF_INLINE_MAGIC_NUMBER) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image isn't in the correct format (inline GdkPixbuf format)"));
return NULL;
}
......@@ -239,10 +314,15 @@ gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf,
switch (format)
{
case GDK_PIXBUF_INLINE_RAW:
pixbuf = read_raw_inline (p, copy_pixels, length - 8);
pixbuf = read_raw_inline (p, copy_pixels, length - 8, error);
break;
default:
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
_("This version of the software is unable to read images with type code %d"),
format);
return NULL;
}
......
......@@ -275,8 +275,9 @@ get_libdir (void)
/* actually load the image handler - gdk_pixbuf_get_module only get a */
/* reference to the module to load, it doesn't actually load it */
/* perhaps these actions should be combined in one function */
void
gdk_pixbuf_load_module (GdkPixbufModule *image_module)
gboolean
gdk_pixbuf_load_module (GdkPixbufModule *image_module,
GError **error)
{
char *module_name;
char *path;
......@@ -285,7 +286,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
gpointer save_sym;
char *name;
g_return_if_fail (image_module->module == NULL);
g_return_val_if_fail (image_module->module == NULL, FALSE);
name = image_module->module_name;
......@@ -304,10 +305,14 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
module = g_module_open (path, G_MODULE_BIND_LAZY);
if (!module) {
g_warning ("Unable to load module: %s: %s", path, g_module_error ());
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_FAILED,
_("Unable to load image-loading module: %s: %s"),
path, g_module_error ());
g_free (module_name);
g_free (path);
return;
return FALSE;
}
g_free (path);
} else {
......@@ -337,7 +342,9 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
image_module->load_animation = load_sym;
if (pixbuf_module_symbol (module, name, "image_save", &save_sym))
image_module->save = save_sym;
image_module->save = save_sym;
return TRUE;
}
#else
......@@ -406,8 +413,9 @@ m_stop_load (tiff);
m_load (xpm);
m_load_xpm_data (xpm);
void
gdk_pixbuf_load_module (GdkPixbufModule *image_module)
gboolean
gdk_pixbuf_load_module (GdkPixbufModule *image_module,
GError **error)
{
image_module->module = (void *) 1;
......@@ -417,7 +425,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
image_module->load_increment = mname (png,load_increment);
image_module->stop_load = mname (png,stop_load);
image_module->save = mname (png,save);
return;
return TRUE;
}
if (strcmp (image_module->module_name, "bmp") == 0){
......@@ -425,7 +433,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
image_module->begin_load = mname (bmp,begin_load);
image_module->load_increment = mname (bmp,load_increment);
image_module->stop_load = mname (bmp,stop_load);
return;
return TRUE;
}
if (strcmp (image_module->module_name, "wbmp") == 0){
......@@ -433,7 +441,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
image_module->begin_load = mname (wbmp,begin_load);
image_module->load_increment = mname (wbmp,load_increment);
image_module->stop_load = mname (wbmp,stop_load);
return;
return TRUE;
}
if (strcmp (image_module->module_name, "gif") == 0){
......@@ -442,7 +450,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
image_module->load_increment = mname (gif,load_increment);
image_module->stop_load = mname (gif,stop_load);
image_module->load_animation = mname (gif,load_animation);
return;
return TRUE;
}
if (strcmp (image_module->module_name, "ico") == 0){
......@@ -450,7 +458,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
image_module->begin_load = mname (ico,begin_load);
image_module->load_increment = mname (ico,load_increment);
image_module->stop_load = mname (ico,stop_load);
return;
return TRUE;
}
if (strcmp (image_module->module_name, "jpeg") == 0){
......@@ -459,34 +467,42 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
image_module->load_increment = mname (jpeg,load_increment);
image_module->stop_load = mname (jpeg,stop_load);
image_module->save = mname (jpeg,save);
return;
return TRUE;
}
if (strcmp (image_module->module_name, "pnm") == 0){
image_module->load = mname (pnm,load);
image_module->begin_load = mname (pnm,begin_load);
image_module->load_increment = mname (pnm,load_increment);
image_module->stop_load = mname (pnm,stop_load);
return;
return TRUE;
}
if (strcmp (image_module->module_name, "ras") == 0){
image_module->load = mname (ras,load);
image_module->begin_load = mname (ras,begin_load);
image_module->load_increment = mname (ras,load_increment);
image_module->stop_load = mname (ras,stop_load);
return;
return TRUE;
}
if (strcmp (image_module->module_name, "tiff") == 0){
image_module->load = mname (tiff,load);
image_module->begin_load = mname (tiff,begin_load);
image_module->load_increment = mname (tiff,load_increment);
image_module->stop_load = mname (tiff,stop_load);
return;
return TRUE;
}
if (strcmp (image_module->module_name, "xpm") == 0){
image_module->load = mname (xpm,load);
image_module->load_xpm_data = mname (xpm,load_xpm_data);
return;
return TRUE;
}
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
_("Image type '%s' is not supported"),
image_module->module_name);
return FALSE;
}
......@@ -495,7 +511,8 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
GdkPixbufModule *
gdk_pixbuf_get_named_module (const char *name)
gdk_pixbuf_get_named_module (const char *name,
GError **error)
{
int i;
......@@ -504,11 +521,19 @@ gdk_pixbuf_get_named_module (const char *name)
return &(file_formats[i]);
}
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
_("Image type '%s' is not supported"),
name);
return NULL;
}
GdkPixbufModule *
gdk_pixbuf_get_module (guchar *buffer, guint size)
gdk_pixbuf_get_module (guchar *buffer, guint size,
const gchar *filename,
GError **error)
{
int i;
......@@ -517,15 +542,30 @@ gdk_pixbuf_get_module (guchar *buffer, guint size)
return &(file_formats[i]);
}
if (filename)
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
_("Couldn't recognize the image file format for file '%s'"),
filename);
else
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
_("Unrecognized image file format"));
return NULL;
}
/**
* gdk_pixbuf_new_from_file:
* @filename: Name of file to load.
* @error: Return location for an error
*
* Creates a new pixbuf by loading an image from a file. The file format is
* detected automatically.
* detected automatically. If NULL is returned, then @error will be set.
* Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
*
* Return value: A newly-created pixbuf with a reference count of 1, or NULL if
* any of several error conditions occurred: the file could not be opened,
......@@ -533,7 +573,8 @@ gdk_pixbuf_get_module (guchar *buffer, guint size)
* allocate the image buffer, or the image file contained invalid data.
**/
GdkPixbuf *
gdk_pixbuf_new_from_file (const char *filename)
gdk_pixbuf_new_from_file (const char *filename,
GError **error)
{
GdkPixbuf *pixbuf;
int size;
......@@ -544,34 +585,82 @@ gdk_pixbuf_new_from_file (const char *filename)
g_return_val_if_fail (filename != NULL, NULL);
f = fopen (filename, "rb");
if (!f)
if (!f) {
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
_("Failed to open file '%s': %s"),
filename, g_strerror (errno));
return NULL;
}
size = fread (&buffer, 1, sizeof (buffer), f);
if (size == 0) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Image file '%s' contains no data"),
filename);
fclose (f);
return NULL;
}
image_module = gdk_pixbuf_get_module (buffer, size);
if (!image_module) {
g_warning ("Unable to find handler for file: %s", filename);
fclose (f);
return NULL;
}
image_module = gdk_pixbuf_get_module (buffer, size, filename, error);
if (image_module == NULL) {
fclose (f);
return NULL;
}
if (image_module->module == NULL)
gdk_pixbuf_load_module (image_module);
if (!gdk_pixbuf_load_module (image_module, error)) {
fclose (f);
return NULL;
}
if (image_module->load == NULL) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
_("Don't know how to load the image in file '%s'"),
filename);
fclose (f);
return NULL;
}
fseek (f, 0, SEEK_SET);
pixbuf = (* image_module->load) (f);
pixbuf = (* image_module->load) (f, error);
fclose (f);
if (pixbuf == NULL && error != NULL && *error == NULL) {
/* I don't trust these crufty longjmp()'ing image libs
* to maintain proper error invariants, and I don't
* want user code to segfault as a result. We need to maintain
* the invariant that error gets set if NULL is returned.
*/
g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_FAILED,
_("Failed to load image '%s': reason not known, probably a corrupt image file"),
filename);