From 302c58b8cff8a153c4fe196b22f26e357c932d5f Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Fri, 31 Jan 2014 22:00:27 -0600 Subject: [PATCH] [libpng17] Added pngimage test program for png_read_png and png_write_png. This is a work-in-progress; no tests are run automatically at present and the program by virtue of exhaustively testing all the transforms is very slow. --- ANNOUNCE | 2 +- CHANGES | 2 +- Makefile.am | 6 +- contrib/libtests/pngimage.c | 264 ++++++++++++++++++++++++++++++++++++ 4 files changed, 271 insertions(+), 3 deletions(-) create mode 100644 contrib/libtests/pngimage.c diff --git a/ANNOUNCE b/ANNOUNCE index 71f808454..dc30d1863 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -500,7 +500,7 @@ Version 1.7.0beta30 [February 1, 2014] Fixed a large number of instances where PNGCBAPI was omitted from function definitions. Added pngimage test program for png_read_png and png_write_png. This - is a work-in-progress, no tests are run automatically at present and + is a work-in-progress; no tests are run automatically at present and the program by virtue of exhaustively testing all the transforms is very slow. diff --git a/CHANGES b/CHANGES index a7b1d5280..3dc56b705 100644 --- a/CHANGES +++ b/CHANGES @@ -4789,7 +4789,7 @@ Version 1.7.0beta30 [February 1, 2014] Fixed a large number of instances where PNGCBAPI was omitted from function definitions. Added pngimage test program for png_read_png and png_write_png. This - is a work-in-progress, no tests are run automatically at present and + is a work-in-progress; no tests are run automatically at present and the program by virtue of exhaustively testing all the transforms is very slow. diff --git a/Makefile.am b/Makefile.am index 9efc20dff..b4e9bc931 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ PNGLIB_BASENAME= libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@ ACLOCAL_AMFLAGS = -I scripts # test programs - run on make check, make distcheck -check_PROGRAMS= pngtest pngunknown pngstest pngvalid +check_PROGRAMS= pngtest pngunknown pngstest pngvalid pngimage # Utilities - installed bin_PROGRAMS= pngfix png-fix-itxt @@ -34,6 +34,9 @@ pngstest_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la pngunknown_SOURCES = contrib/libtests/pngunknown.c pngunknown_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la +pngimage_SOURCES = contrib/libtests/pngimage.c +pngimage_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la + pngfix_SOURCES = contrib/tools/pngfix.c pngfix_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la @@ -214,6 +217,7 @@ pngtest.o: pnglibconf.h contrib/libtests/makepng.o: pnglibconf.h contrib/libtests/pngstest.o: pnglibconf.h contrib/libtests/pngunknown.o: pnglibconf.h +contrib/libtests/pngimage.o: pnglibconf.h contrib/libtests/pngvalid.o: pnglibconf.h contrib/libtests/readpng.o: pnglibconf.h contrib/libtests/tarith.o: pnglibconf.h diff --git a/contrib/libtests/pngimage.c b/contrib/libtests/pngimage.c new file mode 100644 index 000000000..0e9a62e12 --- /dev/null +++ b/contrib/libtests/pngimage.c @@ -0,0 +1,264 @@ +/* pngimage.c + * + * Copyright (c) 2014 John Cunningham Bowler + * + * Last changed in libpng 1.6.9 [January 30, 2014] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Test the png_read_png and png_write_png interfaces. Given a PNG file load it + * using png_read_png and then write with png_write_png. Test all possible + * transforms. + */ +#include +#include +#include +#include + +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +#if defined(PNG_INFO_IMAGE_SUPPORTED) && defined(PNG_READ_SUPPORTED) +#ifdef PNG_WRITE_SUPPORTED +/* File data, held in a linked list of buffers - not all of these are in use. */ +struct buffer_list +{ + struct buffer_list *next; /* next buffer in list */ + png_byte buffer[1024]; /* the actual buffer */ +}; + +struct buffer +{ + struct buffer_list *last; /* last buffer in use */ + size_t end_count; /* bytes in the last buffer */ + struct buffer_list first; /* the very first buffer */ +}; + +static struct buffer * +get_buffer(png_structp png_ptr) +{ + return (struct buffer*)png_get_io_ptr(png_ptr); +} + +static void PNGCBAPI +write_function(png_structp png_ptr, png_bytep data, png_size_t size) +{ + static struct buffer write_buffer; /* Preallocated list for write */ + struct buffer *buffer = get_buffer(png_ptr); + + if (buffer == NULL) + { + /* This is the first write for this PNG, use the global buffer but rewind + * it to the start of the buffer list: + */ + write_buffer.last = &write_buffer.first; + write_buffer.end_count = 0; + + buffer = &write_buffer; + png_set_write_fn(png_ptr, buffer, write_function, NULL/*flush*/); + } + + /* Write the data into the buffer, adding buffers as required */ + while (size > 0) + { + struct buffer_list *last = buffer->last; + size_t avail; + + if (buffer->end_count >= sizeof last->buffer) + { + + if (last->next == NULL) + { + struct buffer_list *add = + (struct buffer_list*)malloc(sizeof *add); + + if (add == NULL) + png_error(png_ptr, "pngimage: out of memory buffering output"); + + add->next = NULL; + last->next = add; + } + + last = last->next; + buffer->last = last; + buffer->end_count = 0; + } + + avail = (sizeof last->buffer) - buffer->end_count; + if (avail > size) + avail = size; + + memcpy(last->buffer + buffer->end_count, data, avail); + buffer->end_count -= avail; + size -= avail; + data += avail; + } +} + +static int +write_png(png_infop info_ptr, int transforms) +{ + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0); + + if (png_ptr == NULL) + { + fprintf(stderr, "png_image: failed to create write png_struct\n"); + return 0; + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, NULL); + return 0; + } + + /* Passing NULL for io_ptr causes write_function to initialize the buffer on + * the first write. + */ + png_set_write_fn(png_ptr, NULL/*io_ptr*/, write_function, NULL/*flush*/); + +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + /* Remove the user limits, if any */ + png_set_user_limits(png_ptr, 0x7fffffff, 0x7fffffff); +# endif + + png_write_png(png_ptr, info_ptr, transforms, NULL/*params*/); + + png_destroy_write_struct(&png_ptr, NULL); + return 1; /* success */ +} + +static void +do_write_tests(png_infop info_ptr, int read_transforms) +{ + /* TODO: fix this, it currently crashes (probably because of the re-use of + * the info_ptr!) + */ + if (!write_png(info_ptr, 0/*transform*/)) + exit(1); + + (void)read_transforms; +} +#endif + +static int +read_png(FILE *fp /*input image*/, png_bytepp rows /*may be NULL*/, + int transforms, int test_write) +{ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); + png_infop info_ptr = NULL; + + if (png_ptr == NULL) + return 0; + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return 0; + } + +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + /* Remove the user limits, if any */ + png_set_user_limits(png_ptr, 0x7fffffff, 0x7fffffff); +# endif + +# ifdef PNG_STDIO_SUPPORTED + rewind(fp); + png_init_io(png_ptr, fp); +# else + fprintf(stderr, "png_image: no stdio support, test skipped\n"); + exit(77); +# endif + + /* The png_read_png API requires us to make the info struct, but it does the + * call to png_read_info. + */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + png_error(png_ptr, "OOM allocating info structure"); + + /* The test uses either local allocation of the info structure or allocation + * by libpng depending on the passed in row pointer buffer. + */ + if (rows != NULL) + png_set_rows(png_ptr, info_ptr, rows); + + png_read_png(png_ptr, info_ptr, transforms, NULL); + + /* Now get the rows if necessary. */ + if (rows == NULL) + { + rows = png_get_rows(png_ptr, info_ptr); + if (rows == NULL) + png_error(png_ptr, "pngimage: no image allocated"); + } + + if (test_write) + { +# ifdef PNG_WRITE_SUPPORTED + /* This just exits on error */ + do_write_tests(info_ptr, transforms); +# endif + } + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return 1; +} + +int +main(int argc, const char * const *argv) +{ + /* For each file on the command line test it with a range of transforms */ + int i; + + for (i=1; i