[libpng16] Made read 'inflate' handling like write 'deflate' handling. The

read code now claims and releases png_ptr->zstream, like the write code.
The bug whereby the progressive reader failed to release the zstream
is now fixed, all initialization is delayed, and the code checks for
changed parameters on deflate rather than always calling
deflatedEnd/deflateInit.
This commit is contained in:
John Bowler 2012-03-05 20:57:40 -06:00 committed by Glenn Randers-Pehrson
parent e2ae0f2f2b
commit 42a2b556e9
10 changed files with 360 additions and 340 deletions

View File

@ -1,5 +1,5 @@
Libpng 1.6.0beta16 - March 4, 2012
Libpng 1.6.0beta16 - March 6, 2012
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.
@ -258,7 +258,7 @@ Version 1.6.0beta15 [March 2, 2012]
without the necessary color data.
Removed whitespace from the end of lines in all source files and scripts.
Version 1.6.0beta16 [March 4, 2012]
Version 1.6.0beta16 [March 6, 2012]
Relocated palette-index checking function from pngrutil.c to pngtrans.c
Added palette-index checking while writing.
Changed png_inflate() and calling routines to avoid overflow problems.
@ -275,6 +275,12 @@ Version 1.6.0beta16 [March 4, 2012]
Added contrib/libtests/tarith.c to test internal arithmetic functions from
png.c. This is a libpng maintainer program used to validate changes to the
internal arithmetic functions.
Made read 'inflate' handling like write 'deflate' handling. The read
code now claims and releases png_ptr->zstream, like the write code.
The bug whereby the progressive reader failed to release the zstream
is now fixed, all initialization is delayed, and the code checks for
changed parameters on deflate rather than always calling
deflatedEnd/deflateInit.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit

View File

@ -4009,7 +4009,7 @@ Version 1.6.0beta15 [March 2, 2012]
without the necessary color data.
Removed whitespace from the end of lines in all source files and scripts.
Version 1.6.0beta16 [March 4, 2012]
Version 1.6.0beta16 [March 6, 2012]
Relocated palette-index checking function from pngrutil.c to pngtrans.c
Added palette-index checking while writing.
Changed png_inflate() and calling routines to avoid overflow problems.
@ -4026,6 +4026,12 @@ Version 1.6.0beta16 [March 4, 2012]
Added contrib/libtests/tarith.c to test internal arithmetic functions from
png.c. This is a libpng maintainer program used to validate changes to the
internal arithmetic functions.
Made read 'inflate' handling like write 'deflate' handling. The read
code now claims and releases png_ptr->zstream, like the write code.
The bug whereby the progressive reader failed to release the zstream
is now fixed, all initialization is delayed, and the code checks for
changed parameters on deflate rather than always calling
deflatedEnd/deflateInit.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit

12
png.c
View File

@ -283,7 +283,6 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
*/
if (png_user_version_check(&create_struct, user_png_ver))
{
/* TODO: delay initializing the zlib structure until it really is
* needed.
*/
@ -309,6 +308,13 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
*png_ptr = create_struct;
/* png_ptr->zstream holds a back-pointer to the png_struct, so
* this can only be done now:
*/
png_ptr->zstream.zalloc = png_zalloc;
png_ptr->zstream.zfree = png_zfree;
png_ptr->zstream.opaque = png_ptr;
/* This is the successful return point */
return png_ptr;
}
@ -762,13 +768,13 @@ png_get_copyright(png_const_structrp png_ptr)
#else
# ifdef __STDC__
return PNG_STRING_NEWLINE \
"libpng version 1.6.0beta16 - March 3, 2012" PNG_STRING_NEWLINE \
"libpng version 1.6.0beta16 - March 6, 2012" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2012 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.6.0beta16 - March 3, 2012\
return "libpng version 1.6.0beta16 - March 6, 2012\
Copyright (c) 1998-2012 Glenn Randers-Pehrson\
Copyright (c) 1996-1997 Andreas Dilger\
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";

View File

