[libpng] Rebased on 1.6.47 + "official" APNG patch.

The "official" patch doesn't put the APNG functions in the pngrutil.c
dispatch table like my version did, but my version might've been
a bit broken...
This commit is contained in:
David Korth 2025-04-20 02:27:45 -04:00
parent 301c895d33
commit b6538e24c9
5 changed files with 208 additions and 212 deletions

View File

@ -295,6 +295,5 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
png_byte next_frame_dispose_op;
png_byte next_frame_blend_op;
#endif
};
#endif /* PNGINFO_H */

View File

@ -1,4 +1,3 @@
/* pngpriv.h - private declarations for use inside libpng
*
* Copyright (c) 2018-2024 Cosmin Truta
@ -862,6 +861,7 @@
#define png_zTXt PNG_U32(122, 84, 88, 116)
#ifdef PNG_APNG_SUPPORTED
/* For png_struct.apng_flags: */
#define PNG_FIRST_FRAME_HIDDEN 0x0001U
#define PNG_APNG_APP 0x0002U
@ -1662,36 +1662,36 @@ PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
#ifdef PNG_READ_APNG_SUPPORTED
PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_acTL,(png_structrp png_ptr, png_inforp info_ptr,
PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
png_uint_32 length),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_fcTL,(png_structrp png_ptr, png_inforp info_ptr,
PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
png_uint_32 length),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_fdAT,(png_structrp png_ptr, png_inforp info_ptr,
PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
png_uint_32 length),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(png_handle_result_code,png_ensure_sequence_number,(png_structrp png_ptr,
PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
png_uint_32 length),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structrp png_ptr),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structrp png_ptr,
png_inforp info_ptr),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
png_infop info_ptr),PNG_EMPTY);
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structrp png_ptr),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
#endif /* PNG_READ_APNG_SUPPORTED */
#ifdef PNG_WRITE_APNG_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structrp png_ptr,
PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structrp png_ptr,
PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
png_uint_32 width, png_uint_32 height,
png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den,
png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structrp png_ptr,
PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
png_const_bytep data, png_size_t length),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structrp png_ptr),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structrp png_ptr,
png_inforp info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
#endif /* PNG_WRITE_APNG_SUPPORTED */
#endif /* PNG_APNG_SUPPORTED */

View File

@ -162,6 +162,17 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
break;
}
#ifdef PNG_READ_APNG_SUPPORTED
else if (chunk_name == png_acTL)
png_handle_acTL(png_ptr, info_ptr, length);
else if (chunk_name == png_fcTL)
png_handle_fcTL(png_ptr, info_ptr, length);
else if (chunk_name == png_fdAT)
png_handle_fdAT(png_ptr, info_ptr, length);
#endif
else
png_handle_chunk(png_ptr, info_ptr, length);
}

View File

