Merge branch 'libpng17-20151130' of git://github.com/jbowler/libpng-1 into libpng17

This commit is contained in:
Glenn Randers-Pehrson 2015-12-01 11:20:41 -06:00
commit b427d7216d
11 changed files with 324 additions and 300 deletions

View File

@ -4276,62 +4276,71 @@ make_error(png_store* const ps, png_byte const colour_type,
#undef exception__env #undef exception__env
/* And clear these flags */ /* And clear these flags */
ps->expect_error = 0;
ps->expect_warning = 0; ps->expect_warning = 0;
/* Now write the whole image, just to make sure that the detected, or if (ps->expect_error)
* undetected, errro has not created problems inside libpng. ps->expect_error = 0;
*/
if (png_get_rowbytes(pp, pi) !=
transform_rowsize(pp, colour_type, bit_depth))
png_error(pp, "row size incorrect");
else else
{ {
int npasses = set_write_interlace_handling(pp, interlace_type); /* Now write the whole image, just to make sure that the detected, or
int pass; * undetected, errro has not created problems inside libpng. This
* doesn't work if there was a png_error in png_write_info because that
* can abort before PLTE was written.
*/
if (png_get_rowbytes(pp, pi) !=
transform_rowsize(pp, colour_type, bit_depth))
png_error(pp, "row size incorrect");
if (npasses != npasses_from_interlace_type(pp, interlace_type)) else
png_error(pp, "write: png_set_interlace_handling failed");
for (pass=0; pass<npasses; ++pass)
{ {
png_uint_32 y; int npasses = set_write_interlace_handling(pp, interlace_type);
int pass;
for (y=0; y<h; ++y) if (npasses != npasses_from_interlace_type(pp, interlace_type))
png_error(pp, "write: png_set_interlace_handling failed");
for (pass=0; pass<npasses; ++pass)
{ {
png_byte buffer[TRANSFORM_ROWMAX]; png_uint_32 y;
transform_row(pp, buffer, colour_type, bit_depth, y); for (y=0; y<h; ++y)
{
png_byte buffer[TRANSFORM_ROWMAX];
# if do_own_interlace transform_row(pp, buffer, colour_type, bit_depth, y);
/* If do_own_interlace *and* the image is interlaced we need a
* reduced interlace row; this may be reduced to empty. # if do_own_interlace
*/ /* If do_own_interlace *and* the image is interlaced we
if (interlace_type == PNG_INTERLACE_ADAM7) * need a reduced interlace row; this may be reduced to
{ * empty.
/* The row must not be written if it doesn't exist, notice
* that there are two conditions here, either the row isn't
* ever in the pass or the row would be but isn't wide
* enough to contribute any pixels. In fact the wPass test
* can be used to skip the whole y loop in this case.
*/ */
if (PNG_ROW_IN_INTERLACE_PASS(y, pass) && if (interlace_type == PNG_INTERLACE_ADAM7)
PNG_PASS_COLS(w, pass) > 0) {
interlace_row(buffer, buffer, /* The row must not be written if it doesn't exist,
bit_size(pp, colour_type, bit_depth), w, pass, * notice that there are two conditions here, either the
0/*data always bigendian*/); * row isn't ever in the pass or the row would be but
else * isn't wide enough to contribute any pixels. In fact
continue; * the wPass test can be used to skip the whole y loop
} * in this case.
# endif /* do_own_interlace */ */
if (PNG_ROW_IN_INTERLACE_PASS(y, pass) &&
PNG_PASS_COLS(w, pass) > 0)
interlace_row(buffer, buffer,
bit_size(pp, colour_type, bit_depth), w, pass,
0/*data always bigendian*/);
else
continue;
}
# endif /* do_own_interlace */
png_write_row(pp, buffer); png_write_row(pp, buffer);
}
} }
} } /* image writing */
}
png_write_end(pp, pi); png_write_end(pp, pi);
}
/* The following deletes the file that was just written. */ /* The following deletes the file that was just written. */
store_write_reset(ps); store_write_reset(ps);

View File

@ -727,22 +727,20 @@ png_read_destroy(png_structrp png_ptr)
png_free(png_ptr, png_ptr->read_buffer); png_free(png_ptr, png_ptr->read_buffer);
png_ptr->read_buffer = NULL; png_ptr->read_buffer = NULL;
if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) if (png_ptr->palette != NULL)
{ {
png_free(png_ptr, png_ptr->palette); png_free(png_ptr, png_ptr->palette);
png_ptr->num_palette = 0; png_ptr->num_palette = 0;
png_ptr->palette = NULL; png_ptr->palette = NULL;
} }
png_ptr->free_me &= PNG_BIC_MASK(PNG_FREE_PLTE);
#ifdef PNG_READ_tRNS_SUPPORTED #ifdef PNG_READ_tRNS_SUPPORTED
if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) if (png_ptr->trans_alpha != NULL)
{ {
png_free(png_ptr, png_ptr->trans_alpha); png_free(png_ptr, png_ptr->trans_alpha);
png_ptr->num_trans = 0; png_ptr->num_trans = 0;
png_ptr->trans_alpha = NULL; png_ptr->trans_alpha = NULL;
} }
png_ptr->free_me &= PNG_BIC_MASK(PNG_FREE_TRNS);
#endif #endif
if (png_ptr->zstream.state != NULL) if (png_ptr->zstream.state != NULL)

