diff --git a/ANNOUNCE b/ANNOUNCE index 3f02f3e54..3e2445007 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -285,6 +285,23 @@ Version 1.7.0beta13 [May 10, 2013] Added a call to png_set_packing() Initialize dimension values so if sscanf fails at least we have known invalid values. + Calculate our own zlib windowBits when decoding rather than trusting the + CMF bytes in the PNG datastream. + Added an option to force maximum window size for inflating, which was + the behavior of libpng15 and earlier. + Added png-fix-itxt and png-fix-too-far-back to the built programs and + removed warnings from the source code and timepng that are revealed as + a result. + Detect wrong libpng versions linked to png-fix-too-far-back, which currently + only works with libpng versions that can be made to reliably fail when + the deflate data contains an out-of-window reference. This means only + 1.6 and later. + Attempt to detect configuration issues with png-fix-too-far-back, which + requires both the correct libpng and the correct zlib to function + correctly. + Check ZLIB_VERNUM for mismatches, enclose #error in quotes + Added information in the documentation about problems with and fixes for + the bad CRC and bad iTXt chunk situations. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index 80cc136fd..daac04650 100644 --- a/CHANGES +++ b/CHANGES @@ -4573,6 +4573,23 @@ Version 1.7.0beta13 [May 10, 2013] Added a call to png_set_packing() Initialize dimension values so if sscanf fails at least we have known invalid values. + Calculate our own zlib windowBits when decoding rather than trusting the + CMF bytes in the PNG datastream. + Added an option to force maximum window size for inflating, which was + the behavior of libpng15 and earlier. + Added png-fix-itxt and png-fix-too-far-back to the built programs and + removed warnings from the source code and timepng that are revealed as + a result. + Detect wrong libpng versions linked to png-fix-too-far-back, which currently + only works with libpng versions that can be made to reliably fail when + the deflate data contains an out-of-window reference. This means only + 1.6 and later. + Attempt to detect configuration issues with png-fix-too-far-back, which + requires both the correct libpng and the correct zlib to function + correctly. + Check ZLIB_VERNUM for mismatches, enclose #error in quotes + Added information in the documentation about problems with and fixes for + the bad CRC and bad iTXt chunk situations. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/LICENSE b/LICENSE index 5969dac04..9514e7fc2 100644 --- a/LICENSE +++ b/LICENSE @@ -10,7 +10,7 @@ this sentence. This code is released under the libpng license. -libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, April 30, 2013, are +libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, May 10, 2013, are Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.2.5 with the following individual added to the list of Contributing Authors @@ -108,4 +108,4 @@ certification mark of the Open Source Initiative. Glenn Randers-Pehrson glennrp at users.sourceforge.net -April 30, 2013 +May 10, 2013 diff --git a/Makefile.am b/Makefile.am index 006cb9368..c51ee4d53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,6 +9,9 @@ ACLOCAL_AMFLAGS = -I scripts # test programs - run on make check, make distcheck check_PROGRAMS= pngtest pngunknown pngstest pngvalid +# Utilities - installed +bin_PROGRAMS= png-fix-too-far-back png-fix-itxt + pngtest_SOURCES = pngtest.c pngtest_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la @@ -21,6 +24,11 @@ pngstest_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la pngunknown_SOURCES = contrib/libtests/pngunknown.c pngunknown_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la +png_fix_too_far_back_SOURCES = contrib/tools/png-fix-too-far-back.c +png_fix_too_far_back_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la + +png_fix_itxt_SOURCES = contrib/tools/png-fix-itxt.c + # Generally these are single line shell scripts to run a test with a particular # set of parameters: TESTS =\ @@ -182,14 +190,15 @@ endif $(srcdir)/scripts/pnglibconf.h.prebuilt: @echo "Attempting to build $@" >&2 @echo "This is a machine generated file, but if you want to make" >&2 - @echo "a new one simply make 'scripts/pnglibconf.out' and copy that" >&2 + @echo "a new one simply make 'scripts/pnglibconf.out', copy that" >&2 + @echo "AND set PNG_ZLIB_VERNUM to 0 (you MUST do this)" >&2 @exit 1 # The following is necessary to ensure that the local pnglibconf.h is used, not # an installed one (this can happen immediately after on a clean system if # 'make test' is the first thing the user does.) -contrib/libtests/pngstest.o contrib/libtests/pngvalid.o pngtest.o: pnglibconf.h -contrib/libtests/pngunknown.o: pnglibconf.h +pngstest.o pngvalid.o pngtest.o pngunknown.o timepng.o: pnglibconf.h +png-fix-too-far-back.o png-fix-itxt.o: pnglibconf.h # We must use -DPNG_NO_USE_READ_MACROS here even when the library may actually # be built with PNG_USE_READ_MACROS; this prevents the read macros from diff --git a/README b/README index c5f21335c..19d755a14 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -README for libpng version 1.7.0beta13 - April 30, 2013 (shared library 17.0) +README for libpng version 1.7.0beta13 - May 10, 2013 (shared library 17.0) See the note about version numbers near the top of png.h See INSTALL for instructions on how to install libpng. diff --git a/contrib/tools/png-fix-itxt.c b/contrib/tools/png-fix-itxt.c new file mode 100644 index 000000000..7cbd996ce --- /dev/null +++ b/contrib/tools/png-fix-itxt.c @@ -0,0 +1,153 @@ + +/* png-fix-itxt version 1.0.0 + * + * Copyright 2013 Glenn Randers-Pehrson + * Last changed in libpng 1.6.3 [(PENDING RELEASE)] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Usage: + * + * png-fix-itxt.exe < bad.png > good.png + * + * Fixes a PNG file written with libpng-1.6.0 or 1.6.1 that has one or more + * uncompressed iTXt chunks. Assumes that the actual length is greater + * than or equal to the value in the length byte, and that the CRC is + * correct for the actual length. This program hunts for the CRC and + * adjusts the length byte accordingly. It is not an error to process a + * PNG file that has no iTXt chunks or one that has valid iTXt chunks; + * such files will simply be copied. + * + * Requires zlib (for crc32 and Z_NULL); build with + * + * gcc -O -o png-fix-itxt png-fix-itxt.c -lz + * + * If you need to handle iTXt chunks larger than 500000 kbytes you must + * rebuild png-fix-itxt with a larger values of MAX_LENGTH (or a smaller value + * if you know you will never encounter such huge iTXt chunks). + */ + +#include +#include + +#define MAX_LENGTH 500000 + +#define GETBREAK ((unsigned char)(inchar=getchar())); if (inchar == EOF) break + +int +main(void) +{ + unsigned int i; + unsigned char buf[MAX_LENGTH]; + unsigned long crc; + unsigned char c; + int inchar; + +/* Skip 8-byte signature */ + for (i=8; i; i--) + { + c=GETBREAK; + putchar(c); + } + +if (inchar != EOF) +for (;;) + { + /* Read the length */ + unsigned long length; /* must be 32 bits! */ + c=GETBREAK; buf[0] = c; length = c; length <<= 8; + c=GETBREAK; buf[1] = c; length += c; length <<= 8; + c=GETBREAK; buf[2] = c; length += c; length <<= 8; + c=GETBREAK; buf[3] = c; length += c; + + /* Read the chunkname */ + c=GETBREAK; buf[4] = c; + c=GETBREAK; buf[5] = c; + c=GETBREAK; buf[6] = c; + c=GETBREAK; buf[7] = c; + + + /* The iTXt chunk type expressed as integers is (105, 84, 88, 116) */ + if (buf[4] == 105 && buf[5] == 84 && buf[6] == 88 && buf[7] == 116) + { + if (length >= MAX_LENGTH-12) + break; /* To do: handle this more gracefully */ + + /* Initialize the CRC */ + crc = crc32(0, Z_NULL, 0); + + /* Copy the data bytes */ + for (i=8; i < length + 12; i++) + { + c=GETBREAK; buf[i] = c; + } + + /* Calculate the CRC */ + crc = crc32(crc, buf+4, (uInt)length+4); + + for (;;) + { + /* Check the CRC */ + if (((crc >> 24) & 0xff) == buf[length+8] && + ((crc >> 16) & 0xff) == buf[length+9] && + ((crc >> 8) & 0xff) == buf[length+10] && + ((crc ) & 0xff) == buf[length+11]) + break; + + length++; + + if (length >= MAX_LENGTH-12) + break; + + c=GETBREAK; + buf[length+11]=c; + + /* Update the CRC */ + crc = crc32(crc, buf+7+length, 1); + } + + /* Update length bytes */ + buf[0] = (length << 24) & 0xff; + buf[1] = (length << 16) & 0xff; + buf[2] = (length << 8) & 0xff; + buf[3] = (length ) & 0xff; + + /* Write the fixed iTXt chunk (length, name, data, crc) */ + for (i=0; i +#include +#include +#include + +#define PROGRAM_NAME "png-fix-too-far-back" + +/* Define the following to use this program against your installed libpng, + * rather than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +#if PNG_LIBPNG_VER < 10603 /* 1.6.3 */ +# error "png-fix-too-far-back will not work with libpng prior to 1.6.3" +#endif + +#ifdef PNG_READ_SUPPORTED +#include + +#ifndef PNG_MAXIMUM_INFLATE_WINDOW +# error "png-fix-too-far-back not supported in this libpng version" +#endif + +#if PNG_ZLIB_VERNUM >= 0x1240 + +/* Copied from pngpriv.h */ +#ifdef __cplusplus +# define png_voidcast(type, value) static_cast(value) +# define png_constcast(type, value) const_cast(value) +# define png_aligncast(type, value) \ + static_cast(static_cast(value)) +# define png_aligncastconst(type, value) \ + static_cast(static_cast(value)) +#else +# define png_voidcast(type, value) (value) +# define png_constcast(type, value) ((type)(value)) +# define png_aligncast(type, value) ((void*)(value)) +# define png_aligncastconst(type, value) ((const void*)(value)) +#endif /* __cplusplus */ + +static int idat_error = 0; +static int verbose = 0; +static int errors = 0; +static int warnings = 0; +#ifdef PNG_MAXIMUM_INFLATE_WINDOW + static int set_option = 0; +#endif +static const char *name = "stdin"; +static uLong crc_IDAT_head; /* CRC32 of "IDAT" */ +static uLong crc_IEND; +static z_stream z_idat; + +/* Control structure for the temporary file */ +typedef struct +{ + size_t image_size; + off_t file_size; + fpos_t header_pos; + fpos_t crc_pos; + uLong crc_tail; /* CRC of bytes after header */ + png_uint_32 len_tail; /* Count thereof */ + png_byte header[2]; + + /* Image info */ + png_uint_32 width; + png_uint_32 height; + png_byte bit_depth; + png_byte color_type; + png_byte compression_method; + png_byte filter_method; + png_byte interlace_method; +} IDAT_info; + +static png_uint_32 +mult(png_uint_32 n, png_uint_32 m) +{ + if ((n + (m-1)) / m > 0xffffffff/m) + { + fprintf(stderr, "%s: overflow (%lu, %u)\n", name, (unsigned long)n, m); + exit(2); + } + + return n * m; +} + +static size_t +image_size(const IDAT_info *info) +{ + unsigned int pd = info->bit_depth; + size_t cb; + + switch (info->color_type) + { + case 0: case 3: + break; + + case 2: /* rgb */ + pd *= 3; + break; + + case 4: /* ga */ + pd *= 2; + break; + + case 6: /* rgba */ + pd *= 4; + break; + + default: + fprintf(stderr, "%s: invalid color type (%d)\n", name, + info->color_type); + exit(2); + } + + switch (info->interlace_method) + { + case PNG_INTERLACE_ADAM7: + /* Interlacing makes the image larger because of the replication of + * both the filter byte and the padding to a byte boundary. + */ + { + int pass; + + for (cb=0, pass=0; pass<=6; ++pass) + { + png_uint_32 pw = PNG_PASS_COLS(info->width, pass); + + if (pw > 0) + cb += mult(((mult(pd, pw)+7) >> 3)+1, + PNG_PASS_ROWS(info->height, pass)); + } + } + break; + + case PNG_INTERLACE_NONE: + cb = mult(info->height, 1+((mult(info->width, pd) + 7) >> 3)); + break; + + default: + fprintf(stderr, "%s: invalid interlace type %d\n", name, + info->interlace_method); + exit(2); + } + + return cb; +} + +static int +image_windowBits(const IDAT_info *info) +{ + size_t cb = image_size(info); + + if (cb > 16384) return 15; + if (cb > 8192) return 14; + if (cb > 4096) return 13; + if (cb > 2048) return 12; + if (cb > 1024) return 11; + if (cb > 512) return 10; + if (cb > 256) return 9; + return 8; +} + +static void +error_handler(png_structp png_ptr, png_const_charp message) +{ + if (strcmp(message, "IDAT: invalid distance too far back") == 0) + idat_error = 1; + + else if (errors || verbose) + fprintf(stderr, "%s: %s\n", name, message); + + png_longjmp(png_ptr, 1); +} + +static void +warning_handler(png_structp png_ptr, png_const_charp message) +{ + if (warnings || verbose) + fprintf(stderr, "%s: %s\n", name, message); + + (void)png_ptr; +} + +static int +read_png(FILE *fp) +{ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0, + error_handler, warning_handler); + png_infop info_ptr = NULL; + png_bytep row = NULL, display = NULL; + + if (png_ptr == NULL) + return 0; + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (row != NULL) free(row); + if (display != NULL) free(display); + return 0; + } + +# ifdef PNG_MAXIMUM_INFLATE_WINDOW + png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, set_option != 0); +# 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"); + + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); + + png_read_info(png_ptr, info_ptr); + + /* Limit the decompression buffer size to 1 - this ensures that overlong + * length codes are always detected. + */ + png_set_compression_buffer_size(png_ptr, 1); + + { + png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); + + row = png_voidcast(png_byte*, malloc(rowbytes)); + display = png_voidcast(png_byte*, malloc(rowbytes)); + + if (row == NULL || display == NULL) + png_error(png_ptr, "OOM allocating row buffers"); + + { + png_uint_32 height = png_get_image_height(png_ptr, info_ptr); + int passes = png_set_interlace_handling(png_ptr); + int pass; + + png_start_read_image(png_ptr); + + for (pass = 0; pass < passes; ++pass) + { + 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. + */ + while (y-- > 0) + png_read_row(png_ptr, row, display); + } + } + } + + /* 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(row); + free(display); + return 1; +} + +/* Chunk tags (copied from pngpriv.h) */ +#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) +#define PNG_CHUNK(b1,b2,b3,b4) \ + (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) + +#if PNG_LIBPNG_VER < 10700 /* These were moved to png.h in 1.7.0 */ +#define png_IHDR PNG_CHUNK( 73, 72, 68, 82) +#define png_IDAT PNG_CHUNK( 73, 68, 65, 84) +#define png_IEND PNG_CHUNK( 73, 69, 78, 68) +#define png_PLTE PNG_CHUNK( 80, 76, 84, 69) +#define png_bKGD PNG_CHUNK( 98, 75, 71, 68) +#define png_cHRM PNG_CHUNK( 99, 72, 82, 77) +#define png_gAMA PNG_CHUNK(103, 65, 77, 65) +#define png_hIST PNG_CHUNK(104, 73, 83, 84) +#define png_iCCP PNG_CHUNK(105, 67, 67, 80) +#define png_iTXt PNG_CHUNK(105, 84, 88, 116) +#define png_oFFs PNG_CHUNK(111, 70, 70, 115) +#define png_pCAL PNG_CHUNK(112, 67, 65, 76) +#define png_sCAL PNG_CHUNK(115, 67, 65, 76) +#define png_pHYs PNG_CHUNK(112, 72, 89, 115) +#define png_sBIT PNG_CHUNK(115, 66, 73, 84) +#define png_sPLT PNG_CHUNK(115, 80, 76, 84) +#define png_sRGB PNG_CHUNK(115, 82, 71, 66) +#define png_sTER PNG_CHUNK(115, 84, 69, 82) +#define png_tEXt PNG_CHUNK(116, 69, 88, 116) +#define png_tIME PNG_CHUNK(116, 73, 77, 69) +#define png_tRNS PNG_CHUNK(116, 82, 78, 83) +#define png_zTXt PNG_CHUNK(122, 84, 88, 116) +#endif + +static void +rx(FILE *fp, png_bytep buf, off_t cb) +{ + if (fread(buf,cb,1,fp) != 1) { + fprintf(stderr, "%s: failed to read %lu bytes\n", name, + (unsigned long)cb); + exit(2); + } +} + +static png_uint_32 +r32(FILE *fp) +{ + png_byte buf[4]; + rx(fp, buf, 4); + return ((((((png_uint_32)buf[0] << 8)+buf[1]) << 8)+buf[2]) << 8) + buf[3]; +} + +static void +wx(FILE *fp, png_const_bytep buf, off_t cb) +{ + if (fwrite(buf,cb,1,fp) != 1) { + fprintf(stderr, "%s: failed to write %lu bytes\n", name, + (unsigned long)cb); + exit(3); + } +} + +static void +w32(FILE *fp, png_uint_32 val) +{ + png_byte buf[4]; + buf[0] = (png_byte)(val >> 24); + buf[1] = (png_byte)(val >> 16); + buf[2] = (png_byte)(val >> 8); + buf[3] = (png_byte)(val); + wx(fp, buf, 4); +} + +static void +wcrc(FILE *fp, uLong crc) +{ + /* Safe cast because a CRC is 32 bits */ + w32(fp, (png_uint_32)crc); +} + +static void +copy(FILE *fp, FILE *fpIn, off_t cb) +{ + png_byte buffer[1024]; + + while (cb >= 1024) + { + rx(fpIn, buffer, 1024); + wx(fp, buffer, 1024); + cb -= 1024; + } + + if (cb > 0) + { + rx(fpIn, buffer, cb); + wx(fp, buffer, cb); + } +} + +static void +skip_bytes(FILE *fpIn, png_uint_32 cb) +{ + png_byte buffer[1024]; + + while (cb >= 1024) + { + rx(fpIn, buffer, 1024); + cb -= 1024; + } + + if (cb > 0) + rx(fpIn, buffer, cb); +} + +static void +safe_getpos(FILE *fp, fpos_t *pos) +{ + if (fgetpos(fp, pos)) + { + perror("tmpfile"); + fprintf(stderr, "%s: tmpfile fgetpos failed\n", name); + exit(3); + } +} + +static void +safe_setpos(FILE *fp, fpos_t *pos) +{ + if (fflush(fp)) + { + perror("tmpfile"); + fprintf(stderr, "%s: tmpfile fflush failed\n", name); + exit(3); + } + + if (fsetpos(fp, pos)) + { + perror("tmpfile"); + fprintf(stderr, "%s: tmpfile fsetpos failed\n", name); + exit(3); + } +} + +static void +idat_update(FILE *fp, IDAT_info *info) +{ + uLong crc; + + safe_setpos(fp, &info->header_pos); + wx(fp, info->header, 2); + + crc = crc32(crc_IDAT_head, info->header, 2); + crc = crc32_combine(crc, info->crc_tail, info->len_tail); + + safe_setpos(fp, &info->crc_pos); + wcrc(fp, crc); +} + +static void +set_bits(const char *file, FILE *fp, IDAT_info *info, int bits) +{ + int byte1 = (info->header[0] & 0xf) + ((bits-8) << 4); + int byte2 = info->header[1] & 0xe0; + + /* The checksum calculation: */ + byte2 += 0x1f - ((byte1 << 8) + byte2) % 0x1f; + + info->header[0] = (png_byte)byte1; + info->header[1] = (png_byte)byte2; + + if (verbose) + fprintf(stderr, "%s: trying windowBits %d (Z_CMF = 0x%x)\n", file, bits, + byte1); + + idat_update(fp, info); +} + +static void +ptagchar(png_uint_32 ch) +{ + ch &= 0xff; + if (isprint(ch)) + putc(ch, stderr); + + else + fprintf(stderr, "[%02x]", ch); +} + +static void +ptag(png_uint_32 tag) +{ + if (tag != 0) + { + ptag(tag >> 8); + ptagchar(tag); + } +} + +static int +fix_one(FILE *fp, FILE *fpIn, IDAT_info *info, png_uint_32 max_IDAT, int strip) +{ + int state = 0; + /* 0: at beginning, before first IDAT + * 1: read first CMF header byte + * 2: read second byte, in first IDAT + * 3: after first IDAT + * +4: saw deflate stream end. + */ + int truncated_idat = 0; /* Count of spurious IDAT bytes */ + uLong crc_idat = 0; /* Running CRC of current IDAT */ + png_uint_32 len_IDAT = 0; /* Length of current IDAT */ + fpos_t pos_IDAT_length; /* fpos_t of length field in current IDAT */ + + /* The signature: */ + { + png_byte buf[8]; + rx(fpIn, buf, 8); + wx(fp, buf, 8); + } + + info->file_size = 45; /* signature + IHDR + IEND */ + + for (;;) /* Chunk for loop */ + { + png_uint_32 len = r32(fpIn); + png_uint_32 tag = r32(fpIn); + + if (tag == png_IHDR) + { + /* Need width, height, color type, bit depth and interlace for the + * file. + */ + info->width = r32(fpIn); + info->height = r32(fpIn); + rx(fpIn, &info->bit_depth, 1); + rx(fpIn, &info->color_type, 1); + rx(fpIn, &info->compression_method, 1); + rx(fpIn, &info->filter_method, 1); + rx(fpIn, &info->interlace_method, 1); + + /* And write the information. */ + w32(fp, len); + w32(fp, tag); + w32(fp, info->width); + w32(fp, info->height); + wx(fp, &info->bit_depth, 1); + wx(fp, &info->color_type, 1); + wx(fp, &info->compression_method, 1); + wx(fp, &info->filter_method, 1); + wx(fp, &info->interlace_method, 1); + + /* Copy the CRC */ + copy(fp, fpIn, 4); + } + + else if (tag == png_IEND) + { + /* Ok, write an IEND chunk and finish. */ + w32(fp, 0); + w32(fp, png_IEND); + wcrc(fp, crc_IEND); + break; + } + + else if (tag == png_IDAT && len > 0) + { + /* Write the chunk header now if it hasn't been written yet */ + if (len_IDAT == 0) + { + /* The length is set at the end: */ + safe_getpos(fp, &pos_IDAT_length); + w32(fp, max_IDAT); /* length, not yet written */ + w32(fp, png_IDAT); + + if (state == 0) /* Start of first IDAT */ + { + safe_getpos(fp, &info->header_pos); + /* This will become info->crc_tail: */ + crc_idat = crc32(0L, Z_NULL, 0); + } + + else + crc_idat = crc_IDAT_head; + } + + /* Do the zlib 2-byte header, it gets written out but not added + * to the CRC (yet): + */ + while (len > 0 && state < 2) + { + rx(fpIn, info->header + state, 1); + wx(fp, info->header + state, 1); + ++len_IDAT; + --len; + + if (state++ == 1) + { + /* The zlib stream is used to validate the compressed IDAT + * data in the most relaxed way possible. + */ + png_byte bdummy; + int ret; + + z_idat.next_in = info->header; + z_idat.avail_in = 2; + z_idat.next_out = &bdummy; /* Else Z_STREAM_ERROR! */ + z_idat.avail_out = 0; + + ret = inflate(&z_idat, Z_NO_FLUSH); + if (ret != Z_OK || z_idat.avail_in != 0) + { + fprintf(stderr, + "%s: unexpected/invalid inflate result %d \"%s\"\n", + name, ret, z_idat.msg); + return 1; + } + } + } /* while in zlib header */ + + /* Process further bytes in the IDAT chunk */ + while (len > 0 && state < 4) + { + png_byte b; + + rx(fpIn, &b, 1); + --len; + + /* Do this 1 byte at a time to guarantee + * detecting errors (in particular zlib can skip the + * 'too-far-back' error if the output buffer is bigger than + * the window size.) + */ + z_idat.next_in = &b; + z_idat.avail_in = 1; + + do + { + int ret; + png_byte bout; + + z_idat.next_out = &bout; + z_idat.avail_out = 1; + + ret = inflate(&z_idat, Z_SYNC_FLUSH); + + if (z_idat.avail_out == 0) + ++info->image_size; + + switch (ret) + { + case Z_OK: + /* Just keep going */ + break; + + case Z_BUF_ERROR: + if (z_idat.avail_in > 0) + { + fprintf(stderr, + "%s: unexpected buffer error \"%s\"\n", + name, z_idat.msg); + return 1; + } + goto end_loop; + + case Z_STREAM_END: + /* End of stream */ + state |= 4; + goto end_loop; + + default: + fprintf(stderr, "%s: bad zlib stream %d, \"%s\"\n", + name, ret, z_idat.msg); + return 1; + } + } while (z_idat.avail_in > 0 || z_idat.avail_out == 0); + + /* The byte need not be consumed, if, for example, there is a + * spurious byte after the end of the zlib data. + */ + end_loop: + if (z_idat.avail_in == 0) + { + /* Write it and update the length information and running + * CRC. + */ + wx(fp, &b, 1); + crc_idat = crc32(crc_idat, &b, 1); + ++len_IDAT; + } + + else + ++truncated_idat; + + if (len_IDAT >= max_IDAT || state >= 4) + { + /* Either the IDAT chunk is full or we've seen the end of + * the deflate stream, or both. Flush the chunk and handle + * the details of the first chunk. + */ + fpos_t save; + + if ((state & 3) < 3) /* First IDAT */ + { + safe_getpos(fp, &info->crc_pos); + info->crc_tail = crc_idat; + info->len_tail = len_IDAT-2; + } + + /* This is not the correct value for the first IDAT! */ + wcrc(fp, crc_idat); + state |= 3; + + /* Update the length if it is not max_IDAT: */ + if (len_IDAT != max_IDAT) + { + safe_getpos(fp, &save); + safe_setpos(fp, &pos_IDAT_length); + w32(fp, len_IDAT); + safe_setpos(fp, &save); + } + + /* Add this IDAT to the file size: */ + info->file_size += 12 + len_IDAT; + } + } /* while len > 0 && state < 4 */ + + /* The above loop only exits on 0 bytes left or end of stream. If + * the stream ended with bytes left, discard them: + */ + if (len > 0) + { + truncated_idat += len; + /* Skip those bytes and the CRC */ + skip_bytes(fpIn, len+4); + } + + else + skip_bytes(fpIn, 4); /* The CRC */ + } /* IDAT and len > 0 */ + + else + { + int skip = 0; + + if (tag == png_IDAT) + skip = 1; + + else if (state == 0) + { + /* Chunk before IDAT */ + if (!skip) switch (strip) + { + case 0: /* Don't strip */ + break; + + case 1: /* Keep gAMA, sRGB */ + if (tag == png_gAMA || tag == png_sRGB) + break; + /* Fall through */ + + default: /* Keep only IHDR, PLTE, tRNS */ + if (tag == png_IHDR || tag == png_PLTE || tag == png_tRNS) + break; + + skip = 1; + break; + } + } + + else if (state >= 4) + { + /* Keep nothing after IDAT if stripping: */ + skip = strip; + } + + else + { + /* This is either an unterminated deflate stream or a spurious + * non-IDAT chunk in the list of IDAT chunks. Both are fatal + * errors. + */ + fprintf(stderr, "%s: tag '", name); + ptag(tag); + fprintf(stderr, "' after unterminated IDAT\n"); + break; + } + + /* Skip or send? */ + if (skip) + { + if (tag != png_IDAT && (tag & 0x20000000) == 0) + { + fprintf(stderr, "%s: unknown critical chunk '", name); + ptag(tag); + fprintf(stderr, "'\n"); + return 1; + } + + /* Skip this tag */ + if (fseek(fpIn, len+4, SEEK_CUR)) + { + perror(name); + fprintf(stderr, "%s: seek failed\n", name); + return 1; + } + } + + else /* Keep this tag */ + { + w32(fp, len); + w32(fp, tag); + copy(fp, fpIn, len+4); + info->file_size += 12+len; + } + } /* Not IDAT or len == 0 */ + } /* Chunk for loop */ + + /* Break out of the loop on error or end */ + if (state >= 4) + { + if (truncated_idat) + fprintf(stderr, "%s: removed %d bytes from end of IDAT\n", name, + truncated_idat); + + return 0; /* success */ + } + + /* This is somewhat generic but it works: */ + fprintf(stderr, "%s: unterminated/truncated PNG (%d)\n", name, state); + + return 1; +} + +static FILE *fpIn; + +static int +fix_file(FILE *fp, const char *file, png_uint_32 max_IDAT, int inplace, + int strip, int optimize, const char *output) +{ + IDAT_info info; + int imageBits, oldBits, bestBits, lowBits, newBits, ok_read; + + memset(&info, 0, sizeof info); + + name = file; + idat_error = 0; + + /* fpIn is closed by the caller if necessary */ + fpIn = fopen(file, "rb"); + if (fpIn == NULL) + { + perror(file); + fprintf(stderr, "%s: open failed\n", file); + return 1; + } + + /* With no arguments just check this file */ + if (optimize == 0 && strip == 0 && inplace == 0 && output == NULL) + return !read_png(fpIn); + + /* Otherwise, maybe, fix it */ + if (fix_one(fp, fpIn, &info, max_IDAT, strip)) + return 1; + + /* oldBits may be invalid, imageBits is always OK, newBits always records the + * actual window bits of the temporary file (fp). + */ + bestBits = imageBits = image_windowBits(&info); + newBits = oldBits = 8+(info.header[0] >> 4); + ok_read = 0; /* records a successful read */ + + /* Find the optimal (lowest) newBits */ + if (optimize) + for (lowBits=8; lowBits < bestBits;) + { + /* This will always set 'newBits' to a value lower than 'bestBits' because + * 'lowBits' is less than 'bestBits': + */ + newBits = (bestBits + lowBits) >> 1; + + set_bits(file, fp, &info, newBits); + + rewind(fp); + idat_error = 0; + + if (!read_png(fp)) + { + /* If idat_error is *not* set this is some other problem */ + if (!idat_error) + return 1; + + /* This is the hypothetical case where the IDAT has too much data *and* + * the window size is wrong. In fact this should never happen because + * of the way libpng handles a deflate stream that produces extra data. + */ + if (newBits >= imageBits) + { + fprintf(stderr, "%s: imageBits(%d) too low (%d)\n", file, imageBits, + newBits); + return 1; + } + + if (lowBits <= newBits) + lowBits = newBits+1; + } + + else + { + bestBits = newBits; + ok_read = 1; + } + } + + else if (bestBits > oldBits) + { + /* See if the original value is ok */ + rewind(fp); + idat_error = 0; + + if (read_png(fp)) + { + ok_read = 1; + bestBits = oldBits; + } + + else if (!idat_error) + return 1; + + /* Otherwise there is an IDAT error and no optimization is being done, so + * just use imageBits (which is already set in bestBits). + */ + } + + if (newBits != bestBits) + { + /* Update the header to the required value */ + newBits = bestBits; + + set_bits(file, fp, &info, newBits); + } + + if (!ok_read) + { + /* bestBits has not been checked */ + idat_error = 0; + rewind(fp); + ok_read = read_png(fp); + + if (idat_error) + { + /* This should never happen */ + fprintf(stderr, "%s: imageBits(%d) too low [%d]\n", file, imageBits, + newBits); + return 1; + } + + /* This means that the PNG has some other error */ + if (!ok_read) + return 1; + } + + /* Have a valid newBits */ + if (optimize) + printf("%2d %2d %2d %s %s %d %s\n", newBits, oldBits, imageBits, + newBits < imageBits ? "<" : "=", + newBits < oldBits ? "reduce " : + (newBits > oldBits ? "INCREASE" : "ok "), + newBits - oldBits, name); + +# ifdef PNG_MAXIMUM_INFLATE_WINDOW + /* Because setting libpng to use the maximum window bits breaks the + * read_png test above. + */ + if (set_option) + return 0; +# endif + + if (output != NULL || (inplace && (bestBits != oldBits || strip))) + { + FILE *fpOut; + + if (output != NULL) + fpOut = fopen(output, "wb"); + + else + { + fpOut = freopen(file, "wb", fpIn); + fpIn = NULL; + } + + if (fpOut == NULL) + { + perror(output); + fprintf(stderr, "%s: %s: open failed\n", file, output); + exit(3); + } + + rewind(fp); + copy(fpOut, fp, info.file_size); + + if (fflush(fpOut) || ferror(fpOut) || fclose(fpOut)) + { + perror(output != NULL ? output : file); + fprintf(stderr, "%s: %s: close failed\n", file, output); + if (output != NULL) + remove(output); + exit(3); + } + } + + return 0; +} + +static void +usage(const char *prog, int rc) +{ + /* ANSI C-90 limits strings to 509 characters, so use a string array: */ + size_t i; + static const char *usage_string[] = { +" Tests, optimizes and optionally fixes the zlib header in PNG files.\n", +" Optionally, when fixing, strips ancilliary chunks from the file.\n", +"\n", +"OPTIONS\n", +" OPERATION\n", +" By default files are just checked for readability.\n", +" --optimize (-o):\n", +" Find the smallest deflate window size for the file, also outputs\n", +" a summary of the result for each file.\n", +" --strip (-s):\n", +" Remove chunks except for IHDR, PLTE, IEND, tRNS, gAMA, sRGB. If\n", +" given twice remove gAMA and sRGB as well.\n", +" --max=:\n", +" Use IDAT chunks sized . If not given the the IDAT\n", +" chunks will be the maximum size permitted; 2^31-1 bytes.\n", +" MESSAGES\n", +" By default the program is silent.\n", +" --errors (-e):\n", +" Output errors from libpng (except too-far-back).\n", +" --warnings (-w):\n", +" Output warnings from libpng.\n", +" --verbose (-v):\n", +" Describe program progress (refer to the source).\n", +" OUTPUT\n", +" By default nothing is written.\n", +" --out=:\n", +" Write the optimized/corrected version of the next PNG to\n", +" . This overrides the following two options\n", +" --suffix=:\n", +" Set --out= for all following files, unless\n", +" overridden on a per-file basis by explicit --out. If no\n", +" --suffix= value is given behaves as --inplace.\n", +" --inplace (-i):\n", +" Modify the file in place. THIS IS DANGEROUS - please keep a\n", +" backup of the file because a program interrupt or bug will\n", +" result in a corrupted file.\n", +#ifdef PNG_MAXIMUM_INFLATE_WINDOW +" INTERNAL OPTIONS\n", +" --test:\n", +" Test the PNG_MAXIMUM_INFLATE_WINDOW option. Setting this\n", +" disables output as this would produce a broken file.\n", +#endif +"\n", +"EXIT CODES\n", +" 0: Success, all files pass the test, any output written ok.\n", +" 1: At least one file had a read error, all files checked.\n", +" 2: A file had an unrecoverable error (integer overflow, bad format),\n", +" the program exited immediately, without processing further files.\n", +" 3: An IO or out of memory error, or a file could not be opened.h\n", +"\n", +"DESCRIPTION\n", +" " PROGRAM_NAME " checks each PNG file on the command line\n", +" for errors. By default it is silent and just returns an exit code\n", +" (as above). Options allow the zlib error:\n", +"\n", +" \"invalid distance too far back\"\n", +"\n", +" to be fixed during the read and therefore test the file for other\n", +" errors that may prevent reading.\n", +"\n", +" Setting one of the \"OUTPUT\" options causes the possibly modified\n", +" file to be written to a new file or, with --inplace, to the existing\n", +" file.\n", +"\n", +" IMPORTANT: --inplace will overwrite the original file, if you use it\n", +" be sure to keep a backup of the original file, this program can fail\n", +" during the write and has been known to have serious bugs! A failure\n", +" during write will certainly damage the original file.\n", +"\n", +" Notice that some PNG files with the zlib header problem can still be\n", +" read by libpng under some circumstances. This program will still\n", +" detect and, if requested, correct the error.\n", +"\n", +" The output produced with --optimize is as follows:\n", +"\n", +" opt-bits curr-bits image-bits opt-flag opt-type change file\n", +"\n", +" opt-bits: The minimum window bits (8-15) that works, if the file\n", +" is written this is the value that will be stored.\n", +" curr-bits: The value currently stored in the file.\n", +" image-bits: The window bits value corresponding to the size of the\n", +" uncompressed PNG image data. When --optimize is not\n", +" given but --strip is, this value will be used if lower\n", +" than the current value.\n", +" opt-flag: < if the optimized bit value is less than that implied by\n", +" the PNG image size (opt-bits < image-bits)\n", +" = if optimization is not possible (opt-bits = image-bits)\n", +" opt-type: reduce if opts-bits < curr-bits\n", +" ok if opt-bits = curr-bits (no change required)\n", +" INCREASE if opt-bits > curr-bits (the file has the bug)\n", +" change: opt-bits - curr-bits, so negative if optimization is\n", +" possible, 0 if no change is required, positive if the\n", +" bug is present.\n", +" file: The file name.\n", +}; + + fprintf(stderr, "Usage: %s {[options] png-file}\n", prog); + + for (i=0; i < (sizeof usage_string)/(sizeof usage_string[0]); ++i) + fputs(usage_string[i], stderr); + + exit(rc); +} + +int +main(int argc, const char **argv) +{ + int err, strip = 0, optimize = 0, inplace = 0, done = 0; + png_uint_32 max_IDAT = 0x7fffffff; + FILE *fp; + const char *outfile = NULL; + const char *suffix = NULL; + const char *prog = *argv; + static const png_byte idat_bytes[4] = { 73, 68, 65, 84 }; + static const png_byte iend_bytes[4] = { 73, 69, 78, 68 }; + + /* Initialize this first, could be stored as a constant: */ + crc_IEND = crc_IDAT_head = crc32(0L, Z_NULL, 0); + crc_IDAT_head = crc32(crc_IDAT_head, idat_bytes, 4); + crc_IEND = crc32(crc_IEND, iend_bytes, 4); + + z_idat.next_in = Z_NULL; + z_idat.avail_in = 0; + z_idat.zalloc = Z_NULL; + z_idat.zfree = Z_NULL; + z_idat.opaque = Z_NULL; + + err = inflateInit(&z_idat); + if (err != Z_OK) + { + fprintf(stderr, "inflateInit failed %d \"%s\"\n", err, z_idat.msg); + inflateEnd(&z_idat); + return 3; + } + + fp = tmpfile(); + if (fp == NULL) + { + perror("tmpfile"); + fprintf(stderr, "could not open a temporary file\n"); + return 3; + } + + err = 0; + while (--argc > 0) + { + ++argv; + + if (strcmp(*argv, "--inplace") == 0 || strcmp(*argv, "-i") == 0) + ++inplace; + + else if (strncmp(*argv, "--max=", 6) == 0) + max_IDAT = (png_uint_32)atol(6+*argv); + + else if (strcmp(*argv, "--optimize") == 0 || strcmp(*argv, "-o") == 0) + ++optimize; + + else if (strncmp(*argv, "--out=", 6) == 0) + outfile = 6+*argv; + + else if (strncmp(*argv, "--suffix=", 9) == 0) + suffix = 9+*argv; + + else if (strcmp(*argv, "--strip") == 0 || strcmp(*argv, "-s") == 0) + ++strip; + + else if (strcmp(*argv, "--errors") == 0 || strcmp(*argv, "-e") == 0) + ++errors; + + else if (strcmp(*argv, "--warnings") == 0 || strcmp(*argv, "-w") == 0) + ++warnings; + + else if (strcmp(*argv, "--verbose") == 0 || strcmp(*argv, "-v") == 0) + ++verbose; + +# ifdef PNG_MAXIMUM_INFLATE_WINDOW + else if (strcmp(*argv, "--test") == 0) + ++set_option; +# endif + + else if ((*argv)[0] == '-') + usage(prog, 3); + + else + { + int ret, overwrite; + + if (outfile != NULL) + overwrite = 0; + + else if (suffix != NULL) + { + if (*suffix == 0) + overwrite = 1; + + else + { + static char temp_name[FILENAME_MAX]; + size_t filelen = strlen(*argv); + size_t suffixlen = strlen(suffix); + + if (filelen + suffixlen >= FILENAME_MAX) + { + fprintf(stderr, "%s: output file name too long: %s%s\n", prog, + *argv, suffix); + exit(3); + } + + memcpy(temp_name, *argv, filelen); + memcpy(temp_name+filelen, suffix, suffixlen); + temp_name[filelen+suffixlen] = 0; + + outfile = temp_name; + overwrite = 0; + } + } + + else + overwrite = inplace; + + err += + fix_file(fp, *argv, max_IDAT, overwrite, strip, optimize, outfile); + + if (fpIn != NULL) + { + fclose(fpIn); + fpIn = NULL; + } + + z_idat.next_in = z_idat.next_out = Z_NULL; + z_idat.avail_in = z_idat.avail_out = 0; + ret = inflateReset(&z_idat); + if (ret != Z_OK) + { + fprintf(stderr, "inflateReset failed %d \"%s\"\n", ret, z_idat.msg); + inflateEnd(&z_idat); + return 3; + } + + rewind(fp); + outfile = NULL; + ++done; + } + } + + inflateEnd(&z_idat); + + if (!done) + usage(prog, 0); + + return err != 0; +} + +#else /* PNG_ZLIB_VERNUM < 0x1240 */ +int +main(void) +{ + fprintf(stderr, + "png-fix-too-far-back needs libpng with a zlib >=1.2.4 (not 0x%x)\n", + PNG_ZLIB_VERNUM); + return 77; +} +#endif /* PNG_ZLIB_VERNUM */ + +#else /* No read support */ + +int +main(void) +{ + fprintf(stderr, "png-fix-too-far-back does not work without read support\n"); + return 77; +} +#endif /* PNG_READ_SUPPORTED */ diff --git a/libpng-manual.txt b/libpng-manual.txt index e289432cb..611f0b525 100644 --- a/libpng-manual.txt +++ b/libpng-manual.txt @@ -1,6 +1,6 @@ libpng-manual.txt - A description on how to use and modify libpng - libpng version 1.7.0beta13 - April 30, 2013 + libpng version 1.7.0beta13 - May 10, 2013 Updated and distributed by Glenn Randers-Pehrson Copyright (c) 1998-2013 Glenn Randers-Pehrson @@ -11,7 +11,7 @@ libpng-manual.txt - A description on how to use and modify libpng Based on: - libpng versions 0.97, January 1998, through 1.7.0beta13 - April 30, 2013 + libpng versions 0.97, January 1998, through 1.7.0beta13 - May 10, 2013 Updated and distributed by Glenn Randers-Pehrson Copyright (c) 1998-2013 Glenn Randers-Pehrson @@ -5021,6 +5021,21 @@ The machine-generated configure files are no longer included in branches libpng16 and later of the GIT repository. They continue to be included in the tarball releases, however. +Libpng-1.6.0 and later use the CMF bytes at the beginning of the IDAT stream +to set the size of the sliding window for reading instead of using the default +32-kbyte sliding window size. It was discovered that there are hundreds of PNG +files in the wild that have incorrect CMF bytes that cause libpng to now issue +a "too far back" error and reject the file. Libpng-1.6.3 provides a way to +revert to the libpng-1.5.x behavior (ignoring the CMF bytes and using a +32-kbyte sliding window), and provides a tool +(contrib/tools/png-fix-too-far-back) for optimizing the CMF bytes +correctly. + +Libpng-1.6.0 and libpng-1.6.1 wrote uncompressed iTXt chunks with the wrong +length, which resulted in PNG files that cannot be read beyond the bad iTXt +chunk. This error was fixed in libpng-1.6.3, and a tool (called +contrib/tools/png-fix-itxt) has been added to the libpng distribution. + XIII. Changes to Libpng from version 1.6.x to 1.7.x Some functions that were deprecated in libpng-1.6.0 were removed: @@ -5215,7 +5230,7 @@ Other rules can be inferred by inspecting the libpng source. XVII. Y2K Compliance in libpng -April 30, 2013 +May 10, 2013 Since the PNG Development group is an ad-hoc body, we can't make an official declaration. diff --git a/libpng.3 b/libpng.3 index 5a73d0cd2..b7100754d 100644 --- a/libpng.3 +++ b/libpng.3 @@ -1,4 +1,4 @@ -.TH LIBPNG 3 "April 30, 2013" +.TH LIBPNG 3 "May 10, 2013" .SH NAME libpng \- Portable Network Graphics (PNG) Reference Library 1.7.0beta13 .SH SYNOPSIS @@ -494,7 +494,7 @@ Following is a copy of the libpng-manual.txt file that accompanies libpng. .SH LIBPNG.TXT libpng-manual.txt - A description on how to use and modify libpng - libpng version 1.7.0beta13 - April 30, 2013 + libpng version 1.7.0beta13 - May 10, 2013 Updated and distributed by Glenn Randers-Pehrson Copyright (c) 1998-2013 Glenn Randers-Pehrson @@ -505,7 +505,7 @@ libpng-manual.txt - A description on how to use and modify libpng Based on: - libpng versions 0.97, January 1998, through 1.7.0beta13 - April 30, 2013 + libpng versions 0.97, January 1998, through 1.7.0beta13 - May 10, 2013 Updated and distributed by Glenn Randers-Pehrson Copyright (c) 1998-2013 Glenn Randers-Pehrson @@ -5516,6 +5516,21 @@ The machine-generated configure files are no longer included in branches libpng16 and later of the GIT repository. They continue to be included in the tarball releases, however. +Libpng-1.6.0 and later use the CMF bytes at the beginning of the IDAT stream +to set the size of the sliding window for reading instead of using the default +32-kbyte sliding window size. It was discovered that there are hundreds of PNG +files in the wild that have incorrect CMF bytes that cause libpng to now issue +a "too far back" error and reject the file. Libpng-1.6.3 provides a way to +revert to the libpng-1.5.x behavior (ignoring the CMF bytes and using a +32-kbyte sliding window), and provides a tool +(contrib/tools/png-fix-too-far-back) for optimizing the CMF bytes +correctly. + +Libpng-1.6.0 and libpng-1.6.1 wrote uncompressed iTXt chunks with the wrong +length, which resulted in PNG files that cannot be read beyond the bad iTXt +chunk. This error was fixed in libpng-1.6.3, and a tool (called +contrib/tools/png-fix-itxt) has been added to the libpng distribution. + .SH XIII. Changes to Libpng from version 1.6.x to 1.7.x Some functions that were deprecated in libpng-1.6.0 were removed: @@ -5710,7 +5725,7 @@ Other rules can be inferred by inspecting the libpng source. .SH XVII. Y2K Compliance in libpng -April 30, 2013 +May 10, 2013 Since the PNG Development group is an ad-hoc body, we can't make an official declaration. @@ -5980,7 +5995,7 @@ possible without all of you. Thanks to Frank J. T. Wojcik for helping with the documentation. -Libpng version 1.7.0beta13 - April 30, 2013: +Libpng version 1.7.0beta13 - May 10, 2013: Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc. Currently maintained by Glenn Randers-Pehrson (glennrp at users.sourceforge.net). @@ -6003,7 +6018,7 @@ this sentence. This code is released under the libpng license. -libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, April 30, 2013, are +libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, May 10, 2013, are Copyright (c) 2004,2006-2007 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.2.5 with the following individual added to the list of Contributing Authors @@ -6102,7 +6117,7 @@ certification mark of the Open Source Initiative. Glenn Randers-Pehrson glennrp at users.sourceforge.net -April 30, 2013 +May 10, 2013 .\" end of man page diff --git a/libpngpf.3 b/libpngpf.3 index d38522177..ff565ed95 100644 --- a/libpngpf.3 +++ b/libpngpf.3 @@ -1,4 +1,4 @@ -.TH LIBPNGPF 3 "April 30, 2013" +.TH LIBPNGPF 3 "May 10, 2013" .SH NAME libpng \- Portable Network Graphics (PNG) Reference Library 1.7.0beta13 (private functions) diff --git a/png.5 b/png.5 index 6b466fba5..dea1235b4 100644 --- a/png.5 +++ b/png.5 @@ -1,4 +1,4 @@ -.TH PNG 5 "April 30, 2013" +.TH PNG 5 "May 10, 2013" .SH NAME png \- Portable Network Graphics (PNG) format .SH DESCRIPTION diff --git a/png.c b/png.c index 39ae975de..8eb6c2bc2 100644 --- a/png.c +++ b/png.c @@ -691,13 +691,13 @@ png_get_copyright(png_const_structrp png_ptr) #else # ifdef __STDC__ return PNG_STRING_NEWLINE \ - "libpng version 1.7.0beta13 - April 30, 2013" PNG_STRING_NEWLINE \ + "libpng version 1.7.0beta13 - May 10, 2013" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2013 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ PNG_STRING_NEWLINE; # else - return "libpng version 1.7.0beta13 - April 30, 2013\ + return "libpng version 1.7.0beta13 - May 10, 2013\ Copyright (c) 1998-2013 Glenn Randers-Pehrson\ Copyright (c) 1996-1997 Andreas Dilger\ Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; diff --git a/png.h b/png.h index 35e7fe5dd..63f8decbb 100644 --- a/png.h +++ b/png.h @@ -1,7 +1,7 @@ /* png.h - header file for PNG reference library * - * libpng version 1.7.0beta13 - April 30, 2013 + * libpng version 1.7.0beta13 - May 10, 2013 * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -11,7 +11,7 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.7.0beta13 - April 30, 2013: Glenn + * libpng versions 0.97, January 1998, through 1.7.0beta13 - May 10, 2013: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -200,7 +200,7 @@ * * This code is released under the libpng license. * - * libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, April 30, 2013, are + * libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, May 10, 2013, are * Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson, and are * distributed according to the same disclaimer and license as libpng-1.2.5 * with the following individual added to the list of Contributing Authors: @@ -312,7 +312,7 @@ * Y2K compliance in libpng: * ========================= * - * April 30, 2013 + * May 10, 2013 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. @@ -380,7 +380,7 @@ /* Version information for png.h - this should match the version in png.c */ #define PNG_LIBPNG_VER_STRING "1.7.0beta13" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.7.0beta13 - April 30, 2013\n" + " libpng version 1.7.0beta13 - May 10, 2013\n" #define PNG_LIBPNG_VER_SONUM 17 #define PNG_LIBPNG_VER_DLLNUM 17 @@ -2916,7 +2916,8 @@ PNG_EXPORT(243, int, png_get_palette_max, (png_const_structrp png_ptr, #ifdef PNG_ARM_NEON_API_SUPPORTED # define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ #endif -#define PNG_OPTION_NEXT 2 /* Next option - numbers must be even */ +#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ +#define PNG_OPTION_NEXT 4 /* Next option - numbers must be even */ /* Return values: NOTE: there are four values and 'off' is *not* zero */ #define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ diff --git a/pngconf.h b/pngconf.h index a75e0d560..a0164b755 100644 --- a/pngconf.h +++ b/pngconf.h @@ -1,7 +1,7 @@ /* pngconf.h - machine configurable file for libpng * - * libpng version 1.7.0beta13 - April 30, 2013 + * libpng version 1.7.0beta13 - May 10, 2013 * * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngpriv.h b/pngpriv.h index 3e137b57d..b6725d223 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -629,6 +629,24 @@ #include "pngstruct.h" #include "pnginfo.h" +/* Validate the include paths - the include path used to generate pnglibconf.h + * must match that used in the build, or we must be using pnglibconf.h.prebuilt: + */ +#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM +# error ZLIB_VERNUM != PNG_ZLIB_VERNUM \ + "-I (include path) error: see the notes in pngpriv.h" + /* This means that when pnglibconf.h was built the copy of zlib.h that it + * used is not the same as the one being used here. Because the build of + * libpng makes decisions to use inflateInit2 and inflateReset2 based on the + * zlib version number and because this affects handling of certain broken + * PNG files the -I directives must match. + * + * The most likely explanation is that you passed a -I in CFLAGS, this will + * not work; all the preprocessor directories and in particular all the -I + * directives must be in CPPFLAGS. + */ +#endif + /* This is used for 16 bit gamma tables -- only the top level pointers are * const; this could be changed: */ diff --git a/pngrutil.c b/pngrutil.c index b82b4ea23..29154e189 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -311,7 +311,7 @@ png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) * chunk apparently owns the stream. Prior to release it does a png_error. */ static int -png_inflate_claim(png_structrp png_ptr, png_uint_32 owner, int window_bits) +png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) { if (png_ptr->zowner != 0) { @@ -346,6 +346,22 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner, int window_bits) */ { int ret; /* zlib return code */ +# if PNG_ZLIB_VERNUM >= 0x1240 + +# if defined(PNG_SET_OPTION_SUPPORTED) && \ + defined(PNG_MAXIMUM_INFLATE_WINDOW) + int window_bits; + + if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == + PNG_OPTION_ON) + window_bits = 15; + + else + window_bits = 0; +# else +# define window_bits 0 +# endif +# endif /* Set this for safety, just in case the previous owner left pointers to * memory allocations. @@ -357,8 +373,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner, int window_bits) if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) { -# if ZLIB_VERNUM < 0x1240 - PNG_UNUSED(window_bits) +# if PNG_ZLIB_VERNUM < 0x1240 ret = inflateReset(&png_ptr->zstream); # else ret = inflateReset2(&png_ptr->zstream, window_bits); @@ -367,7 +382,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner, int window_bits) else { -# if ZLIB_VERNUM < 0x1240 +# if PNG_ZLIB_VERNUM < 0x1240 ret = inflateInit(&png_ptr->zstream); # else ret = inflateInit2(&png_ptr->zstream, window_bits); @@ -385,6 +400,10 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner, int window_bits) return ret; } + +# ifdef window_bits +# undef window_bits +# endif } #ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED @@ -557,14 +576,8 @@ png_decompress_chunk(png_structrp png_ptr, if (limit < *newlength) *newlength = limit; - /* Now try to claim the stream; the 'warn' setting causes zlib to be told - * to use the maximum window size during inflate; this hides errors in the - * deflate header window bits value which is used if '0' is passed. In - * fact this only has an effect with zlib versions 1.2.4 and later - see - * the comments in png_inflate_claim above. - */ - ret = png_inflate_claim(png_ptr, png_ptr->chunk_name, - png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0); + /* Now try to claim the stream. */ + ret = png_inflate_claim(png_ptr, png_ptr->chunk_name); if (ret == Z_OK) { @@ -1334,8 +1347,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { read_length -= keyword_length+2; - if (png_inflate_claim(png_ptr, png_iCCP, - png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0) == Z_OK) + if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK) { Byte profile_header[132]; Byte local_buffer[PNG_INFLATE_BUF_SIZE]; @@ -4412,7 +4424,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) * IDAT stream has a bogus deflate header window_bits value, but this should * not be happening any longer!) */ - if (png_inflate_claim(png_ptr, png_IDAT, 0) != Z_OK) + if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK) png_error(png_ptr, png_ptr->zstream.msg); png_ptr->flags |= PNG_FLAG_ROW_INIT; diff --git a/projects/vstudio/readme.txt b/projects/vstudio/readme.txt index 2cab71007..28050f325 100644 --- a/projects/vstudio/readme.txt +++ b/projects/vstudio/readme.txt @@ -1,7 +1,7 @@ VisualStudio instructions -libpng version 1.7.0beta13 - April 30, 2013 +libpng version 1.7.0beta13 - May 10, 2013 Copyright (c) 1998-2010 Glenn Randers-Pehrson diff --git a/projects/vstudio/zlib.props b/projects/vstudio/zlib.props index 27d0082db..c26c20c6e 100644 --- a/projects/vstudio/zlib.props +++ b/projects/vstudio/zlib.props @@ -2,7 +2,7 @@