diff --git a/ANNOUNCE b/ANNOUNCE index be141ed4f..76d967dc5 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,5 +1,5 @@ -Libpng 1.7.0beta80 - May 5, 2016 +Libpng 1.7.0beta80 - May 6, 2016 This is not intended to be a public release. It will be replaced within a few weeks by a public version or by another test version. @@ -1264,9 +1264,10 @@ Version 1.7.0beta79 [March 9, 2016] (Robert C. Seacord). Various other flags in png.h made unsigned as well. Fixed some misleading indentation (Krishnaraj Bhat). -Version 1.7.0beta80 [May 5, 2016] +Version 1.7.0beta80 [May 6, 2016] Fixed typo (missing underscore) in #define PNG_READ_16_TO_8_SUPPORTED Bug report by (Y.Ohashik). + Quieted two Coverity issues in contrib/libtests/timepng.c. Write code update (John Bowler): Implemented better defaulting of zlib settings based on image properties. Replaced pngtest.png with one compressed with the new zlib settings. @@ -1283,6 +1284,11 @@ Version 1.7.0beta80 [May 5, 2016] There are minimal API changes beyond removal of the selection options. Work is still to be done to investigate a filter selection mechanism that is at least as good as the previous one. + Minor write bug-fixes, remove unimplemented code. A debug() assert + fired if windowBits was set to 8 for the Huffman only and no-compression + cases. This commit changes it to do some extra checking. Removed + unreachable code in pz_default_settings and eliminated a spurious + warning in pngcp for small files. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index 95c5496e3..3bc6fa290 100644 --- a/CHANGES +++ b/CHANGES @@ -5564,9 +5564,10 @@ Version 1.7.0beta79 [March 9, 2016] (Robert C. Seacord). Various other flags in png.h made unsigned as well. Fixed some misleading indentation (Krishnaraj Bhat). -Version 1.7.0beta80 [May 5, 2016] +Version 1.7.0beta80 [May 6, 2016] Fixed typo (missing underscore) in #define PNG_READ_16_TO_8_SUPPORTED Bug report by (Y.Ohashik). + Quieted two Coverity issues in contrib/libtests/timepng.c. Write code update (John Bowler): Implemented better defaulting of zlib settings based on image properties. Replaced pngtest.png with one compressed with the new zlib settings. @@ -5583,6 +5584,11 @@ Version 1.7.0beta80 [May 5, 2016] There are minimal API changes beyond removal of the selection options. Work is still to be done to investigate a filter selection mechanism that is at least as good as the previous one. + Minor write bug-fixes, remove unimplemented code. A debug() assert + fired if windowBits was set to 8 for the Huffman only and no-compression + cases. This commit changes it to do some extra checking. Removed + unreachable code in pz_default_settings and eliminated a spurious + warning in pngcp for small files. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/contrib/examples/pngcp.c b/contrib/examples/pngcp.c index 3e61c3406..e6de44bfb 100644 --- a/contrib/examples/pngcp.c +++ b/contrib/examples/pngcp.c @@ -1199,7 +1199,7 @@ getsearchopts(struct display *dp, const char *opt_str, int *value) else if (opt == OPTIND(dp, windowBits)) { /* Changing windowBits for strategies that do not search the window is - * pointless. Huffman-only does not search, RLE only searchs backwards + * pointless. Huffman-only does not search, RLE only searches backwards * one byte, so given that the maximum string length is 258, a windowBits * of 9 is always sufficient. */ diff --git a/contrib/libtests/timepng.c b/contrib/libtests/timepng.c index 7c937971c..4073ab6ef 100644 --- a/contrib/libtests/timepng.c +++ b/contrib/libtests/timepng.c @@ -1,8 +1,8 @@ /* timepng.c * - * Copyright (c) 2013 John Cunningham Bowler + * Copyright (c) 2013,2016 John Cunningham Bowler * - * Last changed in libpng 1.6.1 [March 28, 2013] + * Last changed in libpng 1.6.22 [(PENDING RELEASE)] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -10,15 +10,17 @@ * * Load an arbitrary number of PNG files (from the command line, or, if there * are no arguments on the command line, from stdin) then run a time test by - * reading each file by row. The test does nothing with the read result and - * does no transforms. The only output is a time as a floating point number of - * seconds with 9 decimal digits. + * reading each file by row or by image (possibly with transforms in the latter + * case). The only output is a time as a floating point number of seconds with + * 9 decimal digits. */ #define _POSIX_C_SOURCE 199309L /* for clock_gettime */ #include #include #include +#include +#include #include @@ -35,36 +37,61 @@ # include "../../png.h" #endif -static int read_png(FILE *fp) +/* The following is to support direct compilation of this file as C++ */ +#ifdef __cplusplus +# define voidcast(type, value) static_cast(value) +#else +# define voidcast(type, value) (value) +#endif /* __cplusplus */ + +#if ((defined(PNG_SEQUENTIAL_READ_SUPPORTED)) && defined(PNG_STDIO_SUPPORTED)\ + && defined(PNG_EASY_ACCESS_SUPPORTED) && defined(PNG_INFO_IMAGE_SUPPORTED)) +typedef struct { - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); - png_infop info_ptr = NULL; - png_bytep row = NULL, display = NULL; + FILE *input; + FILE *output; +} io_data; - if (png_ptr == NULL) - return 0; +static PNG_CALLBACK(void, read_and_copy, + (png_structp png_ptr, png_bytep buffer, png_size_t cb)) +{ + io_data *io = (io_data*)png_get_io_ptr(png_ptr); - if (setjmp(png_jmpbuf(png_ptr))) + if (fread(buffer, cb, 1, io->input) != 1) + png_error(png_ptr, strerror(errno)); + + if (fwrite(buffer, cb, 1, io->output) != 1) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - if (row != NULL) free(row); - if (display != NULL) free(display); - return 0; + perror("temporary file"); + fprintf(stderr, "temporary file PNG write failed\n"); + exit(1); } +} - png_init_io(png_ptr, fp); +static void read_by_row(png_structp png_ptr, png_infop info_ptr, + FILE *write_ptr, FILE *read_ptr) +{ + /* These don't get freed on error, this is fine; the program immediately + * exits. + */ + png_bytep row = NULL, display = NULL; + io_data io_copy; - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - png_error(png_ptr, "OOM allocating info structure"); + if (write_ptr != NULL) + { + /* Set up for a copy to the temporary file: */ + io_copy.input = read_ptr; + io_copy.output = write_ptr; + png_set_read_fn(png_ptr, &io_copy, read_and_copy); + } png_read_info(png_ptr, info_ptr); { png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); - row = malloc(rowbytes); - display = malloc(rowbytes); + row = voidcast(png_bytep,malloc(rowbytes)); + display = voidcast(png_bytep,malloc(rowbytes)); if (row == NULL || display == NULL) png_error(png_ptr, "OOM allocating row buffers"); @@ -81,7 +108,8 @@ static int read_png(FILE *fp) png_uint_32 y = height; /* NOTE: this trashes the row each time; interlace handling won't - * work, but this avoids memory thrashing for speed testing. + * work, but this avoids memory thrashing for speed testing and is + * somewhat representative of an application that works row-by-row. */ while (y-- > 0) png_read_row(png_ptr, row, display); @@ -91,9 +119,51 @@ static int read_png(FILE *fp) /* Make sure to read to the end of the file: */ png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + /* Free this up: */ free(row); free(display); +} + +static PNG_CALLBACK(void, no_warnings, (png_structp png_ptr, + png_const_charp warning)) +{ + (void)png_ptr; + (void)warning; +} + +static int read_png(FILE *fp, png_int_32 transforms, FILE *write_file) +{ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0, + no_warnings); + 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_BENIGN_ERRORS_SUPPORTED + png_set_benign_errors(png_ptr, 1/*allowed*/); +# endif + png_init_io(png_ptr, fp); + + info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr == NULL) + png_error(png_ptr, "OOM allocating info structure"); + + if (transforms < 0) + read_by_row(png_ptr, info_ptr, write_file, fp); + + else + png_read_png(png_ptr, info_ptr, transforms, NULL/*params*/); + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 1; } @@ -108,7 +178,7 @@ static int mytime(struct timespec *t) return 0; } -static int perform_one_test(FILE *fp, int nfiles) +static int perform_one_test(FILE *fp, int nfiles, png_int_32 transforms) { int i; struct timespec before, after; @@ -120,7 +190,7 @@ static int perform_one_test(FILE *fp, int nfiles) { for (i=0; i {files}\n" +" Read the files into , output the count. Options are ignored.\n" +" timepng --dissemble [options]\n" +" Time files from , additional files may not be given.\n" +" Otherwise:\n" +" Read the files into a temporary file and time the decode\n" +"Transforms:\n" +" --by-image: read by image with png_read_png\n" +" --: implies by-image, use PNG_TRANSFORM_\n" +" Otherwise: read by row using png_read_row (to a single row buffer)\n" + /* ISO C90 string length max 509 */);fprintf(stderr, +"{files}:\n" +" PNG files to copy into the assembly and time. Invalid files are skipped\n" +" with appropriate error messages. If no files are given the list of files\n" +" is read from stdin with each file name terminated by a newline\n" +"Output:\n" +" For --assemble the output is the name of the assembly file followed by the\n" +" count of the files it contains; the arguments for --dissemble. Otherwise\n" +" the output is the total decode time in seconds.\n"); + + exit(99); } int main(int argc, char **argv) { int ok = 0; - FILE *fp = tmpfile(); + int err = 0; + int nfiles = 0; + int transforms = -1; /* by row */ + const char *assembly = NULL; + FILE *fp; - if (fp != NULL) + if (argc > 2 && strcmp(argv[1], "--assemble") == 0) { - int err = 0; - int nfiles = 0; - - if (argc > 1) + /* Just build the test file, argv[2] is the file name. */ + assembly = argv[2]; + fp = fopen(assembly, "wb"); + if (fp == NULL) { - int i; + perror(assembly); + fprintf(stderr, "timepng --assemble %s: could not open for write\n", + assembly); + usage(NULL); + } - for (i=1; i 3 && strcmp(argv[1], "--dissemble") == 0) + { + fp = fopen(argv[2], "rb"); + + if (fp == NULL) + { + perror(argv[2]); + fprintf(stderr, "timepng --dissemble %s: could not open for read\n", + argv[2]); + usage(NULL); + } + + nfiles = atoi(argv[3]); + if (nfiles <= 0) + { + fprintf(stderr, + "timepng --dissemble : %s is not a count\n", + argv[3]); + exit(99); + } +#ifdef __COVERITY__ + else + { + nfiles &= PNG_UINT_31_MAX; + } +#endif + + argv += 3; + argc -= 3; + } + + else /* Else use a temporary file */ + { +#ifndef __COVERITY__ + fp = tmpfile(); +#else + /* Experimental. Coverity says tmpfile() is insecure because it + * generates predictable names. + * + * It is possible to satisfy Coverity by using mkstemp(); however, + * any platform supporting mkstemp() undoubtedly has a secure tmpfile() + * implementation as well, and doesn't need the fix. Note that + * the fix won't work on platforms that don't support mkstemp(). + * + * https://www.securecoding.cert.org/confluence/display/c/ + * FIO21-C.+Do+not+create+temporary+files+in+shared+directories + * says that most historic implementations of tmpfile() provide + * only a limited number of possible temporary file names + * (usually 26) before file names are recycled. That article also + * provides a secure solution that unfortunately depends upon mkstemp(). + */ + char tmpfile[] = "timepng-XXXXXX"; + int filedes; + umask(0177); + filedes = mkstemp(tmpfile); + if (filedes < 0) + fp = NULL; + else + { + fp = fdopen(filedes,"w+"); + /* Hide the filename immediately and ensure that the file does + * not exist after the program ends + */ + (void) unlink(tmpfile); + } +#endif + + if (fp == NULL) + { + perror("tmpfile"); + fprintf(stderr, "timepng: could not open the temporary file\n"); + exit(1); /* not a user error */ + } + } + + /* Handle the transforms: */ + while (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-') + { + const char *opt = *++argv + 2; + + --argc; + + /* Transforms turn on the by-image processing and maybe set some + * transforms: + */ + if (transforms == -1) + transforms = PNG_TRANSFORM_IDENTITY; + + if (strcmp(opt, "by-image") == 0) + { + /* handled above */ + } + +# define OPT(name) else if (strcmp(opt, #name) == 0)\ + transforms |= PNG_TRANSFORM_ ## name + + OPT(STRIP_16); + OPT(STRIP_ALPHA); + OPT(PACKING); + OPT(PACKSWAP); + OPT(EXPAND); + OPT(INVERT_MONO); + OPT(SHIFT); + OPT(BGR); + OPT(SWAP_ALPHA); + OPT(SWAP_ENDIAN); + OPT(INVERT_ALPHA); + OPT(STRIP_FILLER); + OPT(STRIP_FILLER_BEFORE); + OPT(STRIP_FILLER_AFTER); + OPT(GRAY_TO_RGB); + OPT(EXPAND_16); + OPT(SCALE_16); + + else + { + fprintf(stderr, "timepng %s: unrecognized transform\n", opt); + usage(fp); + } + } + + /* Handle the files: */ + if (argc > 1 && nfiles > 0) + usage(fp); /* Additional files not valid with --dissemble */ + + else if (argc > 1) + { + int i; + + for (i=1; i 0) + { + if (assembly != NULL) + { + if (fflush(fp) && !ferror(fp) && fclose(fp)) + { + perror(assembly); + fprintf(stderr, "%s: close failed\n", assembly); + } else { - err = 1; - break; + printf("%s %d\n", assembly, nfiles); + fflush(stdout); + ok = !ferror(stdout); } } + + else + { + ok = perform_one_test(fp, nfiles, transforms); + (void)fclose(fp); + } } else - { - char filename[FILENAME_MAX+1]; - - while (fgets(filename, FILENAME_MAX+1, stdin)) - { - size_t len = strlen(filename); - - if (filename[len-1] == '\n') - { - filename[len-1] = 0; - if (add_one_file(fp, filename)) - ++nfiles; - - else - { - err = 1; - break; - } - } - - else - { - fprintf(stderr, "timepng: truncated file name ...%s\n", - filename+len-32); - err = 1; - break; - } - } - - if (ferror(stdin)) - { - fprintf(stderr, "timepng: stdin: read error\n"); - err = 1; - } - } - - if (!err) - { - if (nfiles > 0) - ok = perform_one_test(fp, nfiles); - - else - fprintf(stderr, "usage: timepng {files} or ls files | timepng\n"); - } - - (void)fclose(fp); + usage(fp); } else - fprintf(stderr, "timepng: could not open temporary file\n"); + (void)fclose(fp); /* Exit code 0 on success. */ return ok == 0; } +#else /* !sufficient support */ +int main(void) { return 77; } +#endif /* !sufficient support */ diff --git a/png.h b/png.h index 9bce9707c..7930e1843 100644 --- a/png.h +++ b/png.h @@ -1,7 +1,7 @@ /* png.h - header file for PNG reference library * - * libpng version 1.7.0beta80, May 5, 2016 + * libpng version 1.7.0beta80, May 6, 2016 * * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) @@ -12,7 +12,7 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.7.0beta80, May 5, 2016: + * libpng versions 0.97, January 1998, through 1.7.0beta80, May 6, 2016: * Glenn Randers-Pehrson. * See also "Contributing Authors", below. */ @@ -25,7 +25,7 @@ * * This code is released under the libpng license. * - * libpng versions 1.0.7, July 1, 2000, through 1.7.0beta80, May 5, 2016, are + * libpng versions 1.0.7, July 1, 2000, through 1.7.0beta80, May 6, 2016, are * Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are * derived from libpng-1.0.6, and are distributed according to the same * disclaimer and license as libpng-1.0.6 with the following individuals @@ -218,7 +218,7 @@ * Y2K compliance in libpng: * ========================= * - * May 5, 2016 + * May 6, 2016 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. @@ -288,7 +288,7 @@ /* Version information for png.h - this should match the version in png.c */ #define PNG_LIBPNG_VER_STRING "1.7.0beta80" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.7.0beta80 - May 5, 2016\n" + " libpng version 1.7.0beta80 - May 6, 2016\n" #define PNG_LIBPNG_VER_SONUM 17 #define PNG_LIBPNG_VER_DLLNUM 17