@ -766,7 +766,7 @@ png_push_read_IDAT(png_structrp png_ptr)
{
png_ptr->process_mode = PNG_READ_CHUNK_MODE;
if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))
png_error(png_ptr, "Not enough compressed data");
return;
@ -838,6 +838,7 @@ png_push_read_IDAT(png_structrp png_ptr)
png_crc_finish(png_ptr, 0);
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
}
}
@ -854,13 +855,14 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
* handle the uncompressed results.
*/
png_ptr->zstream.next_in = buffer;
/* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */
png_ptr->zstream.avail_in = (uInt)buffer_length;
/* Keep going until the decompressed data is all processed
* or the stream marked as finished.
*/
while (png_ptr->zstream.avail_in > 0 &&
!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))
{
int ret;
@ -871,9 +873,9 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
*/
if (!(png_ptr->zstream.avail_out > 0))
{
png_ptr->zstream.avail_out =
(uInt) PNG_ROWBYTES(png_ptr->pixel_depth,
png_ptr->iwidth) + 1;
/* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */
png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth,
png_ptr->iwidth) + 1);
png_ptr->zstream.next_out = png_ptr->row_buf;
}
@ -891,7 +893,8 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
if (ret != Z_OK && ret != Z_STREAM_END)
{
/* Terminate the decompression. */
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
/* This may be a truncated stream (missing or
* damaged end code). Treat that as a warning.
@ -919,7 +922,8 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
{
/* Extra data. */
png_warning(png_ptr, "Extra compressed data in IDAT");
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
/* Do no more processing; skip the unprocessed
* input check below.
@ -934,7 +938,7 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
/* And check for the end of the stream. */
if (ret == Z_STREAM_END)
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
}
/* All the data should have been processed, if anything

View File

@ -510,36 +510,36 @@ typedef const png_uint_16p * png_const_uint_16pp;
/* Flags for the png_ptr->flags rather than declaring a byte for each one */
#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001
#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002
#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004
#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008
#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010
#define PNG_FLAG_ZLIB_FINISHED 0x0020
#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */
#define PNG_FLAG_ZSTREAM_IN_USE 0x0004 /* Added to libpng-1.6.0 */
#define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */
/* 0x0010 unused */
/* 0x0020 unused */
#define PNG_FLAG_ROW_INIT 0x0040
#define PNG_FLAG_FILLER_AFTER 0x0080
#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100
#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200
#define PNG_FLAG_CRC_CRITICAL_USE 0x0400
#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800
#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */
#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */
#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */
#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */
#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */
#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */
#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000
#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000
#define PNG_FLAG_LIBRARY_MISMATCH 0x20000
#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000
#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000
/* 0x100000 unused */
/* 0x200000 unused */
/* 0x400000 unused */
#define PNG_FLAG_BENIGN_ERRORS_WARN 0x800000 /* Added to libpng-1.4.0 */
#define PNG_FLAG_ZTXT_CUSTOM_STRATEGY 0x1000000 /* 5 lines added */
#define PNG_FLAG_ZTXT_CUSTOM_LEVEL 0x2000000 /* to libpng-1.5.4 */
#define PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL 0x4000000
#define PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS 0x8000000
#define PNG_FLAG_ZTXT_CUSTOM_METHOD 0x10000000
/* 0x20000000 unused */
/* 0x40000000 unused */
#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000
#define PNG_FLAG_LIBRARY_MISMATCH 0x20000
#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000
#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000
#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */
/* 0x200000 unused */
/* 0x400000 unused */
/* 0x800000 unused */
/* 0x1000000 unused */
/* 0x2000000 unused */
/* 0x4000000 unused */
/* 0x8000000 unused */
/* 0x10000000 unused */
/* 0x20000000 unused */
/* 0x40000000 unused */
#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
PNG_FLAG_CRC_ANCILLARY_NOWARN)
@ -734,6 +734,9 @@ extern "C" {
* All of these functions must be declared with PNG_INTERNAL_FUNCTION.
*/
/* Zlib support */
PNG_INTERNAL_FUNCTION(void,png_inflate_claim,(png_structrp png_ptr),PNG_EMPTY);
#if defined PNG_FLOATING_POINT_SUPPORTED &&\
!defined PNG_FIXED_POINT_MACRO_SUPPORTED
PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr,

View File

@ -48,61 +48,14 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
if (png_ptr != NULL)
{
int ok = 0;
/* TODO: why does this happen here on read, but in png_write_IHDR on
* write? If it happened there then there would be no error handling case
* here and png_ptr could be a png_structrp.
/* TODO: delay this, it can be done in png_init_io (if the app doesn't
* do it itself) avoiding setting the default function if it is not
* required.
*/
png_ptr->zstream.zalloc = png_zalloc;
png_ptr->zstream.zfree = png_zfree;
png_ptr->zstream.opaque = png_ptr;
switch (inflateInit(&png_ptr->zstream))
{
case Z_OK:
ok = 1;
break;
case Z_MEM_ERROR:
png_warning(png_ptr, "zlib memory error");
break;
case Z_STREAM_ERROR:
png_warning(png_ptr, "zlib stream error");
break;
case Z_VERSION_ERROR:
png_warning(png_ptr, "zlib version error");
break;
default:
png_warning(png_ptr, "Unknown zlib error");
break;
}
if (ok)
{
png_ptr->zstream.next_out = png_ptr->zbuf;
png_ptr->zstream.avail_out = png_ptr->zbuf_size;
/* TODO: delay this, it can be done in png_init_io (if the app doesn't
* do it itself) avoiding setting the default function if it is not
* required.
*/
png_set_read_fn(png_ptr, NULL, NULL);
return png_ptr;
}
/* Else something went wrong in the zlib initialization above; it would
* much simplify this code if the creation of the zlib stuff was to be
* delayed until it is needed.
*/
png_destroy_read_struct(&png_ptr, NULL, NULL);
png_set_read_fn(png_ptr, NULL, NULL);
}
return NULL;
return png_ptr;
}
@ -471,15 +424,17 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
png_error(png_ptr, "Invalid attempt to read row data");
png_ptr->zstream.next_out = png_ptr->row_buf;
png_ptr->zstream.avail_out =
(uInt)(PNG_ROWBYTES(png_ptr->pixel_depth,
/* TODO: WARNING: BAD NEWS ALERT: this fails, terminally, if the row width is
* bigger than a uInt.
*/
png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth,
png_ptr->iwidth) + 1);
do
{
if (!(png_ptr->zstream.avail_in))
{
while (!png_ptr->idat_size)
while (png_ptr->idat_size == 0)
{
png_crc_finish(png_ptr, 0);
@ -487,7 +442,7 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
if (png_ptr->chunk_name != png_IDAT)
png_error(png_ptr, "Not enough image data");
}
png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
png_ptr->zstream.avail_in = png_ptr->zbuf_size;
png_ptr->zstream.next_in = png_ptr->zbuf;
if (png_ptr->zbuf_size > png_ptr->idat_size)
png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
@ -495,7 +450,11 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
png_ptr->idat_size -= png_ptr->zstream.avail_in;
}
ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
/* Use NO_FLUSH, not SYNC_FLUSH, here because we keep reading data until
* we have a row to process (so leave it to zlib to decide when to flush
* the output.)
*/
ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
if (ret == Z_STREAM_END)
{
@ -503,7 +462,9 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
png_ptr->idat_size)
png_benign_error(png_ptr, "Extra compressed data");
png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
/* Release the stream */
png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
break;
}