View File

@ -5985,21 +5985,15 @@ setup_palette_cache(png_structp png_ptr, png_byte cache[8*256])
static void static void
png_remove_PLTE_and_tRNS(png_structrp png_ptr) png_remove_PLTE_and_tRNS(png_structrp png_ptr)
{ {
if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) if (png_ptr->palette != NULL)
{
png_ptr->free_me &= PNG_BIC_MASK(PNG_FREE_PLTE);
png_free(png_ptr, png_ptr->palette); png_free(png_ptr, png_ptr->palette);
}
png_ptr->palette = NULL; png_ptr->palette = NULL;
png_ptr->num_palette = 0; png_ptr->num_palette = 0;
# ifdef PNG_READ_tRNS_SUPPORTED # ifdef PNG_READ_tRNS_SUPPORTED
if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) if (png_ptr->trans_alpha != NULL)
{
png_ptr->free_me &= PNG_BIC_MASK(PNG_FREE_TRNS);
png_free(png_ptr, png_ptr->trans_alpha); png_free(png_ptr, png_ptr->trans_alpha);
}
png_ptr->trans_alpha = NULL; png_ptr->trans_alpha = NULL;
png_ptr->num_trans = 0; png_ptr->num_trans = 0;
@ -6102,13 +6096,10 @@ update_palette(png_structp png_ptr, png_cache_paramsp cp,
* entries were shifted or inverted. This could be fixed, but it would * entries were shifted or inverted. This could be fixed, but it would
* complicate the libpng API to expose the information. * complicate the libpng API to expose the information.
*/ */
png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
png_ptr->free_me |= PNG_FREE_PLTE;
/* Write the transformed palette: */ /* Write the transformed palette: */
{ {
png_colorp palette = png_ptr->palette; png_colorp palette = png_voidcast(png_colorp, png_calloc(png_ptr,
sizeof (png_color[PNG_MAX_PALETTE_LENGTH])));
png_const_bytep p; png_const_bytep p;
const int is_color = (cp->tend.format & PNG_FORMAT_FLAG_COLOR) != 0; const int is_color = (cp->tend.format & PNG_FORMAT_FLAG_COLOR) != 0;
unsigned int i; unsigned int i;
@ -6118,6 +6109,10 @@ update_palette(png_structp png_ptr, png_cache_paramsp cp,
png_byte trans_alpha[PNG_MAX_PALETTE_LENGTH]; png_byte trans_alpha[PNG_MAX_PALETTE_LENGTH];
# endif /* READ_tRNS */ # endif /* READ_tRNS */
memset(palette, 0xFFU, sizeof (png_color[PNG_MAX_PALETTE_LENGTH]));
png_free(png_ptr, png_ptr->palette);
png_ptr->palette = palette;
for (i=0, p=cache.b8; i<cp->tend.width; ++i) for (i=0, p=cache.b8; i<cp->tend.width; ++i)
{ {
if (is_color) if (is_color)
@ -6148,12 +6143,17 @@ update_palette(png_structp png_ptr, png_cache_paramsp cp,
# ifdef PNG_READ_tRNS_SUPPORTED # ifdef PNG_READ_tRNS_SUPPORTED
if (num_trans > 0) if (num_trans > 0)
{ {
png_ptr->trans_alpha = png_voidcast(png_bytep, png_malloc(png_ptr, png_bytep tRNS = png_voidcast(png_bytep, png_malloc(png_ptr,
PNG_MAX_PALETTE_LENGTH)); PNG_MAX_PALETTE_LENGTH));
png_ptr->free_me |= PNG_FREE_TRNS;
memcpy(png_ptr->trans_alpha, trans_alpha, num_trans); memset(tRNS, 0xFFU, PNG_MAX_PALETTE_LENGTH);
memset(png_ptr->trans_alpha+num_trans, 0xFFU,
PNG_MAX_PALETTE_LENGTH-num_trans); if (png_ptr->trans_alpha != NULL)
png_free(png_ptr, png_ptr->trans_alpha);
png_ptr->trans_alpha = tRNS;
memcpy(tRNS, trans_alpha, num_trans);
png_ptr->num_trans = png_check_bits(png_ptr, num_trans, 9); png_ptr->num_trans = png_check_bits(png_ptr, num_trans, 9);
} }
# endif /* READ_tRNS */ # endif /* READ_tRNS */

View File

@ -849,8 +849,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr)
{ {
png_color palette[PNG_MAX_PALETTE_LENGTH]; png_color palette[PNG_MAX_PALETTE_LENGTH];
png_uint_32 length = png_ptr->chunk_length; png_uint_32 length = png_ptr->chunk_length;
int max_palette_length, num, i; png_uint_32 max_palette_length, num, i;
png_colorp pal_ptr;
png_debug(1, "in png_handle_PLTE"); png_debug(1, "in png_handle_PLTE");
@ -878,7 +877,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr)
} }
/* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */
num = (int)length / 3; num = length / 3U;
/* If the palette has 256 or fewer entries but is too large for the bit /* If the palette has 256 or fewer entries but is too large for the bit
* depth, we don't issue an error, to preserve the behavior of previous * depth, we don't issue an error, to preserve the behavior of previous
@ -886,21 +885,21 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr)
* here. * here.
*/ */
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
max_palette_length = (1 << png_ptr->bit_depth); max_palette_length = (1U << png_ptr->bit_depth);
else else
max_palette_length = PNG_MAX_PALETTE_LENGTH; max_palette_length = PNG_MAX_PALETTE_LENGTH;
if (num > max_palette_length) if (num > max_palette_length)
num = max_palette_length; num = max_palette_length;
for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) for (i = 0; i < num; ++i)
{ {
png_byte buf[3]; png_byte buf[3];
png_crc_read(png_ptr, buf, 3); png_crc_read(png_ptr, buf, 3);
pal_ptr->red = buf[0]; palette[i].red = buf[0];
pal_ptr->green = buf[1]; palette[i].green = buf[1];
pal_ptr->blue = buf[2]; palette[i].blue = buf[2];
} }
/* If we actually need the PLTE chunk (ie for a paletted image), we do /* If we actually need the PLTE chunk (ie for a paletted image), we do
@ -911,7 +910,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr)
#ifndef PNG_READ_OPT_PLTE_SUPPORTED #ifndef PNG_READ_OPT_PLTE_SUPPORTED
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
#endif #endif
png_crc_finish(png_ptr, (int) length - num * 3); png_crc_finish(png_ptr, length - num * 3U);
#ifndef PNG_READ_OPT_PLTE_SUPPORTED #ifndef PNG_READ_OPT_PLTE_SUPPORTED
else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
@ -942,16 +941,16 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr)
} }
#endif /* READ_OPT_PLTE */ #endif /* READ_OPT_PLTE */
/* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its
* own copy of the palette. This has the side effect that when png_start_row
* is called (this happens after any call to png_read_update_info) the
* info_ptr palette gets changed. This is extremely unexpected and
* confusing.
*
* Fix this by not sharing the palette in this way.
*/
png_set_PLTE(png_ptr, info_ptr, palette, num); png_set_PLTE(png_ptr, info_ptr, palette, num);
/* Ok, make our own copy since the set succeeded: */
debug(png_ptr->palette == NULL); /* should only get set once */
png_ptr->palette = png_voidcast(png_colorp, png_malloc(png_ptr,
sizeof (png_color[PNG_MAX_PALETTE_LENGTH])));
memset(png_ptr->palette, 0xFFU, sizeof (png_color[PNG_MAX_PALETTE_LENGTH]));
memcpy(png_ptr->palette, info_ptr->palette, 3*num);
png_ptr->num_palette = info_ptr->num_palette;
/* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before
* IDAT. Prior to 1.6.0 this was not checked; instead the code merely * IDAT. Prior to 1.6.0 this was not checked; instead the code merely
* checked the apparent validity of a tRNS chunk inserted before PLTE on a * checked the apparent validity of a tRNS chunk inserted before PLTE on a
@ -1606,10 +1605,13 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr)
static void static void
png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr) png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr)
{ {
png_uint_32 num_trans;
png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
png_debug(1, "in png_handle_tRNS"); png_debug(1, "in png_handle_tRNS");
png_ptr->num_trans = 0U; /* safety */
if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
{ {
/* libpng 1.7.0: this used to be a benign error, but it doesn't look very /* libpng 1.7.0: this used to be a benign error, but it doesn't look very
@ -1633,7 +1635,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr)
} }
png_crc_read(png_ptr, buf, 2); png_crc_read(png_ptr, buf, 2);
png_ptr->num_trans = 1; num_trans = 1U;
png_ptr->trans_color.gray = png_get_uint_16(buf); png_ptr->trans_color.gray = png_get_uint_16(buf);
} }
@ -1648,7 +1650,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr)
} }
png_crc_read(png_ptr, buf, 6); png_crc_read(png_ptr, buf, 6);
png_ptr->num_trans = 1; num_trans = 1U;
png_ptr->trans_color.red = png_get_uint_16(buf); png_ptr->trans_color.red = png_get_uint_16(buf);
png_ptr->trans_color.green = png_get_uint_16(buf + 2); png_ptr->trans_color.green = png_get_uint_16(buf + 2);
png_ptr->trans_color.blue = png_get_uint_16(buf + 4); png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
@ -1656,21 +1658,18 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr)
else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{ {
png_uint_32 length;
/* png_find_chunk_op checks this: */ /* png_find_chunk_op checks this: */
debug(png_ptr->mode & PNG_HAVE_PLTE); debug(png_ptr->mode & PNG_HAVE_PLTE);
length = png_ptr->chunk_length; num_trans = png_ptr->chunk_length;
if (length > png_ptr->num_palette || length == 0) if (num_trans > png_ptr->num_palette || num_trans == 0)
{ {
png_handle_bad_length(png_ptr); png_handle_bad_length(png_ptr);
return; return;
} }
png_crc_read(png_ptr, readbuf, length); png_crc_read(png_ptr, readbuf, num_trans);
png_ptr->num_trans = length & 0x1FF;
} }
else else
@ -1680,20 +1679,22 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr)
} }
if (png_crc_finish(png_ptr, 0)) if (png_crc_finish(png_ptr, 0))
{
png_ptr->num_trans = 0;
return; return;
/* Set it into the info_struct: */
png_set_tRNS(png_ptr, info_ptr, readbuf, num_trans, &png_ptr->trans_color);
/* Now make a copy of the buffer if one is required (palette images). */
debug(png_ptr->trans_alpha == NULL);
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
png_ptr->trans_alpha = png_voidcast(png_bytep,
png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
memset(png_ptr->trans_alpha, 0xFFU, PNG_MAX_PALETTE_LENGTH);
memcpy(png_ptr->trans_alpha, info_ptr->trans_alpha, num_trans);
} }
/* TODO: this is a horrible side effect in the palette case because the png_ptr->num_trans = png_check_bits(png_ptr, num_trans, 9);
* png_struct ends up with a pointer to the tRNS buffer owned by the
* png_info. Fix this.
*/
png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
&(png_ptr->trans_color));
if (info_ptr != NULL)
png_ptr->trans_alpha = info_ptr->trans_alpha;
} }
#else #else
# define png_handle_tRNS NULL # define png_handle_tRNS NULL