@ -2735,6 +2735,179 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
# define png_handle_iTXt NULL
#endif
#ifdef PNG_READ_APNG_SUPPORTED
void /* PRIVATE */
png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_byte data[8];
png_uint_32 num_frames;
png_uint_32 num_plays;
png_uint_32 didSet;
png_debug(1, "in png_handle_acTL");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
{
png_error(png_ptr, "Missing IHDR before acTL");
}
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
png_warning(png_ptr, "Invalid acTL after IDAT skipped");
png_crc_finish(png_ptr, length);
return;
}
else if (png_ptr->mode & PNG_HAVE_acTL)
{
png_warning(png_ptr, "Duplicate acTL skipped");
png_crc_finish(png_ptr, length);
return;
}
else if (length != 8)
{
png_warning(png_ptr, "acTL with invalid length skipped");
png_crc_finish(png_ptr, length);
return;
}
png_crc_read(png_ptr, data, 8);
png_crc_finish(png_ptr, 0);
num_frames = png_get_uint_31(png_ptr, data);
num_plays = png_get_uint_31(png_ptr, data + 4);
/* the set function will do error checking on num_frames */
didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
if(didSet)
png_ptr->mode |= PNG_HAVE_acTL;
}
void /* PRIVATE */
png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_byte data[22];
png_uint_32 width;
png_uint_32 height;
png_uint_32 x_offset;
png_uint_32 y_offset;
png_uint_16 delay_num;
png_uint_16 delay_den;
png_byte dispose_op;
png_byte blend_op;
png_debug(1, "in png_handle_fcTL");
png_ensure_sequence_number(png_ptr, length);
if (!(png_ptr->mode & PNG_HAVE_IHDR))
{
png_error(png_ptr, "Missing IHDR before fcTL");
}
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
/* for any frames other then the first this message may be misleading,
* but correct. PNG_HAVE_IDAT is unset before the frame head is read
* i can't think of a better message */
png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
png_crc_finish(png_ptr, length-4);
return;
}
else if (png_ptr->mode & PNG_HAVE_fcTL)
{
png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
png_crc_finish(png_ptr, length-4);
return;
}
else if (length != 26)
{
png_warning(png_ptr, "fcTL with invalid length skipped");
png_crc_finish(png_ptr, length-4);
return;
}
png_crc_read(png_ptr, data, 22);
png_crc_finish(png_ptr, 0);
width = png_get_uint_31(png_ptr, data);
height = png_get_uint_31(png_ptr, data + 4);
x_offset = png_get_uint_31(png_ptr, data + 8);
y_offset = png_get_uint_31(png_ptr, data + 12);
delay_num = png_get_uint_16(data + 16);
delay_den = png_get_uint_16(data + 18);
dispose_op = data[20];
blend_op = data[21];
if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
{
png_warning(png_ptr, "fcTL for the first frame must have zero offset");
return;
}
if (info_ptr != NULL)
{
if (png_ptr->num_frames_read == 0 &&
(width != info_ptr->width || height != info_ptr->height))
{
png_warning(png_ptr, "size in first frame's fcTL must match "
"the size in IHDR");
return;
}
/* The set function will do more error checking */
png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
x_offset, y_offset, delay_num, delay_den,
dispose_op, blend_op);
png_read_reinit(png_ptr, info_ptr);
png_ptr->mode |= PNG_HAVE_fcTL;
}
}
void /* PRIVATE */
png_have_info(png_structp png_ptr, png_infop info_ptr)
{
if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
{
png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
info_ptr->num_frames++;
}
}
void /* PRIVATE */
png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_ensure_sequence_number(png_ptr, length);
/* This function is only called from png_read_end(), png_read_info(),
* and png_push_read_chunk() which means that:
* - the user doesn't want to read this frame
* - or this is an out-of-place fdAT
* in either case it is safe to ignore the chunk with a warning */
png_warning(png_ptr, "ignoring fdAT chunk");
png_crc_finish(png_ptr, length - 4);
PNG_UNUSED(info_ptr)
}
void /* PRIVATE */
png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
{
png_byte data[4];
png_uint_32 sequence_number;
if (length < 4)
png_error(png_ptr, "invalid fcTL or fdAT chunk found");
png_crc_read(png_ptr, data, 4);
sequence_number = png_get_uint_31(png_ptr, data);
if (sequence_number != png_ptr->next_seq_num)
png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
"number found");
png_ptr->next_seq_num++;
}
#endif /* PNG_READ_APNG_SUPPORTED */
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
static int
@ -2997,195 +3170,9 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
*
* ATM just cause unknown handling for all three chunks:
*/
#ifdef PNG_READ_APNG_SUPPORTED
// FIXME: Not static due to use in pngread.c, png_read_frame_head().
png_handle_result_code /* PRIVATE */
png_handle_acTL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte data[8];
png_uint_32 num_frames;
png_uint_32 num_plays;
png_uint_32 didSet;
png_debug(1, "in png_handle_acTL");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
{
png_chunk_benign_error(png_ptr, "Missing IHDR before acTL");
return handled_error;
}
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "Invalid acTL after IDAT skipped");
return handled_error;
}
else if (png_ptr->mode & PNG_HAVE_acTL)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "Duplicate acTL skipped");
return handled_error;
}
else if (length != 8)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "acTL with invalid length skipped");
return handled_error;
}
png_crc_read(png_ptr, data, 8);
png_crc_finish(png_ptr, 0);
num_frames = png_get_uint_31(png_ptr, data);
num_plays = png_get_uint_31(png_ptr, data + 4);
/* the set function will do error checking on num_frames */
didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
if(didSet)
png_ptr->mode |= PNG_HAVE_acTL;
return handled_ok;
}
png_handle_result_code /* PRIVATE */
png_handle_fcTL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte data[22];
png_uint_32 width;
png_uint_32 height;
png_uint_32 x_offset;
png_uint_32 y_offset;
png_uint_16 delay_num;
png_uint_16 delay_den;
png_byte dispose_op;
png_byte blend_op;
png_debug(1, "in png_handle_fcTL");
png_ensure_sequence_number(png_ptr, length);
if (!(png_ptr->mode & PNG_HAVE_IHDR))
{
png_chunk_benign_error(png_ptr, "Missing IHDR before fcTL");
return handled_error;
}
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
/* for any frames other then the first this message may be misleading,
* but correct. PNG_HAVE_IDAT is unset before the frame head is read
* i can't think of a better message */
png_crc_finish(png_ptr, length-4);
png_chunk_benign_error(png_ptr, "Invalid fcTL after IDAT skipped");
return handled_error;
}
else if (png_ptr->mode & PNG_HAVE_fcTL)
{
png_crc_finish(png_ptr, length-4);
png_chunk_benign_error(png_ptr, "Duplicate fcTL within one frame skipped");
return handled_error;
}
else if (length != 26)
{
png_crc_finish(png_ptr, length-4);
png_chunk_benign_error(png_ptr, "fcTL with invalid length skipped");
return handled_error;
}
png_crc_read(png_ptr, data, 22);
png_crc_finish(png_ptr, 0);
width = png_get_uint_31(png_ptr, data);
height = png_get_uint_31(png_ptr, data + 4);
x_offset = png_get_uint_31(png_ptr, data + 8);
y_offset = png_get_uint_31(png_ptr, data + 12);
delay_num = png_get_uint_16(data + 16);
delay_den = png_get_uint_16(data + 18);
dispose_op = data[20];
blend_op = data[21];
if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
{
png_chunk_benign_error(png_ptr, "fcTL for the first frame must have zero offset");
return handled_error;
}
if (info_ptr != NULL)
{
if (png_ptr->num_frames_read == 0 &&
(width != info_ptr->width || height != info_ptr->height))
{
png_chunk_benign_error(png_ptr, "size in first frame's fcTL must match the size in IHDR");
return handled_error;
}
/* The set function will do more error checking */
png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
x_offset, y_offset, delay_num, delay_den,
dispose_op, blend_op);
png_read_reinit(png_ptr, info_ptr);
png_ptr->mode |= PNG_HAVE_fcTL;
}
return handled_ok;
}
void /* PRIVATE */
png_have_info(png_structrp png_ptr, png_inforp info_ptr)
{
if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
{
png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
info_ptr->num_frames++;
}
}
png_handle_result_code /* PRIVATE */
png_handle_fdAT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_ensure_sequence_number(png_ptr, length);
/* This function is only called from png_read_end(), png_read_info(),
* and png_push_read_chunk() which means that:
* - the user doesn't want to read this frame
* - or this is an out-of-place fdAT
* in either case it is safe to ignore the chunk with a warning */
png_crc_finish(png_ptr, length - 4);
png_chunk_benign_error(png_ptr, "ignoring fdAT chunk");
PNG_UNUSED(info_ptr)
return handled_error;
}
png_handle_result_code /* PRIVATE */
png_ensure_sequence_number(png_structrp png_ptr, png_uint_32 length)
{
png_byte data[4];
png_uint_32 sequence_number;
if (length < 4)
{
png_chunk_benign_error(png_ptr, "invalid fcTL or fdAT chunk found");
return handled_error;
}
png_crc_read(png_ptr, data, 4);
sequence_number = png_get_uint_31(png_ptr, data);
if (sequence_number != png_ptr->next_seq_num)
{
png_chunk_benign_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence number found");
return handled_error;
}
png_ptr->next_seq_num++;
return handled_ok;
}
#else
#define png_handle_acTL NULL
#define png_handle_fcTL NULL
#define png_handle_fdAT NULL
#endif /* PNG_READ_APNG_SUPPORTED */
/*
* 1.6.47: This is the new table driven interface to all the chunk handling.
@ -4447,7 +4434,6 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
png_error(png_ptr, "Not enough image data");
}
#endif /* PNG_READ_APNG_SUPPORTED */
avail_in = png_ptr->IDAT_read_size;
if (avail_in > png_chunk_max(png_ptr))
@ -4936,7 +4922,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
* before a new IDAT is read. It resets some parts of png_ptr
* to make them usable by the read functions again */
void /* PRIVATE */
png_read_reset(png_structrp png_ptr)
png_read_reset(png_structp png_ptr)
{
png_ptr->mode &= ~PNG_HAVE_IDAT;
png_ptr->mode &= ~PNG_AFTER_IDAT;
@ -4945,7 +4931,7 @@ png_read_reset(png_structrp png_ptr)
}
void /* PRIVATE */
png_read_reinit(png_structrp png_ptr, png_inforp info_ptr)
png_read_reinit(png_structp png_ptr, png_infop info_ptr)
{
png_ptr->width = info_ptr->next_frame_width;
png_ptr->height = info_ptr->next_frame_height;
@ -4959,7 +4945,7 @@ png_read_reinit(png_structrp png_ptr, png_inforp info_ptr)
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
/* same as png_read_reset() but for the progressive reader */
void /* PRIVATE */
png_progressive_read_reset(png_structrp png_ptr)
png_progressive_read_reset(png_structp png_ptr)
{
#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */

View File

@ -1995,7 +1995,7 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
#ifdef PNG_WRITE_APNG_SUPPORTED
void /* PRIVATE */
png_write_acTL(png_structrp png_ptr,
png_write_acTL(png_structp png_ptr,
png_uint_32 num_frames, png_uint_32 num_plays)
{
png_byte buf[8];
@ -2014,7 +2014,7 @@ png_write_acTL(png_structrp png_ptr,
}
void /* PRIVATE */
png_write_fcTL(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
png_byte blend_op)
@ -2051,7 +2051,7 @@ png_write_fcTL(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
}
void /* PRIVATE */
png_write_fdAT(png_structrp png_ptr,
png_write_fdAT(png_structp png_ptr,
png_const_bytep data, png_size_t length)
{
png_byte buf[4];
@ -2925,7 +2925,7 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
#ifdef PNG_WRITE_APNG_SUPPORTED
void /* PRIVATE */
png_write_reset(png_structrp png_ptr)
png_write_reset(png_structp png_ptr)
{
png_ptr->row_number = 0;
png_ptr->pass = 0;
@ -2933,7 +2933,7 @@ png_write_reset(png_structrp png_ptr)
}
void /* PRIVATE */
png_write_reinit(png_structrp png_ptr, png_inforp info_ptr,
png_write_reinit(png_structp png_ptr, png_infop info_ptr,
png_uint_32 width, png_uint_32 height)
{
if (png_ptr->num_frames_written == 0 &&