View File

@ -277,6 +277,59 @@ png_crc_error(png_structrp png_ptr)
return (0);
}
/* png_inflate_claim: claim the zstream for some nefarious purpose that involves
* decompression.
*/
void /* PRIVATE */
png_inflate_claim(png_structrp png_ptr)
{
/* Implementation note: unlike 'png_deflate_claim' this internal function
* does not take the size of the data as an argument. Some efficiency could
* be gained by using this when it is known *if* the zlib stream itself does
* not record the number, however this is a chimera: the original writer of
* the PNG may have selected a lower window size, and we really must follow
* that because, for systems with with limited capabilities, we would
* otherwise reject the applications attempts to use a smaller window size.
* (zlib doesn't have an interface to say "this or lower"!)
*/
if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_IN_USE))
{
int ret; /* zlib return code */
/* Do this for safety now. */
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)
ret = inflateReset(&png_ptr->zstream);
else
{
ret = inflateInit(&png_ptr->zstream);
if (ret == Z_OK)
png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
}
if (ret == Z_OK)
png_ptr->flags |= PNG_FLAG_ZSTREAM_IN_USE;
else
{
/* A problem; the flags are set ok, but we need a credible error
* message.
*/
if (png_ptr->zstream.msg != NULL)
png_error(png_ptr, png_ptr->zstream.msg);
else
png_error(png_ptr, "zlib initialization error");
}
}
else
png_error(png_ptr, "zstream already in use (internal error)");
}
#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
/* png_inflate: returns one of the following error codes. If output is not NULL
* the uncompressed data is placed there, up to output_size. output_size is
@ -308,15 +361,6 @@ png_inflate(png_structrp png_ptr, png_bytep data, png_uint_32 input_size,
png_alloc_size_t avail_out = *output_size;
png_uint_32 avail_in = input_size;
/* TODO: PROBLEM: png_ptr-zstream is not reset via inflateReset after reading
* the image, consequently the first compressed chunk (zTXt or iTXt) after
* the data gets a 'finished' stream and the first call to inflate returns
* zero decompressed bytes. This was handled silently before 1.6 by
* returning empty uncompressed data. This is a temporary work-round (it's
* harmless if the stream is already reset).
*/
inflateReset(&png_ptr->zstream);
/* zlib can't necessarily handle more than 65535 bytes at once (i.e. it can't
* even necessarily handle 65536 bytes) because the type uInt is "16 bits or
* more". Consequently it is necessary to chunk the input to zlib. This
@ -423,6 +467,7 @@ png_inflate(png_structrp png_ptr, png_bytep data, png_uint_32 input_size,
switch (ret)
{
case Z_STREAM_END:
png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
return PNG_INFLATE_OK;
case Z_BUF_ERROR: /* no progress in zlib */
@ -479,6 +524,8 @@ png_decompress_chunk(png_structrp png_ptr, png_uint_32 chunklength,
*/
png_alloc_size_t limit = PNG_SIZE_MAX;
png_inflate_claim(png_ptr);
# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
if (png_ptr->user_chunk_malloc_max > 0 &&
png_ptr->user_chunk_malloc_max < limit)
@ -532,6 +579,7 @@ png_decompress_chunk(png_structrp png_ptr, png_uint_32 chunklength,
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = (png_charp)text;
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
return NULL;
}
@ -540,10 +588,12 @@ png_decompress_chunk(png_structrp png_ptr, png_uint_32 chunklength,
case PNG_INFLATE_TRUNCATED:
png_free(png_ptr, text);
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
return "libpng inflate error";
default: /* PNG_INFLATE_ERROR */
png_free(png_ptr, text);
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
return (png_const_charp)png_ptr->zbuf;
}
}
@ -556,11 +606,13 @@ png_decompress_chunk(png_structrp png_ptr, png_uint_32 chunklength,
default: /* PNG_INFLATE_ERROR */
/* png_inflate puts the error message in zbuf. */
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
return (png_const_charp)png_ptr->zbuf;
}
}
/* out of memory returns. */
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
return "insufficient memory";
}
#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */
@ -3830,19 +3882,20 @@ png_read_finish_row(png_structrp png_ptr)
}
#endif /* PNG_READ_INTERLACING_SUPPORTED */
if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
/* Here after at the end of the last row of the last pass. */
if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))
{
char extra;
Byte extra;
int ret;
png_ptr->zstream.next_out = (Byte *)&extra;
png_ptr->zstream.avail_out = (uInt)1;
png_ptr->zstream.next_out = &extra;
png_ptr->zstream.avail_out = 1;
for (;;)
{
if (!(png_ptr->zstream.avail_in))
{
while (!png_ptr->idat_size)
while (png_ptr->idat_size == 0)
{
png_crc_finish(png_ptr, 0);
png_ptr->idat_size = png_read_chunk_header(png_ptr);
@ -3850,17 +3903,17 @@ png_read_finish_row(png_structrp png_ptr)
png_error(png_ptr, "Not enough image data");
}
png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
png_ptr->zstream.avail_in = png_ptr->zbuf_size;
png_ptr->zstream.next_in = png_ptr->zbuf;
if (png_ptr->zbuf_size > png_ptr->idat_size)
png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
png_ptr->zstream.avail_in = png_ptr->idat_size;
png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
png_ptr->idat_size -= png_ptr->zstream.avail_in;
}
ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
if (ret == Z_STREAM_END)
{
@ -3868,8 +3921,7 @@ png_read_finish_row(png_structrp png_ptr)
png_ptr->idat_size)
png_warning(png_ptr, "Extra compressed data");
png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
break;
}
@ -3880,11 +3932,8 @@ png_read_finish_row(png_structrp png_ptr)
if (!(png_ptr->zstream.avail_out))
{
png_warning(png_ptr, "Extra compressed data");
png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
break;
}
}
png_ptr->zstream.avail_out = 0;
}
@ -3892,8 +3941,7 @@ png_read_finish_row(png_structrp png_ptr)
if (png_ptr->idat_size || png_ptr->zstream.avail_in)
png_warning(png_ptr, "Extra compression data");
inflateReset(&png_ptr->zstream);
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
png_ptr->mode |= PNG_AFTER_IDAT;
}
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
@ -3921,7 +3969,7 @@ png_read_start_row(png_structrp png_ptr)
png_size_t row_bytes;
png_debug(1, "in png_read_start_row");
png_ptr->zstream.avail_in = 0;
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
png_init_read_transformations(png_ptr);
#endif
@ -4169,6 +4217,9 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
png_debug1(3, "irowbytes = %lu",
(unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
/* Finally claim the zstream for the inflate of the IDAT data. */
png_inflate_claim(png_ptr);
png_ptr->flags |= PNG_FLAG_ROW_INIT;
}
#endif /* PNG_READ_SUPPORTED */

View File

@ -68,20 +68,8 @@ struct png_struct_def
z_stream zstream; /* pointer to decompression structure (below) */
png_bytep zbuf; /* buffer for zlib */
uInt zbuf_size; /* size of zbuf (typically 65536) */
#ifdef PNG_WRITE_SUPPORTED
/* Added in 1.5.4: state to keep track of whether the zstream has been
* initialized and if so whether it is for IDAT or some other chunk.
*/
#define PNG_ZLIB_UNINITIALIZED 0
#define PNG_ZLIB_FOR_IDAT 1
#define PNG_ZLIB_FOR_TEXT 2 /* anything other than IDAT */
#define PNG_ZLIB_USE_MASK 3 /* bottom two bits */
#define PNG_ZLIB_IN_USE 4 /* a flag value */
png_uint_32 zlib_state; /* State of zlib initialization */
/* End of material added at libpng 1.5.4 */
int zlib_level; /* holds zlib compression level */
int zlib_method; /* holds zlib compression method */
int zlib_window_bits; /* holds zlib compression window bits */
@ -89,8 +77,7 @@ struct png_struct_def
int zlib_strategy; /* holds zlib compression strategy */
#endif
/* Added at libpng 1.5.4 */
#if defined(PNG_WRITE_COMPRESSED_TEXT_SUPPORTED) || \
defined(PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED)
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
int zlib_text_level; /* holds zlib compression level */
int zlib_text_method; /* holds zlib compression method */
int zlib_text_window_bits; /* holds zlib compression window bits */
@ -98,6 +85,14 @@ struct png_struct_def
int zlib_text_strategy; /* holds zlib compression strategy */
#endif
/* End of material added at libpng 1.5.4 */
/* Added at libpng 1.6.0 */
#ifdef PNG_WRITE_SUPPORTED
int zlib_set_level; /* Actual values set into the zstream on write */
int zlib_set_method;
int zlib_set_window_bits;
int zlib_set_mem_level;
int zlib_set_strategy;
#endif
png_uint_32 width; /* width of image in pixels */
png_uint_32 height; /* height of image in pixels */

View File

@ -472,6 +472,23 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);
#endif /* PNG_USER_MEM_SUPPORTED */
/* Set the zlib control values to defaults; they can be overridden by the
* application after the struct has been created.
*/
png_ptr->zlib_strategy = Z_FILTERED; /* may be overridden if no filters */
png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
png_ptr->zlib_mem_level = 8;
png_ptr->zlib_window_bits = 15;
png_ptr->zlib_method = 8;
#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY;
png_ptr->zlib_text_level = Z_DEFAULT_COMPRESSION;
png_ptr->zlib_text_mem_level = 8;
png_ptr->zlib_text_window_bits = 15;
png_ptr->zlib_text_method = 8;
#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */
if (png_ptr != NULL)
{
/* TODO: delay this, it can be done in png_init_io() (if the app doesn't
@ -827,7 +844,7 @@ png_write_destroy(png_structrp png_ptr)
png_debug(1, "in png_write_destroy");
/* Free any memory zlib uses */
if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED)
if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)
deflateEnd(&png_ptr->zstream);
/* Free our memory. png_free checks NULL for us. */
@ -1266,7 +1283,6 @@ png_set_compression_level(png_structrp png_ptr, int level)
if (png_ptr == NULL)
return;
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
png_ptr->zlib_level = level;
}
@ -1278,7 +1294,6 @@ png_set_compression_mem_level(png_structrp png_ptr, int mem_level)
if (png_ptr == NULL)
return;
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
png_ptr->zlib_mem_level = mem_level;
}
@ -1290,6 +1305,8 @@ png_set_compression_strategy(png_structrp png_ptr, int strategy)
if (png_ptr == NULL)
return;
/* The flag setting here prevents the libpng dynamic selection of strategy.
*/
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
png_ptr->zlib_strategy = strategy;
}
@ -1303,22 +1320,24 @@ png_set_compression_window_bits(png_structrp png_ptr, int window_bits)
if (png_ptr == NULL)
return;
/* Prior to 1.6.0 this would warn but then set the window_bits value, this
* meant that negative window bits values could be selected which would cause
* libpng to write a non-standard PNG file with raw deflate or gzip
* compressed IDAT or ancilliary chunks. Such files can be read and there is
* no warning on read, so this seems like a very bad idea.
*/
if (window_bits > 15)
{
png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
window_bits = 15;
}
else if (window_bits < 8)
{
png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
window_bits = 8;
}
#ifndef WBITS_8_OK
/* Avoid libpng bug with 256-byte windows */
if (window_bits == 8)
{
png_warning(png_ptr, "Compression window is being reset to 512");
window_bits = 9;
}
#endif
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
png_ptr->zlib_window_bits = window_bits;
}
@ -1330,10 +1349,12 @@ png_set_compression_method(png_structrp png_ptr, int method)
if (png_ptr == NULL)
return;
/* This would produce an invalid PNG file if it worked, but it doesn't and
* deflate will fault it, so it is harmless to just warn here.
*/
if (method != 8)
png_warning(png_ptr, "Only compression method 8 is supported by PNG");
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
png_ptr->zlib_method = method;
}
@ -1347,7 +1368,6 @@ png_set_text_compression_level(png_structrp png_ptr, int level)
if (png_ptr == NULL)
return;
png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_LEVEL;
png_ptr->zlib_text_level = level;
}
@ -1359,7 +1379,6 @@ png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level)
if (png_ptr == NULL)
return;
png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL;
png_ptr->zlib_text_mem_level = mem_level;
}
@ -1371,7 +1390,6 @@ png_set_text_compression_strategy(png_structrp png_ptr, int strategy)
if (png_ptr == NULL)
return;
png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_STRATEGY;
png_ptr->zlib_text_strategy = strategy;
}
@ -1385,21 +1403,17 @@ png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits)
return;
if (window_bits > 15)
{
png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
window_bits = 15;
}
else if (window_bits < 8)
{
png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
window_bits = 8;
}
#ifndef WBITS_8_OK
/* Avoid libpng bug with 256-byte windows */
if (window_bits == 8)
{
png_warning(png_ptr, "Text compression window is being reset to 512");
window_bits = 9;
}
#endif
png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS;
png_ptr->zlib_text_window_bits = window_bits;
}
@ -1414,7 +1428,6 @@ png_set_text_compression_method(png_structrp png_ptr, int method)
if (method != 8)
png_warning(png_ptr, "Only compression method 8 is supported by PNG");
png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_METHOD;
png_ptr->zlib_text_method = method;
}
#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */

