[cairo-commit] src/cairo-png.c test/create-from-png.c

Chris Wilson ickle at kemper.freedesktop.org
Tue Sep 25 15:47:29 PDT 2007


 src/cairo-png.c        |   57 ++++++++++++++++++++++-----------
 test/create-from-png.c |   84 +++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 113 insertions(+), 28 deletions(-)

New commits:
diff-tree 1469de5211e84e40490fa612538986768748bd55 (from f1d84271d363cc80cdef92ec9cac2cf29783bfe0)
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Sep 25 23:35:25 2007 +0100

    [cairo-png] Propagate error from read and write funcs.
    
    Use the png_struct->error_ptr to propagate the error status from the
    user/stdio read and write functions through the png_error() to the
    cairo_surface_write_to_png*() and cairo_surface_read_from_png*()
    functions. From there the error is returned back to the user either
    directly or as the most appropriate error surface.
    
    (Fixes https://bugs.freedesktop.org/show_bug.cgi?id=6909)

diff --git a/src/cairo-png.c b/src/cairo-png.c
index eaecbbd..8ad4c9a 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -91,8 +91,13 @@ static void
 png_simple_error_callback (png_structp png_save_ptr,
 	                   png_const_charp error_msg)
 {
-    _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    longjmp (png_save_ptr->jmpbuf, CAIRO_STATUS_NO_MEMORY);
+    cairo_status_t *error = png_get_error_ptr (png_save_ptr);
+
+    /* default to the most likely error */
+    if (*error == CAIRO_STATUS_SUCCESS)
+	*error = CAIRO_STATUS_NO_MEMORY;
+
+    longjmp (png_save_ptr->jmpbuf, 1);
 }
 
 static void
@@ -108,7 +113,7 @@ write_png (cairo_surface_t	*surface,
 	   void			*closure)
 {
     int i;
-    volatile cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_status_t status;
     cairo_image_surface_t *image;
     void *image_extra;
     png_struct *png;
@@ -129,7 +134,7 @@ write_png (cairo_surface_t	*surface,
 	return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
 
     if (image->height && image->width) {
-	rows = _cairo_malloc_ab (image->height, sizeof(png_byte*));
+	rows = _cairo_malloc_ab (image->height, sizeof (png_byte*));
 	if (rows == NULL) {
 	    status = CAIRO_STATUS_NO_MEMORY;
 	    goto BAIL1;
@@ -139,7 +144,7 @@ write_png (cairo_surface_t	*surface,
 	    rows[i] = (png_byte *) image->data + i * image->stride;
     }
 
-    png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL,
+    png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
 	                           png_simple_error_callback,
 	                           png_simple_warning_callback);
     if (png == NULL) {
@@ -153,8 +158,7 @@ write_png (cairo_surface_t	*surface,
 	goto BAIL3;
     }
 
-    status = setjmp (png_jmpbuf (png));
-    if (status)
+    if (setjmp (png_jmpbuf (png)))
 	goto BAIL3;
 
     png_set_write_fn (png, closure, write_func, NULL);
@@ -234,8 +238,11 @@ stdio_write_func (png_structp png, png_b
 	size_t ret = fwrite (data, 1, size, fp);
 	size -= ret;
 	data += ret;
-	if (size && ferror (fp))
-	    png_error(png, "Write Error");
+	if (size && ferror (fp)) {
+	    cairo_status_t *error = png_get_error_ptr (png);
+	    *error = CAIRO_STATUS_WRITE_ERROR;
+	    png_error (png, NULL);
+	}
     }
 }
 
@@ -286,8 +293,11 @@ stream_write_func (png_structp png, png_
 
     png_closure = png_get_io_ptr (png);
     status = png_closure->write_func (png_closure->closure, data, size);
-    if (status)
-	png_error(png, "Write Error");
+    if (status) {
+	cairo_status_t *error = png_get_error_ptr (png);
+	*error = status;
+	png_error (png, NULL);
+    }
 }
 
 /**
@@ -369,10 +379,11 @@ read_png (png_rw_ptr	read_func,
     int depth, color_type, interlace;
     unsigned int i;
     unsigned int pixel_size;
+    cairo_status_t status;
 
     /* XXX: Perhaps we'll want some other error handlers? */
     png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
-                                  NULL,
+                                  &status,
 	                          png_simple_error_callback,
 	                          png_simple_warning_callback);
     if (png == NULL)
@@ -384,8 +395,10 @@ read_png (png_rw_ptr	read_func,
 
     png_set_read_fn (png, closure, read_func);
 
+    status = CAIRO_STATUS_SUCCESS;
     if (setjmp (png_jmpbuf (png))) {
-	surface = (cairo_surface_t*) &_cairo_surface_nil_read_error;
+	if (status != CAIRO_STATUS_NO_MEMORY)
+	    surface = (cairo_surface_t*) &_cairo_surface_nil_read_error;
 	goto BAIL;
     }
 
@@ -408,7 +421,7 @@ read_png (png_rw_ptr	read_func,
         png_set_gray_1_2_4_to_8 (png);
 #endif
     /* transform transparency to alpha */
-    if (png_get_valid(png, info, PNG_INFO_tRNS))
+    if (png_get_valid (png, info, PNG_INFO_tRNS))
         png_set_tRNS_to_alpha (png);
 
     if (depth == 16)
@@ -436,7 +449,7 @@ read_png (png_rw_ptr	read_func,
     if (data == NULL)
 	goto BAIL;
 
-    row_pointers = _cairo_malloc_ab (png_height, sizeof(char *));
+    row_pointers = _cairo_malloc_ab (png_height, sizeof (char *));
     if (row_pointers == NULL)
 	goto BAIL;
 
@@ -479,8 +492,11 @@ stdio_read_func (png_structp png, png_by
 	size_t ret = fread (data, 1, size, fp);
 	size -= ret;
 	data += ret;
-	if (size && ferror (fp))
-	    png_error(png, "Read Error");
+	if (size && ferror (fp)) {
+	    cairo_status_t *error = png_get_error_ptr (png);
+	    *error = CAIRO_STATUS_READ_ERROR;
+	    png_error (png, NULL);
+	}
     }
 }
 
@@ -541,8 +557,11 @@ stream_read_func (png_structp png, png_b
 
     png_closure = png_get_io_ptr (png);
     status = png_closure->read_func (png_closure->closure, data, size);
-    if (status)
-	png_error(png, "Read Error");
+    if (status) {
+	cairo_status_t *error = png_get_error_ptr (png);
+	*error = status;
+	png_error (png, NULL);
+    }
 }
 
 /**
diff --git a/test/create-from-png.c b/test/create-from-png.c
index 4aefc34..fe08b30 100644
--- a/test/create-from-png.c
+++ b/test/create-from-png.c
@@ -39,6 +39,18 @@ cairo_test_t test = {
     draw
 };
 
+static cairo_status_t
+no_memory_error (void *closure, unsigned char *data, unsigned int size)
+{
+    return CAIRO_STATUS_NO_MEMORY;
+}
+
+static cairo_status_t
+read_error (void *closure, unsigned char *data, unsigned int size)
+{
+    return CAIRO_STATUS_READ_ERROR;
+}
+
 static cairo_test_status_t
 draw (cairo_t *cr, int width, int height)
 {
@@ -46,18 +58,10 @@ draw (cairo_t *cr, int width, int height
     char *filename;
     cairo_surface_t *surface;
 
-    surface = cairo_image_surface_create_from_png ("___THIS_FILE_DOES_NOT_EXIST___");
-    if (cairo_surface_status (surface) != CAIRO_STATUS_FILE_NOT_FOUND) {
-	cairo_test_log ("Error: expected \"file not found\", but got: %s\n",
-			cairo_status_to_string (cairo_surface_status (surface)));
-	return CAIRO_TEST_FAILURE;
-    }
-
     xasprintf (&filename, "%s/%s", srcdir ? srcdir : ".",
 	       "create-from-png-ref.png");
 
     surface = cairo_image_surface_create_from_png (filename);
-
     if (cairo_surface_status (surface)) {
 	cairo_test_log ("Error reading PNG image %s: %s\n",
 			filename,
@@ -65,7 +69,6 @@ draw (cairo_t *cr, int width, int height
 	free (filename);
 	return CAIRO_TEST_FAILURE;
     }
-
     free (filename);
 
     cairo_set_source_surface (cr, surface, 0, 0);
@@ -79,5 +82,68 @@ draw (cairo_t *cr, int width, int height
 int
 main (void)
 {
+    char *srcdir = getenv ("srcdir");
+    char *filename;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+
+    surface = cairo_image_surface_create_from_png ("___THIS_FILE_DOES_NOT_EXIST___");
+    if (cairo_surface_status (surface) != CAIRO_STATUS_FILE_NOT_FOUND) {
+	cairo_test_log ("Error: expected \"file not found\", but got: %s\n",
+			cairo_status_to_string (cairo_surface_status (surface)));
+	cairo_surface_destroy (surface);
+	return CAIRO_TEST_FAILURE;
+    }
+
+    surface = cairo_image_surface_create_from_png_stream (no_memory_error, NULL);
+    if (cairo_surface_status (surface) != CAIRO_STATUS_NO_MEMORY) {
+	cairo_test_log ("Error: expected \"out of memory\", but got: %s\n",
+			cairo_status_to_string (cairo_surface_status (surface)));
+	cairo_surface_destroy (surface);
+	return CAIRO_TEST_FAILURE;
+    }
+
+    surface = cairo_image_surface_create_from_png_stream (read_error, NULL);
+    if (cairo_surface_status (surface) != CAIRO_STATUS_READ_ERROR) {
+	cairo_test_log ("Error: expected \"read error\", but got: %s\n",
+			cairo_status_to_string (cairo_surface_status (surface)));
+	cairo_surface_destroy (surface);
+	return CAIRO_TEST_FAILURE;
+    }
+
+    /* cheekily test error propagation from the user write funcs as well ... */
+    xasprintf (&filename, "%s/%s", srcdir ? srcdir : ".",
+	       "create-from-png-ref.png");
+
+    surface = cairo_image_surface_create_from_png (filename);
+    if (cairo_surface_status (surface)) {
+	cairo_test_log ("Error reading PNG image %s: %s\n",
+			filename,
+			cairo_status_to_string (cairo_surface_status (surface)));
+	free (filename);
+	return CAIRO_TEST_FAILURE;
+    }
+    free (filename);
+
+    status = cairo_surface_write_to_png_stream (surface,
+	                                   (cairo_write_func_t) no_memory_error,
+					   NULL);
+    if (status != CAIRO_STATUS_NO_MEMORY) {
+	cairo_test_log ("Error: expected \"out of memory\", but got: %s\n",
+			cairo_status_to_string (status));
+	cairo_surface_destroy (surface);
+	return CAIRO_TEST_FAILURE;
+    }
+    status = cairo_surface_write_to_png_stream (surface,
+	                                        (cairo_write_func_t) read_error,
+						NULL);
+    if (status != CAIRO_STATUS_READ_ERROR) {
+	cairo_test_log ("Error: expected \"read error\", but got: %s\n",
+			cairo_status_to_string (status));
+	cairo_surface_destroy (surface);
+	return CAIRO_TEST_FAILURE;
+    }
+    cairo_surface_destroy (surface);
+
     return cairo_test (&test);
 }


More information about the cairo-commit mailing list