View File

@ -533,30 +533,20 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
png_error(png_ptr, "Invalid palette"); png_error(png_ptr, "Invalid palette");
#endif /* MNG_FEATURES */ #endif /* MNG_FEATURES */
/* It may not actually be necessary to set png_ptr->palette here;
* we do it for backward compatibility with the way the png_handle_tRNS
* function used to do the allocation.
*
* 1.6.0: the above statement appears to be incorrect; something has to set
* the palette inside png_struct on read.
*/
png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
/* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
* of num_palette entries, in case of an invalid PNG file or incorrect * of num_palette entries, in case of an invalid PNG file or incorrect
* call to png_set_PLTE() with too-large sample values. * call to png_set_PLTE() with too-large sample values.
*/ */
png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
if (num_palette > 0) if (num_palette > 0)
memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color))); memcpy(info_ptr->palette, palette, num_palette * (sizeof (png_color)));
info_ptr->palette = png_ptr->palette;
info_ptr->num_palette = png_ptr->num_palette = png_check_bits(png_ptr,
num_palette, 9);
info_ptr->num_palette = png_check_bits(png_ptr, num_palette, 9);
info_ptr->free_me |= PNG_FREE_PLTE; info_ptr->free_me |= PNG_FREE_PLTE;
info_ptr->valid |= PNG_INFO_PLTE; info_ptr->valid |= PNG_INFO_PLTE;
} }
@ -962,11 +952,11 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
/* Expect png_set_PLTE to happen before png_set_tRNS, so num_palette will /* Expect png_set_PLTE to happen before png_set_tRNS, so num_palette will
* be set, but this is not a requirement of the API. * be set, but this is not a requirement of the API.
*/ */
if (png_ptr->num_palette) if (info_ptr->num_palette)
max_num = png_ptr->num_palette; max_num = info_ptr->num_palette;
else else
max_num = 1 << png_ptr->bit_depth; max_num = 1 << info_ptr->bit_depth;
if (num_trans > max_num) if (num_trans > max_num)
{ {

View File

@ -370,17 +370,18 @@ struct png_struct_def
* the hope is that such processors will generate code that is both smaller * the hope is that such processors will generate code that is both smaller
* and faster. * and faster.
*/ */
#ifdef PNG_READ_SUPPORTED
png_colorp palette; /* palette from the input file */ png_colorp palette; /* palette from the input file */
#endif /* READ */
#ifdef PNG_READ_tRNS_SUPPORTED #ifdef PNG_READ_tRNS_SUPPORTED
png_bytep trans_alpha; /* alpha values for paletted files */ png_bytep trans_alpha; /* alpha values for paletted files */
#endif #endif /* READ_tRNS */
png_uint_32 width; /* width of image in pixels */ png_uint_32 width; /* width of image in pixels */
png_uint_32 height; /* height of image in pixels */ png_uint_32 height; /* height of image in pixels */
png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */
png_uint_32 chunk_length; /* Length (possibly remaining) in said chunk. */ png_uint_32 chunk_length; /* Length (possibly remaining) in said chunk. */
png_uint_32 crc; /* current chunk CRC value */ png_uint_32 crc; /* current chunk CRC value */
png_uint_32 free_me; /* items libpng is responsible for freeing */
unsigned int flags; /* flags (should be bit fields) */ unsigned int flags; /* flags (should be bit fields) */
unsigned int mode :6; /* where we are in the PNG file */ unsigned int mode :6; /* where we are in the PNG file */
@ -566,7 +567,7 @@ struct png_struct_def
* wherein !(r==g==b). * wherein !(r==g==b).
*/ */
#endif /* RGB_TO_GRAY */ #endif /* RGB_TO_GRAY */
#endif /* TRANFORM_MECH */ #endif /* TRANSFORM_MECH */
#ifdef PNG_READ_SUPPORTED #ifdef PNG_READ_SUPPORTED
/* These, and IDAT_size below, control how much input and output (at most) is /* These, and IDAT_size below, control how much input and output (at most) is
@ -599,12 +600,7 @@ struct png_struct_def
int zlib_set_window_bits; int zlib_set_window_bits;
int zlib_set_mem_level; int zlib_set_mem_level;
int zlib_set_strategy; int zlib_set_strategy;
#endif /* WRITE */
unsigned int zbuffer_start; /* Bytes written from start */
png_uint_32 zbuffer_len; /* Length of data in list */
png_compression_bufferp zbuffer_list; /* Created on demand during write */
png_compression_bufferp *zbuffer_end; /* 'next' field of current buffer */
#endif
/* ERROR HANDLING */ /* ERROR HANDLING */
#ifdef PNG_SETJMP_SUPPORTED #ifdef PNG_SETJMP_SUPPORTED
@ -748,14 +744,23 @@ struct png_struct_def
* zlib expects a 'zstream' as the fundamental control structure, it allows * zlib expects a 'zstream' as the fundamental control structure, it allows
* all the parameters to be passed as one pointer. * all the parameters to be passed as one pointer.
*/ */
png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */
z_stream zstream; /* decompression structure */ z_stream zstream; /* decompression structure */
unsigned int zstream_start:1; /* before first byte of stream */ png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */
unsigned int zstream_ended:1; /* no more zlib output available */ # ifdef PNG_WRITE_SUPPORTED
unsigned int zstream_error:1; /* zlib error message has been output */ png_compression_bufferp zbuffer_list; /* Created on demand during write */
png_compression_bufferp *zbuffer_end; /* 'next' field of current buffer */
png_uint_32 zbuffer_len; /* Length of data in list */
unsigned int zbuffer_start; /* Bytes written from start */
# endif /* WRITE */
# ifdef PNG_READ_SUPPORTED
unsigned int zstream_ended:1; /* no more zlib output available [read] */
unsigned int zstream_error:1; /* zlib error message has been output [read] */
# endif /* READ */
# ifdef PNG_PROGRESSIVE_READ_SUPPORTED
unsigned int zstream_eod :1; /* all the required uncompressed data has been unsigned int zstream_eod :1; /* all the required uncompressed data has been
* received; set by the zstream using code for * received; set by the zstream using code for
* its own purposes. */ * its own purposes. [progressive read] */
# endif /* PROGRESSIVE_READ */
/* MNG SUPPORT */ /* MNG SUPPORT */
#ifdef PNG_MNG_FEATURES_SUPPORTED #ifdef PNG_MNG_FEATURES_SUPPORTED

View File

@ -580,12 +580,13 @@ init_transform_mech(png_structrp png_ptr, png_transform_control *tc, int start)
#ifdef PNG_PALETTE_MAX_SUPPORTED #ifdef PNG_PALETTE_MAX_SUPPORTED
static int static int
set_palette_max(png_structrp png_ptr, png_transformp tr, unsigned int max) set_palette_max(png_structrp png_ptr, png_transformp tr, unsigned int max,
unsigned int format_max)
/* Called whenever a new maximum pixel value is found */ /* Called whenever a new maximum pixel value is found */
{ {
/* One of these must be true: */ /* One of these must be true: */
# ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED # ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
if (max >= png_ptr->num_palette && !png_ptr->palette_index_check_issued) if (max >= tr->args && !png_ptr->palette_index_check_issued)
{ {
# ifdef PNG_READ_SUPPORTED # ifdef PNG_READ_SUPPORTED
# ifdef PNG_WRITE_SUPPORTED # ifdef PNG_WRITE_SUPPORTED
@ -604,7 +605,7 @@ set_palette_max(png_structrp png_ptr, png_transformp tr, unsigned int max)
png_ptr->palette_index_max = png_check_bits(png_ptr, max, 9); png_ptr->palette_index_max = png_check_bits(png_ptr, max, 9);
# endif # endif
if (max == (1U << png_ptr->bit_depth)-1U) if (max == format_max)
{ {
tr->fn = NULL; /* no point continuing once the max has been seen */ tr->fn = NULL; /* no point continuing once the max has been seen */
return 1; /* stop */ return 1; /* stop */
@ -633,7 +634,7 @@ palette_max_1bpp(png_transformp *tr, png_transform_controlp tc)
} }
/* If the code reaches this point there is a set pixel */ /* If the code reaches this point there is a set pixel */
(void)set_palette_max(tc->png_ptr, *tr, 1); (void)set_palette_max(tc->png_ptr, *tr, 1U, 1U);
} }
static void static void
@ -690,7 +691,7 @@ palette_max_2bpp(png_transformp *tr, png_transform_controlp tc)
continue; continue;
/* new_max is greater than max: */ /* new_max is greater than max: */
if (set_palette_max(tc->png_ptr, *tr, new_max)) if (set_palette_max(tc->png_ptr, *tr, new_max, 3U))
return; return;
/* Record new_max: */ /* Record new_max: */
@ -726,7 +727,7 @@ palette_max_4bpp(png_transformp *tr, png_transform_controlp tc)
if (max > (*tr)->args) if (max > (*tr)->args)
{ {
if (set_palette_max(tc->png_ptr, *tr, max)) if (set_palette_max(tc->png_ptr, *tr, max, 15U))
return; return;
(*tr)->args = max; (*tr)->args = max;
@ -752,7 +753,7 @@ palette_max_8bpp(png_transformp *tr, png_transform_controlp tc)
if (max > (*tr)->args) if (max > (*tr)->args)
{ {
if (set_palette_max(tc->png_ptr, *tr, max)) if (set_palette_max(tc->png_ptr, *tr, max, 255U))
return; return;
(*tr)->args = max; (*tr)->args = max;
@ -765,13 +766,19 @@ palette_max_init(png_transformp *tr, png_transform_controlp tc)
# define png_ptr (tc->png_ptr) # define png_ptr (tc->png_ptr)
if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) != 0) if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) != 0)
{ {
if (tc->init == PNG_TC_INIT_FINAL) switch (tc->bit_depth) if (tc->init == PNG_TC_INIT_FINAL)
{ {
case 1: (*tr)->fn = palette_max_1bpp; break; /* Record the palette depth to check here: */
case 2: (*tr)->fn = palette_max_2bpp; break; (*tr)->args = png_ptr->num_palette;
case 4: (*tr)->fn = palette_max_4bpp; break;
case 8: (*tr)->fn = palette_max_8bpp; break; switch (tc->bit_depth)
default:impossible("palette bit depth"); {
case 1: (*tr)->fn = palette_max_1bpp; break;
case 2: (*tr)->fn = palette_max_2bpp; break;
case 4: (*tr)->fn = palette_max_4bpp; break;
case 8: (*tr)->fn = palette_max_8bpp; break;
default:impossible("palette bit depth");
}
} }
} }

View File

@ -1319,14 +1319,6 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,
if (color_type == PNG_COLOR_TYPE_PALETTE) if (color_type == PNG_COLOR_TYPE_PALETTE)
{ {
affirm(num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH); affirm(num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH);
if ((unsigned int)/*SAFE*/num_trans > png_ptr->num_palette)
{
/* This is an error which can only be reliably detected late. */
png_app_error(png_ptr,
"Invalid number of transparent colors specified");
return;
}
{ {
# ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED # ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
union union
@ -1907,9 +1899,146 @@ png_start_IDAT(png_structrp png_ptr)
} }
static void static void
png_compress_IDAT(png_structrp png_ptr, png_const_voidp input, uInt input_len, png_write_IDAT(png_structrp png_ptr, int end_of_image)
int flush)
{ {
png_compression_bufferp *listp = &png_ptr->zbuffer_list;
png_compression_bufferp list;
png_uint_32 output_len = png_ptr->zbuffer_len;
png_uint_32 start = png_ptr->zbuffer_start;
png_uint_32 size = png_ptr->IDAT_size;
const png_uint_32 min_size = (end_of_image ? 1U : size);
affirm(output_len >= min_size);
/* png_struct::zbuffer_end points to the pointer to the next (unused)
* compression buffer. We don't need those blocks to produce output so
* free them now to save space. This also ensures that *zbuffer_end is
* NULL so can be used to store the list head when wrapping the list.
*/
png_free_buffer_list(png_ptr, png_ptr->zbuffer_end);
/* Write at least one chunk, of size 'size', write chunks until
* 'output_len' is less than 'min_size'.
*/
list = *listp;
/* First, if this is the very first IDAT (PNG_HAVE_IDAT not set)
* optimize the CINFO field:
*/
# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
if ((png_ptr->mode & PNG_HAVE_IDAT) == 0U)
{
affirm(start == 0U);
optimize_cmf(list->output, png_image_size(png_ptr));
}
# endif /* WRITE_OPTIMIZE_CMF */
do /* write chunks */
{
/* 'size' is the size of the chunk to write, limited to IDAT_size:
*/
if (size > output_len) /* Z_FINISH */
size = output_len;
debug(size >= min_size);
png_write_chunk_header(png_ptr, png_IDAT, size);
do /* write the data of one chunk */
{
/* The chunk data may be split across multiple compression
* buffers. This loop moves 'list' down the available
* compression buffers.
*/
png_uint_32 avail = PNG_ROW_BUFFER_SIZE - start; /* in *list */
if (avail > output_len) /* valid bytes */
avail = output_len;
if (avail > size) /* bytes needed for chunk */
avail = size;
affirm(list != NULL && avail > 0U &&
start+avail <= PNG_ROW_BUFFER_SIZE);
png_write_chunk_data(png_ptr, list->output+start, avail);
output_len -= avail;
size -= avail;
start += avail;
if (start == PNG_ROW_BUFFER_SIZE)
{
/* End of the buffer. If all the compressed data has been
* consumed (output_len == 0) this will set list to NULL
* because of the png_free_buffer_list call above. At this
* point 'size' should be 0 too and the loop will terminate.
*/
start = 0U;
listp = &list->next;
list = *listp; /* May be NULL at the end */
}
} while (size > 0);
png_write_chunk_end(png_ptr);
size = png_ptr->IDAT_size; /* For the next chunk */
} while (output_len >= min_size);
png_ptr->mode |= PNG_HAVE_IDAT;
png_ptr->zbuffer_len = output_len;
if (output_len > 0U) /* Still got stuff to write */
{
affirm(!end_of_image && list != NULL);
/* If any compression buffers have been completely written move them
* to the end of the list so that they can be re-used and move
* 'list' to the head:
*/
if (listp != &png_ptr->zbuffer_list) /* list not at start */
{
debug(list != png_ptr->zbuffer_list /* obviously */ &&
listp != png_ptr->zbuffer_end /* because *end == NULL */);
*png_ptr->zbuffer_end = png_ptr->zbuffer_list;
*listp = NULL;
png_ptr->zbuffer_list = list;
}
/* 'list' is now at the start, so 'start' can be stored. */
png_ptr->zbuffer_start = start;
png_ptr->zbuffer_len = output_len;
}
else /* output_len == 0U; all compressed data has been written */
{
if (end_of_image)
{
png_ptr->zowner = 0U; /* release z_stream */
png_ptr->mode |= PNG_AFTER_IDAT;
}
/* Else: this is unlikely but possible; the compression code managed
* to exactly fill an IDAT chunk with the data for this block of row
* bytes so nothing is left in the buffer list. Simply reset the
* output pointers to the start of the list. This code is executed
* on Z_FINISH as well just to make the state safe.
*/
png_ptr->zstream.next_out = NULL;
png_ptr->zstream.avail_out = 0U;
png_ptr->zbuffer_start = 0U;
png_ptr->zbuffer_len = 0U;
png_ptr->zbuffer_end = &png_ptr->zbuffer_list;
} /* output_len == 0 */
}
typedef struct
{
png_compression_bufferp *zbuffer_end; /* 'next' field of current buffer */
png_uint_32 zbuffer_len; /* Length of data in list */
} png_IDAT_compression_state;
static int
png_compress_IDAT_test(png_structrp png_ptr, png_IDAT_compression_state *state,
z_stream *zstream, png_const_voidp input, uInt input_len, int flush)
{
png_uint_32 output_len = 0U;
int ret; int ret;
/* The stream must have been claimed: */ /* The stream must have been claimed: */
@ -1919,22 +2048,34 @@ png_compress_IDAT(png_structrp png_ptr, png_const_voidp input, uInt input_len,
* buffer list. next_in must be set here, avail_in comes from the input_len * buffer list. next_in must be set here, avail_in comes from the input_len
* parameter: * parameter:
*/ */
{ zstream->next_in = PNGZ_INPUT_CAST(png_voidcast(const Bytef*, input));
png_uint_32 output_len = 0U; ret = png_compress(png_ptr, zstream, &state->zbuffer_end, input_len,
&output_len, flush);
implies(ret == Z_OK || ret == Z_FINISH, zstream->avail_in == 0U);
zstream->next_in = NULL;
zstream->avail_in = 0U; /* safety */
png_ptr->zstream.next_in = /* If IDAT_size is set to PNG_UINT_31_MAX the length will be larger, but
PNGZ_INPUT_CAST(png_voidcast(const Bytef*,input)); * not enough to overflow a png_uint_32.
ret = png_compress(png_ptr, &png_ptr->zstream, &png_ptr->zbuffer_end, */
input_len, &output_len, flush); state->zbuffer_len += output_len;
implies(ret == Z_OK || ret == Z_FINISH, png_ptr->zstream.avail_in == 0U); return ret;
png_ptr->zstream.next_in = NULL;
png_ptr->zstream.avail_in = 0U; /* safety */
/* If IDAT_size is set to PNG_UINT_31_MAX the length will be larger, but }
* not enough to overflow a png_uint_32.
*/ static void
png_ptr->zbuffer_len += output_len; png_compress_IDAT(png_structp png_ptr, png_const_voidp input, uInt input_len,
} int flush)
{
png_IDAT_compression_state state;
int ret;
state.zbuffer_end = png_ptr->zbuffer_end;
state.zbuffer_len = png_ptr->zbuffer_len;
ret = png_compress_IDAT_test(png_ptr, &state, &png_ptr->zstream, input,
input_len, flush);
png_ptr->zbuffer_end = state.zbuffer_end;
png_ptr->zbuffer_len = state.zbuffer_len;
/* Check the return code. */ /* Check the return code. */
if (ret == Z_OK || ret == Z_STREAM_END) if (ret == Z_OK || ret == Z_STREAM_END)
@ -1956,133 +2097,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_voidp input, uInt input_len,
* written this function call is complete. * written this function call is complete.
*/ */
if (flush == Z_FINISH || png_ptr->zbuffer_len >= png_ptr->IDAT_size) if (flush == Z_FINISH || png_ptr->zbuffer_len >= png_ptr->IDAT_size)
{ png_write_IDAT(png_ptr, flush == Z_FINISH);
png_compression_bufferp *listp = &png_ptr->zbuffer_list;
png_compression_bufferp list;
png_uint_32 output_len = png_ptr->zbuffer_len;
png_uint_32 start = png_ptr->zbuffer_start;
png_uint_32 size = png_ptr->IDAT_size;
const png_uint_32 min_size = (flush == Z_FINISH ? 1U : size);
affirm(output_len >= min_size);
/* png_struct::zbuffer_end points to the pointer to the next (unused)
* compression buffer. We don't need those blocks to produce output so
* free them now to save space. This also ensures that *zbuffer_end is
* NULL so can be used to store the list head when wrapping the list.
*/
png_free_buffer_list(png_ptr, png_ptr->zbuffer_end);
/* Write at least one chunk, of size 'size', write chunks until
* 'output_len' is less than 'min_size'.
*/
list = *listp;
/* First, if this is the very first IDAT (PNG_HAVE_IDAT not set)
* optimize the CINFO field:
*/
# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
if ((png_ptr->mode & PNG_HAVE_IDAT) == 0U)
{
affirm(start == 0U);
optimize_cmf(list->output, png_image_size(png_ptr));
}
# endif /* WRITE_OPTIMIZE_CMF */
do /* write chunks */
{
/* 'size' is the size of the chunk to write, limited to IDAT_size:
*/
if (size > output_len) /* Z_FINISH */
size = output_len;
debug(size >= min_size);
png_write_chunk_header(png_ptr, png_IDAT, size);
do /* write the data of one chunk */
{
/* The chunk data may be split across multiple compression
* buffers. This loop moves 'list' down the available
* compression buffers.
*/
png_uint_32 avail = PNG_ROW_BUFFER_SIZE - start; /* in *list */
if (avail > output_len) /* valid bytes */
avail = output_len;
if (avail > size) /* bytes needed for chunk */
avail = size;
affirm(list != NULL && avail > 0U &&
start+avail <= PNG_ROW_BUFFER_SIZE);
png_write_chunk_data(png_ptr, list->output+start, avail);
output_len -= avail;
size -= avail;
start += avail;
if (start == PNG_ROW_BUFFER_SIZE)
{
/* End of the buffer. If all the compressed data has been
* consumed (output_len == 0) this will set list to NULL
* because of the png_free_buffer_list call above. At this
* point 'size' should be 0 too and the loop will terminate.
*/
start = 0U;
listp = &list->next;
list = *listp; /* May be NULL at the end */
}
} while (size > 0);
png_write_chunk_end(png_ptr);
size = png_ptr->IDAT_size; /* For the next chunk */
} while (output_len >= min_size);
png_ptr->mode |= PNG_HAVE_IDAT;
png_ptr->zbuffer_len = output_len;
if (output_len > 0U) /* Still got stuff to write */
{
affirm(flush != Z_FINISH && list != NULL);
/* If any compression buffers have been completely written move them
* to the end of the list so that they can be re-used and move
* 'list' to the head:
*/
if (listp != &png_ptr->zbuffer_list) /* list not at start */
{
debug(list != png_ptr->zbuffer_list /* obviously */ &&
listp != png_ptr->zbuffer_end /* because *end == NULL */);
*png_ptr->zbuffer_end = png_ptr->zbuffer_list;
*listp = NULL;
png_ptr->zbuffer_list = list;
}
/* 'list' is now at the start, so 'start' can be stored. */
png_ptr->zbuffer_start = start;
png_ptr->zbuffer_len = output_len;
}
else /* output_len == 0U; all compressed data has been written */
{
if (flush == Z_FINISH) /* end of data */
{
png_ptr->zowner = 0U; /* release z_stream */
png_ptr->mode |= PNG_AFTER_IDAT;
}
/* Else: this is unlikely but possible; the compression code managed
* to exactly fill an IDAT chunk with the data for this block of row
* bytes so nothing is left in the buffer list. Simply reset the
* output pointers to the start of the list. This code is executed
* on Z_FINISH as well just to make the state safe.
*/
png_ptr->zstream.next_out = NULL;
png_ptr->zstream.avail_out = 0U;
png_ptr->zbuffer_start = 0U;
png_ptr->zbuffer_len = 0U;
png_ptr->zbuffer_end = &png_ptr->zbuffer_list;
} /* output_len == 0 */
} /* flush == FINISH || png_ptr->zbuffer_len >= png_ptr->IDAT_size */
} }
else /* ret != Z_OK && ret != Z_STREAM_END */ else /* ret != Z_OK && ret != Z_STREAM_END */

View File

@ -496,7 +496,7 @@ option READ_16BIT requires READ enables 16BIT
option READ_TRANSFORMS requires READ option READ_TRANSFORMS requires READ
= NO_READ_TRANSFORMS READ_TRANSFORMS_NOT_SUPPORTED = NO_READ_TRANSFORMS READ_TRANSFORMS_NOT_SUPPORTED
option READ_QUANTIZE requires READ_TRANSFORMS enables TRANFORM_MECH option READ_QUANTIZE requires READ_TRANSFORMS enables TRANSFORM_MECH
# Read gamma handling. Gamma processing is a core part of libpng and many of # Read gamma handling. Gamma processing is a core part of libpng and many of
# the capabilities are dependent on libpng performing gamma correction. # the capabilities are dependent on libpng performing gamma correction.

View File

@ -116,7 +116,6 @@
#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_TEXT_SUPPORTED #define PNG_TEXT_SUPPORTED
#define PNG_TIME_RFC1123_SUPPORTED #define PNG_TIME_RFC1123_SUPPORTED
#define PNG_TRANFORM_MECH_SUPPORTED
#define PNG_TRANSFORM_MECH_SUPPORTED #define PNG_TRANSFORM_MECH_SUPPORTED
#define PNG_UNKNOWN_CHUNKS_SUPPORTED #define PNG_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_USER_CHUNKS_SUPPORTED #define PNG_USER_CHUNKS_SUPPORTED