View File

@ -214,87 +214,159 @@ png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,
length);
}
/* Initialize the compressor for the appropriate type of compression. */
static void
png_zlib_claim(png_structrp png_ptr, png_uint_32 state)
/* This is used below to find the size of an image to pass to png_deflate_claim,
* so it only needs to be accurate if the size is less than 16384 bytes (the
* point at which a lower LZ window size can be used.)
*/
static png_alloc_size_t
png_image_size(png_structrp png_ptr)
{
if (!(png_ptr->zlib_state & PNG_ZLIB_IN_USE))
/* Only return sizes up to the maximum of a png_uint_32, do this by limiting
* the width and height used to 15 bits.
*/
png_uint_32 h = png_ptr->height;
if (png_ptr->rowbytes < 32768 && h < 32768)
{
/* If already initialized for 'state' do not re-init. */
if (png_ptr->zlib_state != state)
if (png_ptr->interlaced)
{
int ret = Z_OK;
png_const_charp who = "-";
/* Interlacing makes the image larger because of the replication of
* both the filter byte and the padding to a byte boundary.
*/
png_uint_32 w = png_ptr->width;
unsigned int pd = png_ptr->pixel_depth;
png_alloc_size_t cbBase;
int pass;
/* If actually initialized for another state do a deflateEnd. */
if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED)
for (cbBase=0, pass=0; pass<=6; ++pass)
{
ret = deflateEnd(&png_ptr->zstream);
who = "end";
png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED;
png_uint_32 pw = PNG_PASS_COLS(w, pass);
if (pw > 0)
cbBase += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass);
}
/* zlib itself detects an incomplete state on deflateEnd */
if (ret == Z_OK) switch (state)
{
# ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
case PNG_ZLIB_FOR_TEXT:
ret = deflateInit2(&png_ptr->zstream,
png_ptr->zlib_text_level, png_ptr->zlib_text_method,
png_ptr->zlib_text_window_bits,
png_ptr->zlib_text_mem_level, png_ptr->zlib_text_strategy);
who = "text";
break;
# endif
case PNG_ZLIB_FOR_IDAT:
ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
png_ptr->zlib_method, png_ptr->zlib_window_bits,
png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
who = "IDAT";
break;
default:
png_error(png_ptr, "invalid zlib state");
}
if (ret == Z_OK)
png_ptr->zlib_state = state;
else /* an error in deflateEnd or deflateInit2 */
{
size_t pos = 0;
char msg[64];
pos = png_safecat(msg, sizeof msg, pos,
"zlib failed to initialize compressor (");
pos = png_safecat(msg, sizeof msg, pos, who);
switch (ret)
{
case Z_VERSION_ERROR:
pos = png_safecat(msg, sizeof msg, pos, ") version error");
break;
case Z_STREAM_ERROR:
pos = png_safecat(msg, sizeof msg, pos, ") stream error");
break;
case Z_MEM_ERROR:
pos = png_safecat(msg, sizeof msg, pos, ") memory error");
break;
default:
pos = png_safecat(msg, sizeof msg, pos, ") unknown error");
break;
}
png_error(png_ptr, msg);
}
return cbBase;
}
/* Here on success, claim the zstream: */
png_ptr->zlib_state |= PNG_ZLIB_IN_USE;
else
return (png_ptr->rowbytes+1) * h;
}
else
return 0xffffffffU;
}
/* Initialize the compressor for the appropriate type of compression. */
static void
png_deflate_claim(png_structrp png_ptr, int for_IDAT,
png_alloc_size_t data_size)
{
if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_IN_USE))
{
int level = png_ptr->zlib_level;
int method = png_ptr->zlib_method;
int windowBits = png_ptr->zlib_window_bits;
int memLevel = png_ptr->zlib_mem_level;
int strategy; /* set below */
int ret; /* zlib return code */
/* Do this for safety now. */
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
if (for_IDAT)
{
if (png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)
strategy = png_ptr->zlib_strategy;
else if (png_ptr->do_filter != PNG_FILTER_NONE)
strategy = Z_FILTERED;
else
strategy = Z_DEFAULT_STRATEGY;
}
else
{
# ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
level = png_ptr->zlib_text_level;
method = png_ptr->zlib_text_method;
windowBits = png_ptr->zlib_text_window_bits;
memLevel = png_ptr->zlib_text_mem_level;
strategy = png_ptr->zlib_text_strategy;
# else
/* If customization is not supported the values all come from the
* IDAT values except for the strategy, which is fixed to the
* default. (This is the pre-1.6.0 behavior too, although it was
* implemented in a very different way.)
*/
strategy = Z_DEFAULT_STRATEGY;
# endif
}
/* Adjust 'windowBits' down if larger than 'data_size'; to stop this
* happening just pass 32768 as the data_size parameter.
*/
if (data_size <= 256)
windowBits = 8;
else if (data_size <= 16384) /* Else 15 bits required */ for (;;)
{
png_uint_32 test = 1U << (windowBits-1);
if (data_size > test)
break;
--windowBits;
}
/* Check against the previous initialized values, if any. */
if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) &&
(png_ptr->zlib_set_level != level ||
png_ptr->zlib_set_method != method ||
png_ptr->zlib_set_window_bits != windowBits ||
png_ptr->zlib_set_mem_level != memLevel ||
png_ptr->zlib_set_strategy != strategy))
{
if (deflateEnd(&png_ptr->zstream) != Z_OK)
png_warning(png_ptr, "deflateEnd failed (ignored)");
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED;
}
/* Now initialize if required, setting the new parameters, otherwise just
* to a simple reset to the previous parameters.
*/
if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)
ret = deflateReset(&png_ptr->zstream);
else
{
ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,
memLevel, strategy);
if (ret == Z_OK)
png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
}
/* The return code is from either deflateReset or deflateInit2; they have
* pretty much the same set of error codes.
*/
if (ret == Z_OK)
{
/* No problem, so the stream is now 'in use'. */
png_ptr->flags |= PNG_FLAG_ZSTREAM_IN_USE;
}
else
{
/* A problem; the flags are set ok, but we need a credible error
* message.
*/
if (png_ptr->zstream.msg != NULL)
png_error(png_ptr, png_ptr->zstream.msg);
else
png_error(png_ptr, "zlib initialization error");
}
}
else
@ -305,52 +377,10 @@ png_zlib_claim(png_structrp png_ptr, png_uint_32 state)
* error but will not fail.
*/
static void
png_zlib_release(png_structrp png_ptr)
png_deflate_release(png_structrp png_ptr)
{
if (png_ptr->zlib_state & PNG_ZLIB_IN_USE)
{
int ret = deflateReset(&png_ptr->zstream);
png_ptr->zlib_state &= ~PNG_ZLIB_IN_USE;
if (ret != Z_OK)
{
png_const_charp err;
PNG_WARNING_PARAMETERS(p)
switch (ret)
{
case Z_VERSION_ERROR:
err = "version";
break;
case Z_STREAM_ERROR:
err = "stream";
break;
case Z_MEM_ERROR:
err = "memory";
break;
default:
err = "unknown";
break;
}
png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, ret);
png_warning_parameter(p, 2, err);
if (png_ptr->zstream.msg)
err = png_ptr->zstream.msg;
else
err = "[no zlib message]";
png_warning_parameter(p, 3, err);
png_formatted_warning(png_ptr, p,
"zlib failed to reset compressor: @1(@2): @3");
}
}
if (png_ptr->flags & PNG_FLAG_ZSTREAM_IN_USE)
png_ptr->flags &= ~PNG_FLAG_ZSTREAM_IN_USE;
else
png_warning(png_ptr, "zstream not in use (internal error)");
@ -416,7 +446,7 @@ png_text_compress(png_structrp png_ptr,
* data, or if the input string is incredibly large (although this
* wouldn't cause a failure, just a slowdown due to swapping).
*/
png_zlib_claim(png_ptr, PNG_ZLIB_FOR_TEXT);
png_deflate_claim(png_ptr, 0/*!for IDAT*/, text_len);
/* Set up the compression buffers */
/* TODO: the following cast hides a ****CERTAIN**** overflow problem. */
@ -663,7 +693,7 @@ png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp)
(png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out));
/* Reset zlib for another zTXt/iTXt or image data */
png_zlib_release(png_ptr);
png_deflate_release(png_ptr);
}
#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */
@ -819,11 +849,6 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
/* Write the chunk */
png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
/* Initialize zlib with PNG info */
png_ptr->zstream.zalloc = png_zalloc;
png_ptr->zstream.zfree = png_zfree;
png_ptr->zstream.opaque = (voidpf)png_ptr;
if (!(png_ptr->do_filter))
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
@ -834,55 +859,6 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
png_ptr->do_filter = PNG_ALL_FILTERS;
}
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
{
if (png_ptr->do_filter != PNG_FILTER_NONE)
png_ptr->zlib_strategy = Z_FILTERED;
else
png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
}
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
png_ptr->zlib_mem_level = 8;
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
png_ptr->zlib_window_bits = 15;
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
png_ptr->zlib_method = 8;
#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_STRATEGY))
png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY;
if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_LEVEL))
png_ptr->zlib_text_level = png_ptr->zlib_level;
if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL))
png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level;
if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS))
png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits;
if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_METHOD))
png_ptr->zlib_text_method = png_ptr->zlib_method;
#else
png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY;
png_ptr->zlib_text_level = png_ptr->zlib_level;
png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level;
png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits;
png_ptr->zlib_text_method = png_ptr->zlib_method;
#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */
/* Record that the compressor has not yet been initialized. */
png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED;
png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */
}
@ -2103,8 +2079,8 @@ png_write_start_row(png_structrp png_ptr)
png_ptr->usr_width = png_ptr->width;
}
png_zlib_claim(png_ptr, PNG_ZLIB_FOR_IDAT);
png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
png_deflate_claim(png_ptr, 1/*for IDAT*/, png_image_size(png_ptr));
png_ptr->zstream.avail_out = png_ptr->zbuf_size;
png_ptr->zstream.next_out = png_ptr->zbuf;
}
@ -2225,8 +2201,7 @@ png_write_finish_row(png_structrp png_ptr)
png_ptr->zstream.avail_out);
}
png_zlib_release(png_ptr);
png_ptr->zstream.data_type = Z_BINARY;
png_deflate_release(png_ptr);
}
#ifdef PNG_WRITE_INTERLACING_SUPPORTED